【问题标题】:manually copy .data section from flash to ram with IAR EWARM使用 IAR EWARM 手动将 .data 部分从闪存复制到 ram
【发布时间】: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 是个问题。

标签: c embedded iar


【解决方案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 标准启动已被删除。
  • 我知道这一点;我的观点只是提醒标准库的某些部分可能无法正常工作。
猜你喜欢
  • 2016-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-06
  • 2014-12-05
  • 1970-01-01
  • 2017-03-11
相关资源
最近更新 更多