大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是恩智浦i.MXRT1170上Cortex-M7内核的FlexRAM ECC功能

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

  今天痞子衡就先给大家简单介绍一下i.MXRT1170上Cortex-M7内核下的FlexRAM ECC功能:

一、FlexRAM ECC功能简介

1.1 FlexRAM v2特点

  i.MXRT1170上的FlexRAM模块是v2版本,相比i.MXRT10xx上的FlexRAM v1版本,主要就是增加了ECC功能。关于FlexRAM v1基本功能,建议你先阅读痞子衡之前写过的文章 《恩智浦i.MX RT1xxx系列MCU外设那些事(2)- 百变星君FlexRAM》,痞子衡今天主要聊v2新增的功能。

  我们知道i.MXRT1170是Cortex-M7和Cortex-M4双核架构,我们看下它的CM7内核系统框图,FlexRAM本质上是为CM7内核设计的,因为其管理的TCM空间仅能由CM7访问的,不过如果将FlexRAM也分配出一部分给OCRAM,这部分OCRAM(即文章开头memory map表里从0x20360000开始的空间)其实CM4也能正常访问。

  在框图中你还会发现,FlexRAM中物理SRAM总大小是640KB,不是我们知道的可自由配置的512KB,这是因为需要额外128KB RAM来存放ECC校验值,关于这个细节在下一节里展开聊。

1.2 关于ECC设计细节

  关于ECC,大家最早接触的应该是ONFI Raw NAND上的应用,NAND Flash因为其物理特性的原因(允许坏块的存在),必须要包含ECC功能,痞子衡写过的一篇文章 《并行NAND接口标准(ONFI)及SLC Raw NAND简介》, 里面的 2.6 Raw NAND坏块与ECC 简单介绍了ECC在Raw NAND上的应用。

  在Raw NAND上,通常是每写入512bytes数据计算出一个ECC校验值(4bytes),读取时也是读完全部512bytes数据后进行ECC校验,ECC校验能力一般用 (n+1) bit检错,n bit纠错 来表达,即这512bytes数据里如果发生n+1 bit及以下的错误时能够检查出来,如果发生n bit及以下的错误时,能够自动纠正。比如典型的Micron MT29F4G08就是5-bit检错,4-bit纠错。

  但是FlexRAM本质上是RAM,跟Flash(尤其是NAND)读写机制不一样,RAM是随机地址按Byte读写,NAND是以Page为单位顺序读写,所以NAND上ECC实现机制不适用于RAM。那么FlexRAM到底采用的是什么样的ECC设计呢?

1.2.1 ECC检验能力

  好了,不卖关子了,公布答案。FlexRAM中每4bytes(针对DTCM)或8bytes(针对ITCM/OCRAM)数据就会计算出一个ECC校验值(7/8bits),ECC校验值都被放在了ECC RAM里。因为校验数据块分割得很小,所以此时不需要提供多bit纠错能力,FlexRAM采用的是最经典的Single-bit Error Correction and Dual-bit Error Detection(SEC-DED,汉明校验码)。关于SEC-DED,你可以去Linux内核里看其在NAND上应用的源码实现 nand_ecc.c,写得非常经典。

存储类型 ECC校验数据块大小 ECC校验值长度 ECC校验能力
Raw NAND 512 bytes 4 bytes 5-bit检错,4-bit纠错
FlexRAM 4/8 bytes 7/8 bits 2-bit检错,1-bit纠错
1.2.2 ECC RAM分配

  128KB ECC RAM并不是只能用来存储ECC校验值的,其也可以当做普通OCRAM来使用,ECC RAM具体功能是根据当前FlexRAM分配以及ECC是否开启而定的。eFuse里默认的512KB FlexRAM配置是256KB ITCM, 256KB DTCM, 没有OCRAM。

  在默认FlexRAM配置情况下,如果TCM ECC没有开启,那么128KB ECC RAM全部都是普通OCRAM,其地址空间如下表所示:

  在默认FlexRAM配置情况下,如果TCM ECC已经开启,那么128KB ECC RAM全部都用来存储ECC校验值,这个区域仅能由FlexRAM模块内部访问,用户无法访问这128KB区域(不在memory map空间里),毕竟ECC校验值不能被随便改。

  如果我们在eFuse或者IOMUXC_GPR寄存器里将FlexRAM配置改掉,分配出一部分给OCRAM(比如256KB TCM, 256KB OCRAM),那这128KB ECC RAM功能分配就稍微复杂一些了。最简单的情况是TCM和OCRAM ECC都没有开启,那么这128KB ECC RAM还是普通OCRAM,map地址是紧跟在FlexRAM OCRAM后面的,如下表所示:

  如果TCM和OCRAM ECC都开启了,那么这128KB ECC RAM就还是全部用来存储ECC校验值了,用户无法访问。

  如果OCRAM ECC没有开启,不管TCM ECC是否开启,这128KB ECC RAM中本用于存储OCRAM ECC的区域都将被划分为普通OCRAM,另一部分用于存储TCM ECC的区域(无论是否真的要存储ECC校验值)用户则无法访问。区域划分比例与OCRAM在总FlexRAM大小中占比保持一致,比如512KB FlexRAM(一共16个bank,每个bank 32KB)划分出了256KB OCRAM,那么128KB ECC RAM(也是16个bank,每个bank 8KB)则划出了64KB作为普通OCRAM,如下表所示:

1.2.3 ECC错误触发处理

  ECC错误分两种,分别是1-bit错误和2-bit错误。从软件层面来看,1-bit错误可以不用管,FlexRAM模块会自动纠错。我们主要处理2-bit错误,由于2-bit错误仅能检错,无法纠错,所以发生了这个错误,就意味着读取的数据不可靠了,需要丢弃并重新写一次(丢弃之前可以再retry read一次看是否还是报错)。

  关于ECC错误处理,可根据如下FlexRAM寄存器来操作,首先当然是在INT_SIG_EN寄存器中使能multi-bit ECC Error,当有2-bit错误发生时,系统会触发FLEXRAM_IRQn(中断号是50),在中断处理程序里找到相应的ECC_MULTI_ERROR_ADDR,对这个地址重新写一次初始化数据(按ECC校验块长度一次性写入),最后清除INT_STATUS寄存器里的相应状态位。

  需要注意的是,上述处理流程仅对FlexRAM中存放的是普通业务数据且发生ECC错误时有效,如果ECC错误发生在关键代码段或变量段中,这个处理是不适用的,因为这种ECC错误可能会造成程序崩溃。

Offset Register
10h Interrupt Status Register (INT_STATUS)
14h Interrupt Status Enable Register (INT_STAT_EN)
18h Interrupt Enable Register (INT_SIG_EN)
30h OCRAM multi-bit ECC Error Address Register (OCRAM_ECC_MULTI_ERROR_ADDR)
50h ITCM multi-bit ECC Error Address Register (ITCM_ECC_MULTI_ERROR_ADDR)
6Ch D0TCM multi-bit ECC Error Address Register (D0TCM_ECC_MULTI_ERROR_ADDR)
84h D1TCM multi-bit ECC Error Address Register (D1TCM_ECC_MULTI_ERROR_ADDR)

二、开启FlexRAM ECC的步骤

  FlexRAM ECC需要按照标准步骤去开启,需要特别注意的是开启ECC操作的代码不能放在待开启ECC的FlexRAM空间里(比如TCM ECC要开启,那么开启ECC操作的代码不能使用任何TCM空间),因此不管是XIP还是Non-XIP应用程序,最好是用一个二级loader(这个loader可以链接在固定OCRAM1/2空间里,或者XIP)来完成ECC开启操作然后再加载应用程序执行。痞子衡给了如下示例loader代码工程,代码里主要有四个步骤:

参考代码:https://github.com/JayHeng/cortex-m-apps/blob/master/apps/coremark_imxrt1176/cm7_loader/loader.c

2.1 使能TCM的RMW(可选)

  如果需要开启TCM ECC,那么首先需要在CM7内核寄存器里开启TCM RMW(Read-Modify-Write)功能,这是ARM的规定,可在 Cortex-M7 Technical RM 手册里找到相关信息如下。手册里明确写了RMW位同时也控制了外部逻辑(即MCU厂商的设计)来支持ECC功能。

  操作函数代码如下:

void enable_cm7_tcm_rmw(void)
{
SCB->ITCMCR |= SCB_ITCMCR_RMW_Msk;
SCB->DTCMCR |= SCB_DTCMCR_RMW_Msk;
}

2.2 使能FlexRAM的ECC

  现在需要开启FlexRAM ECC,在i.MXRT1170参考手册里的FlexRAM章节可以找到FLEXRAM_CTRL寄存器定义,其中bit5和bit4就是用来分别控制TCM和OCRAM的ECC开关。

  操作函数代码如下:

void enable_flexram_tcm_ecc(void)
{
*(uint32_t *)(FLEXRAM_BASE + 0x108) |= (1u << 5);
} void enable_flexram_ocram_ecc(void)
{
*(uint32_t *)(FLEXRAM_BASE + 0x108) |= (1u << 4);
}

2.3 初始化FlexRAM的ECC值

  FlexRAM ECC开启了之后,此时还不能随机访问FlexRAM,因为初始ECC校验值还没有填充,如果这时候去读FlexRAM会产生错误。我们首先需要将会用到的FlexRAM空间全部初始化一遍(就是以ECC校验数据块大小对齐方式从头到尾写入一遍,写入内容不限,正常用全0)。

  操作函数代码如下:

#define ITCM_START   0x00000000
#define ITCM_SIZE (256*1024U) //只是示例长度,根据实际情况修改
#define DTCM_START 0x20000000
#define DTCM_SIZE (256*1024U) //只是示例长度,根据实际情况修改
#define OCRAM_START 0x20360000
#define OCRAM_SIZE (256*1024U) //只是示例长度,根据实际情况修改 void init_flexram_itcm_ecc(void)
{
for (uint32_t i = 0; i < ITCM_SIZE; i += sizeof(uint64_t))
{
*(uint64_t *)(ITCM_START + i) = 0;
}
} void init_flexram_dtcm_ecc(void)
{
for (uint32_t i = 0; i < DTCM_SIZE; i += sizeof(uint32_t))
{
*(uint32_t *)(DTCM_START + i) = 0;
}
} void init_flexram_ocram_ecc(void)
{
for (uint32_t i = 0; i < OCRAM_SIZE; i += sizeof(uint64_t))
{
*(uint64_t *)(OCRAM_START + i) = 0;
}
}

2.4 加载应用程序执行

  当FlexRAM初始ECC校验值已经被填充之后,此时便可以正常随机读写FlexRAM了。如果此时加载的是一个在ITCM里执行并且data段在DTCM里的应用程序,可以参考痞子衡前面给出的示例loader工程。

  这是loader工程完整主函数代码,其中memcpy那一句代码里的cm7_app_code是应用程序binary数组(用Python脚本将应用程序工程生成的.bin文件转换成C语言数组放到loader工程源文件里)。

#define APP_START 0U

int main(void)
{
enable_cm7_tcm_ecc();
enable_flexram_tcm_ecc();
init_flexram_itcm_ecc();
init_flexram_dtcm_ecc(); // Copy image to RAM.
memcpy((void *)APP_START, cm7_app_code, APP_LEN); uint32_t appStack = *(uint32_t *)(APP_START);
uint32_t appEntry = *(uint32_t *)(APP_START + 4); // Turn off interrupts.
__disable_irq(); // Set the VTOR to default.
SCB->VTOR = APP_START; // Memory barriers for good measure.
__ISB();
__DSB(); // Set main stack pointer and process stack pointer.
__set_MSP(appStack);
__set_PSP(appStack); // Jump to app entry point, does not return.
void (*entry)(void) = (void (*)(void))appEntry;
entry();
}

三、ECC对内存访问性能的影响

  FlexRAM开了ECC后,访问性能会有一定降低,毕竟数据访问中插入了额外的ECC校验工作,不过这个影响非常小,因为一次ECC校验仅增加1-2个机器cycle。下面是FlexRAM分配出的不同存储类型的基本情况,其中OCRAM可以被L1 Cache加速,所以从应用程序角度开ECC对其访问性能影响就更小了,我们主要讨论ECC对TCM性能的影响。

FlexRAM分配类型 ECC校验数据块大小 总线类型 访问速度 L1 Cache加速
ITCM 8 bytes ITCM_ITF 64-bits 与CM7同频
DTCM 4 bytes DTCM_ITF 2x32-bit 与CM7同频
OCRAM 8 bytes AXI64 与CM7频率的1/4

  为了简化测试,痞子衡就用经典的benchmark程序(Coremark和Dhrystone)来测试ECC对TCM的影响,测试工程如下:

Coremark工程:https://github.com/JayHeng/cortex-m-apps/tree/master/apps/coremark_imxrt1176/bsp/build7804_cm7_loader

Dhrystone工程:https://github.com/JayHeng/cortex-m-apps/tree/master/apps/dhrystone_imxrt1176/bsp/build8402_cm7_loader

  需要特别提醒的是,我们知道i.MXRT1170 CM7内核最高可以配置到1GHz,但是开了TCM ECC后,为了保证访问可靠性,此时CM7内核最好是工作在800MHz,下面的benchmark结果也是在800MHz主频下得到的:

Benchmark类型 TCM ECC开关 Benchmark结果
coremark 关闭 Total ticks : 2023600

Total time (secs): 20.236000

Iterations/Sec : 3953.350465

Iterations : 80000

CoreMark 1.0 : 3953.350465
coremark 开启 Total ticks : 2023657

Total time (secs): 20.236570

Iterations/Sec : 3953.239111

Iterations : 80000

CoreMark 1.0 : 3953.239111
dhrystone 关闭 Dhrystones per Second: 3622138.51

DMIPS: 2061.5472

DMIPS/MHz: 2.0698
dhrystone 开启 Dhrystones per Second: 3621977.04

DMIPS: 2061.4553

DMIPS/MHz: 2.0697

  从benchmark结果来看,ECC是否开启对性能影响特别小,可以忽略,当然benchmark测试并不是特别精确地反映了性能影响,底下有空痞子衡会再专门用memcpy函数来测试性能影响。

  至此,恩智浦i.MXRT1170上Cortex-M7内核的FlexRAM ECC功能痞子衡便介绍完毕了,掌声在哪里~~~

欢迎订阅

文章会同时发布到我的 博客园主页CSDN主页微信公众号 平台上。

微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。

痞子衡嵌入式:简析i.MXRT1170 Cortex-M7 FlexRAM ECC功能特点、开启步骤、性能影响的更多相关文章

  1. 痞子衡嵌入式:揭秘i.MXRT1170 eFuse空间访问可靠性的保护策略(冗余与ECC)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是恩智浦i.MXRT1170的eFuse空间访问可靠性保护策略. 关于i.MXRT系列的eFuse/OTP,痞子衡之前在介绍Boot时写过 ...

  2. 痞子衡嵌入式:在i.MXRT1170上启动含DQS的Octal Flash可不严格设Dummy Cycle (以MT35XU512为例)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是Octal或Hyper Flash上DQS信号与Dummy Cycle联系. 关于在 i.MXRT 上启动 NOR Flash 时如何设 ...

  3. 痞子衡嵌入式:揭秘i.MXRT1170上用J-Link连接复位后PC总是停在0x223104的原因

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1170上安全调试策略实现对JLink调试的影响. 痞子衡之前写过一篇旧文 <i.MXRT600的ISP模式下用J-L ...

  4. 痞子衡嵌入式:揭秘i.MXRT1170上串行NOR Flash双程序可交替启动设计

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1170上串行NOR Flash双程序可交替启动设计. 在上一篇文章 <i.MXRT1060/1010上串行NOR F ...

  5. 痞子衡嵌入式:聊聊i.MXRT1170双核下不同GPIO组的访问以及中断设计

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1170双核下不同GPIO组的访问以及中断设计. 在双核 i.MXRT1170 下设计应用程序,有一个比较重要的考虑点就是外 ...

  6. 痞子衡嵌入式:简析i.MXRT1170 Cortex-M4 L-MEM ECC功能特点、开启步骤、性能影响

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是恩智浦i.MXRT1170上Cortex-M4内核的L-MEM ECC功能. 本篇是 <简析i.MXRT1170 Cortex-M ...

  7. 痞子衡嵌入式:简析i.MXRT1170 XECC功能特点及其保护串行NOR Flash和SDRAM之道

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是i.MXRT1170 XECC功能特点及其保护串行NOR Flash和SDRAM之道. ECC 是 "Error Correc ...

  8. 痞子衡嵌入式:测一测i.MXRT1170 Raw NAND启动时间(从POR到进App的Reset_Handler)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是恩智浦i.MX RT1170 Raw NAND启动时间. 关于i.MXRT1170这颗划时代的MCU,痞子衡去年10月在其刚发布的时候, ...

  9. 痞子衡嵌入式:大话双核i.MXRT1170之Cortex-M7与Cortex-M4互相激活之道

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是恩智浦i.MXRT1170上Cortex-M7与Cortex-M4内核互相激活的方法. 痞子衡最近在深耕i.MXRT1170这颗划时代的 ...

随机推荐

  1. A. Reorder the Array

    You are given an array of integers. Vasya can permute (change order) its integers. He wants to do it ...

  2. new Date在IOS下面的兼容问题

    此问题坑爹啊,着实坑爹,要不是本宝宝鬼机灵再次进行了测试,不然测试都测不出来的问题,问题源头,有两个时间: let start =  "2018-08-08 00:00:00" ; ...

  3. 如何学习kafka?

      本文是我学习kafka的一个思路和总结,希望对刚接触kafka的你有所帮助.在学习kafka之前,最好能对kafka有一个简单的了解,可以提出一些问题,带着问题去学习,就会容易一些. 0 什么是k ...

  4. linux使用php动态安装模块mysqli.so(ext/mysqlnd/mysqlnd.h: 没有那个文件或目录)

    由于我先安装的php,再安装的mysql! 正常过程: 1.安装mysql 2.安装php configure时带–with-mysql参数 现在我不想重装,因此使用phpize动态安装mysqli, ...

  5. 单片机基础——使用GPIO输出点亮一个LED灯

    1. 准备工作 硬件准备 开发板首先需要准备一个小熊派IoT开发板,并通过USB线与电脑连接. 软件准备 需要安装好Keil - MDK及芯片对应的包,以便编译和下载生成的代码,可参考MDK安装教程 ...

  6. django 从零开始 9 自定义密码验证加密

    先上想法,想对数据库账号的密码进行一个加密,但是django文档中的加密方法set_password貌似是只针对他们默认的user模型 或者继承 AbstractBaseUser的模型有效 from ...

  7. 程序员过关斩将-- 喷一喷坑爹的面向UI编程

    摒弃面向UI编程 为何喷起此次话题,因为前不久和我们首席架构师沟通,谈起程序设计问题,一不小心把UI扯进来,更把那些按照UI来编程的后台工程师也扯了进来.今天特意百度了一下(其实程序员应该去googl ...

  8. vue中moment.js的使用

    一.介绍 moment.js是一款现在对时间处理的强大的函数. Moment被设计用于在浏览器和Node.js中工作. 目前ci系统使用的浏览器有:IE8.IE9在Windows 7上.Chrome在 ...

  9. Excel表格转Json数据结构

    Excel表格转Json数据结构 辗转了好几个项目,每个项目的导表工具都巨难用,速度慢,潜规则多,扩展性差,不易于调试.Sqlite,Json,Lua,Xml各种格式都用过. 举个例子: 大多数导表工 ...

  10. 手动生成WebService代理类

    方式一: 手动生成WebService代理类需要把一句生成语句,如 wsdl.exe /l:cs /out:D:/ProxyServices.cs http://localhost/WebServic ...