GD32F450VI系列单片机IAP实现远程升级代码解析
#include 'gd32f4xx.h'
#define BOOTLOADER_SIZE 0x4000 // Bootloader的大小为16KB #define APPLICATION_ADDRESS 0x08010000 // 应用程序的起始地址为64KB
#define PAGE_SIZE 0x400 // Flash的页大小为1KB
typedef void (*pFunction)(void);
void jump_to_application(void) { pFunction app_entry = (pFunction)(*(uint32_t )(APPLICATION_ADDRESS + 4)); __set_MSP((uint32_t *)APPLICATION_ADDRESS); app_entry(); }
void flash_erase(uint32_t address) { FLASH_Unlock(); FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
FLASH_ErasePage(address);
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
FLASH_Lock();
}
void flash_write(uint32_t address, uint32_t *data, uint32_t size) { FLASH_Unlock(); FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
for (uint32_t i = 0; i < size; i += 4) {
FLASH_ProgramWord(address + i, data[i / 4]);
while (FLASH_GetFlagStatus(FLASH_FLAG_BSY | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR) != RESET);
}
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
FLASH_Lock();
}
int main(void) { uint32_t *application_data = (uint32_t *)APPLICATION_ADDRESS; uint32_t *bootloader_data = (uint32_t *)0x20000000; // 从外部存储器读取的数据
// 检查是否需要更新
if (bootloader_data[0] != application_data[0]) {
// 擦除应用程序区域
for (uint32_t address = APPLICATION_ADDRESS; address < APPLICATION_ADDRESS + BOOTLOADER_SIZE; address += PAGE_SIZE) {
flash_erase(address);
}
// 写入新的应用程序
for (uint32_t address = APPLICATION_ADDRESS; address < APPLICATION_ADDRESS + BOOTLOADER_SIZE; address += 4) {
flash_write(address, &bootloader_data[(address - APPLICATION_ADDRESS) / 4], 4);
}
// 更新标志位,表示已经更新
application_data[0] = bootloader_data[0];
// 跳转到应用程序
jump_to_application();
}
while (1) {
// 程序主循环
}
}
这段代码首先定义了Bootloader的大小为16KB,应用程序的起始地址为64KB,Flash的页大小为1KB。
'jump_to_application'函数用于跳转到应用程序的入口地址,首先获取应用程序的起始地址和栈指针,然后执行应用程序的入口函数。
'flash_erase'函数用于擦除指定地址的Flash页,首先解锁Flash,然后擦除指定地址的页,最后锁定Flash。
'flash_write'函数用于向指定地址的Flash写入数据,首先解锁Flash,然后逐个写入数据,写入完成后等待Flash操作完成,最后锁定Flash。
'main'函数中首先定义了应用程序数据和Bootloader数据的指针,然后检查是否需要更新。如果需要更新,则先擦除应用程序区域,然后逐个写入新的应用程序数据,最后更新标志位,并跳转到应用程序。
如果不需要更新,程序将进入一个无限循环,执行其他任务。
原文地址: https://www.cveoy.top/t/topic/p0wv 著作权归作者所有。请勿转载和采集!