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

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

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

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

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

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

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

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

 

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

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

 

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

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

 

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

可我已经在代码里对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呢?

 

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

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

 

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

 

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

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

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

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

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

 

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

 

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

 

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


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

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

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

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

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

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

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

<think>好的,我现在要解决用户的问题:代码在SRAM上无法运行的原因及解决方案。根据用户提供的引用内容,我需要结合这些信息来分析和解答。 首先,用户提供的引用中有几个关键点。引用[1]提到,要在内部SRAM中调试代码,需要设置启动方式为从SRAM启动,修改分散加载文件,以及正确下载程序到SRAM。引用[2]指出启动文件不需要修改,因为它由链接器决定存储位置。引用[3]提到SWD编程SRAM项目的问题,可能与下载方式有关。引用[4]是关于电池供电的SRAM,可能涉及电源问题。引用[5]讨论了引脚配置错误可能导致启动失败。 那么,代码在SRAM无法运行的可能原因有哪些呢?我需要从启动配置、链接脚本、下载过程、电源管理、引脚配置这几个方面考虑。 启动方式是否正确?根据引用[1],必须设置启动模式为SRAM启动,比如STM32的BOOT引脚配置是否正确。如果启动模式不对,芯片可能无法从SRAM启动。 链接脚本是否正确?引用[1]和[2]都提到分散加载文件或链接脚本需要将代码空间指向SRAM的地址。如果链接脚本没有正确配置,代码可能被错误地链接到Flash或其他位置,导致运行失败。 下载过程是否有问题?引用[3]提到使用SWD下载到SRAM时可能出现问题,比如下载工具或方法不正确,导致程序没有正确写入SRAM。 电源问题?引用[4]中的电池供电SRAM如果电压不稳,可能导致SRAM数据丢失或无法运行。不过这可能更多是掉电保存的问题,但如果是运行时供电不足,也可能导致问题。 引脚配置错误?引用[5]指出引脚配置错误可能导致外设无法工作或芯片无法启动。例如,如果某些关键引脚(如时钟或复位)配置错误,可能影响整个系统的运行。 接下来,我需要将这些可能的原因整理成解决方案,并参考用户提供的引用进行支持。 另外,用户的问题可能涉及具体步骤,比如如何设置启动模式、修改链接脚本等。需要详细说明每一步的操作,并确保引用对应的来源。 可能还需要考虑其他因素,比如代码中是否有依赖Flash特定地址的部分,例如中断向量表的定位是否正确。在SRAM运行时,中断向量表可能需要重定位到SRAM地址,否则中断无法正确处理。 此外,调试配置是否正确?比如调试器设置中是否指定了正确的下载地址和运行地址,是否有启用正确的初始化脚本等。 总结下来,主要问题可能出在启动模式、链接脚本、下载配置、电源和引脚配置这几个方面。需要逐一检查这些部分,并参考用户提供的引用给出解决方案。</think>### 代码在 SRAM 上无法运行的原因及解决方案 #### 1. **启动模式配置错误** - **原因**:芯片未正确设置为从 SRAM 启动STM32 等 MCU 需要通过 BOOT 引脚选择启动源(如 FLASH、SRAM 或系统存储器)[^1]。 - **解决方案**: - 将 BOOT 引脚配置为从 SRAM 启动(例如 STM32 的 BOOT0=1、BOOT1=1)。 - 检查复位后是否执行了 SRAM 中的代码,可通过调试器查看 PC 指针是否指向 SRAM 地址范围。 #### 2. **链接脚本未适配 SRAM 地址** - **原因**:代码的链接脚本未将代码段和数据段分配到 SRAM 的物理地址范围,导致程序逻辑地址与实际存储位置不匹配[^2]。 - **解决方案**: - 修改分散加载文件(如 `.ld` 文件),将 `ROM` 和 `RAM` 的起始地址设置为 SRAM 的物理地址(例如 STM32F10x 的 SRAM 起始地址为 `0x20000000`)。 - 确保中断向量表地址(如 `VECT_TAB_SRAM`)已重定向到 SRAM[^2]。 #### 3. **下载过程异常** - **原因**:程序未正确下载到 SRAM 中,可能因调试工具配置错误或下载算法不支持 SRAM 编程[^3]。 - **解决方案**: - 使用支持 SRAM 编程的调试工具(如 J-Link、ST-Link),并确认下载地址设置为 SRAM 起始地址。 - 检查调试配置中的 `Load Application to Device` 选项是否启用,避免直接烧录到 FLASH。 #### 4. **电源或引脚配置错误** - **原因**: - SRAM 供电不稳定(如电池供电的 BBSRAM 电压不足)导致数据丢失[^4]。 - 关键引脚(如时钟、复位引脚)配置错误,导致芯片无法正常运行[^5]。 - **解决方案**: - 检查电源电路,确保 SRAM 的供电电压符合要求(如 1.8V/3.3V)。 - 使用 STM32CubeMX 验证引脚功能配置(如 GPIO 模式、复用功能)是否冲突[^5]。 #### 5. **代码未适配 SRAM 特性** - **原因**:代码中直接依赖 FLASH 特性(如固定地址常量),或未初始化 SRAM 的时钟和控制器。 - **解决方案**: - 避免使用绝对地址访问 FLASH,改用动态内存分配或相对地址。 - 在代码初始化阶段手动启用 SRAM 时钟(部分芯片需配置 `RCC_AHBENR` 寄存器)。 --- ### 操作步骤示例(以 STM32 为例) 1. **设置 BOOT 引脚**:硬件连接 BOOT0=1、BOOT1=1。 2. **修改链接脚本**: ```ld MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K } ``` 3. **配置调试器**:在 IDE(如 Keil)中设置下载地址为 `0x20000000`,并勾选 `Run to main()`。 4. **验证供电**:用万用表测量 SRAM 供电电压是否为 3.3V。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值