使用 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的主要内容,如果未能解决你的问题,请参考以下文章

在IAR(EWARM)中移植STM32固件库

STM32F407VET6之IAR之ewarm7.80.4工程建立(基于官方固件库1.6版本)

IAR EWARM7.2下,STLink V2调试stm32f103开发板,能下载程序,但是不能断点

STM32F407VET6之IAR之ewarm7.80.4工程建立(基于官方固件库1.6版本) 的工程文件目录

IAR重大升级,支持VS Code,ST发布第一个带有处理单元的传感器

IAR重大升级,支持VS Code,ST发布第一个带有处理单元的传感器