flash基本规划
为实现IAP升级,一般将flash规划成如上区域。 bootloader: 系统引导 app: 主程序运行的地方 update: 新的主程序固件存放的地方 这里给bootloader预留16K的空间,所以APP所在地址是0x08004000 ,编译APP时,要注意将中断向量表的偏移地址设置为0x4000
bootloader要完成的功能
根据以上描述,bootloader应有以下功能
- 跳转功能,可以跳转到app区执行主程序
- 固件搬运功能,因为固件中断向量偏移是固定的
0x4000 ,所以如果有新固件,需要将新固件转移到app区再跳转(APP区地址偏移需和中断向量偏移对应)
bootloader实现
根据上节分析,实现bootloader要有如下工作:
- 编写读写内部flash的接口
- 编写跳转到指定地址运行程序的代码
- 根据ST官方例程实现的flash操作接口:
擦除操作
uint32_t FLASH_If_Erase(uint32_t start_page, uint8_t pages)
{
uint32_t PageError = 0;
FLASH_EraseInitTypeDef pEraseInit;
HAL_StatusTypeDef status = HAL_OK;
HAL_FLASH_Unlock();
pEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;
pEraseInit.PageAddress = start_page;
pEraseInit.Banks = FLASH_BANK_1;
pEraseInit.NbPages = pages;
status = HAL_FLASHEx_Erase(&pEraseInit, &PageError);
HAL_FLASH_Lock();
if (status != HAL_OK)
{
return FLASHIF_ERASEKO;
}
return FLASHIF_OK;
}
写flash
#define UPDATE_APP_ADDRESS (uint32_t)0x0802C000
#define APP_ADDRESS (uint32_t)0x08004000
uint32_t FLASH_If_Write(uint32_t destination, uint32_t *p_source, uint32_t length)
{
uint32_t i = 0;
HAL_FLASH_Unlock();
for (i = 0; (i < length) && (destination <= (USER_FLASH_END_ADDRESS-4)); i++)
{
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, destination, *(uint32_t*)(p_source+i)) == HAL_OK)
{
if (*(uint32_t*)destination != *(uint32_t*)(p_source+i))
{
return(FLASHIF_WRITINGCTRL_ERROR);
}
destination += 4;
}
else
{
return (FLASHIF_WRITING_ERROR);
}
}
HAL_FLASH_Lock();
return (FLASHIF_OK);
}
void AppMove(void) {
uint32_t file_size = *(uint32_t*)UPDATE_APP_ADDRESS;
uint32_t pages_use = 0;
uint32_t* data_ptr = NULL;
uint32_t file_size_word = 0;
if (file_size != 0xffffffff) {
printf("move app\n");
data_ptr = (uint32_t*)(UPDATE_APP_ADDRESS + 4);
pages_use = file_size / FLASH_PAGE_SIZE + 1;
printf("size: %d pages_use: %d\n", file_size, pages_use);
file_size_word = file_size / 4;
FLASH_If_Erase(APP_ADDRESS, pages_use);
FLASH_If_Write(APP_ADDRESS, data_ptr, file_size_word);
FLASH_If_Erase(UPDATE_APP_ADDRESS, pages_use);
} else {
printf("no new app\n");
}
}
typedef void (*pFunction)(void);
void AppJump(void) {
printf("jump\n");
if (((*(__IO uint32_t*)APP_ADDRESS) & 0x2FFE0000 ) == 0x20000000) {
uint32_t jump_addr = *(__IO uint32_t*)(APP_ADDRESS + 4);
pFunction jump_to_app = (pFunction)jump_addr;
__set_MSP(*(__IO uint32_t*)APP_ADDRESS);
__disable_irq();
jump_to_app();
}
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART3_UART_Init();
AppMove();
AppJump();
while (1)
{
}
}
bool就完成了 IAP参考这里
|