IAP在线升级一
一.前言
IAP升级在许多场合都会用到,而且涉及到芯片的核心底层,所以特此记录。
二.流程和框架
1.flash分区
- 将flash分为boot_app区和user_app区
boot_app存放的起始地址为0x00000000,大小为0x00008000(32kb)
user_app存放的起始地址为0x00008000,大小为0x00078000(480kb)
2.拷贝app到spi_flash
- 系统上有FatFs文件系统,所以拷贝起来很方便。
点击查看代码
FRESULT sdcard2spiflash(const char *psrc, const char *pdst) //真正搬运数据用到的函数
{
FRESULT res;
uint16_t br = 0;
uint16_t bw = 0;
FIL *fsrc = lv_mem_alloc(sizeof(FIL));
FIL *fdst = lv_mem_alloc(sizeof(FIL));
uint8_t *tempbuf = lv_mem_alloc(4096);
res = f_open(fsrc, (const TCHAR *)psrc, FA_READ | FA_OPEN_EXISTING); //打开只读文件(sfud内存卡)
if (res == FR_OK)
res = f_open(fdst, (const TCHAR *)pdst, FA_WRITE | FA_CREATE_ALWAYS); //第一个打开成功,才开始打开第二个
if (res == FR_OK) //两个都打开成功了
{
while (res == 0) //开始复制
{
res = f_read(fsrc, tempbuf, 4096, (UINT *)&br); //源头读出512字节
if (res || br == 0)
break;
res = f_write(fdst, tempbuf, (UINT)br, (UINT *)&bw); //写入目的文件
if (res || bw < br)
break;
}
f_close(fsrc);
f_close(fdst);
lv_mem_free(fsrc);
lv_mem_free(fdst);
}
lv_mem_free(tempbuf);
return res;
}
void copy_user_app(void)
{
char psrc[64] = {"sd:/obj_code.bin"}, pdst[64] = {"spiflash:/obj_code.bin"};
lv_obj_t *label_copy_info_tmp = lv_label_create(lv_scr_act());
lv_label_set_text(label_copy_info_tmp, psrc);
lv_obj_align(label_copy_info_tmp, LV_ALIGN_CENTER, 0, 0);
lv_task_handler();
gui2show();
if (sdcard2spiflash(psrc, pdst) != FR_OK)
{
lv_label_set_text(label_copy_info_tmp, LV_SYMBOL_WARNING "obj_code sdcard to spi flash error.");
lv_obj_align(label_copy_info_tmp, LV_ALIGN_CENTER, 0, 0);
lv_task_handler();
gui2show();
while (1)
;
}
lv_obj_del(label_copy_info_tmp);
}
- 3.启动boot程序
点击查看代码
void JumpToBootApp(uint32_t addr)
{
__disable_irq();
NVIC_SystemReset(); //直接复位重启,进入boot_app
// uint32_t sp = *((volatile uint32_t *)(addr));
// uint32_t pc = *((volatile uint32_t *)(addr + 4));
// typedef void (*Func_void_void)(void);
// Func_void_void ResetHandler = (Func_void_void)pc;
// SCB->VTOR = addr; //Reset IRQ_ADDR
// __set_MSP(sp);
// ResetHandler();
// while(1) __NOP();
}
- 4.boot程序
利用文件系统将app程序拷贝user_app区
点击查看代码
#define FLASH_APP1_ADDR 0x00008000 //第一个应用程序起始地址(存放在FLASH)
void iap_write_appbin_to_MCUflash(uint32_t appxaddr,uint8_t *appbuf,uint32_t len)
{
uint32_t t;
uint16_t i=0;
uint32_t temp;
uint32_t fwaddr=appxaddr;
uint8_t *dfu=appbuf;
static uint32_t byte_count = 0;
for(t=0;t<len;t+=4)
{
temp=(uint32_t)dfu[3]<<24;
temp|=(uint32_t)dfu[2]<<16;
temp|=(uint32_t)dfu[1]<<8;
temp|=(uint32_t)dfu[0];
dfu+=4;//Æ«ÒÆ4¸ö×Ö½Ú
iapbuf[i++]=temp;
if(i==1024)
{
byte_count++;
i=0;
FLASH_Erase(fwaddr);
FLASH_Write(fwaddr, iapbuf, 1024);
#if 0
fwaddr+=4096;
#endif
}
}
if(i)
{
printf("code size writtern in MCU_flash: %d byte.\r\n",byte_count*4096 + i*4);
FLASH_Erase(fwaddr);
FLASH_Write(fwaddr,iapbuf,i);
}
}
FRESULT spiflash_to_MCUflash(void)
{
FRESULT res;
uint16_t br = 0;
uint32_t read_byte_count = 0;
FIL *fsrc = (FIL *)malloc(sizeof(FIL));
FIL *fdst = (FIL *)malloc(sizeof(FIL));
char psrc[64] = {"spiflash:/obj_code.bin"};
uint8_t *tempbuf = (uint8_t *)malloc(4096);
memset(tempbuf, 0, 4096);
res = f_open(fsrc, (const TCHAR *)psrc, FA_READ | FA_OPEN_EXISTING);
if (res != FR_OK)
{
printf("failed: open obj_code.bin \r\n");
return res;
}
else
{
uint32_t flash_sector_offset = 0;
uint32_t app_addr;
printf("UserApp updating... \r\n");
while (res == 0)
{
res = f_read(fsrc, tempbuf, 4096, (UINT *)&br);
read_byte_count += (uint32_t)br;
if (res || br == 0)
break;
app_addr = FLASH_APP1_ADDR+flash_sector_offset*4096;
iap_write_appbin_to_MCUflash(app_addr,tempbuf,br);
flash_sector_offset++;
}
printf("code size readed from FatFs: %d byte.\r\n",read_byte_count);
f_close(fsrc);
f_close(fdst);
free(fsrc);
free(fdst);
}
free(tempbuf);
return res;
}
int main(void)
{
SystemInit();
key_init();
PrintSerialInit();
while(1)
{
if(GPIO_GetBit(GPIOM, PIN16) == 0)
{
//swm_delay_ms(15);
if(GPIO_GetBit(GPIOM, PIN16) == 0)
{
printf("APP:Enter BootApp mode\r\n");
printf(" Please update User_APP\r\n");
if(0 != file_sys_init())
{
break;
}
spiflash_to_MCUflash();
printf("have updated User_app\r\n");
printf("leave UserBoot, enter User_APP\r\n");
JumpToApp(FLASH_APP1_ADDR);
}
}
else
{
printf("leave UserBoot, enter User_APP\r\n");
JumpToApp(FLASH_APP1_ADDR);
}
}
JumpToApp(FLASH_APP1_ADDR);
while(1==1)
{
}
}
点击查看代码
void JumpToApp(uint32_t addr)
{
__disable_irq();
uint32_t sp = *((volatile uint32_t *)(addr));
uint32_t pc = *((volatile uint32_t *)(addr + 4));
typedef void (*Func_void_void)(void);
Func_void_void ResetHandler = (Func_void_void)pc;
SCB->VTOR = addr;
__set_MSP(sp);
ResetHandler();
while(1) __NOP();
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通