STM32H743从RAM启动异常的案例分享~

有人使用STM32H743芯片做产品开发,反映没法将代码放在RAM区进行调试运行。基于他的反馈,这边找了块STM32H743的Nucleo开发板进行测试。 不妨找个基于该开发板的一个最简例程,GPIO的按键操作并触发中断,每按键一次将LED进行亮暗切换。下面使用ARM MDK开发环境进行测试。

芯片内部有多个SRAM区域,先考虑将代码放到D1域的AXI_SRAM里去运行,其它堆栈数据使用D1域的DTCM RAM。

STM32H743从RAM启动异常的案例分享~_第1张图片

STM32H743从RAM启动异常的案例分享~_第2张图片

除准备基本的程序代码外,另外稍加配置。首先,在IDE环境里做存储空间的配置,如下图所示:

STM32H743从RAM启动异常的案例分享~_第3张图片

然后在初始化代码里修改中断矢量表的入口地址:

STM32H743从RAM启动异常的案例分享~_第4张图片

结合BOOT脚通过STM32CubeProgrammer修改程序启动地址的配置:

STM32H743从RAM启动异常的案例分享~_第5张图片

配置准备工作大致有三项:存储安排、中断矢量入口重定位、修改BOOT启动配置。

准备就绪后编译运行,没问题!程序正是在AXIM RAM里运行。

 

STM32H743片内有多个SRAM区,难道客户将代码放在别的SRAM区运行而遇到问题?片内D2域还有好几块SRAM区,比方SRAM1/SRAM2/SRAM3.

STM32H743从RAM启动异常的案例分享~_第6张图片

当我尝试将上面的AXIM_SRAM换成SRAM1SRAM2进行验证测试时【当然其它地方也相应做了修改】,果真发现代码不运行并提示大量访问错误。

 

难道D2域的SRAM不能运行程序?没理由啊,手册上明确说明这几块SRAM区都是可以运行程序的。配置环节反复确认没有问题。

像这种情况我们比较容易怀疑到D2域SRAM区的供电以及时钟开启问题。从库代码的系统初始化函数SystemInit()也能找到些端倪或提醒。即若要使用D2域的SRAM存放数据的话,需先使能相应RAM区的时钟。鉴于此,在系统初始化函数里我将SRAM1/SRAM2/SRAM3的时钟使能开启,再行测试。可是,依然没法正常运行。

 

进一步查看STM32H743的参考手册得知,D2域的SRAM1/SRAM2/SRAM3在芯片复位后并不像D1域里的FLASHAXI SRAMTCM RAM等在复位后就被直接开启使能了,相反它们默认是关闭的。那么,要想使用D2域的SRAM1/SRAM2/SRAM3就必须手动使能之。【下图中红色方框框住的外设或存储区在芯片复位后即被自动使能开启,可被CPU访问,其它的需单独开启后方可使用】

STM32H743从RAM启动异常的案例分享~_第7张图片

我已经在代码里对SRAM1等做了开启使能,为何还不行呢?

其实,代码里的开启使能充其量不过是物理代码上的实现,但程序本身没法得到正常可靠地运行。因为现在的代码不仅仅是要从SRAM运行,而且还要从SRAM1启动。从SRAM123区域启动需要该部分存储器被正常供电并开启时钟了,而其正常供电和时钟开启反过来又需要程序能在SRAM123正常启动。这个逻辑导致程序根本不能正常运行,相当于锁在那里了。

似乎有点绕,打个生活中的比方,假设你手机已经没电了,需要人给你提供充电器,但你需要用你的手机给人电话告知提供充电器的人。因为手机没电没法通知送充电器的人,同时送充电器的人没法得到通知又不会给你充电器。

 

看来对于STM32H743单核芯片来说,代码没法直接放到SRAM1/2/3区域启动运行。当然,我们可以让程序从D1的存储区正常启动后,再使能D2域的SRAM时钟并将有关代码安排在D2域的RAM区运行是没有问题的。

 

刚才前面验证的时候,程序执行代码放在D1域的AXI_RAM,堆栈数据也使用D1域的TCM_RAM。结合上面的分析,要想代码从RAM里启动运行,程序代码需放在D1区才行,那堆栈数据是否可以不用D1域的,而使用D2域的SRAM呢?

 

在前面测试的基础上,程序代码依然使用D1AXI_SRAM,而将堆栈数据区改为D2SRAM1试试看。

STM32H743从RAM启动异常的案例分享~_第8张图片

一切调整完毕,再行验证。结果是程序没法正常运行,出现硬错。

 

关于这个异常,我们不难想到是因为需要进行堆栈操作时,SRAM1区的时钟还未准备好,但我在系统初始化函数SystemInit里已经开启了D2域的SRAM区的时钟了。不过,根据使能D2域的SRAM区时钟的代码位置来看,在整个初始化代码里已经比较靠后了,如果在它开启之前出现堆栈操作就会出现异常。

 

我们尝试将使能D2SRAM时钟的代码往前挪,挪到哪里呢?原则上是越前越好。挪到SystemInit()函数进门的地方?如下面这样子:

经过测试,感觉还可以,至少运行正常。不过,我们知道,如果是基于STM32库函数来组建工程的话,该初始化函数是在启动文件的复位程序里被调用的。

STM32H743从RAM启动异常的案例分享~_第9张图片

那意味着这个地方就可能发生栈操作,将使能D2域SRAM时钟的代码放在调用systemInit函数之前最为合理。这样的话就需使用汇编指令修改启动文件。D2域SRAM时钟的开关由寄存器RCC_AHB2ENR控制,通过内存读写指令把要写入寄存器的数据调整为写入该寄存器地址所对应的内存单元。

我们借助IDE不难找到该寄存器的地址是0x580244DC,当使能SRAM123区相关时钟时它的值为0xE0000000

STM32H743从RAM启动异常的案例分享~_第10张图片

这样我们可以在调用SystemInit函数前通过汇编指令实现D2域相关SRAM时钟的使能。

 

STM32H743从RAM启动异常的案例分享~_第11张图片

上面主要就STM32H743RAM启动运行所产生的问题做些特定地、探讨性地分享交流,顺便了解下H743芯片内部框架的一些特性。

 

上面文字的前半部分,侧重了介绍实现从RAM启动的配置过程及注意事项。我们知道D2SRAM并非芯片复位后就立即可用,须手动使能后方可使用。当然,并非只是D2域的SRAM默认关闭,其它域也有复位后默认关闭的外设或模块,比如D3域的BDMA,SAI4等,这些都是要注意的。

 

上面文字的后半部分主要是为了加深对STM32H743片内D2SRAM的时钟默认关闭特性的了解而延申的,以供参考。一般来讲,我们在应用开发过程中如果规划合理,是轮不到对启动文件大动干戈的。具体到这里,我们会优先选用D1域的RAM做堆栈以充分发挥其快速特性,毕竟D2域是相对慢速域。


1.熊谱翔:变化的RT-Thread,不变的初心

2.在嵌入式应用中,有一种管理资源的好方法!

3.一次事件会触发两次中断?

4.放弃MBP,用 8GB 的树莓派4 工作一天,是这样的感受!

5.用STM32 MPU做项目,不要低估软硬件,不要放弃MCU的起源!

6.枪与半导体:上一场科技世界大战

免责声明:本文系网络转载,版权归原作者所有。如涉及作品版权问题,请与我们联系,我们将根据您提供的版权证明材料确认版权并支付稿酬或者删除内容。

你可能感兴趣的:(STM32H743从RAM启动异常的案例分享~)