当 SRAM 中 "declaring" 向量 table 时 MCU 崩溃

MCU crashes when "declaring" vector table in SRAM

我在 imx rt 1024(nxp 芯片)上有一个新的标准 c++ 项目,我在其中尝试将矢量 table 移动到 SRAM。它失败了,这取决于我在链接描述文件中应用的更改。

该项目是MCUxpresso从零开始新建的项目。我不是在寻找与 MCUxpresso 相关或 c/c++/启动代码相关的答案。我只想正确理解下面显示的更改后的链接描述文件的后果。

有效的部分

我的起点是我的 evk 板上的一个小程序,它使用一个简单的 FreeRTOS 任务来使 LED 闪烁。当我将矢量 table 放入 flash 时,这很好用。

链接描述文件:

/* Not relevant for this question, other than showing there is something 
  written to flash before my vector table, harmless I think, but didn't want to leave 
  out of this question 
*/
.boot_hdr : ALIGN(4)
{
    __boot_hdr_start__ = ABSOLUTE(.) ;
    KEEP(*(.boot_hdr.conf))
    . = 0x1000 ;
    KEEP(*(.boot_hdr.ivt))
    . = 0x1020 ;
    KEEP(*(.boot_hdr.boot_data))
    . = 0x1030 ;
    KEEP(*(.boot_hdr.dcd_data))
    __boot_hdr_end__ = ABSOLUTE(.) ;
    . = 0x2000 ;
} >PROGRAM_FLASH

/*
   Here I write my vector table to flash
*/
.vector : ALIGN(4)
{
    __vector_table_flash_start__ = ADDR(.vector) ;
    __vector_table_itc_start__ = LOADADDR(.vector) ;

    KEEP(*(.isr_vector))
    __vector_table_flash_end__ = ABSOLUTE(.) ;
    . = ALIGN(4) ;
} >PROGRAM_FLASH

向量的反汇编代码table

重置处理程序的反汇编代码

注:0x600022e5对应0x600022e4,这个跟arm.thumb有关系。我不太清楚它是如何工作的。

当我 运行 这个应用程序时,它 运行 没问题。如果我在 ResetHandler 中设置断点,它就会中断,我可以单步执行启动代码并跳转到 main。当我让程序运行时,我的led会每秒闪烁

失败的部分

我更改了我的链接描述文件以将我的向量 table 放入 SRAM,如下所示

.vector : ALIGN(4)
{
    __vector_table_flash_start__ = ADDR(.vector) ;
    __vector_table_itc_start__ = LOADADDR(.vector) ;

    KEEP(*(.isr_vector))
    __vector_table_flash_end__ = ABSOLUTE(.) ;
    . = ALIGN(4) ;
} >SRAM_ITC AT>PROGRAM_FLASH

供参考,内存部分:

MEMORY
{
  PROGRAM_FLASH (rx) : ORIGIN = 0x60000000, LENGTH = 0x400000 
  SRAM_DTC (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000 
  SRAM_ITC (rwx) : ORIGIN = 0x0, LENGTH = 0x10000 
  SRAM_OC (rwx) : ORIGIN = 0x20200000, LENGTH = 0x20000 
}
ENTRY(ResetISR)

当我上传时,我的程序甚至没有到达重置向量。它直接进入树林,并在程序代码之外的某个地方崩溃。

问题

当我使用 >SRAM_ITC AT>PROGRAM_FLASH 调整我的链接描述文件时到底发生了什么?

我很确定生成的 elf 文件仍然包含从地址 0x60002000 开始的整个向量 table。 >SRAM_ITC 仅告诉链接器在启动代码将所有部分复制到其最终 ram 位置后,内存的某些部分将在哪里结束。正确的?那么最初跳转到 0x60002004(保存重置处理程序位置的地址)到底是怎么失败的呢? nxp 引导加载程序始终期望该位置上的复位向量。我没有改变那个。我只告诉链接器那个位置上的内存最终将在 SRAM 中结束。我在这里误解了什么?

也许是一个愚蠢的问题:如果我的上述假设完全错误,有没有办法从反汇编中看到?我认为 objdump 只显示最终地址,但据我所知,我的调试探针只会写入闪存。所以在将我的代码上传到我的目标之后,我仍然假设这些东西被写入了闪存,并且在重置后内置的引导加载程序将跳转到 0x60002004 并将 PC 设置为位于 0x60002000 的地址。我在哪里可以看到编程到闪存的实际字节块?

从我的自定义引导加载程序将向量 table 复制到 sram 解决了这个问题。这样 nxp 的“片上引导加载程序”就可以跳转到我的自定义引导加载程序。

在我从我的自定义引导加载程序到我的应用程序之前,我将向量 table 复制到 sram 并将 SCB->VTOR 设置为 sram 向量的开头 table.