大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是恩智浦 i.MXRT1170 的 eFuse 空间访问可靠性保护策略。

 

关于 i.MXRT 系列的 eFuse/OTP,痞子衡之前在介绍 Boot 时写过两篇,分别是针对 RT1050 的《eFuse 及其烧写方法》 和针对 RT600 的《OTP 及其烧写方法》,今天要介绍的 i.MXRT1170 eFuse 其实是这两者的融合,在空间组织上(尤其是 Shadow Register)更像 RT1050,但是在访问可靠性保护策略上又接近 RT600。关于访问可靠性保护策略,痞子衡之前没有提及,今天咱们就展开聊一聊。

 

一、eFuse 基本情况

eFuse 是 i.MXRT1170 内嵌的一块 OTP(One Time Programmable) memory,仅可被烧写一次(这里指的是 bit 位从 0 到 1 不可逆),但可以被多次读取。eFuse memory 的烧写情况根据可靠性保护策略不同而不同。如果被冗余方法保护,那么 eFuse 是按 bit 被烧写的;如果是被 ECC 方法保护的,那么 eFuse 是按 word 被烧写的。

 

i.MXRT1170 的 eFuse memory 用户地址空间有 8Kbit(地址范围为 0x900 - 0x18F0,低 4bit 地址位无效),分为 32 个 BANK,每个 BANK 含 8 个 word(1word = 4bytes)。下图中 0x00 - 0xFF 是 eFuse 的用户 bank word 索引地址,其与 eFuse 空间地址对应关系是:

fuse_address = user_fuse_index * 0x10 + 0x900

 

此外 i.MXRT1170 的 eFuse memory 还有额外的 0.5Kbit 地址空间(范围为 0x800 - 0x8F0,低 4bit 地址位无效),用于存放厂商(NXP)配置以及一些敏感配置,其与 eFuse 空间地址对应关系是:

fuse_address = supp_fuse_index * 0x10

 

不管是 8Kbit 用户空间还是额外的 0.5Kbit 敏感空间,我们都是可以访问的,其 index 其实是统一编址的,下面这个 index 才是真正用于 blhost 工具或者 OCOTP API 的地址参数:

fuse_address = fuse_index * 0x10 + 0x800

 

 

关于 i.MXRT1170 的 eFuse 一般特性(比如 Lock 属性、OCOTP 控制器、Shadow Register)可参考痞子衡在文章开头给出的两篇文章,这里不予赘述。

 

二、eFuse 烧写方法

有三种方法或工具可以帮助烧写 eFuse,我们以烧写和回读 eFuse 地址 0xA80(MAC1_ADDR)为例,将 0x12345678 烧写进 MAC1_ADDR 并回读。根据上面公式我们可以得出 fuse_index = (fuse_address - 0x800) / 0x10 = 0x28,这个 fuse_index 便是底下我们传给烧写工具的地址。

 

2.1 blhost 工具

blhost 是个上位机命令行工具,其能正常工作的前提是预先加载一个特殊 flashloader 程序(\SDK_x.x.x_MIMXRT1170-EVK\boards\evkmimxrt1170\bootloader_examples\flashloader)进 MCU 来实现 eFuse 烧写,flashloader 中集成了 OCOTP 驱动。关于 blhost 使用方法,详见痞子衡 Boot 系列文章,这里仅列出两个命令:

\NXP-MCUBootUtility\tools\blhost2_3\win> .\blhost.exe -u -- efuse-program-once 0x28 12345678
\NXP-MCUBootUtility\tools\blhost2_3\win> .\blhost.exe -u -- efuse-read-once 0x28

 

2.2 OCOTP 驱动

如果你觉得 blhost 工具这一套太复杂,可以直接借助 SDK 包里的 ocotp 例程(\SDK_x.x.x_MIMXRT1170-EVK\boards\evkmimxrt1170\driver_examples\ocotp),代码也是非常简单清晰:

 1#include "fsl_ocotp.h"
 2
 3int main(void)
 4{
 5    status_t status = kStatus_Success;
 6    uint32_t fuseData = 0U;
 7
 8    /* 初始化 OCOTP 模块 */
 9    OCOTP_Init(OCOTP, 0U);
10
11    /* 将 word 数据(0x12345678)写入 fuse index 为 0x28 的 eFuse memory 里 */
12    status = OCOTP_WriteFuseShadowRegister(OCOTP, 0x28, 0x12345678);
13
14    /* 从 fuse index 为 0x28 的 eFuse memory 处读出一个 word*/
15    status = OCOTP_ReadFuseShadowRegisterExt(OCOTP, 0x28, &fuseData, 1);
16}

 

2.3 MCUBootUtility 工具

 

如果你觉得 blhost 使用不友好,OCOTP 驱动又需要改代码和下载运行,那么还有一个工具可以帮到你,那就是痞子衡开发的 MCUBootUtility 图形界面工具,小白都能轻松上手烧写 eFuse:

 

 

三、访问可靠性保护策略

eFuse 的特性其实主要是 OCOTP 模块决定的,翻开 i.MXRT1170 参考手册的 OCOTP 章节的 Features 小节,可以看到其比 RT1050 OCOTP 多了如下这三行:

• Supports ECC mode programming and reading for MTR fuse words by SkyBlue IPS bus
• Supports ECC mode programming and reading for all the user fuse words
• Supports redundancy mode programming and reading for all the supplementary fuse words

 

简单地说就是 eFuse 空间被分成了两类,一类受 ECC 保护,一类受 redundancy(冗余)保护,这是本文要介绍的重点。

 

3.1 冗余保护

redundancy(冗余)保护是比较简单的访问可靠性保护策略,这个策略基本设计思想就是冗余,将 fuse word 一分为二,低 16bit 是用户操作区,高 16bit 是系统冗余区。烧写时用户只需要管低 16bit,高 16bit 则由系统自动完成复制烧写。回读时得到的结果则是低 16bit 与高 16bit 的或(OR)结果。这样的好处就是除非用户操作区(低 16bit)和系统冗余区(高 16bit)均发生错误才会导致访问不可靠。

 

redundancy(冗余)保护虽然一定程度上提高了访问可靠性,但代价是牺牲了一半存储空间,所谓鱼和熊掌不可兼得,这个也是可以理解的。下面这些 eFuse 区域是受 redundancy(冗余)保护的,从功能上看这些区域是按 bit 定义的,功能比较分散,所以存在多次烧写的需求,适用 redundancy(冗余)保护。

 

 

3.2 ECC 保护

ECC 保护是相对复杂的访问可靠性保护策略,ECC 算法是采用经典的 SEC-DED(纠正 1bit,检查 2bit),每个 fuse word 算出一个 ECC 校验值(7bit),这个校验值紧跟着存在 efuse word 后面(bit31:0 是用户区,bit38:32 是 ECC 区),ECC 区无法被用户直接访问。如果在回读时发生 ECC 错误,可在 HW_OCOTP_OUT_STATUS0 寄存器(这是 RT1170 OCOTP 模块新增的寄存器)里如下 bit 找到信息。

 

 

ECC 保护极大地提高了访问可靠性,但综合 eFuse 特点其代价就是整个 fuse word 仅可被烧写一次(即使你一次只改一个 bit)。下面这些 eFuse 区域是受 ECC 保护的,不过从功能上看这些区域功能比较单一,一般都是一次性烧写,所以也适用 ECC 保护。

 

 

至此,恩智浦 i.MXRT1170 的 eFuse 空间访问可靠性保护策略痞子衡便介绍完毕了,掌声在哪里~~~