前言
最近项目里做了一个U盘升级的需求,用雅特力的例程进行了些许更改,在这里记录分享一下。
原理
这里原理不赘述了,大家可以直接去官网上下载应用笔记和例程:
下载AN0030
U盘IAP升级的大致思路就是满足升级条件后,读取bin,然后写入flash再进行跳转。
具体操作
项目用的是AT32F423,flash有128K,我把前32K用来放IAP,后96K放APP(两个工程),在KEIL上分开下载(APP程序下载不是必须的),如下所示:
APP的bin文件可以通过KEIL生成:
fromelf.exe --bin -o “@L.bin” “#L”
注意英文输入法
将IAP先烧进单片机,把APP的bin文件放进U盘,进入IAP后将U盘插上即可完成升级。
更改部分
读取bin函数
例程里给find_upgradebin函数是读取文件名确定gbin_list[bin_id].BaseAddr,我在使用过程中出现了读取错误的问题
而且对文件名有限制,我这改了一下:
uint8_t find_upgradebin(char *path)
{
FRESULT res;
FILINFO fno;
DIR dir;
char *fn;
char *po = NULL;
res = f_opendir(&dir, path);
if(res == FR_OK)
{
while(bin_id == 0)
{
res = f_readdir(&dir, &fno);
if(res != FR_OK || fno.fname[0] == 0)
{
break;
}
if(fno.fname[0] == '.')
{
continue;
}
fn = fno.fname;
if((po = strchr(fn, '.')) != NULL)
{
/*find upgrade bin*/
if((!memcmp(po + 1 , "BIN", 3) || !memcmp(po+1, "bin", 3)))
{
gbin_list.BaseAddr = FLASH_APP_START_ADDR;
gbin_list.Filesize = fno.fsize;
memcpy(gbin_list.BinName, fno.fname, 256);
bin_id ++;
}
}
}
}
f_closedir(&dir);
if(bin_id == 0)
return BIN_FAILED;
else
return BIN_OK;
}
#define IAP_USE_FLASH_SIZE (32*1024) //32K
#define FLASH_APP_START_ADDR 0x08008000
使用的时候bin文件名不要太长就行。
跳转函数
#define SET_MSP(dwValue) __ASM volatile ("msr msp, "#dwValue)
void (*pfTarget)(void);
void IAP_Jump(uint32_t dwAddr)
{
uint32_t dwStkPtr, dwJumpAddr;
uint32_t i = 0;
dwStkPtr = *(UINT32 *)dwAddr;
dwJumpAddr = *(UINT32 *)(dwAddr + sizeof(uint32_t));
if ( (dwStkPtr < SRAM_BASE) || ((dwStkPtr & 0xFF000000) != SRAM_BASE || (dwJumpAddr < FLASH_APP_START_ADDR) || ((dwJumpAddr & 0xFF000000) != FLASH_BASE)) )
return;
for ( i = 0; i < 1000000; i ++)
__NOP();
IAP_Clear();
SET_MSP(dwStkPtr);
pfTarget = (void (*)(void))dwJumpAddr;
pfTarget();
}
我在使用例程的跳转函数中出现过:打印显示已经跳转成功,但实际并没有成功的情况。这里加个判断,未成功会重复打印,当然在项目中可以用其他现象来判断。
IAP_Clear函数里写了外设的时钟关闭,中断关闭和标志清除等等,可以根据自己的情况写,不加清除会出现跳转后卡死的情况。
实际起到跳转作用的是SET_MSP。
注意
我把IAP放在了前面(0x08000000-0x08008000),APP放在了后面(0x08008000~)。上电后先执行IAP,在IAP初始化加了一个判断,不需要升级直接跳转到APP(也可以APP在前)
if(UPFlag == RESET)
{
IAP_Jump(FLASH_APP_START_ADDR);
}
APP内主函数里需要先加
SCB->VTOR=FLASH_BASE|0x00008000UL;
更改中断向量表。