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)
 	{
 	}
}
最后跳转到指定APP
点击查看代码
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();
}

三.技术点

posted @   Charles_hui  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示