基于我在这里找到的示例(lbus)https://github.com/alphalove/stm32-projects/tree/master/lbus_bootloader,我已经成功地为STM32103C8T6芯片实现了CAN总线引导加载程序。
我用过libopencm3。
在对引导加载程序代码进行很小的更改之前,我的工作一直很好。之后,引导加载程序将不再启动主固件。
引导加载程序从0x08000000开始,大小为8k。主固件从0x08002000开始。
连同其他事情,booloader会检查主固件的完整性,如果可以,则通过调用run_firmware()函数来启动它。此功能在设置向量表地址,初始化主堆栈指针,然后跳转到主固件的开始之前,关闭引导加载程序中使用的所有芯片外设。以下是run_firmware()函数的示例/代码段。
#define FW_ADDR 0x08002000
run_firmware() { // Set vector table base address.
// bunch of code to reset all peripherals
// Set Vector Table address
SCB_VTOR = FW_ADDR & 0xFFFF;
// Initialise master stack pointer
__asm__ volatile("msr msp, %0"::"g"(*(volatile uint32_t *)FW_ADDR));
// Jump to application
(*(void (**)())(FW_ADDR + 4))();
}
直到今天,当我添加了一些其他的也称为run_firmware()函数的引导加载程序代码时,它一直运行良好。现在调用run_firmware函数不会启动主固件,而是失败,直到看门狗将芯片复位。在代码中第二次调用run_firmware()时,该函数不再起作用。
这是地址跳转的限制吗?添加额外的调用是否已更改了导致问题的二进制文件中run_firmware()代码的位置?汇编中的%0和“ g”在做什么?
老实说,启动主固件的代码是我从上面链接的lbus示例中借来的魔术。所以我不太确定为什么会失败。
如果你不知道...我是一个硬汉!
任何指导将不胜感激!
提前感谢。
alex
//FW_ADDR has to be aligned to 0x100
SCB -> VTOR = FW_ADDR;
__set_MSP(*(volatile uint32_t *)FW_ADDR);
void (*start)(void) = (void *)*(volatile uint32_t *)(FW_ADDR + 4);
start();
或者,如果您喜欢怪异的表情
((void(*)(void))(FW_ADDR + 4))();
请记住,必须链接您的应用程序才能匹配新的起点。
跳转地址没有任何限制,只是必须将其放置在扇区的起始地址处。要解决您的问题,请确保引导加载程序的代码大小不超过8 KB,如果这样做会增加引导加载程序的大小并更改主应用程序的起始地址]