本帖最后由 小恩GG 于 2025-9-3 17:18 编辑
概述
在某些应用中,为了实现更高效的 I/O 时序控制,程序需要从 RAM 而非 Flash 执行,以提升性能。当程序体积较大(例如约 192 KB),可选择将程序放入 RAMC、RAMD 和 RAME 等区域执行。同时,为数据存储(包括堆和栈)选择合适的 RAM 区域也尤为重要。
当栈放在如 RAMB 等其他 RAM 区域时,调试;则可正常进行而在调试过程中,若将栈放在 RAMX,可能会遇到调试失败的问题。
硬件环境:
开发板:FRDM-MCXN947
软件环境:
IDE:MCUXpresso IDE v11.9.0
SDK:SDK Builder | MCUXpresso SDKBuilder (nxp.com)
基础工程: Hello_world
1. 常见问题
是否可以将 RAMX 用作堆或数据存储区域(不包含栈)?
使用 RAMX 时有什么限制?
为什么将栈放在 RAMX 时调试会失败?
2. 调查与实验
我们基于 MCXN947 Hello World 示例工程 在 MCUXpresso IDE 中进行了验证和实验。默认情况下,该程序存放在内部 Flash。 当栈放在 RAMX 并进行调试时,程序无法启动,程序计数器(PC)无法跳转至应用程序入口。 为了进一步分析,我们做了以下实验:
2.1 实验1 创建函数: __attribute__((section("criticalFunc"))) void critical_func1(uint32_t n) { PRINTF("Arg = %d .\r\n", n); PRINTF("critical_func1.\r\n"); PRINTF("critical_func1.\r\n"); } 将函数数据区放在 RAMX,将堆放在 RAMX,调试正常。
结论:
RAMX 可以用于堆或数据区。
2.2 实验2
将函数数据区放在 RAMX,将栈放在 RAMX,无法调试。
2.3 实验3
将函数数据区放在 RAMX,将栈放在 RAMX,并将应用程序整体链接至 RAM,
调试正常。
2.4 实验结论
RAMX 使用限制
当代码运行在 内部 Flash 时:
RAMX 可用于存放堆或数据区,但不建议用于栈。
当代码运行在 RAM 时:
RAMX 可用于存放堆、数据区和栈。
是否可将栈放在 RAMX,取决于程序代码的存放位置(Flash 或 RAM)
3. 栈放在 RAMX 导致调试失败的原因
当 BootROM 准备跳转至存放在 Flash 的应用程序时,会检查向量表中的初始栈指针(SP)是否位于有效的内存区域。在当前 BootROM 实现中,RAMX 并未被视作有效的栈区域。如果初始 SP 在 RAMX,BootROM 将拒绝启动该程序。
4. 解决方案
可以通过修改启动代码来规避此限制。
方法如下:
在向量表中,将初始 SP 设置为有效的 SRAM 区域的临时值。
在 Reset Handler 开头,通过汇编手动将实际 SP(位于 RAMX)加载到 MSP。
例如:
- __attribute__ ((used, section(".isr_vector")))
- void (* const g_pfnVectors[])(void) = {
- (void*)0x20040000, // 临时栈指针
- ResetISR, // 复位处理函数
- NMI_Handler,
- HardFault_Handler,
- // ...
- };
- __attribute__ ((naked, section(".after_vectors.reset")))
- void ResetISR(void) {
- __asm volatile ("cpsid i"); // 禁用中断
- __asm volatile (
- "LDR R0, =0xE000ED08 \n"
- "STR %0, [R0] \n"
- "MSR MSP, %2 \n"
- "MSR MSPLIM, %1 \n"
- :
- : "r"(g_pfnVectors), "r"(_vStackBase), "r"(_vStackTop)
- : "r0", "r1", "r2"
- );
- // 后续初始化...
- }
复制代码
5. 总结
RAMX 可用于堆或数据区,不含栈时无问题。
当代码位于 Flash 时,不建议栈放在 RAMX,除非修改启动代码。
当代码位于 RAM 时,RAMX 可用于栈、堆及数据区。
修改启动代码可支持栈放在 RAMX,并保证正常调试。
|