查看: 5060|回复: 0

[分享] [痞子衡]XECC为串行NOR Flash和SDRAM保驾护航

[复制链接]
  • TA的每日心情
    开心
    2025-7-11 08:53
  • 签到天数: 301 天

    连续签到: 2 天

    [LV.8]以坛为家I

    3942

    主题

    7563

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    40257
    最后登录
    2025-9-10
    发表于 2021-9-6 10:58:14 | 显示全部楼层 |阅读模式
    大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是i.MXRT1170 XECC功能特点及其保护串行NOR Flash和SDRAM之道。


    ECC 是 “Error Correcting Code” 的简写,ECC 能够实现错误检查和纠正,含有 ECC 功能的内存一般称为 ECC 内存,使用了 ECC 内存的系统在稳定性和可靠性上得到很大提升。相比前几代不带 ECC 的 i.MXRT10xx 型号,新一代 i.MXRT1170 在 ECC 上做了全面武装,从 eFuse到 FlexRAM,从 OCRAM 到外部存储空间全都加上了 ECC 功能。如下表所示,不同类型的存储由不同的 ECC 控制器来守护:
    12.png
    今天痞子衡给大家简单介绍一下 i.MXRT1170 上用于保护挂载在 FlexSPI 和 SEMC 接口上的外部存储器的 XECC 功能:


    一、XECC功能简介
    1.1 XECC特点
    从用户角度来说,其实 XECC 的设计特别简单,当 XECC 使能后,任何对 ECC 保护区域的 AHB 访问(注意仅 AHB 方式才能激活 XECC,IPG 方式是不受 XECC 影响的)都会被 XECC 模块接管,WECC 组件负责根据用户写入的数据值产生 ECC 校验值一并存入目标地址,RECC 组件负责根据用户读取的地址获取相应 ECC 检验值并做检验处理后再返回数据值。WECC 和 RECC 组件可独立开关控制。
    13.png
    XECC 模块一共有三个,分别是 XECC_FLEXSPI1、XECC_FLEXSPI2、XECC_SEMC,每个模块均支持 4 个 ECC 区域的设置(区域最小单位 4KB,即 ECC_BASE/EDD_ADDRx 寄存器的低 12bits 总是 0)。
    14.png
    1.2 关于ECC设计细节
    关于 ECC 基本概念,参看《简析i.MXRT1170 Cortex-M7 FlexRAM ECC功能特点、开启步骤、性能影响》 的 1.2节,这里不予赘述。


    1.2.1 ECC检验能力
    XECC 中每 4bits 数据就会计算出一个 ECC 校验值(4bits),不同于 FlexRAM ECC 会有专门的独立存储空间用于存放 ECC 校验值,XECC 校验值是紧跟着放在源数据后面的,这意味着 XECC 校验值会占据目标存储器(Flash 或 SDRAM)里受 ECC 保护区域的一半空间。


    为便于 master 通过 AHB 总线访问,实际 XECC 检验值是拓展到 32bits 来存储的,即 32bits 原始数据后面会紧跟着 32bits XECC 检验值,如此往复如下图所示。
    15.png
    比如 XECC 保护挂在 FlexSPI1 上的 Flash,设置的 Flash ECC 保护区域为 0x30000000 - 0x30000FFF,共 4KB 空间。那么从实际物理空间角度(IPG 方式去读)来说 0x30000000 处保存的是原始 4bytes 用户数据(D0),0x30000004 处保存的是 4bytes XECC 校验值(E0),0x30000008 处保存的又是原始 4bytes 用户数据(D1),0x3000000c 处保存的又是 4bytes XECC 校验值(E1)...


    注意上述地址均表述的是实际物理地址,但 master 通过 AHB 总线直接读写 Flash 时,仅需访问 0x30000000 - 0x300007FF 空间里的 2KB 实际用户数据即可,完全不需在意另外 2KB 的 XECC 检验值的处理,SoC 系统里直接做了自动处理与地址转换,即 0x30000000 处对应校验后的 4bytes 用户数据(D0),0x30000004 处对应校验后的 4bytes 用户数据(D1)...


    1.2.2 ECC错误触发处理
    ECC 错误分两种,分别是 1-bit 错误和 2-bit 错误(针对 4bits 数据而言)。从软件层面来看,1-bit 错误可以不用管,XECC 模块会自动纠错。我们主要处理 2-bit 错误,由于 2-bit 错误仅能检错,无法纠错,所以发生了这个错误,就意味着读取的数据不可靠了。对于 1/2 bit错误,XECC 均提供了中断响应(XECC_xxModule_INT_IRQn / XECC_xxModule_FATAL_INT_IRQn)。


    对于 32bits 数据而言,XECC 是可以纠正其中发生的 8bits 错误的,但前提是按序分割开的每 4bits 数据位仅能有 1bit 错误,如果这 4bits 数据位里有多 bit 错误,我们依然想校正的话,需要借助 Data Swap 功能,这里不再单独展开,可查看 RM 了解细节。
    16.png
    二、开启XECC的步骤
    2.1 激活XECC特性
    芯片出厂,默认是没有激活 XECC 特性的,如果需要开启 XECC,需要烧写 efuse,fusemap 中 0x840[3] 对应的是 XECC_ENABLE bit,我们需要将这个 bit 烧写成 1,才能激活 XECC 特性。
    17.png
    2.2 初始化存储器接口外设

    在初始化 XECC 模块之前一般先初始化存储器接口外设,这里我们先初始化 FlexSPI1,因为测试板卡 MIMXRT1170-EVK 上默认是 FlexSPI1 连接的串行 NOR Flash。
    1. void init_flexspi_flash(void)
    2. {
    3.     flexspi_nor_flash_init(FLEXSPI1);

    4.     // 尽量等待 FlexSPI 总线空闲再退出
    5.     if ((FLEXSPI1->MCR0 & FLEXSPI_MCR0_MDIS_MASK) != FLEXSPI_MCR0_MDIS_MASK)
    6.     {
    7.         while (!FLEXSPI_GetBusIdleStatus(FLEXSPI1));
    8.     }

    9.     FLEXSPI_SoftwareReset(FLEXSPI1);
    10. }
    复制代码
    2.3 SDK驱动初始化XECC
    然后可以直接利用 SDK 里的 fsl_xecc 驱动对 XECC 模块进行初始化,代码非常简单,如下示例代码就是初始化 XECC_FLEXSPI1,使能 0x30000000 - 0x30000FFF 区域的读写 ECC 功能:
    1. #include "fsl_xecc.h"

    2. void init_flexspi_xecc(void)
    3. {
    4.     xecc_config_t config;
    5.     XECC_GetDefaultConfig(&config);

    6.     // 同时使能读写 XECC
    7.     config.enableXECC     = true;
    8.     config.enableWriteECC = true;
    9.     config.enableReadECC  = true;

    10.     // 设置 ECC 区域(0x30000000 - 0x30000FFF)
    11.     config.Region0BaseAddress = FlexSPI1_AMBA_BASE;
    12.     config.Region0EndAddress  = FlexSPI1_AMBA_BASE + 0x1000;

    13.     // 初始化 XECC 模块
    14.     XECC_Init(XECC_FLEXSPI1, config);
    15. }
    复制代码
    2.4 AHB方式读写ECC目标区域
    最后就是利用 《其实i.MXRT下改造FlexSPI driver同样支持AHB方式去写入NOR Flash》 一文 3.3 节里的 flexspi_nor_flash_program() 函数来对 Flash 做 AHB 方式的写入,以激活 XECC 工作。为了验证 XECC 是否工作正常,可以分别用 IPG 和 AHB 方式读回写入的区域看最终结果。
    1. SDK_ALIGN(static uint8_t s_nor_program_buffer[256], 4);
    2. static uint8_t s_nor_ipg_read_buffer[256];
    3. static uint8_t s_nor_ahb_read_buffer[256];

    4. void test_flash_ecc_rw(void)
    5. {
    6.     // 擦除 Flash 0x30000000 开始的 4KB 区域(1个Sector)
    7.     flexspi_nor_flash_erase_sector(FLEXSPI1, 0x0);

    8.     for (uint32_t i = 0; i < 0xFFU; i++)
    9.     {
    10.         s_nor_program_buffer[i] = i;
    11.     }
    12.     // AHB 方式写 256 字节数据进 Flash 0x30000000 开始的地址
    13.     flexspi_nor_flash_program(FLEXSPI1, 0x30000000, s_nor_program_buffer, 256);

    14.     DCACHE_CleanInvalidateByRange(0x30000000, 0x1000);

    15.     // IPG 方式从 Flash 0x30000000 开始的地址读出 256 字节数据
    16.     flexspi_nor_flash_read(FLEXSPI1, 0x0, (void *)s_nor_ipg_read_buffer, 256);

    17.     // AHB 方式从 Flash 0x30000000 开始的地址读出 256 字节数据
    18.     memcpy((void *)s_nor_ahb_read_buffer, (void *)0x30000000, 256);
    19. }
    复制代码
    18.png
    至此,简析i.MXRT1170 XECC功能特点及其保护串行NOR Flash和SDRAM之道痞子衡便介绍完毕了,掌声在哪里~~~









    qiandao qiandao
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-9-10 13:54 , Processed in 0.086205 second(s), 22 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表