使用 IAR EWARM 手动将 .data 部分从闪存复制到 ram
Posted
技术标签:
【中文标题】使用 IAR EWARM 手动将 .data 部分从闪存复制到 ram【英文标题】:manually copy .data section from flash to ram with IAR EWARM 【发布时间】:2018-07-03 16:44:59 【问题描述】:我为 Kinetis K24 Cortex M4 编写了引导加载程序。引导加载程序在运行时通过 USB 将附加功能加载到 ram 中。这个 ramcode 作为它自己的 EWARM 项目存在,生成一个二进制文件。该二进制文件的入口点必须始终为 0x20000000,并且向量表必须始终位于 0x20007000 以便与我的 .NET 工具很好地配合使用。 IAR 启动代码处理 .bss 和 .data 副本的清除,但它也做了一些我不想要的其他事情。我不知道如何将 IAR 入口点强制到特定地址,所以我创建了自己的入口点,像这样
#pragma section=".bss"
#pragma location=".init"
__interwork int __low_level_init(void)
char * from = __section_begin(".bss");
char * to = __section_end(".bss");
__DI(); // Disable interrupts
memset(from, 0x00 , (to - from));
memcpy(__vector_table, (unsigned char *)ROM_VECTOR_LOCATION, VECTOR_TABLE_SIZE);
SCB_VTOR = (unsigned int) & __vector_table;
main();
SCB_VTOR = (uint32_t)ROM_VECTOR_LOCATION;
当我调试代码时,我可以看到初始化为非零值的全局变量采用随机值。我相信这是因为我没有将 .data 部分从 LMA 复制到 VMA。
我的问题是如何将 .data 部分的副本从 LMA 复制到 VMA?
如果我能弄清楚如何分解它,我也愿意使用 IAR 启动代码,但入口点不能是重置向量。入口点必须是 0x20000000 并且向量表必须位于 0x20007000
【问题讨论】:
你已经做了一些数据的memcpy
,为什么不添加另一个呢?您需要的所有信息都应该提供给您,是吗? .data
段在 FLASH 中的开始和结束,以及它在 RAM 中的某个位置?
Some useful tips & tricks for how to roll out the "CRT" yourself on a generic MCU。最值得注意的是,您的代码似乎无法在您初始化 .data 和 .bss 之前设置时钟。那将是非常糟糕的。虽然当然不是所有来自该链接的都适用于 Cortex M4,但 ARM 通过硬件等设置 SP。
是的,我认为这将是一个简单的副本,但我不知道此信息的位置。它不在我的链接器脚本中,地图文件中没有任何内容突出。
如果你想初始化变量,从 __low_level_init 调用 main 不是一个好主意。 __low_level_init 在初始化代码之前被调用。
无论如何,我不知道 IAR 对各个段的命名是什么,但显然你需要一个 memcpy
,从 .data
初始化器存储在闪存中的任何位置,到名为 .data
的 RAM 块。检查您的链接器文件/映射文件/符号浏览器以找出使用的名称。我不认为 LMA/VMA 是个问题。
【参考方案1】:
处理 .data 部分副本的 IAR 函数称为 __iar_data_init3()。我曾考虑直接调用它,但不敢相信它是如此简单。 IAR 建议这是正确的解决方案。我还使用了关键字 __root 来防止编译器删除我的“未使用”函数。这使我可以将其重命名为更合适的名称,例如 startup()。调用它 __low_level_init() 只是为了防止编译器删除它。 __low_level_init() 不是作为启动序列的一部分调用的,而是我在引导加载程序中加载程序计数器的入口点。这是我的最终解决方案
#pragma section=".bss"
#pragma location=".init"
__root void startup()
char * from = __section_begin(".bss");
char * to = __section_end(".bss");
memset(from, 0x00 , (to - from));
__iar_data_init3();
memcpy(__vector_table, (unsigned char *)ROM_VECTOR_LOCATION, VECTOR_TABLE_SIZE);
__DI(); // Disable interrupts
SCB_VTOR = (unsigned int) & __vector_table;
main();
SCB_VTOR = (uint32_t)ROM_VECTOR_LOCATION;
还有一个名为 __iar_zero_init3() 的函数可以处理 .bss 的归零,但是在第一次尝试时它导致我的程序崩溃。我无法想象它需要做很多工作才能让它工作。
【讨论】:
向量表包括初始堆栈指针值。在这个解决方案中,您似乎正在使用main()
中的引导加载程序堆栈,这可能与内存驻留代码重叠。
@Clifford 我正在共享堆栈。我不确定我对此有何感受,但我现在要放手了。在调用 main 之前更新堆栈指针并在之后恢复它不会有太多工作。
标准启动也会初始化标准库;因此,如果某些库调用依赖于静态数据,它们可能会失败。例如堆管理。
@clifford 标准启动已被删除。
我知道这一点;我的观点只是提醒标准库的某些部分可能无法正常工作。以上是关于使用 IAR EWARM 手动将 .data 部分从闪存复制到 ram的主要内容,如果未能解决你的问题,请参考以下文章
STM32F407VET6之IAR之ewarm7.80.4工程建立(基于官方固件库1.6版本)
IAR EWARM7.2下,STLink V2调试stm32f103开发板,能下载程序,但是不能断点
STM32F407VET6之IAR之ewarm7.80.4工程建立(基于官方固件库1.6版本) 的工程文件目录