在STM32F4上跳转到第二个固件

3
我正在为运行在stm32上的应用程序构建引导加载程序。 这样做的目的是为了能够更新主应用程序。
由于我们的软件非常模块化,我的想法是只配置一个最小版本。所有的初始化都是相同的,它跳转到一个包含所有引导加载功能的main函数(检查外部闪存上是否有新的固件,如果是,则将其写入内部闪存),最后跳转到实际的应用程序 - 它再次进行所有初始化,但这次带有额外的外设等,最终调用真正的main
内部闪存的存储布局如下:
|0x08000000 boot loader
|----------------------
|0x08006000 application

引导加载程序主要看起来是这样的。
extern void CallApplication(void);

int main(void) {
    printf("starting bootloader\n");

    printf("will jump to " TOSTRING(APP_START_ADDRESS) "\n");

    CallApplication();

    return 0;
}

其中CallApplication是用汇编语言编写的

#define VTABLE_START_ADDRESS APP_START_ADDRESS
#define NVIC_VTABLE 0xE000ED08  // Vector Table Offset

    .globl CallApplication
    .thumb_func
CallApplication:
    // Set the application's vector table start address.
    movw    r0, #(VTABLE_START_ADDRESS & 0xffff)
    movt    r0, #(VTABLE_START_ADDRESS >> 16)
    movw    r1, #(NVIC_VTABLE & 0xffff)
    movt    r1, #(NVIC_VTABLE >> 16)
    str     r0, [r1]

    // Load the stack pointer from the application's vector table.
    ldr     sp, [r0]

    // Load the initial PC from the application's vector table and branch to
    // the application's entry point.
    ldr     r0, [r0, #4]
    bx      r0

这几乎可以工作 - “真正”的应用程序被调用,进行初始化,但最终因为未知原因而崩溃。 有趣的是,引导加载程序的故障ISR(0x080022ae)被调用,而不是真正应用程序的ISR(> 0x08006000),因此显然设置新向量表的某些内容失败了。
2016-02-11 00:21:16,958 - INFO # init UART
2016-02-11 00:21:16,963 - INFO # Application:   boot_loader
2016-02-11 00:21:16,973 - INFO # -- init done, starting main --
2016-02-11 00:21:16,974 - INFO # starting bootloader
2016-02-11 00:21:16,976 - INFO # will jump to 0x8006000
2016-02-11 00:21:16,978 - INFO # init UART
2016-02-11 00:21:16,985 - INFO # Application:   hello_world
2016-02-11 00:21:17,797 - INFO # -- init done, starting main --
(hard fault led starts flashing)

我在这里缺失什么?

主应用程序的链接脚本定义了:

MEMORY
{
  FLASH (rx)      : ORIGIN = 0x08006000, LENGTH = 488K
  SRAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K
}

引导加载程序所做的是

MEMORY
{
  FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 24K
  SRAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K
}

剩下的部分是共享的。
SECTIONS
{
    .text :
    {
        _text = .;

        /*
         * The vector table must be placed to the top of the
         * memory map. To achieve this, it was assigned to a 
         * special section called ".isr_vector"
         */
        KEEP(*(.isr_vector))

        /* followed by .text and .rodata: */
        *(.text*)
        *(.rodata*)

        _etext = .;
    } > FLASH

    /* Just to make sure that the contents does not exceed the flash size */
    . = ORIGIN(FLASH) + LENGTH(FLASH);


    /*
     * .data and .bss are placed into SRAM:
     */
    .data : AT(ADDR(.text) + SIZEOF(.text))
    {
        _data = .;
        *(.data*)
        _edata = .;
    } > SRAM

    .bss :
    {
        /* _bss and _ebss will be required during initialization */
        _bss = .;
        *(.bss*)
        _ebss = .;
    } > SRAM

    .aux : {
        . = ALIGN(4);
        *(.auxdata) /* .auxdata section */
        . = ALIGN(4);
    } > SRAM

    /* Just to make sure that the contents does not exceed the SRAM size */
    . = ORIGIN(SRAM) + LENGTH(SRAM);
}

编辑:我重新编写了关于在C中设置VTOR的部分,这让我更清楚地理解发生了什么,但我仍然最终进入了启动加载程序的DefaultISR。

printf("starting bootloader\n");

printf("will jump to " TOSTRING(APP_START_ADDRESS) "\n");

printf("before: %x\n", SCB->VTOR);

SCB->VTOR += APP_START_ADDRESS;

printf("after: %x\n", SCB->VTOR);

asm volatile("mov r0, #0x6000");
asm volatile("ldr sp, [r0]");
asm volatile("ldr r0, [r0, #4]");
asm volatile("bx r0");

输出

2016-02-11 23:49:31,833 - INFO # starting bootloader
2016-02-11 23:49:31,835 - INFO # will jump to 0x6000
2016-02-11 23:49:31,836 - INFO # before: 8000000
2016-02-11 23:49:31,837 - INFO # after: 8006000
2016-02-11 23:49:31,839 - INFO # init UART
2016-02-11 23:49:31,841 - INFO # …

这很难远程调试。异常出现在哪里?使用调试器逐步执行您的代码。 - too honest for this site
我调用 __set_BASEPRI(0) 启用中断后,程序立即崩溃。 - user1273684
哎呀!是哪个异常?检查SCS寄存器、状态、地址等。如果你不知道我在说什么,读读手册,特别是架构参考手册,还有其他相关的。Cortex-M4不是PIC16或AVR。 - too honest for this site
1
看起来我错了,它没有崩溃,只是调用了默认的中断处理程序 - 仍然是引导加载程序的中断处理程序。因此设置新的 VTABLE 没有起作用。 - user1273684
注意:使用标准名称。例如,向量寄存器为VTOR。很抱歉,我无法再帮助您了。只有一个信息:这不是STM的错!对我来说它可以工作。 - too honest for this site
我并没有声称这是STM的错,我确信它只是按照我的指示执行:p 我仍然不知道我在设置SCB->VTOR方面缺少了什么,现在我正在将我的偏移量添加到其中,但旧位置仍然被用来查找要跳转到哪个ISR:( - user1273684
2个回答

3
我的情况是STM32L Cortex-M3,但我认为它的工作方式是相同的。
在bootloader中,禁用所有中断源(不要屏蔽它们)后,我执行以下操作:
#define APP_LOCATION 0x08006000

typedef void (*pFunction)(void);
pFunction jump;
volatile uint32_t jumpAddress;
register uint32_t regMainStackPointer __ASM("msp");

void Jump( void ) {
    jumpAddress = *( volatile uint32_t* )( APP_LOCATION + 4 );
    jump = ( pFunction )jumpAddress;
    mainStackPointer = *( volatile uint32_t* )APP_LOCATION;
    jump();
}

在应用程序中,在启用任何中断之前,需要做的第一件事是:
SCB->VTOR = 0x0x08006000;

这里的链接器是相等的。
我在你的代码中注意到了一些奇怪的东西:
SCB->VTOR += APP_START_ADDRESS;

如果APP_START_ADDRESS包含地址(0x08006000)而不是偏移量(0x6000),则VTOR中的结果值将为0x08000000 + 0x08006000,也许问题就出在这里?
如果你能展示一些应用程序代码可能会有所帮助。
希望这有所帮助。

2

HAL中的CPU初始化函数正在执行

  /* Configure the Vector Table location add offset address ------------------*/
#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif

这将覆盖我的设置SCB->VTOR

如果去除此设置,它就会正常工作,不需要其他操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接