
做嵌入式開發(fā)的朋友都應(yīng)該遇到過這種情況產(chǎn)品已經(jīng)在客戶那邊跑了大半年突然發(fā)現(xiàn)一個邏輯Bug或者客戶提了新需求要改功能。這時候最頭疼的不是改代碼本身而是怎么把手里的新固件刷到設(shè)備里去。拆機、接燒錄器、連線、下載一套流程下來費時費力不說遇到封裝比較小或者打了膠的板子簡直想砸東西。我最早做STM32F103C8T6項目的時候也被這個問題卡了很久后來把官方bootloader配合串口做IAP升級這套玩法徹底摸透了才算是真正解脫出來。所謂官方bootloader就是STM32芯片出廠時在系統(tǒng)存儲器System Memory里固化的一段引導(dǎo)程序用戶既不能修改也不能擦除。它的作用很單純通過串口、CAN或USB等接口把用戶代碼直接寫入芯片內(nèi)部的Flash。對于STM32F103C8T6這顆芯片來說最常用的就是USART1串口下載方式。我們不需要額外寫任何引導(dǎo)代碼只需要把BOOT0引腳拉高讓芯片上電后從系統(tǒng)存儲器啟動再用PC端的下載工具把編譯好的HEX文件通過串口發(fā)過去就能完成固件更新。對開發(fā)階段快速調(diào)板、小批量產(chǎn)線刷機、售后遠程協(xié)助升級來說這套方案性價比極高硬件成本就是幾塊錢的USB轉(zhuǎn)TTL模塊軟件工具則完全免費。這篇文章適合誰看如果你是剛接觸STM32的小白想搞明白怎么不借助ST-Link也能給板子燒程序或者你已經(jīng)在做產(chǎn)品正在糾結(jié)如何設(shè)計可靠的固件升級方案這篇文章都能提供一個直接可落地的參考。我會把原理、接線、工具配置、操作步驟、中斷向量表重映射這些關(guān)鍵細節(jié)一次講透也會把那些資料里很少寫、但實際開發(fā)中一定會踩的坑全部翻出來。1. 先搞懂原理為什么BOOT0拉高就能下載程序1.1 三種啟動模式與官方bootloader的定位STM32F103系列芯片上電后CPU會從哪個地址開始取指是由BOOT0和BOOT1兩個引腳的電平狀態(tài)決定的。具體映射關(guān)系如下表所示BOOT0BOOT1啟動區(qū)域說明0任意主Flash正常運行用戶程序也就是我們平時的工作模式10系統(tǒng)存儲器運行出廠固化的bootloader用于串口下載程序11SRAM調(diào)試用程序在RAM中運行掉電即失很多人第一次看到這張表會有點懵其實理解起來很簡單芯片上電后第一件事就是去讀取0x00000000地址處的初始棧指針以及0x00000004地址處的復(fù)位向量然后跳過去執(zhí)行代碼。這三種啟動模式本質(zhì)上是把不同的物理存儲區(qū)域映射到了0x00000000這個地址上。當(dāng)BOOT01、BOOT10時0x00000000映射到System Memory也就是那一段出廠固化的指令區(qū)。注意這里有個關(guān)鍵細節(jié)STM32F103C8T6的引腳上那個BOOT1其實是PB2引腳在芯片內(nèi)部已經(jīng)下拉所以很多時候我們只控制BOOT0一個引腳就夠了。1.2 官方bootloader到底做了什么當(dāng)芯片從系統(tǒng)存儲器啟動后CPU執(zhí)行的是ST出廠時寫好的引導(dǎo)程序。這段程序會初始化USART1PA9為TXPA10為RX等待PC端下載工具發(fā)送特定的命令幀。它以固定的通信協(xié)議接收數(shù)據(jù)將固件數(shù)據(jù)寫入用戶Flash區(qū)域并支持擦除、校驗、讀保護設(shè)置等操作。整個過程完全由ROM里的代碼完成我們在應(yīng)用層不需要做任何干預(yù)。這里要順帶澄清一個概念。嚴(yán)格來說通過官方bootloader下載程序標(biāo)準(zhǔn)術(shù)語叫ISPIn-System Programming在系統(tǒng)編程而在應(yīng)用運行時跳轉(zhuǎn)到自研bootloader再更新固件的做法才叫IAPIn-Application Programming在應(yīng)用編程。但國內(nèi)嵌入式圈子里大家交流時經(jīng)?;煊眠@兩個詞既然標(biāo)題用了“IAP升級”我后面就順著這個叫法但心里要清楚門道。真正的IAP方案需要自己寫bootloader我在文章最后會展開講。1.3 為什么選擇官方bootloader而不是自研引導(dǎo)程序STM32F103C8T6的官方bootloader方案最大的優(yōu)勢就是零代碼成本。芯片內(nèi)置的引導(dǎo)程序經(jīng)過ST官方長期驗證穩(wěn)定性有保障不需要占用用戶Flash空間來存放bootloader整個64KB Flash全部可以留給應(yīng)用程序支持HEX文件直接下載不需要額外的格式轉(zhuǎn)換配合FlyMcu或STM32CubeProgrammer這類工具操作非常直觀。它適合的場景包括產(chǎn)品開發(fā)階段頻繁更新固件、小批量產(chǎn)線燒錄、現(xiàn)場售后通過串口升級等等。而自研bootloader的優(yōu)勢在于可控性更強可以實現(xiàn)應(yīng)用內(nèi)升級、加密校驗、回滾機制等高級功能但它會占用Flash空間而且一旦bootloader本身有Bug設(shè)備變磚的風(fēng)險也比較大。官方bootloader方案作為第一步能讓我們用最少的成本跑通整個升級鏈路理解原理之后再去設(shè)計自研方案就有了一個非常扎實的基礎(chǔ)。2. 動手前的準(zhǔn)備工作接線、跳線、工具鏈2.1 需要準(zhǔn)備哪些東西硬件方面最核心的就是一塊STM32F103C8T6最小系統(tǒng)板我試過市面上的Blue Pill開發(fā)板也可以用自己畫的板子。一個USB轉(zhuǎn)TTL模塊CH340或CP2102都可以注意模塊的IO電平必須是3.3V如果買到5V電平的模塊輕則通信異常重則燒芯片。還需要幾根杜邦線。軟件方面推薦準(zhǔn)備兩個工具FlyMcu和STM32CubeProgrammer。FlyMcu是國內(nèi)開發(fā)者做的老牌工具界面簡潔一鍵下載的體驗做得很順手STM32CubeProgrammer是ST官方出品的編程工具功能更全面支持HEX、BIN、ELF等多種格式后續(xù)做批量生產(chǎn)也用它。2.2 進入系統(tǒng)存儲器模式的跳線設(shè)置拿最常見的Blue Pill開發(fā)板舉例板上有一個標(biāo)著BOOT0和BOOT1的跳線帽。要讓芯片進入官方bootloader需要把BOOT0跳線撥到1位置高電平BOOT1跳線保持在0位置低電平。然后按一下復(fù)位鍵或者直接重新上電芯片就會運行系統(tǒng)存儲器里的引導(dǎo)程序。這里有個經(jīng)驗修改BOOT0跳線之后必須復(fù)位或者重新上電才會生效。如果你只是把跳線從0撥到1芯片仍然在跑舊程序很多新手就在這一步卡了很久。2.3 串口接線必須交叉連接官方bootloader使用USART1作為下載接口對應(yīng)引腳是PA9和PA10。USB轉(zhuǎn)TTL模塊和STM32之間需要交叉連接這一點極其重要電腦USB轉(zhuǎn)TTL模塊STM32F103C8T6TXDPA10USART1_RXRXDPA9USART1_TXGNDGND請注意GND必須共地否則通信波形不穩(wěn)定經(jīng)常會出現(xiàn)能識別芯片但是下載中途失敗的情況。3.3V電源線可以接也可以不接如果開發(fā)板使用獨立供電就只接TXD、RXD和GND三根線如果使用USB轉(zhuǎn)TTL模塊直接給板子供電則把3.3V也接上。但務(wù)必確認(rèn)模塊的輸出電壓是3.3V且供電電流足夠否則在擦寫Flash這種電流較大的操作時電壓跌落會導(dǎo)致整片F(xiàn)lash數(shù)據(jù)損壞。3. 核心實操用FlyMcu完成一次完整固件下載3.1 第一步讓Keil生成HEX文件在寫下載步驟之前先說一個前置條件。默認(rèn)情況下Keil MDK編譯STM32工程只會生成AXF文件需要額外勾選一個選項才會生成HEX文件。操作路徑是Options for Target → Output選項卡 → 勾選Create HEX File。這個選項勾上之后每次編譯成功工程目錄下的Objects或Listings文件夾里就會多出一個.hex文件FlyMcu下載時選它即可。如果你希望把APP放到偏移地址并在Flash開頭放一個跳轉(zhuǎn)引導(dǎo)程序那么還需要在Target選項卡里設(shè)置IROM1的起始地址和大小。舉例來說如果Flash總共64KB引導(dǎo)程序占16KBAPP就從0x08004000開始那么IROM1的Start設(shè)為0x08004000Size設(shè)為0xC000。這個設(shè)置直接決定了鏈接器生成的代碼地址一旦搞錯下載成功也會跑飛。3.2 第二步FlyMcu的連接參數(shù)配置把USB轉(zhuǎn)TTL模塊插到電腦上打開設(shè)備管理器確認(rèn)串口號。然后打開FlyMcu左側(cè)區(qū)域進行如下配置選擇串口就是剛才記錄的COM號波特率默認(rèn)115200即可如果下載線質(zhì)量好、環(huán)境穩(wěn)定可以改到460800提高速度勾選“校驗”勾選“編程后執(zhí)行”下拉框里選擇“STM32F10x Low-density/Med-density”或者自動檢測FlyMcu會自動識別芯片型號。這個工具已經(jīng)多年不更新但對付F103系列完全夠用。關(guān)于“編程后執(zhí)行”這個選項需要特別解釋一下。它表示下載完成后由bootloader跳轉(zhuǎn)到0x08000000處執(zhí)行用戶程序。如果你的APP鏈接地址就是0x08000000勾選上之后燒完就能直接運行省去手動復(fù)位的步驟。但如果你的APP放在偏移地址而0x08000000處沒有有效的引導(dǎo)程序那么勾選這個選項沒有任何效果甚至可能跑飛。3.3 第三步一鍵下載流程FlyMcu最方便的一點是支持通過串口的DTR和RTS信號線自動控制復(fù)位引腳和BOOT0引腳實現(xiàn)一鍵下載免去手動跳線的麻煩。前提是你的硬件電路上做了USB轉(zhuǎn)TTL模塊的DTR/RTS到NRST/BOOT0的連接很多開發(fā)板在設(shè)計時已經(jīng)內(nèi)置了這個電路。界面上對應(yīng)的是“DTR的低電平復(fù)位RTS高電平進BootLoader”這個復(fù)選框如果板子上有一鍵下載電路就勾上沒有就保持不勾選手動操作BOOT0跳線。操作步驟在FlyMcu中點擊“...”按鈕選擇編譯生成的HEX文件確認(rèn)串口、波特率等參數(shù)無誤如果手動跳線方式先確保BOOT01復(fù)位板子點擊“開始編程”觀察日志輸出窗口正常流程會依次顯示連接成功、芯片識別、整片擦除、寫入Flash、校驗成功看到校驗成功后把BOOT0跳回0按一下復(fù)位鍵程序開始運行整個過程大概十幾秒比接ST-Link還快。實測下來115200波特率最穩(wěn)定460800雖然快但在某些CH340模塊或長線上容易出現(xiàn)偶發(fā)校驗失敗。3.4 備用方案STM32CubeProgrammer下載步驟如果你更喜歡用ST官方工具流程也非常直觀打開STM32CubeProgrammer在右上角選擇UART模式Port選擇對應(yīng)串口波特率設(shè)為115200確保BOOT01并復(fù)位板子點擊Connect按鈕連接成功后在左側(cè)編程區(qū)點擊Open file選擇HEX文件點擊Download按鈕開始下載下載完成后點擊DisconnectBOOT0跳回0復(fù)位運行CubeProgrammer的優(yōu)勢在于對ST芯片的支持最權(quán)威協(xié)議實現(xiàn)完全貼合官方bootloader幾乎不會出現(xiàn)兼容性問題。如果你用了FlyMcu怎么都連不上換個CubeProgrammer往往能解決問題。3.5 兩種部署方式全量覆蓋與分區(qū)引導(dǎo)使用官方bootloader下載時HEX文件里其實自帶了絕對地址信息。也就是說下載工具會按照HEX里記錄的目標(biāo)地址把數(shù)據(jù)寫到Flash的對應(yīng)位置。這就衍生出兩種不同的部署方式。第一種最簡單APP鏈接地址就是0x08000000下載時直接覆蓋整個Flash。這種情況下不需要做中斷向量表重映射因為CPU復(fù)位后從0x08000000取中斷向量本身就是APP自己的向量表完全匹配。對于不少Demo性項目、或者Flash只有64KB的小容量產(chǎn)品這種方式夠用。第二種是把Flash分成兩個區(qū)域0x08000000放一段跳轉(zhuǎn)引導(dǎo)程序偏移地址放真正的APP。兩次下載或者生成合并HEX就能讓設(shè)備啟動時先執(zhí)行引導(dǎo)程序再由引導(dǎo)程序跳到APP。這種部署已經(jīng)接近真正的IAP架構(gòu)但牽扯到中斷向量表重映射的問題繞不開我單獨用一章講清楚。4. 繞不開的坑中斷向量表重映射4.1 APP偏移后為什么必須處理向量表Cortex-M3內(nèi)核的中斷機制決定了任何中斷響應(yīng)時CPU都會從一個固定的地址0x00000000讀取向量表。如果APP放在0x08008000這類偏移地址而0x00000000仍然映射到Flash首地址那么中斷來了以后CPU去0x08000000查向量表找到的是Flash開頭那一小段引導(dǎo)程序的數(shù)據(jù)根本不是APP的中斷服務(wù)函數(shù)地址自然就進不了中斷函數(shù)表現(xiàn)就是程序一觸發(fā)中斷就死機、進入HardFault或者干脆復(fù)位重啟。很多初學(xué)者把APP放到偏移地址后發(fā)現(xiàn)主循環(huán)跑得挺好一按按鍵或者一收串口數(shù)據(jù)就死機就是這個原因。4.2 一個關(guān)鍵知識點STM32F103沒有VTOR寄存器Cortex-M3內(nèi)核定義了向量表偏移寄存器VTOR用來重設(shè)中斷向量表的位置但這是一個可選實現(xiàn)。很遺憾STM32F1系列出于成本考慮沒有集成VTOR寄存器所以不能像F4、F3那樣直接寫一個SCB-VTOR APP_ADDR就完事。網(wǎng)上很多教程拿F4的例子來教F103屬于典型的藥不對癥。F103的正確做法有兩種一種是把整個APP的中斷向量表復(fù)制到SRAM開頭然后把SRAM重映射到0x00000000地址另一種是保留Flash開頭一段空間通過跳轉(zhuǎn)和查表實現(xiàn)軟重定向。實際產(chǎn)品中第一種更簡單可靠。4.3 標(biāo)準(zhǔn)的向量表重映射代碼實現(xiàn)下面是經(jīng)過驗證的重映射函數(shù)在APP的main函數(shù)第一行調(diào)用#define APP_BASE_ADDR 0x08008000u // 根據(jù)實際偏移修改 #define VECTOR_NUM 96u // F103C8T6實際中斷向量數(shù)量約48個取96足夠 static void VectorTableRemap(void) { uint32_t i; uint32_t src APP_BASE_ADDR; uint32_t dst 0x20000000; // 1. 將APP向量表從Flash復(fù)制到SRAM起始地址 for (i 0; i VECTOR_NUM; i) { *(__IO uint32_t *)(dst (i 2)) *(__IO uint32_t *)(src (i 2)); } // 2. 設(shè)置SYSCFG_CFGR1的MEM_MODE位將SRAM映射到0x00000000 __DMB(); SYSCFG-CFGR1 | SYSCFG_CFGR1_MEM_MODE_0; __DSB(); __ISB(); }使用時要檢查一下你的APP工程里棧頂SP初始值也就是0x08008000地址前4字節(jié)的內(nèi)容它會被復(fù)制到SRAM的0x20000000處。程序啟動時CPU已經(jīng)通過Flash讀取過一次棧指針此時棧區(qū)已經(jīng)初始化完成所以覆蓋SRAM開頭這384字節(jié)96個向量乘以4字節(jié)不會影響正在運行的程序只要鏈接腳本里設(shè)置的棧頂?shù)刂凡辉?x20000000到0x20000180之間即可。以F103C8T6的20KB SRAM為例把棧頂設(shè)置在0x20005000附近向量表就穩(wěn)穩(wěn)地和棧區(qū)隔開了。4.4 一個更省事的方案把引導(dǎo)程序也做進Flash向量表重映射確實容易出問題那有沒有更省事的方法有一種做法是把跳轉(zhuǎn)引導(dǎo)段做得更聰明一點Flash開頭不放簡單的跳轉(zhuǎn)指令而是放一個“影子向量表”每個中斷向量都對應(yīng)一個跳轉(zhuǎn)指令跳轉(zhuǎn)到真正的APP中斷服務(wù)函數(shù)。這種方案能避免SRAM的開銷但代碼復(fù)雜度高而且每加一個中斷都要同步維護兩個表我實際用過一次就不再用了。對于絕大多數(shù)產(chǎn)品向量表重映射配合SRAM重映射是最合適的。5. 實戰(zhàn)排雷我遇到的7個典型故障5.1 串口連接失敗FlyMcu報“無法連接”這是出現(xiàn)頻率最高的問題。排查思路按順序來先確認(rèn)BOOT0確實撥到1且芯片已復(fù)位再確認(rèn)TXD/RXD接線是否交叉然后用萬用表量一下USB轉(zhuǎn)TTL模塊的TXD引腳是否有電平跳變最后檢查串口號是否被其他軟件占用以及波特率是否太高。還有一個容易被忽略的點官方bootloader的USART配置是8位數(shù)據(jù)、偶校驗、1個停止位即8E1而普通串口助手的默認(rèn)配置往往是8N1。FlyMcu和CubeProgrammer會自動協(xié)商這部分一般不用手動管但如果你拿自己的串口調(diào)試工具發(fā)命令就要注意這個區(qū)別。5.2 能識別芯片但擦除或?qū)懭霑r報錯這種情況大多是供電問題或線材太長。擦寫Flash時芯片電流需求會突然增大如果USB轉(zhuǎn)TTL模塊的3.3V輸出能力不足電壓跌落就會導(dǎo)致寫入失敗。解決方法是改用獨立穩(wěn)壓供電把USB轉(zhuǎn)TTL模塊和STM32之間線長控制在15cm以內(nèi)。另外飛線時杜邦線接觸不良也會有同樣表現(xiàn)我建議接線后先輕輕晃一晃確認(rèn)接觸牢靠。5.3 燒寫成功但按下復(fù)位沒反應(yīng)程序沒有跑起來。一般原因有三個一是下載的是偏移地址的APP但Flash開頭的0x08000000沒有引導(dǎo)程序二是Boot0跳線沒有撥回0芯片還在系統(tǒng)存儲器模式自然跑不了用戶程序三是KEIL里沒有勾選Create HEX File實際下載的是舊文件。5.4 APP能運行但一進中斷就死機這就是上一章講的問題APP放在偏移地址但沒有做中斷向量表重映射。解決辦法就是調(diào)用重映射函數(shù)并注意在跳轉(zhuǎn)時進入APP之前關(guān)閉全局中斷在APP里重新初始化外設(shè)。5.5 下載完成后自動執(zhí)行會死機手動復(fù)位就正常FlyMcu的“編程后執(zhí)行”功能是通過設(shè)置PC指針直接跳轉(zhuǎn)到0x08000000實現(xiàn)的。如果你的APP在偏移地址而0x08000000沒有有效代碼勾選這個選項就會死機。遇到這個情況取消勾選“編程后執(zhí)行”燒完后手動復(fù)位即可。5.6 使用了國產(chǎn)替代芯片下載失敗現(xiàn)在很多項目用GD32F103、APM32F103等國產(chǎn)替代芯片。這些芯片的系統(tǒng)存儲器bootloader設(shè)計大體兼容ST但通信時序和Flash操作細節(jié)可能有差異。遇到下載失敗優(yōu)先換STM32CubeProgrammer試試如果仍然失敗需要查閱對應(yīng)芯片手冊確認(rèn)USART1在boot模式下是否有特殊配置。我試過GD32F103C8T6用FlyMcu的STMCU自動檢測模式偶爾失敗選對型號后正常。5.7 板子被寫保護無法擦除之前調(diào)試時用ST-Link給芯片設(shè)置了讀保護或者下載工具設(shè)置了選項字節(jié)再想用串口下載就會失敗。解決辦法是用FlyMcu的“解除讀保護”功能或使用STM32CubeProgrammer在Option Bytes頁面吧Read Out Protection設(shè)置為AA并Apply。執(zhí)行完這個操作后Flash會被整片擦除注意提前備份數(shù)據(jù)?,F(xiàn)象可能原因解決方案無法連接BOOT0未拉高、接線交叉錯誤、串口被占用檢查跳線和接線換串口號寫入報錯供電不足、線材過長、接觸不良獨立供電縮短線材重插杜邦線運行無反應(yīng)Flash開頭無引導(dǎo)、BOOT0未復(fù)位、HEX未生成檢查鏈接地址BOOT0跳回0勾選HEX中斷死機向量表未重映射增加重映射函數(shù)自動執(zhí)行死機勾選了“編程后執(zhí)行”且Flash開頭無有效代碼取消勾選手動復(fù)位寫保護無法擦除選項字節(jié)設(shè)置了讀保護解除讀保護注意會格式化Flash6. 進階思考官方方案之外如何設(shè)計真正的IAP升級6.1 官方bootloader方案的邊界在哪里官方bootloader方案的局限其實很明顯。第一每次升級都需要人手去撥BOOT0跳線或者配合一鍵下載電路無法做到“設(shè)備在應(yīng)用運行中自行升級”。第二官方bootloader通過串口接收數(shù)據(jù)時沒有加密和校驗機制關(guān)鍵產(chǎn)品直接暴露在不安全環(huán)境中會引入風(fēng)險。第三它不具備覆蓋保護機制升級斷電容易變磚。這些局限決定了它更適合開發(fā)調(diào)試和小批量維護而不是一個需要遠程升級、高可靠性的量產(chǎn)產(chǎn)品方案。6.2 自研bootloader的標(biāo)準(zhǔn)架構(gòu)如果要做真正意義上的IAP需要自己在Flash中實現(xiàn)一個輕量級引導(dǎo)程序并讓APP具備觸發(fā)跳轉(zhuǎn)的能力。標(biāo)準(zhǔn)分區(qū)方式如下0x08000000自研bootloader區(qū)存放串口/無線接收、Flash寫入、跳轉(zhuǎn)邏輯0x08008000APP區(qū)存放應(yīng)用功能代碼0x0800F000參數(shù)區(qū)存放升級標(biāo)志、版本號最后一次下載前校驗成功后將升級標(biāo)志寫死APP啟動后檢查是否需要跳轉(zhuǎn)bootloaderAPP接收完新固件后先校驗固件完整性CRC或SHA256寫入升級標(biāo)志然后執(zhí)行系統(tǒng)復(fù)位。復(fù)位后bootloader檢查到升級標(biāo)志進入固件接收模式接收完成后跳轉(zhuǎn)新APP。這樣整個升級觸發(fā)出自應(yīng)用本身操作流程變?yōu)樵O(shè)備端收到升級指令→APP下載固件→跳轉(zhuǎn)bootloader→bootloader校驗后寫入Flash→運行新APP。配合雙Bank方案還可以實現(xiàn)升級失敗自動回滾可靠性遠超官方方案。不過如果做遠程升級串口方式就不夠用了需要給APP加網(wǎng)絡(luò)模塊或者無線透傳模塊把固件數(shù)據(jù)通過網(wǎng)口/4G/WiFi接收下來這時候bootloader內(nèi)部的接收邏輯要改成通過共享內(nèi)存或串口從APP模塊獲取數(shù)據(jù)復(fù)雜度又上一個臺階。很多人把這套系統(tǒng)叫OTA升級本質(zhì)是IAP的傳輸通道擴展。6.3 一些實際操作體會做自研bootloader時我踩過最深的坑是Flash扇區(qū)分配問題。STM32F103C8T6的每一個Flash扇區(qū)是1KB擦除必須按扇區(qū)來所以APP區(qū)起始地址必須對齊扇區(qū)邊界。如果APP區(qū)設(shè)為0x08008000這個地址除以0x400剛好是整數(shù)對齊沒問題如果設(shè)為0x08007000對齊就亂了寫擦除時很容易誤擦掉bootloader代碼直接變磚。有幾次我把bootloader的啟動流程和Flash驅(qū)動分開調(diào)試剛寫完驅(qū)動測試時不小心把bootloader區(qū)也擦掉了只能上ST-Link救回來。另外一點固件傳輸協(xié)議設(shè)計要帶幀序號和ACK機制。一開始我把固件分包發(fā)送但沒做ACK數(shù)據(jù)稍大就丟包升級成功率慘不忍睹。后來改成每一包都要應(yīng)答超時重發(fā)對端校驗通過才發(fā)下一包成功率一下就上去了實測一次幾萬字節(jié)的大型固件傳輸基本是一包都不丟。寫在最后的一個小技巧最后分享一個我常用的升級流程閉環(huán)。無論是官方bootloader還是自研方案升級完成后一定要做一次版本校驗并記錄到Flash參數(shù)區(qū)。對于官方bootloader方案下載工具自帶的校驗功能能保證寫入數(shù)據(jù)準(zhǔn)確性但保證不了寫入之后APP的邏輯是否完整所以建議在APP啟動時讀一次自身Flash區(qū)域的版本號和固件CRC值寫到日志里。這樣現(xiàn)場一旦出問題第一件排查的事就是回看日志里的版本記錄能省下大量吹牛歸零的時間。我自己在正式產(chǎn)品中都保留了官方bootloader作為“最后一道門”即使自研bootloader寫崩了還能通過串口把官方bootloader調(diào)出來做強制恢復(fù)。這套組合用熟了之后再復(fù)雜的固件升級場景心里都有底。