STM32 SD bootloader實(shí)現(xiàn)
前幾天在網(wǎng)上看到了一個(gè)sd bootloader,但是下載需要積分。于是想著自己寫個(gè)簡單的sd卡的bootloader,實(shí)際上就是stm32的iap功能了。簡單介紹一下stm32的iap吧,以下內(nèi)容摘抄自網(wǎng)絡(luò)。
IAP是In Application Programming的首字母縮寫,IAP是用戶自己的程序在運(yùn)行過程中對User Flash的部分區(qū)域進(jìn)行燒寫,目的是為了在產(chǎn)品發(fā)布后可以方便地通過預(yù)留的通信口對產(chǎn)品中的固件程序進(jìn)行更新升級。
通常在用戶需要實(shí)現(xiàn)IAP功能時(shí),即用戶程序運(yùn)行中作自身的更新操作,需要在設(shè)計(jì)固件程序時(shí)編寫兩個(gè)項(xiàng)目代碼,第一個(gè)項(xiàng)目程序不執(zhí)行正常的功能操作,而只是通過某種通信管道(如USB、USART)接收程序或數(shù)據(jù),執(zhí)行對第二部分代碼的更新;第二個(gè)項(xiàng)目代碼才是真正的功能代碼。這兩部分項(xiàng)目代碼都同時(shí)燒錄在User Flash中,當(dāng)芯片上電后,首先是第一個(gè)項(xiàng)目代碼開始運(yùn)行,它作如下操作:
1)檢查是否需要對第二部分代碼進(jìn)行更新
2)如果不需要更新則轉(zhuǎn)到4)
3)執(zhí)行更新操作
4)跳轉(zhuǎn)到第二部分代碼執(zhí)行
第一部分代碼必須通過其它手段,如JTAG或ISP燒入;第二部分代碼可以使用第一部分代碼IAP功能燒入,也可以和第一部分代碼一道燒入,以后需要程序更新是再通過第一部分IAP代碼更新。
對于STM32來說,因?yàn)樗闹袛嘞蛄勘砦挥诔绦虼鎯?chǔ)器的最低地址區(qū),為了使第一部分代碼能夠正確地響應(yīng)中斷,通常會(huì)安排第一部分代碼處于Flash的開始區(qū)域,而第二部分代碼緊隨其后。
在第二部分代碼開始執(zhí)行時(shí),首先需要把CPU的中斷向量表映像到自己的向量表,然后再執(zhí)行其他的操作。
如果IAP程序被破壞,產(chǎn)品必須返廠才能重新燒寫程序,這是很麻煩并且非常耗費(fèi)時(shí)間和金錢的。針對這樣的需求,STM32在對Flash區(qū)域?qū)嵭凶x保護(hù)的同時(shí),自動(dòng)地對用戶Flash區(qū)的開始4頁設(shè)置為寫保護(hù),這樣可以有效地保證IAP程序(第一部分代碼)區(qū)域不會(huì)被意外地破壞。
stm32的iap功能,官方也有com,i2c以及基于USB的DFU,大致原理都是前面所說的那樣。對于sd的bootloader,也就是前面所說的第一部分代碼實(shí)現(xiàn)的主要過程是使用fatfs系統(tǒng)讀取sd卡上的bin文件,并把數(shù)據(jù)寫到第二部分代碼的向量表起始位置,我的設(shè)定是0x8003000處。寫完后讀取flash校驗(yàn)。就是如此的簡單,廢話不多說上代碼!
/*******************************************************************************
*FunctionName:main.
*Description:mainroutine.
*Input:None.
*Output:None.
*Return:None.
*******************************************************************************/
intmain(void)
{
DFU_Button_Config();
/*CheckiftheKeypush-buttononSTM3210x-EVALBoardispressed*/
if(DFU_Button_Read()!=0x00)
{/*Testifusercodeisprogrammedstartingfromaddress0x8003000*/
if(((*(__IOuint32_t*)ApplicationAddress)&0x2FFE0000)==0x20000000)
{/*Jumptouserapplication*/
JumpAddress=*(__IOuint32_t*)(ApplicationAddress+4);
Jump_To_Application=(pFunction)JumpAddress;
/*Initializeuserapplication'sStackPointer*/
__set_MSP(*(__IOuint32_t*)ApplicationAddress);
Jump_To_Application();
}
}/*OtherwiseentersDFUmodetoallowusertoprogramhisapplication*/
UsartInitilize();
RCC_HSICmd(ENABLE);
NVIC_Initilize();
ComPrint("**********************************n");
ComPrint("*STM32SDBootloader*n");
ComPrint("*V1.0*n");
ComPrint("**********************************n");
ComPrint("nSD-LODER:startflashprogram......n");
if(SD_Initilize()==SD_OK)
{
FRESULTstatus=FR_OK;
uint8_tflashProgramSuccess=0;
uint8_tcheckSum=0;
uint32_tsize=0;
uint32_tlength=0;
uint32_tsectorAddr=0;
uint32_ti=0,j=0,k=0,numberOfPage=0;
f_mount(0,&fsrc);
status=f_open(&fp,"upload.bin",FA_READ+FA_OPEN_EXISTING);
if(status==FR_OK&&(size=f_size(&fp))!=0)
{
ComPrint("nSD-LODER:openupload.binsuccess,size=%dKBnn",size/1024);
numberOfPage=size/FLASH_PAGE_SIZE+1;
Hal_Unlock();
for(i=0;i { ComPrint("*"); sectorAddr=ApplicationAddress+i*FLASH_PAGE_SIZE; Hal_Erase(sectorAddr); for(j=0;j { memset(MAL_Buffer,0x0,wTransferSize); status=f_read(&fp,MAL_Buffer,wTransferSize,&length); if(status!=FR_OK||length==0) { ComPrint("SD-LODER:nreadfilefailedwhenprogrampage%d!n",i); gotoEnd_Flash; }