初级会员

- 积分
- 102
- 金钱
- 102
- 注册时间
- 2022-3-13
- 在线时间
- 52 小时
|
1金钱
将STM32F407内置flash分成三个区域:bootloader + firmware_A + firmware_B
系统复位后,先运行的bootloader根据配置选择跳转到不同的firmware。在firmware中,实现对另一块firmware flash区域的烧写从而完成固件的升级
参考探索者开发板的IAP实验及网上的一些资源,已经大致完成了STM32 AB升级的部分功能。
但仍有问题
1. 升级的firmware是一个工程编译出来的(都是firmware_A的IROM1 start/size配置),但bin会随机写到firmware_A或firmware_B区域。
目前暂时的解决方法是从bootloader跳转到firmware后,firmware根据bootloader配置判断当前跳转区域为A还是B,
再在firmware main函数一开头,调用NVIC_SetVectorTable(NVIC_VectTab_FLASH, APP_A_FLASH_ADDRESS_OFFSET)或NVIC_SetVectorTable(NVIC_VectTab_FLASH, APP_B_FLASH_ADDRESS_OFFSET)
尝试通过根据当前PC寄存器判断当前程序是跑在A还是B上,但发现无论bootloader跳转到A还是B,获取的PC寄存器值都落在A区域。
AREA ASMGETPC_PROC, CODE, READONLY
ASMGETPC PROC
EXPORT ASMGETPC
IMPORT g_currentPC
PUSH {R0-R8, LR}
LDR R0, =g_currentPC;
MOV R1, PC
STR R1, [R0] // 将PC值写入全局变量g_currentPC,但没有预期的结果,都落在A区
POP {R0-R8, PC}
ENDP
ALIGN
END
问题是,如何在firmware运行中得知当前firmware是跑在A区还是B区?
2. 按firmwareA的flash配置编译出来的固件升级,从A升级到B是没问题的,但从B升级到A却有问题
在firmware_B中,erase firmware_A flash区域时,FLASH_GetStatus()函数会返回错误
if((FLASH->SR & FLASH_FLAG_RDERR) != (uint32_t)0x00)
{
flashstatus = FLASH_ERROR_RD; // 单步调试走到这里,出现了这个错误,但查手册STM32F407的FLASH_SR没有RDERR,但STM32F42xxx and STM32F43xxx则有RDERR
}
然后keil单步跳到了void HardFault_Handler(void),是个while(1)死循环,
同时keil窗口中出现如下打印
Cannot access Memory (@ 0x08028c86, Read, Acc Size: 2 Byte)
Cannot access Memory (@ 0x08028c88, Read, Acc Size: 4 Byte)
Cannot access Memory
Cannot access Memory (@ 0x08028c8c, Read, Acc Size: 4 Byte)
Cannot access Memory (@ 0x08028c8e, Read, Acc Size: 2 Byte)
Cannot access Memory (@ 0x08028c8e, Read, Acc Size: 2 Byte)
keil memory窗口中,firmware_A区的值在erase时,全部跳变成了0xFF,说明flash erase firmware_A区是成功的。
但,同时Keil的汇编窗口中的地址全部变成了0xFF,感觉虽然bootloader跳转到了B,但当前系统仍然是跑在A
是不是keil编译出的bin不是位置无关的?即编译出的bin必须烧写在keil配置的flash起始地址上?
我bootloader里跳转的代码是:
void iap_load_app(u32 appxaddr)
{
if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000) //检查栈顶地址是否合法.
{
jump2app=(iapfun)*(vu32*)(appxaddr+4); //用户代码区第二个字为程序开始地址(复位地址)
RCC_DeInit();
__disable_irq();
MSR_MSP(*(vu32*)appxaddr); //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
jump2app(); //跳转到APP.
}
}
我firmware里main函数开头的代码是
void setupVectorTable2()
{
...
if (bconfig.firmware_A_or_B == BOOTLOADER_FIRMWARE_A) {
NVIC_SetVectorTable (NVIC_VectTab_FLASH, FIRMWARE_A_FLASH_START_ADDRESS - 0x08000000);
} else {
NVIC_SetVectorTable (NVIC_VectTab_FLASH, FIRMWARE_B_FLASH_START_ADDRESS - 0x08000000);
}
}
int main(void)
{
delay_init(168); //初始化延时函数
AT24CXX_Init(); //IIC初始化
setupVectorTable2(); //根据bootloader配置设置中断向量表
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
__enable_irq();
uart_init(115200); //初始化串口波特率为115200
...
}
|
|