使用stm32f105rct6的can通信做IAP,實現固件的遠程更新功能。IAP的實現包括兩個程序:BootLoader和應用程序。啟動過程先啟動BootLoader,等待1s,若接收到燒寫指令則開始更新程序,若無指令則啟動應用程序。應用程序接收到更新指令后,切換到BootLoader。
遠程程序更新需要防止更新失敗后,程序卡死,只能通過人工現場更新的情況。可以使用看門狗實現重啟返回BootLoader,給重新燒寫留出時間。
實現IAP流程,需要的工作包括:
1、規划單片機存儲區,設置中斷向量位置,生成應用程序bin文件
2、編寫BootLoader,實現應用程序切換
3、編寫遠程更新上位機,實現通信協議
4、插入看門狗程序,實現燒寫失敗后重啟
1、規划單片機存儲區,設置中斷向量位置,生成應用程序bin文件
stm32f105rct6的flash共256KB,規划flash空間:
0x08000000~0x08004000 共16KB空間,給BootLoader
0x08004000~0x08010000 共48KB空間,給應用程序
0x08010000~0x08014000 共16KB空間,保留
0x08014000~0x08018000 共16KB空間,給配置
單片機應用程序在起始地址中的結構,首先是中斷向量,然后是代碼。
中斷向量的結構:開頭4字節堆棧指針,接下來是4字節reset函數地址,之后是其他中斷函數的地址。
單片機開機后,從0x08000000處取得SP,然后從0x08000004處取得reset地址作為PC,在reset函數中調用main函數,進入C語言控制的程序中。
在keil中的options -> target -> IROM 填寫應用程序的起始和長度,並在linker -> use memory layout from target dialog中打鈎
在應用程序中,調用NVIC函數,設置中斷向量位置為0x08004000
生成應用程序的bin文件:
keil中,在options -> user -> after build -> run 中輸入指令
fromelf.exe --bin -o ..\w01sim\bin\mcubin\canext.bin .\obj\test.axf
2、編寫BootLoader,實現應用程序切換
建立一個普通的stm32工程,實現can通信和數據協議、flash燒寫等功能,當超時無指令,或燒寫成功后,需要進行程序切換。
程序切換時,首先應關閉設備時鍾、關閉中斷,避免應用程序中未對設備進行初始化,導致boot方式啟動與冷啟動有功能差別。
切換原理:模擬單片機上電過程,人工設置堆棧指針,調用應用程序入口函數。
切換代碼如下:
1 void switch_2_addr(u32 *pc) //切換到指定的程序指針 2 { 3 u32 i = 0; 4 RCC->APB1RSTR = 0x00000000;//復位結束 5 RCC->APB2RSTR = 0x00000000; 6 7 RCC->AHBENR = 0x00000014; //睡眠模式閃存和SRAM時鍾使能.其他關閉. 8 RCC->APB2ENR = 0x00000000; //外設時鍾關閉. 9 RCC->APB1ENR = 0x00000000; 10 RCC->CR |= 0x00000001; //使能內部高速時鍾HSION 11 RCC->CFGR &= 0xF8FF0000; //復位SW[1:0],HPRE[3:0],PPRE1[2:0],PPRE2[2:0],ADCPRE[1:0],MCO[2:0] 12 RCC->CR &= 0xFEF6FFFF; //復位HSEON,CSSON,PLLON 13 RCC->CR &= 0xFFFBFFFF; //復位HSEBYP 14 RCC->CFGR &= 0xFF80FFFF; //復位PLLSRC, PLLXTPRE, PLLMUL[3:0] and USBPRE 15 RCC->CIR = 0x00000000; //關閉所有中斷 16 17 NVIC->ICER[0] = 0xFFFFFFFF; 18 NVIC->ICER[1] = 0x000007FF; 19 NVIC->ICPR[0] = 0xFFFFFFFF; 20 NVIC->ICPR[1] = 0x000007FF; 21 for(i = 0; i < 0x0B; i++) 22 { 23 NVIC->IP[i] = 0x00000000; 24 } 25 __ASM volatile("cpsid i"); //關閉所有中斷 26 27 MSR_MSP(*pc); //堆棧指針是應用程序起始的第一個u32 28 ((void (*)(void))*(pc+1))();//入口函數是應用程序起始的第二個u32 29 }
其中MSR_MSP函數如下:
1 __asm void MSR_MSP(u32 addr) 2 { 3 MSR MSP, r0 //set Main Stack value 4 BX r14 5 }
3、編寫遠程更新上位機,實現通信協議
上位機實現通信協議:
每個程序具有自己的version,16bit,高1字節為程序代號,低1字節為程序發布版本
通信的過程:
1. 控制方發送查詢指令,應用程序或BootLoader收到后發送自身version
2. 控制方發送起始指令,指令中帶有長度和crc,應用程序收到后,若不准許,則發不准更新包,若准許,則不響應,直接切入BootLoader
3. 控制方持續發送起始指令,BootLoader收到后,回復相同canid的包,准許更新
4. 控制方得到准許后,發送id遞增的can包,將bin文件下載到MCU
5. 發送完成后,控制方額外發送一個can id低16bit為0xffff的包,內容任意,表示結束。BootLoader收到后開始計算crc,若失敗,則發失敗包。若成功,則開始燒寫flash,若燒寫失敗,發送燒寫失敗包。
6. 燒寫成功,BootLoader切換到應用程序,此時控制方一直發查詢指令,直到應用程序回復版本號正確。
4、插入看門狗程序,實現燒寫失敗后重啟
在BootLoader中開看門狗,切換到應用程序后喂狗。若程序燒寫失敗,則切換到應用程序后程序卡死,導致MCU重啟,又進入BootLoader,停留1s,等待下次燒寫。