4

我为我的 SAM4S 编写了一个引导加载程序,它位于扇区 0 并在扇区 1 中加载应用程序。但是问题是,当我尝试跳转到新函数时,它似乎会生成异常(调试器转到 Dummy_Handler()) .

Bootloader 在映射中包含以下条目:

.application    0x00410000        0x0
                0x00410000                . = ALIGN (0x4)
                0x00410000                _sappl = .
                0x00410004                _sjump = (. + 0x4)

应用程序图像映射文件具有:

.vectors       0x00410000       0xd0 src/ASF/sam/utils/cmsis/sam4s/source/templates/gcc/startup_sam4s.o
                0x00410000                exception_table
…
.text.Reset_Handler
                0x0041569c      0x100 src/ASF/sam/utils/cmsis/sam4s/source/templates/gcc/startup_sam4s.o
                0x0041569c                Reset_Handler

异常表定义如下:

const DeviceVectors exception_table = {

        /* Configure Initial Stack Pointer, using linker-generated symbols */
        .pvStack = (void*) (&_estack),

        .pfnReset_Handler      = (void*) Reset_Handler,

引导加载程序将应用程序跳转点声明为:

extern void (*_sjump) ();

然后进行以下调用:

_sjump();

0x00410004 处的内存内容为 0x0041569d,我注意到这不是字对齐的。这是因为我们使用的是 Thumb 指令吗?不管怎样,为什么它不是 0x0041569c?或者更重要的是,为什么这会出现异常?

谢谢,

德万

更新: 找到了这个,但它似乎对我不起作用:

void (*user_code_entry)(void);
unsigned *p; 
p = (uint32_t)&_sappl + 4;
user_code_entry = (void (*)(void))(*p - 1);

if(applGood && tempGood) {
    SCB->VTOR = &_sappl;

    PrintHex(p);
    PrintHex(*p);
    PrintHex(user_code_entry);

    user_code_entry();

}

代码打印:00410004 0041569D 0041569C

更新更新: 尝试使用 C 函数指针跳转的代码产生了以下反汇编:

--- D:\Zebra\PSPT_SAM4S\PSPT_SAM4S\SAM4S_PSPT\BOOTLOADER\Debug/.././BOOTLOADER.c 
user_code_entry(); 
004005BA ldr    r3, [r7, #4]     
004005BC blx    r3

我能够使用以下程序集完成此工作:

"mov   r1, r0        \n"
"ldr   r0, [r1, #4]  \n"
"ldr   sp, [r1]      \n"
"blx   r0"

基于此,我想知道是否需要重置堆栈,如果需要,是否可以在 C 中完成此操作?

4

2 回答 2

3

我对 SAM4E 有同样的问题。我无法猜测您的问题可能是什么,但我可以指出我遇到的困难和我使用的信息。

我的引导加载程序没有将固件的某些部分存储在正确的内存位置。这导致了 dummy_handler 异常。当我修复地址计算中的错误时,引导加载程序运行良好。

我的建议:

  • 按照 ATMEL 的示例:文档示例代码就足够了。main.c 足以了解引导加载程序应该如何工作。没有必要在一开始就进入分区细节。
  • 您可能想阅读如何从 RAM 执行函数/ISR
  • 该网页解释了英特尔 HEX 格式。
  • 最后,在引导加载程序完成升级后,您可以读取闪存并将其发送回主机。然后将其与原始图像进行比较(使用脚本)。这就是我调试引导加载程序的方式。

其他可能有帮助的想法:

  • 你写之前会擦掉每一页吗?
  • 您是否在擦除/写入之前解锁每个内存空间?
  • 您可以锁定引导加载程序的部分以避免错误地覆盖它
  • 您可以锁定升级固件的部分。

您必须指向的地址是 0x00410000 而不是 0x00410004。Atmel 的示例代码(参见函数binary_exec)结合英特尔十六进制格式(记录类型 05)应该可以解决这个问题。

我希望这条信息会有所帮助!

于 2015-02-13T18:34:18.683 回答
2

我在 SAM4S 上遇到了同样的问题,这让我想到了这个问题。所以如果有人再次来到这里,这就是我发现的。正如 ChrisB 所提到的,遵循 Atmel 示例代码是一个好的开始,但是我发现问题是请求跳转的实际代码对 SAM4S 不起作用。缺少的是在向量表之前重新定位堆栈指针,然后加载重置处理程序地址。尝试这样的事情:

static void ExecuteApp(void)
{
    uint32_t i;

   // Pointer to the Application Section
   void (*application_code_entry)(void);

   // -- Disable interrupts and system timer

    __disable_irq();
    SysTick->CTRL = 0; // Disable System timer

    // disable and clear pending IRQs
    for (i = 0; i < 8; i++) 
    {
        NVIC->ICER[i] = 0xFFFFFFFF; // disable IRQ
        NVIC->ICPR[i] = 0xFFFFFFFF; // clear pending IRQ
    }


    // Barriers
    __DSB();    // data synchronization barrier
    __ISB();    // instruction synchronization barrier

    // Rebase the Stack Pointer
     __set_MSP(*(uint32_t *) APPCODE_START_ADDR);

     // Rebase the vector table base address
     SCB->VTOR = ((uint32_t) APPCODE_START_ADDR & SCB_VTOR_TBLOFF_Msk);

     // Load the Reset Handler address of the application
     application_code_entry = (void (*)(void))(unsigned *)(*(unsigned *)
                              (APP_START_RESET_VEC_ADDRESS));

    __DSB();
    __ISB();

    // -- Enable interrupts
    __enable_irq();

     // Jump to user Reset Handler in the application
     application_code_entry();

} 
于 2016-08-04T11:18:54.137 回答