文章背景
在使用RT-Thread GD32F527 的 BSP 时添加 RW007 软件包做联网测试以及添加 RT-Thread LVGL 软件包做 LVGL 示例时都会无缘无故的进入 NMI 中断,这个问题很引人思考,对于一个稳定的系统来说,这种不清不楚进入 NMI 的中断的现象是不可以接受的,所以这个问题有必要一探究竟。
启动代码分析
在启动文件会存在下述部分启动代码:
IMPORT |Image$$RW_IRAM1$$RW$$Base|
LDR R0, =|Image$$RW_IRAM1$$RW$$Base| ADD R1, R0, #0x8000 LDR R2, =0x0MEM_INIT STRD R2, R2, [ R0 ] , #8 CMP R0, R1 BNE MEM_INIT
接下来逐步分析上述代码:
IMPORT |Image$$RW_IRAM1$$RW$$Base|
LDR R0, =|Image$$RW_IRAM1$$RW$$Base|
上述代码表示引用一个来自外部文本的符号,该符号是由链接器生成,并将其加载至 R0 寄存器。
ADD R1, R0, #0x8000LDR R2, =0x0
然后将 R0 偏移 0x8000 字节赋值给 R1 寄存器,并将 R0 寄存器初始化为 0 值,此时 R1 保存着待初始化区域的结束地址。
MEM_INIT STRD R2, R2, [ R0 ] , #8 CMP R0, R1 BNE MEM_INIT
上述代码是最关键的一步,(1)行代码表示将俩字数据存储至 R0 地址指向的地方,然后将地址+ 8 字节。
然后比较 R0 与 R1 的值,如果不相等则再次跳转至MEM_INIT 符号执行。
上述代码的作用就是将 RAM1 区域的起始 0x8000 字节的数据清空。
为什么需要这么做?
不这么做会有什么问题呢?
带着问题我们去看一下数据手册。
我们搜索一个 ECC 的词发现其与 RAM 和 ROM 都有相关的配置。

继续往下看会有这样的一段描述:

上述描述有几个关键词:ECC, 读操作,校验。
那这里简洁的描述关键部分:ECC 可以纠正存储单比特的错误以及发现双比特的错误,但是无法发现双比特无法纠正的问题时就会触发 NMI 中断,数据手册中的描述如下:

问题根源与解决方案
现在回到一开始的问题,为什么添加一些软件包后就会触发 NMI 中断呢?事情到这也逐步清晰了,肯定是和上述描述有关。
这里还有一个背景知识,RAM 在刚启动时其数据是不确定的。
由于在写的行为下才会写入 ECC 的校验码,读取时会和该校验码进行对比校验,由于 RAM 中的数据是不确定且未生成正确校验码,如果直接读取数据就会校验失败触发 NMI 中断。
那么上述问题如何解决呢,可以修改链接脚本上述清空的区域,将其范围改大或者直接清空整块 RAM。
比如上述问题社区的其它小伙伴也遇到类似问题,所以特此写下该文章。

问题原帖:
https://club.rt-thread.org/ask/question/82c4ca58f7662af0.html
ECC功能的价值
当然 ECC 功能是一个非常有用的功能,在一些极端电磁环境,比如有些工业机器人工作在大电压且电磁环境复杂的场景,ECC 在这个时候就能体现它的作用了。
全部0条评论
快来发表一下你的评论吧 !