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