STM32 Bootloader
要解決的問題
- 升級韌體很麻煩,開機殼短路兩個點上電洗掉程式,最後再用JTAG寫程式
- 但是裝置接在CAN bus,為什麼不能用CAN更新軟體,省掉上面步驟?
- Atollic這份文件把bootloader講解得很詳細
Flash規劃
STM32F103C8T6的page size是1KB
- Page[7:0] bootloader
- Page[15:8] main program
- Page[23:16] program to upgrade
- Page[62] bootloader NVRAM
- Page[63] main program NVRAM
我的程式不大,直接多放一份program to update也還好,程式運行中把軟體寫入此區域。重新開機,bootloader偵測到更新需求,把program to update覆蓋main memory完成更新後,再正常開機。所以bootloader邏輯很簡單
if bootloader_nvram_update == True
copy program_to_upgrade to main_program
Jump to main program
修改main program
本來主程式放在Flash開頭,現在被放到8K開始,我們要告訴linker script搬家了
也要告訴軟體,中斷向量表搬家了
主程式的修改就這樣,很簡單吧!
產生bootloader
bootloader也許會精雕細琢壓code size;但是我很懶,stm32cubemx直接產生,畢竟最後我也要讀寫Flash,有現成driver用就是爽
打開main.c,照著Atollic的文件抄,記得加上__disable_irq()才不會噴出hard fault。我也懶得找原因了,推測是跳入主程式時,也許會摸到某些保護跑飛。反正多一行就搞定,別太折磨自己了
實際的PM開銷約3K左右,就可以跳轉入主程式了
燒錄和Debug
現在MCU有兩個子專案,有兩個ELF file,代表要分兩步讓一顆MCU正常使用
- 我用Segger ozone,先載入bootloader.jdebug,燒寫bootloader到page[7:0],不碰其他地方
- 原本專案就有一個stm32.jdebug,燒寫主程式到page[15:8]
Segger Ozone文件有描述怎麼做得聰明一點,一個jdebug file就可以同時處理兩個ELF;不過我偏好讓事情簡單一點,Tool背後不要做太多事
所以開發者的習慣變這樣,想debug哪裡就開哪區,就是人要明確地意識到自己在查哪裡
- 修改主程式,編譯後用stm32.jdebug燒錄和debug
- 修改bootloader,編譯後用bootloader.jdebug,在跳轉到main program之前都能debug
如果要量產,程式編譯完會產生兩個hex檔,他們可以合併起來
結論
- Bootloader的精隨是重新定義中斷向量表跳轉程式,Atollic的文件寫得比我好100倍,真的看不懂網路上也有中文資料可查,原理講解請找專業
- 這篇文章特別解釋,已經會動的專案,怎麼加上bootloader,還有toolchain怎麼調整。不敢說是best practice,起碼流程有稍微想一想,第一次下手可以參考
- 跳轉入主程式前,增加一層bootloader,確實能大幅增加軟體彈性
留言