GD32F527无故进入NMI,真凶竟然是劳苦功高的它 | 技术集结

描述

 

文章背景

在使用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 都有相关的配置。

NMI

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

NMI

上述描述有几个关键词:ECC, 读操作,校验。

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

NMI

问题根源与解决方案

现在回到一开始的问题,为什么添加一些软件包后就会触发 NMI 中断呢?事情到这也逐步清晰了,肯定是和上述描述有关。

这里还有一个背景知识,RAM 在刚启动时其数据是不确定的。

由于在写的行为下才会写入 ECC 的校验码,读取时会和该校验码进行对比校验,由于 RAM 中的数据是不确定且未生成正确校验码,如果直接读取数据就会校验失败触发 NMI 中断。

那么上述问题如何解决呢,可以修改链接脚本上述清空的区域,将其范围改大或者直接清空整块 RAM。

比如上述问题社区的其它小伙伴也遇到类似问题,所以特此写下该文章。

NMI


 

问题原帖:

https://club.rt-thread.org/ask/question/82c4ca58f7662af0.html


 

ECC功能的价值

当然 ECC 功能是一个非常有用的功能,在一些极端电磁环境,比如有些工业机器人工作在大电压且电磁环境复杂的场景,ECC 在这个时候就能体现它的作用了。

 

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分