痞子衡嵌入式:简析i.MXRT1170 Cortex-M7 FlexRAM ECC功能特点、开启步骤、性能影响
大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是恩智浦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功能特点、开启步骤、性能影响的更多相关文章
- 痞子衡嵌入式:揭秘i.MXRT1170 eFuse空间访问可靠性的保护策略(冗余与ECC)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是恩智浦i.MXRT1170的eFuse空间访问可靠性保护策略. 关于i.MXRT系列的eFuse/OTP,痞子衡之前在介绍Boot时写过 ...
- 痞子衡嵌入式:在i.MXRT1170上启动含DQS的Octal Flash可不严格设Dummy Cycle (以MT35XU512为例)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是Octal或Hyper Flash上DQS信号与Dummy Cycle联系. 关于在 i.MXRT 上启动 NOR Flash 时如何设 ...
- 痞子衡嵌入式:揭秘i.MXRT1170上用J-Link连接复位后PC总是停在0x223104的原因
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1170上安全调试策略实现对JLink调试的影响. 痞子衡之前写过一篇旧文 <i.MXRT600的ISP模式下用J-L ...
- 痞子衡嵌入式:揭秘i.MXRT1170上串行NOR Flash双程序可交替启动设计
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1170上串行NOR Flash双程序可交替启动设计. 在上一篇文章 <i.MXRT1060/1010上串行NOR F ...
- 痞子衡嵌入式:聊聊i.MXRT1170双核下不同GPIO组的访问以及中断设计
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1170双核下不同GPIO组的访问以及中断设计. 在双核 i.MXRT1170 下设计应用程序,有一个比较重要的考虑点就是外 ...
- 痞子衡嵌入式:简析i.MXRT1170 Cortex-M4 L-MEM ECC功能特点、开启步骤、性能影响
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是恩智浦i.MXRT1170上Cortex-M4内核的L-MEM ECC功能. 本篇是 <简析i.MXRT1170 Cortex-M ...
- 痞子衡嵌入式:简析i.MXRT1170 XECC功能特点及其保护串行NOR Flash和SDRAM之道
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是i.MXRT1170 XECC功能特点及其保护串行NOR Flash和SDRAM之道. ECC 是 "Error Correc ...
- 痞子衡嵌入式:测一测i.MXRT1170 Raw NAND启动时间(从POR到进App的Reset_Handler)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是恩智浦i.MX RT1170 Raw NAND启动时间. 关于i.MXRT1170这颗划时代的MCU,痞子衡去年10月在其刚发布的时候, ...
- 痞子衡嵌入式:大话双核i.MXRT1170之Cortex-M7与Cortex-M4互相激活之道
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是恩智浦i.MXRT1170上Cortex-M7与Cortex-M4内核互相激活的方法. 痞子衡最近在深耕i.MXRT1170这颗划时代的 ...
随机推荐
- vue 不用npm下载安装包 该如何引用js
公司电脑不让用npm ,vue的项目要使用moment.js, 用了各种script 引用,总是报错 正确的方式应该为: import {moment} from ‘moment.js ’ 不可以全 ...
- js原型继承题目
var F = function(){}; Object.prototype.a = function(){}; Function.prototype.b = function(){}; var f ...
- koa进阶史(一)
1,设置静态文件目录,将__dirname 写成_dirname,乍看没什么毛病,但是一运行之后发现,_dirname is not defined,下次注意哈 app.use(express.sta ...
- 06 yarn是什么
yarn集群中有两个角色: 主节点:Resource Manager 1台 从节点:Node Manager N台 Resource Manager一般安装在一台专门的机器上 Node Mana ...
- 「从零单排HBase 05」核心特性region split
HBase拥有出色的扩展性,其中最依赖的就是region的自动split机制. 1.split触发时机与策略 前面我们已经知道了,数据写入过程中,需要先写memstore,然后memstore满了以后 ...
- 面试总被问分布式ID怎么办? 滴滴(Tinyid)甩给他
整理了一些Java方面的架构.面试资料(微服务.集群.分布式.中间件等),有需要的小伙伴可以关注公众号[程序员内点事],无套路自行领取 一口气说出 9种 分布式ID生成方式,面试官有点懵了 面试总被问 ...
- django 从零开始 3认识url解析
在视图函数中定义一个函数abc 接受得到的参数 并显示在页面上 urls中设置 在页面会显示出错误 找不到该url ,原因是django1版本中使用的是url和re_path ,突然django2变 ...
- 数据结构 5 哈希表/HashMap 、自动扩容、多线程会出现的问题
上一节,我们已经介绍了最重要的B树以及B+树,使用的情况以及区别的内容.当然,本节课,我们将学习重要的一个数据结构.哈希表 哈希表 哈希也常被称作是散列表,为什么要这么称呼呢,散列.散列.其元素分布较 ...
- ASP.NET Core ActionFilter引发的一个EF异常
最近在使用ASP.NET Core的时候出现了一个奇怪的问题.在一个Controller上使用了一个ActionFilter之后经常出现EF报错. InvalidOperationException: ...
- WINDOWS上JDK安装与环境变量设置
一.JDK安装 jdk版本:jdk1.8.0_144 下载链接:https://pan.baidu.com/s/1eS2bFhg 密码:e3q1 下载JDK后点击安装,可以根据需要修改JDK的安装目录 ...