大家好, 我是痞子衡, 是正经搞技术的痞子. 今天痞子衡给大家介绍的是恩智浦 i.MX RTxxx 系列 MCU 的 OTP.
在 i.MXRTxxx 启动系列第二篇文章 Boot 配置(ISP Pin, OTP) 里痞子衡提到了 OTP, 部分 Boot 配置都存储在 OTP memory 里, 但是对 OTP 的介绍仅仅浅尝辄止, 没有深入, 今天痞子衡就为大家再进一步介绍 OTP.
OTP 是 i.MXRTxxx 里一块特殊的存储区域, 用于存放全部芯片配置信息, 其中有一部分配置信息和 Boot 相关. 这块特殊存储区域并不在 ARM 的 4G system address 空间里, 需要用特殊的方式去访问(读 / 写), 如何访问 OTP 是本篇文章的重点.
一, OTP 基本原理
1.1 OTP 属性(OTP, Shadow Lock)
OTP 本质上就是 i.MXRTxxx 内嵌的一块 One Time Programmable memory, 仅可被烧写一次, 但可以被多次读取. OTP memory 的烧写大部分是按 Word 进行的(也有极少部分是按 Bit 进行的), 初始状态下所有 OTP bit 均为 0, 通过特殊的烧写时序可以将 bit 从 0 改成 1, 一旦某 bit 被烧写成 1 后便再也无法被修改(可理解为硬件熔丝烧断了无法恢复).
i.MXRT600 的 OTP memory 总地址空间有 2KB(Word index 范围为 0x000 - 0x1FF), 分为 64 个 BANK, 每个 BANK 含 8 个 Word(1word = 4bytes).
OTP memory 空间除了 OTP 特性外, 还有 Shadow Lock 控制特性, Shadow Lock 控制是 OTP memory 的标配, Lock 控制有二种: 第一种是 WP, 即写保护, 用于保护 OTP 区域对应的 shadow register 不能被改写; 第二种是 RP, 即读保护, 被保护的 OTP 区域对应的 shadow register 不能被读取. 看到这里, 你会发现 i.MXRTyyyy 的 efuse 里的 LOCK 控制是同时针对 efuse 本身和 shadow register 的; 而 i.MXRTxxx 的 OTP 里的 LOCK 控制仅针对 shadow register, 那么对 OTP 本身的保护在哪里呢? 先别急, 后面会给你答案.
Shadow Lock 控制在 OTP 的 BANK0_word4,BANK1_word8/9, 如下是 RT600 具体 Lock bit 定义:
关于 OTP 空间所有 bit 定义详见 Reference Manual 里的 otpmap Descriptions.
1.2 OCOTP 控制器与 Shadow Register
i.MXRTxxx 内部有一个硬件 IP 模块叫 OCOTP_CTRL, 即 OCOTP 控制器, 对 OTP memory 的读写控制操作其实都是通过这个 OCOTP 控制器实现的, 下图是 OCOTP_CTRL 模块图:
OCOTP_CTRL 模块寄存器一共分两类: 一类是 IP 控制寄存器, 用于实现对 OTP memory 的读写操作时序控制; 一类是 Shadow register, 用于上电时自动从 OTP memory 获取数据并缓存, 这样我们可以直接访问 Shadow register 而不用访问 OTP memory 也能获取 OTP 内容(注意: 当芯片运行中烧写 OTP,Shadow register 的值并不会立刻更新, 需要执行 IP 控制器的 reload 命令或者将芯片 reset 才能同步).
下图是 RT600 里的 OCOTP_CTRL 模块寄存器 map, 其中 Shadow register 寄存器偏移地址范围是 0x000 - 0x7FF(注意并不是所有 OTP Word 都会被加载到 Shadow register 里, 虽然 Shadow register 预留了全部的 OTP 位置. 这点与 i.MXRTyyyy efuse 会全部加载到 Shadow register 不同, 原因是 i.MXRTxxx 的 OTP 里会有很多 Peripheral 寄存器加载初值, 如果这些 OTP 值目的是加载 Peripheral, 那就没有必要再加载到 Shadow register 里, 而 i.MXRTyyyy 的 efuse 值没有加载 Peripheral 寄存器的用途).IP 控制寄存器偏移地址范围是 0x800 - 0x82C:
痞子衡写过关于 i.MXRTyyyy 的 eFUSE 烧写的文章 飞思卡尔 i.MX RTyyyy 系列 MCU 启动那些事 (5)- 再聊 eFUSE 及其烧写方法 , 其实 i.MXRTxxx 的 OCOTP 控制器与 i.MXRTyyyy 里的 OCOTP 控制器非常相似, 虽然两者在寄存器组织上有差异, 但其共同点更多. 不过提及差异, 有一个地方痞子衡不得不提, 那就是 CTRL 寄存器的 bit15, 在 i.MXRTyyyy 上这个 bit 是保留的, 但是 i.MXRTxxx 上这个 bit 为 WORDLOCK, 顾名思义即提供对操作的 OTP Word 区域进行保护(主要是写保护), 下一节介绍的 efuse-program-once 命令第三个可选参数[nolock/lock] 其实就是利用了这个 bit.
二, 使用 blhost 烧写 OTP
OTP memory 的烧写是通过 OCOTP_CTRL 模块来实现的, 我们当然可以在 Application 中集成 OCOTP_CTRL 的驱动程序, 然后在 Application 调用 OCOTP_CTRL 的驱动程序完成 OTP 的烧写, 但这种方式并不是痞子衡要介绍的重点, 痞子衡要介绍的是通过 Serial ISP 模式配套的 blhost.exe 上位机工具实现 OTP 的烧写.
痞子衡在前面的文章里介绍过如何进入 Serial ISP 模式与 BootROM 通信, 此处假设你已经使用 blhost 与 BootROM 建立了通信. 让我们再来回顾一下 blhost 的命令 help, 可以得知 efuse-program-once 这个命令就是我们想要的命令.
- PS D:\NXP-MCUBootUtility\tools\blhost2_3\win> .\blhost.exe
- usage: D:\NXP-MCUBootUtility\tools\blhost2_3\win\blhost.exe
- [-p|--port <name>[,<speed>]]
- [-u|--usb [[[<vid>,]<pid>]]]
- -- command <args...>
- Command:
- efuse-program-once <addr> <data> [nolock/lock]
- Program one Word of OCOTP Field
- <addr> is ADDR of OTP Word, not the shadowed memory address.
- <data> is hex digits without prefix '0x'
- efuse-read-once <addr>
- Read one Word of OCOTP Field
- <addr> is ADDR of OTP Word, not the shadowed memory address.
让我们试一下 efuse-program-once 这个命令, 开始试之前要解决 2 个问题:
addr 参数到底是什么地址? 帮助里说是 OTP Word address, 其实这个地址就是 1.1 节里介绍的 Word index,index 范围为 0x000 - 0x1FF, 对应 512 个可读写操作的 OTP Word.
data 参数到底是什么格式? 帮助里说是 hex digits without prefix '0x', 但是似乎没有指明长度, 我们知道每一个 index 对应的是 4byte, 那就应该是 8 位 16 进制数据(实测下来必须要填 8 位, 如果是非 8 位会返回 Error: invalid command or arguments).
弄清了问题, 那我们做一个小测试: 要求将 OTP 里的 REVOKE_IMG_KEY Word 的最低 byte 烧写成 0x5A. 翻看 OTP Memory Footprint 表, 找到 REVOKE_IMG_KEY 的 index 地址是 0x66(对应 Shadow register 地址是 0x40130198), 命令搞起来:
- PS D:\NXP-MCUBootUtility\tools\blhost2_3\win> .\blhost.exe -u -- efuse-program-once 0x66 0000005A
- Inject command 'efuse-program-once'
- Successful generic response to command 'efuse-program-once'
- Response status = 0 (0x0) Success.
- PS D:\NXP-MCUBootUtility\tools\blhost2_3\win> .\blhost.exe -u -- efuse-read-once 0x66
- Inject command 'efuse-read-once'
- Response status = 0 (0x0) Success.
- Response Word 1 = 4 (0x4)
- Response Word 2 = 90 (0x5a)
看起来命令执行正常, 如果此时你用 J-Link 去读取对应 Shadow register 的值, 你会发现刚才烧写的 OTP 数据并没有自动同步更新到 Shadow register 里. 与 i.MXRTyyyy 系列下 Flashloader 里 efuse program 操作有所不同的是, i.MXRTxxx Serial ISP 模式下 blhost 里的 efuse-program-once 命令仅包含 program 命令, 没有集成 reload 命令. 因此想要刷新 Shadow register, 必须复位芯片.
至此, 恩智浦 i.MX RTxxx 系列 MCU 的 OTP 痞子衡便介绍完毕了, 掌声在哪里~~~
来源: https://www.cnblogs.com/henjay724/p/11995128.html