MCU微課堂
CKS32F4xx系列產(chǎn)品串口IAP
第三十三期 2024.3.30
IAP,即在應(yīng)用編程。很多單片機都支持這個功能,CKS32F4xx系列也不例外。
IAP簡介
IAP(In Application Programming)即在應(yīng)用編程,IAP是用戶自己的程序在運行過程中對User Flash的部分區(qū)域進行燒寫,目的是為了在產(chǎn)品發(fā)布后可以方便地通過預(yù)留的通信口對產(chǎn)品中的固件程序進行更新升級。
通常實現(xiàn)IAP功能時,即用戶程序運行中作自身的更新操作,需要在設(shè)計固件程序時編寫兩個項目代碼:
第一個項目程序不執(zhí)行正常的功能操作,而只是通過某種通信方式(如USB、USART)接收程序或數(shù)據(jù),執(zhí)行對第二部分代碼的更新;
第二個項目代碼才是真正的功能代碼。這兩部分項目代碼都同時燒錄在User Flash中,當(dāng)芯片上電后,首先是第一個項目代碼開始運行,它作如下操作:
1.檢查是否需要對第二部分代碼進行更新
2.如果不需要更新則轉(zhuǎn)到4
3.執(zhí)行更新操作
4.跳轉(zhuǎn)到第二部分代碼執(zhí)行
第一部分代碼必須通過其它手段,如JTAG或ISP燒入;第二部分代碼可以使用第一部分代碼IAP功能燒入,也可以和第一部分代碼一起燒入,以后需要程序更新時再通過第一部分IAP代碼更新。
我們將第一個項目代碼稱之為Bootloader程序,第二個項目代碼稱之為APP程序,他們存放在CKS32F4xx系列FLASH的不同地址范圍,一般從最低地址區(qū)開始存放Bootloader,緊跟其后的就是APP程序(注意,如果FLASH容量足夠,是可以設(shè)計很多APP程序的,本章我們只討論一個APP程序的情況,并且程序是存放在FLASH中)。這樣我們就是要實現(xiàn)2個程序:Bootloader和APP。
當(dāng)正常的程序加入IAP程序之后,程序運行流程如圖1所示:
圖1 加入IAP之后程序運行流程圖
在圖1所示流程中,CKS32F4xx系列復(fù)位后,從0X08000004地址取出復(fù)位中斷向量的地址,并跳轉(zhuǎn)到復(fù)位中斷服務(wù)程序,在運行完復(fù)位中斷服務(wù)程序之后跳轉(zhuǎn)到IAP的main函數(shù),如圖標(biāo)號①所示;在執(zhí)行完IAP以后(即將新的APP代碼寫入CKS32F4xx系列的FLASH,圖中灰底部分。新程序的復(fù)位中斷向量起始地址為0X08000004+N+M),跳轉(zhuǎn)至新寫入程序的復(fù)位向量表,取出新程序的復(fù)位中斷向量的地址,并跳轉(zhuǎn)執(zhí)行新程序的復(fù)位中斷服務(wù)程序,隨后跳轉(zhuǎn)至新程序的main函數(shù),如圖標(biāo)號②和③所示,同樣main函數(shù)為一個死循環(huán),并且注意到此時CKS32F4xx系列的FLASH,在不同位置上,共有兩個中斷向量表。在main函數(shù)執(zhí)行過程中,如果CPU得到一個中斷請求,PC指針仍強制跳轉(zhuǎn)到地址0X08000004中斷向量表處,而不是新程序的中斷向量表,如圖標(biāo)號④所示;程序再根據(jù)我們設(shè)置的中斷向量表偏移量,跳轉(zhuǎn)到對應(yīng)中斷源新的中斷服務(wù)程序中,如圖標(biāo)號⑤所示;在執(zhí)行完中斷服務(wù)程序后,程序返回main函數(shù)繼續(xù)運行,如圖標(biāo)號⑥所示。通過以上兩個過程的分析,我們知道IAP程序必須滿足兩個要求:
1)新程序必須在IAP程序之后的某個偏移量為x的地址開始;
2)必須將新程序的中斷向量表相應(yīng)的移動,移動的偏移量為x。
APP程序起始地址設(shè)置方法
隨便打開一個之前的實例工程,點擊Options for Target→Target選項卡,如圖2所示:
圖2 FLASH APP Target選項卡設(shè)置
默認(rèn)的條件下,圖中IROM1的起始地址(Start)一般為0X08000000,大小(Size)為0X100000,即從0X08000000開始的1024K空間為我們的程序存儲區(qū)。而圖中,我們設(shè)置起始地址(Start)為0X08010000,即偏移量為0X10000(64K字節(jié)),因而,留給APP用的FLASH空間(Size)只有0X100000-0X10000=0XF0000(960K字節(jié))大小了。設(shè)置好Start和Szie,就完成APP程序的起始地址設(shè)置。這里的64K字節(jié),需要根據(jù)Bootloader程序大小進行選擇,理論上我們只需要確保APP起始地址在Bootloader之后,并且偏移量為0X200的倍數(shù)即可。
中斷向量表的偏移設(shè)置方法
在系統(tǒng)啟動的時候,會首先調(diào)用SystemInit函數(shù)初始化時鐘系統(tǒng),同時SystemInit還完成了中斷向量表的設(shè)置,打開SystemInit函數(shù),可以看到函數(shù)體的結(jié)尾處有這樣幾行代碼:
#ifdef VECT_TAB_SRAM SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; #else SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; #endif
從代碼可以理解,VTOR寄存器存放的是中斷向量表的起始地址。默認(rèn)的情況VECT_TAB_SRAM是沒有定義,所以執(zhí)行SCB->VTOR=FLASH_BASE|VECT_TAB_OFFSET;對于FLASH APP,我們設(shè)置為FLASH_BASE+偏移量0x10000,所以我們可以在SystemInit函數(shù)里面修改SCB->VTOR的值。當(dāng)然為了盡可能不修改系統(tǒng)級別文件,我們可以也可以在FLASH APP的main函數(shù)最開頭處添加如下代碼實現(xiàn)中斷向量表的起始地址的重設(shè):
SCB->VTOR = FLASH_BASE | 0x10000;
通過以上兩個步驟的設(shè)置,我們就可以生成APP程序了,只要APP程序的FLASH大小不超過我們的設(shè)置即可。
Bootloader程序
代碼清單1:iap_write_appbin函數(shù)
該函數(shù)用于將存放在串口接收buf里面的APP程序?qū)懭氲紽LASH。
void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 appsize) { u32 t; u16 i=0; u32 temp; u32 fwaddr=appxaddr;//當(dāng)前寫入的地址 u8 *dfu=appbuf; for(t=0;t? ?代碼清單2:iap_load_app函數(shù){ temp=(u32)dfu[3]<<24; temp|=(u32)dfu[2]<<16; temp|=(u32)dfu[1]<<8; temp|=(u32)dfu[0]; dfu+=4;//偏移4個字節(jié) iapbuf[i++]=temp; if(i==512) { i=0; STMFLASH_Write(fwaddr,iapbuf,512); fwaddr+=2048;//偏移2048 512*4=2048 } } if(i)STMFLASH_Write(fwaddr,iapbuf,i);//將最后的一些內(nèi)容字節(jié)寫進去. }
該函數(shù)用于跳轉(zhuǎn)到APP程序運行,其參數(shù)appxaddr為APP程序的起始地址,程序先判斷棧頂?shù)刂肥欠窈戏?,在得到合法的棧頂?shù)刂泛?,通過MSR_MSP函數(shù)(該函數(shù)在sys.c文件)設(shè)置棧頂?shù)刂?,最后通過一個虛擬的函數(shù)(jump2app)跳轉(zhuǎn)到APP程序執(zhí)行代碼,實現(xiàn)IAP→APP的跳轉(zhuǎn)。
void iap_load_app(u32 appxaddr) { if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000) { jump2app=(iapfun)*(vu32*)(appxaddr+4); MSR_MSP(*(vu32*)appxaddr); jump2app(); } }? ?代碼清單3:USART1_IRQHandler函數(shù)
本章我們是通過串口接收APP程序的,定義USART_REC_LEN為120K字節(jié),也就是串口最大一次可以接收120K字節(jié)的數(shù)據(jù),這也是本Bootloader程序所能接收的最大APP程序大小。然后新增一個USART_RX_CNT的變量,用于記錄接收到的文件大小,USART1_IRQHandler部分代碼如下:
void USART1_IRQHandler(void) { u8 Res; if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { Res =USART_ReceiveData(USART1);//(USART1->DR); / if(USART_RX_CNT{ USART_RX_BUF[USART_RX_CNT]=Res; USART_RX_CNT++; } } }
Main函數(shù)里實現(xiàn)了串口數(shù)據(jù)處理,以及IAP更新和跳轉(zhuǎn)等各項操作,具體代碼參考例程。
Bootloader程序編寫完成之后,將其下載到CKS32F4xx系列開發(fā)板上,下載完成之后,再通過串口,發(fā)送FLASH APP程序到開發(fā)板,發(fā)送的程序是.bin文件,發(fā)送完成后,XCOM會提示文件發(fā)送完畢,如圖3所示。最后Bootloader程序?qū)瓿葾PP程序的更新和運行。
圖3 串口發(fā)送APP程序界面
審核編輯:黃飛
?
評論
查看更多