因为项目需要,最近重新拾起来STM32,正好趁着这个机会好好的梳理下遇到的知识细节。
一般我们使用STM32发布程序时,都需要考虑增加IAP功能。那么就要将程序分为bootloader和APP两个独立的程序,这里笔记下实现思路和跳转代码。
这里以STM32F407ZGT6为例,该芯片有1MB Flash大小,我们规划分区如下:
| Bootloader | APP | Reserved | | 128K(0x20000) | 640K(0xA0000) | 256K(0x40000) | | | | | 0x8000000 0x8020000 0x80C0000 0x8100000
我们首先修改Bootloader相关配置,主要为代码宏和链接脚本,如下图:
编译之后可以发现分区信息已经修改了,如下图:
然后同样修改APP的配置,如下图:
跳转代码如下:
void cortexMx_jumpto_app(uintptr_t start_address) { /* 1 屏蔽中断响应,并且清除Pending的中断 2 清除所有中断使能 3 重设中断向量寄存器偏移(APP中会在SystemInit函数中重设) 4 重设MSP 5 跳转到指定位置执行 */ uintptr_t nvic_addr = start_address; uintptr_t stack_addr = *( (uintptr_t *)(nvic_addr) ); uintptr_t pc_addr = *( (uintptr_t *)(nvic_addr + sizeof(uintptr_t)) ); /* 禁用外部中断 */ __disable_irq(); /* 停止ARM cortexM systick定时器中断 */ SysTick->CTRL = 0x0; /* 停止STM32HAL库时钟的时基 */ HAL_SuspendTick(); for (uint32_t index = 0; index < sizeof(NVIC->ICPR) / sizeof(NVIC->ICPR[0]); ++index) { NVIC->ICER[index] = 0xFFFFFFFF; NVIC->ICPR[index] = 0xFFFFFFFF; } __set_MSP(stack_addr); __set_CONTROL(0x0); __DSB(); __ISB(); // __enable_irq(); ( (void (*)(void))pc_addr )(); }
有两个需要注意的地方:
1 跳转代码中没有重设NVIC偏移,也没有重新放开外部中断,这里的做法是考虑到APP中会重新设置NVIC偏移,同时会开启中断。
2 在不考虑Flash跨程序修改时,可以修改FLASH_END宏防止程序误写了不该写的区段,但是如果业务上有Flash跨程序修改,比如IAP设计上Bootloader需要修改APP分区的Flash,那么FLASH_END就需要放大到所有可写地址,否则会有写入失败问题。原因很简单,STM32HAL库在Flash写入前对Flash地址做了范围校验:
#define IS_FLASH_ADDRESS(ADDRESS) ((((ADDRESS) >= FLASH_BASE) && ((ADDRESS) <= FLASH_END)) || \ (((ADDRESS) >= FLASH_OTP_BASE) && ((ADDRESS) <= FLASH_OTP_END)))
发表评论