:從SOTA升級到自動回滾)
最近一段時間好幾個做ECU底層軟件的朋友都在問我同一個問題英飛凌TC3xx上做SOTASWAP功能到底怎么配置這個問題確實有門檻。我最早接觸SOTA項目時翻了不少參考手冊和論壇帖子發(fā)現(xiàn)大多數(shù)資料要么只講概念要么直接甩一堆寄存器讓新手一臉懵。后來在TC3xx平臺上把一個完整的SOTA升級流程跑通之后我再回頭看其實SWAP的配置思路并不復(fù)雜關(guān)鍵是把PFlash的Bank規(guī)劃、BMI里的SWAP使能位、以及啟動后的確認窗口這三件事串起來。這篇就把我實際配置TC3xx SWAP功能的過程、用到的工具、踩過的坑和測試方法整理出來希望能給準備做ECU空中升級的兄弟們一點參考。內(nèi)容偏底層建議做Bootloader、BSP或者整車OTA方案的工程師收藏。1. 非SOTA與SOTA模型先搞懂升級這件事本身1.1 傳統(tǒng)刷寫是怎么做的傳統(tǒng)ECU軟件刷寫也就是我們常說的非SOTA模型大多走的是OBD接口或者產(chǎn)線工位。工具鏈一般是CANape、UDE、或者各種專用的Bootloader上位機。Bootloader常駐在一個固定區(qū)域應(yīng)用軟件跑在另一個區(qū)域刷寫時通過診斷會話進入編程模式然后一包一包地把數(shù)據(jù)寫進PFlash。這種方式的優(yōu)點很直接鏈路短、可控性強、工具成熟。缺點也明顯——車必須開到特定地方接上設(shè)備才能升級每一次升級都需要人工參與。到了項目后期如果軟件要頻繁迭代產(chǎn)線刷寫和售后刷寫的成本就會迅速膨脹。而且一旦出現(xiàn)大規(guī)模召回靠線下刷寫去修復(fù)軟件問題周期和成本都很難接受。非SOTA模型的更新邏輯往往是“全量覆蓋”就是直接擦掉舊應(yīng)用再把新應(yīng)用寫進同一個區(qū)域。這個模式在開發(fā)調(diào)試階段問題不大但放到量產(chǎn)車上就有風險如果在擦除完成、寫入未完成時突然斷電整個應(yīng)用區(qū)就廢了ECU可能直接留在Bootloader里等著被救。可以說非SOTA模型把所有的可靠性壓力都壓在了“刷寫過程不能中斷”這個前提上。1.2 SOTA在ECU側(cè)多出來的那些活SOTA模型把升級鏈路徹底改變了。云端軟件包先下發(fā)到車機或者T-BOX再由車機通過CAN、CANFD或者以太網(wǎng)把數(shù)據(jù)轉(zhuǎn)發(fā)給目標ECU。這么一來ECU側(cè)面臨的問題就變了下載過程可能斷網(wǎng)傳輸過程可能丟包刷寫過程可能斷電甚至新版本軟件本身可能是有缺陷的。這些問題不是簡單地“把Bootloader寫好”就能解決。ECU側(cè)至少要承擔三件事第一接收并存儲新版本。這個存儲不能直接覆蓋當前運行的應(yīng)用否則一旦寫入失敗就沒有退路。比較常規(guī)的做法是準備一個備份區(qū)先完整接收并校驗再啟動切換動作。第二完整性和安全性校驗。除了CRC、SHA256這類完整性校驗量產(chǎn)項目通常還會加安全啟動、簽名驗證防止固件被篡改。這部分在TC3xx上可以配合HSM模塊來做。第三激活和回滾。新版本寫進去之后要讓ECU下次啟動時能跑到新版本如果新版本跑不起來還要能自動回到舊版本。這一環(huán)如果全靠軟件在Bootloader里手工處理邏輯會非常復(fù)雜而且很難覆蓋各種異常情況。英飛凌TC3xx的硬件SWAP功能正是為這個場景設(shè)計的。2. TC3xx的SWAP機制硬件是如何實現(xiàn)“雙保險”的2.1 先看PFlash的Bank布局要理解SWAP得先搞清楚TC3xx的程序Flash是怎么組織的。以TC39x為例PFlash劃分成若干個Bank每個Bank的地址空間和容量在參考手冊里都能查到。早期我用TC264做項目時它的Flash規(guī)模和Bank數(shù)量比TC39x少很多但SWAP相關(guān)的基本邏輯是一樣的。每個Bank在邏輯上就是一個獨立的Flash塊。我們常說的A/B分區(qū)在SOTA場景里就是把兩個Bank分別當作當前運行區(qū)和待升級區(qū)。升級時應(yīng)用程序運行在A區(qū)新版本寫入B區(qū)下次啟動時硬件把B區(qū)映射成啟動地址讓CPU直接跑新版本。這個過程中A區(qū)的數(shù)據(jù)一直保留著一旦新版本異常隨時可以切回來。需要注意的是TC3xx系列各個型號的Bank地址并不統(tǒng)一。比如TC39x的PF0、PF1可以作為SWAP的Bank0/Bank1地址從0x80000000開始而TC264這樣的雙核芯片Bank布局又不一樣。配置前一定要把對應(yīng)型號的用戶手冊翻出來確認好兩個用于SWAP的Bank的物理地址和大小否則后面寫鏈接腳本的時候很容易把地址整錯。2.2 啟動時的地址映射魔術(shù)SWAP的核心是一個地址映射交換機。CPU啟動時總是從固定地址取第一條指令正常情況下這個地址指向Bank0。當SWAP功能使能之后硬件會根據(jù)當前的SWAP狀態(tài)決定這個固定啟動地址到底對應(yīng)物理上的哪個Bank。打個比方就像家里有兩個房間你每次進門默認去A房間。SWAP打開之后你手里多了一個開關(guān)撥到哪邊進門就去哪邊。而且這個開關(guān)不是普通門鎖它帶了一個很聰明的機制允許你先試住B房間覺得不合適再自動搬回A房間。這里的“撥開關(guān)”動作在TC3xx上就是BMI配置里的SWAP位。BMI的全稱是Boot Mode Index存在UCB里。UBMUser Boot Mode區(qū)域中的BMI配置了芯片啟動時的各種行為其中SWAP位就是控制這個地址映射關(guān)系的總開關(guān)。啟動時硬件讀BMI的SWAP位再配合PMU里當前的Swap狀態(tài)決定把哪個Bank映射到啟動地址。這里特別提醒一下BMI不是普通變量它在UCB里修改它必須走UCB的擦寫流程不是簡單用調(diào)試器向某個內(nèi)存地址寫個值就行的。剛開始接觸時很多人把BMI當普通寄存器操作結(jié)果要么沒生效要么把UCB整個搞壞芯片直接進不了Boot模式。2.3 確認與回滾SWAP真正值錢的地方SWAP最實用的地方是硬件級確認窗口與自動回滾。當BMI的SWAP位使能之后芯片復(fù)位啟動時硬件并不會立刻把新Bank“釘死”。它會給你一個時間窗口在這個窗口內(nèi)新版本軟件必須完成基本自檢并且向PMU的SWAP確認寄存器寫入確認標志。如果窗口過了確認標志沒寫進去下一次復(fù)位時硬件會自動切回舊Bank。這個機制的價值怎么強調(diào)都不過分。它把“新版本是否可用”的判斷從Bootloader里剝離出來交給了應(yīng)用層自己。應(yīng)用跑不起來、看門狗沒人喂、自檢沒過確認就不會執(zhí)行硬件自然幫你回滾。Bootloader里只需要做很少的事情甚至不需要知道應(yīng)用長什么樣。另外確認窗口不是無限長的。具體窗口大小通過配置寄存器設(shè)定時序是由硬件控制的。也就是說確認動作既不能太早也不能太晚。太早自檢還沒完成就盲目確認可能把有問題的版本釘死太晚超時后確認命令可能不生效回滾反而發(fā)生。這個平衡點是項目上需要反復(fù)標定的。3. 手把手配置SWAP從UCB到應(yīng)用確認3.1 開發(fā)環(huán)境怎么搭開始配置SWAP之前先把環(huán)境準備好。TC3xx的工程編譯可以用英飛凌官方的AURIX Development Studio里面集成了GCC工具鏈免費而且上手快如果公司買了Tasking那直接用Tasking也行。我之前用TC264做項目時最開始就是用AURIX Development Studio搭的工程后面切到Tasking代碼基本不用改太多主要差異在鏈接腳本和編譯選項上。調(diào)試和燒寫工具方面常用的是UDE、PLS UDE還有Lauterbach的Trace32。量產(chǎn)階段刷寫B(tài)ootloader很多人會自己寫一個上位機只需要通過CAN或者CANFD把固件包發(fā)給ECU就行。測試階段我習慣用開源的CAN/CANFD上位機先把刷寫邏輯跑通再接入項目專用的測試臺架。如果只是驗證SWAP功能用調(diào)試器配合工程直接下載是最快的路徑。硬件上建議用官方開發(fā)板比如TC39x的AURIX開發(fā)板操作UCB和BMI都相對安全。自己畫的板子如果供電或者復(fù)位設(shè)計有瑕疵調(diào)試SWAP這種跟啟動強相關(guān)的功能很容易把問題搞混。3.2 UCB與BMISWAP開關(guān)藏在哪UCB是User Configuration Block的縮寫位于PFlash的特定地址存放芯片出廠和用戶配置信息。BMI就在UCB的UBM區(qū)域里。要打開SWAP功能就是要把BMI里的SWAP位置1同時把啟動Bank的選擇位配置好。很多人第一次看到UCB地址就頭疼其實不需要背地址。用UDE或者Trace32都有現(xiàn)成的腳本模板可以直接讀改寫UCB。具體做法一般是先用調(diào)試器讀出當前BMI值按手冊確認每一位的含義再把你需要的值寫進去。這里有個很關(guān)鍵的細節(jié)UCB通常有多個備份比如BMHD和BMHD1修改的時候要保證主備一致否則芯片在啟動校驗時可能會判定配置無效直接進入異常處理。我第一次自己寫UCB時只改了主塊結(jié)果芯片反復(fù)重啟后來發(fā)現(xiàn)是備份塊里的BMI跟主塊不一致導致校驗失敗。另外BMI里還有其他控制位比如啟動模式選擇、HSM相關(guān)設(shè)置。改BMI之前一定要把當前值完整記下來哪怕只是改SWAP一個位也建議先備份一份原始配置。真出了問題還有機會恢復(fù)。3.3 實操步驟把A/B分區(qū)跑起來下面我以TC39x開發(fā)板為例梳理一套完整流程把SWAP從零配置到跑通第一步規(guī)劃內(nèi)存布局。確定兩個Bank分別放什么。假設(shè)App A是當前版本放在Bank0App B是新版本放在Bank1。Bootloader放在一個獨立區(qū)域或者放在Bank0的頭部具體看項目設(shè)計。鏈接腳本里兩個App的起始地址和大小必須嚴格按照Bank的邊界來寫。第二步編譯兩個版本的App。App A和App B是兩份獨立固件它們的鏈接地址不同但入口和中斷向量位置要一致。編譯完成后確保兩個固件都能單獨下載到對應(yīng)Bank運行。第三步把App A下載到Bank0App B下載到Bank1。這里調(diào)試器下載時要指定絕對地址不能只下載到默認的0x80000000。實際操作中很多人這一步會踩坑編譯產(chǎn)物默認的下載地址寫死了結(jié)果兩個Bank的內(nèi)容一樣以為SWAP沒生效其實是下載地址搞錯了。第四步配置BMI的SWAP位。通過調(diào)試器腳本或者UCB操作工具把SWAP使能并設(shè)置啟動時先啟動當前Bank。這一步做完后芯片復(fù)位應(yīng)該還是從App A跑起來因為新版本還沒激活。第五步模擬OTA激活過程。在App A運行期間通過某種方式觸發(fā)SWAP切換。工程實現(xiàn)上可以先把PMU的Swap控制寄存器置成切換狀態(tài)然后復(fù)位芯片。復(fù)位后硬件會嘗試從Bank1啟動也就是App B。第六步在App B里執(zhí)行確認邏輯。App B運行后先做自檢比如CRC校驗、外設(shè)初始化、通信報文上報。全部通過后寫PMU的確認寄存器固定Bank1。確認之后即使再次復(fù)位芯片也會繼續(xù)從Bank1啟動。第七步驗證回滾。把App B的自檢邏輯故意做成失敗不寫確認然后復(fù)位觀察芯片是否自動回到Bank0的App A。這一步是整個流程里最關(guān)鍵的驗證項。3.4 應(yīng)用側(cè)確認代碼怎么寫確認邏輯在應(yīng)用側(cè)代碼量不大核心就是啟動后盡快做自檢自檢通過后寫確認寄存器。/* 偽代碼僅作邏輯示意具體寄存器名與位定義以芯片手冊為準 */ void Sota_ConfirmActiveBank(void) { volatile uint32_t *swap_ctrl (volatile uint32_t *)0xF8000150U; /* PMU SWAP控制寄存器示意地址 */ uint32_t reg_val; if (Sota_SelfCheck() OK) { reg_val *swap_ctrl; reg_val | (1U 1); /* CONF位寫1示意 */ *swap_ctrl reg_val; } }這段代碼只是把關(guān)鍵邏輯展示出來實際工程里寄存器地址和位偏移必須對照對應(yīng)型號參考手冊填寫。TC39x和TC264的PMU模塊地址不同寄存器布局也有差異直接抄網(wǎng)上的代碼很容易出事。確認邏輯放置的位置值得認真想想。放太早自檢覆蓋不足放太晚可能已經(jīng)錯過硬件確認窗口命令寫了也白寫。我的經(jīng)驗是把確認放在應(yīng)用主循環(huán)的早期并且確認前至少完成必要外設(shè)初始化和少數(shù)幾個關(guān)鍵自檢項比如時鐘是否穩(wěn)定、Flash校驗是否通過、通信鏈路是否正常。4. ECU Boot全量測試SOTA能不能上的唯一標準4.1 全量測試覆蓋哪些場景SWAP功能配好之后只是把路修通了。要真正量產(chǎn)還得經(jīng)歷一輪完整的ECU Boot全量測試。這個測試不是簡單驗證“能升級”而是要覆蓋所有可能出問題的場景。我一般的測試矩陣至少包含正常流程升級、升級過程中斷電、固件校驗失敗、確認窗口超時、應(yīng)用自檢失敗回滾、連續(xù)多輪升級、上下電時序異常、以及Bootloader本身刷新。每一類測試都要有明確的預(yù)期結(jié)果和判定標準。很多團隊在功能開發(fā)階段不做全量測試等到整車集成時才發(fā)現(xiàn)回滾邏輯有漏洞那時候再改底層代碼成本會高得多。最好是在臺架上把全量測試跑完再去聯(lián)整車。4.2 超時回滾與斷電測試設(shè)計超時回滾是全量測試里的重點。測試方法是讓ECU從App A切到App B后故意不讓App B執(zhí)行確認動作然后觸發(fā)復(fù)位。觀察硬件是否如預(yù)期回滾到App A。這個測試看起來簡單實際非常容易暴露問題。比如App B雖然沒確認但它在啟動時改了某些外設(shè)狀態(tài)導致App A恢復(fù)啟動后通信狀態(tài)異常。斷電測試更考驗設(shè)計。測試時要在App B寫入過程中隨機切斷電源然后重新上電檢查ECU能否回到一個可恢復(fù)狀態(tài)。借助TC3xx的SWAP硬件機制只要App分區(qū)寫入和切換邏輯正確通??梢曰氐脚f版本繼續(xù)運行。但前提是Bootloader對寫入過程做了足夠的保護比如在寫入前先記錄狀態(tài)標志。這里有一條鐵律任何一次PFlash寫入都必須假設(shè)它會失敗。Bootloader里每個關(guān)鍵步驟前后都要有狀態(tài)記錄和校驗點。只有這樣才能保證即使掉電下次上電也能判斷出當前處于哪個階段該回滾還是該繼續(xù)。4.3 測試階段用什么工具順手全量測試階段工具選得順手能省很多時間。我個人習慣用兩套工具配合一是調(diào)試器負責查看寄存器狀態(tài)、讀寫UCB、跟蹤復(fù)位原因二是CAN/CANFD刷寫上位機負責模擬車機下發(fā)刷寫請求驗證Bootloader的實際刷寫流程?,F(xiàn)在有不少開源CAN/CANFD上位機項目可以直接跑在PC上通過USBCAN設(shè)備跟ECU通信用來調(diào)試Bootloader刷寫協(xié)議很方便。還有一些團隊用虛擬通道的方式在臺架上模擬整車網(wǎng)絡(luò)節(jié)點做更接近實車的集成測試。無論用哪種工具只要能穩(wěn)定地模擬出“云端—車機—ECU”的鏈路就足夠把Bootloader的刷寫邏輯和SWAP切換邏輯驗證清楚。5. 踩坑記錄與排查思路5.1 打開SWAP后芯片“變磚”我遇到過最嚇人的情況是剛使能SWAP之后芯片直接“變磚”——調(diào)試器連不上程序不跑看起來就像芯片報廢了。后來排查發(fā)現(xiàn)問題不在SWAP本身而是我改BMI時把UCB其他配置也帶偏了。處理這類問題首先不要慌。TC3xx的調(diào)試接口通常還保留著可以嘗試用調(diào)試器在芯片上電早期把CPU halt住然后檢查UCB區(qū)域的內(nèi)容確認BMI當前值是否合理。如果UCB還能正常讀寫把BMI恢復(fù)成出廠值或者之前的備份值重新上電基本就能救回來。如果UCB損壞得非常徹底就需要走芯片的恢復(fù)流程用調(diào)試器重新燒寫UCB。這個過程務(wù)必按照參考手冊操作不同型號的恢復(fù)地址和命令格式有差異。最穩(wěn)妥的做法是在做任何UCB修改之前先用調(diào)試器把當前整個UCB區(qū)域讀出來保存成bin文件。有了備份出問題至少還有退路。5.2 確認寫不進去、回滾不如預(yù)期還有一種常見問題應(yīng)用跑起來了自檢也通過但確認命令寫進去后不生效回滾還是發(fā)生了。這個問題多半出在確認窗口時序上或者訪問權(quán)限上。TC3xx的PMU寄存器訪問有些受HSM保護或者需要在特定模式下才能寫。如果HSM已經(jīng)使能應(yīng)用側(cè)的確認操作可能需要通過安全接口來完成直接操作PMU寄存器可能會被拒絕。另一種可能是確認窗口太短應(yīng)用啟動后做了一堆慢速初始化等執(zhí)行到確認代碼時窗口已經(jīng)關(guān)閉了。排查時先加調(diào)試信息打印確認前后的寄存器狀態(tài)確認是否真的寫進去了。再查確認窗口配置看是不是需要重新標定。還有一點有些項目里Bootloader和應(yīng)用對PMU寄存器的訪問方式不同確認邏輯放錯層也會導致問題。5.3 鏈接腳本和刷寫地址不匹配最后一個很隱蔽的坑是鏈接腳本里的地址與實際刷寫地址不一致。App A和App B是兩個獨立工程鏈接腳本里都要寫清楚自己的運行地址。如果地址配置正確但調(diào)試器下載時沒有按絕對地址下載或者是Bootloader在轉(zhuǎn)發(fā)固件時把地址算錯了就會出現(xiàn)“看起來切過去了實際跑的還是同一個東西”的情況。排查這類問題第一步是確認編譯產(chǎn)物里的地址信息打開map文件看每個段的加載地址和運行地址是否正確。第二步是確認下載工具的實際寫入地址尤其用上位機刷寫時地址往往由協(xié)議里的地址字段決定很容易在大小端和地址換算上出錯。這里分享一個我自己的習慣每次刷寫前先把要寫入的數(shù)據(jù)和地址通過上位機日志打出來用腳本比對一次確認無誤再下發(fā)。雖然多花幾秒鐘但能省掉很多排查時間。最后再說點個人感受。SWAP這個功能官方參考手冊里寫得很簡單不就是幾個位嘛但真正在項目里跑起來細節(jié)非常多。配置BMI、寫UCB、搭鏈接腳本、設(shè)計確認邏輯、做全量測試每一步都有隱藏的坑。我前后做了三輪才把完整流程穩(wěn)定下來最大的體會是SWAP只是一個硬件開關(guān)真正的復(fù)雜度在它周圍的軟件設(shè)計里。如果你正在做TC3xx的SOTA建議先拿開發(fā)板把SWAP的回滾流程完整驗證一遍再往下做量產(chǎn)邏輯。這個功能用好了ECU空中升級的可靠性會提升一個量級。