點的算法加載與功耗設(shè)計)
老哥們最近一直在折騰一個比較典型的低功耗振動監(jiān)測節(jié)點用的就是ST的IIS3DWB10IS這顆帶ISPU的高帶寬加速度計。項目本身不復雜——磁吸安裝在設(shè)備外殼上電池供電平時主控睡大覺隔一段時間醒來采集一次振動數(shù)據(jù)判斷有沒有異常。但做到一半我們卡在了一個繞不開的問題上ISPU這個內(nèi)核沒有NVM它的程序只能放在RAM里掉電就丟而整機為了省電偏偏還要做power gating每次喚醒都是冷啟動。那ISPU里跑的FFT和異常檢測算法代碼到底放哪每次上電怎么恢復整個電池節(jié)點的功耗賬該怎么算這篇文章就是我處理這個問題時踩出來的完整思路。我會先講清楚ISPU沒有NVM到底卡在哪再給出我認為最合理的幾種方案和選型邏輯然后詳細算一遍冷啟動的時間與功耗賬最后把調(diào)試中遇到的加載失敗、掉電亂序、Flash壽命這些坑都列出來。如果你手上也在做IIS3DWB10IS或類似帶ISPU傳感器的電池節(jié)點這篇應該能幫你少走很多彎路。1. 先說清楚ISPU沒有NVM到底卡在哪個環(huán)節(jié)1.1 IIS3DWB10IS在電池節(jié)點里的定位IIS3DWB10IS不是一顆普通的加速度計。它本身的振動測量帶寬很高噪聲也低適合軸承故障、齒輪箱、泵和風機這類旋轉(zhuǎn)機械的狀態(tài)監(jiān)測。但真正讓它區(qū)別于普通傳感器的是這個集成的ISPU內(nèi)核——一顆可以在傳感器內(nèi)部跑輕量級信號處理和機器學習推理的可編程單元。在電池供電的振動節(jié)點里ISPU的價值非常直接原始振動數(shù)據(jù)不用一路傳到主控MCUISPU直接在傳感器內(nèi)部做FFT、RMS、峰值提取甚至跑一個異常檢測模型最后只把診斷結(jié)果通過FIFO送出來。主控MCU大部分時間可以保持深度睡眠甚至整機斷電。這樣整個系統(tǒng)的平均功耗可以壓到非常低一節(jié)電池用好幾年的節(jié)點就是這么設(shè)計出來的。不過ISPU雖然能算但它本身沒有非易失存儲。這就引出一個所有做低功耗節(jié)點的人都要面對的問題——算法代碼在掉電之后去哪了。1.2 “ISPU沒有NVM”到底意味著什么先打個比方。ISPU就像一臺沒有硬盤的電腦你寫好的算法程序放在它內(nèi)部的SRAM里掉電以后連操作系統(tǒng)帶應用程序全部清空。每次機器開機你都得先從外部U盤把系統(tǒng)重新灌進去灌完才能開始干活。放在IIS3DWB10IS上就是主控MCU每次上電后都需要通過SPI接口把ISPU的算法二進制文件推送到ISPU內(nèi)部的程序區(qū)然后再讓ISPU復位啟動它才能正常跑起來。這個過程不是可選項而是必須做的因為ISPU自己沒有任何可以持久化保存代碼的空間。所以“power-gated battery node”和“ISPU無NVM”這兩個條件放一起就構(gòu)成了一個矛盾省電要求整機頻繁斷電但每次斷電再上電ISPU都處于“空系統(tǒng)”狀態(tài)必須重新加載算法。而加載算法本身要花時間、要耗電流這個開銷在設(shè)計功耗預算時很容易被忽略但恰恰會決定節(jié)點的喚醒頻率上限和電池壽命。很多第一次用這顆芯片的朋友會下意識問ST為什么不在ISPU里面放一點Flash其實從成本、晶圓面積和功耗的角度看這種設(shè)計是合理的畢竟ISPU的定位是輔助處理器算法代碼由主機管理本來就是常見形態(tài)。但這就逼著系統(tǒng)設(shè)計者必須認真對待“算法從哪來、怎么加載、加載多快”這幾個問題。2. 推薦方案算法代碼應該放在哪里2.1 幾個方案先擺出來對比一下針對ISPU沒有NVM的問題我見過的主流做法有三類各有各的適用場景先用一張表說清楚。方案算法代碼存放位置啟動時序復雜度適合場景A主控Flash存儲每次冷啟動加載放主控MCU片內(nèi)Flash或外掛NOR Flash上電后由MCU通過SPI寫入ISPU低大多數(shù)電池振動節(jié)點喚醒不頻繁B保持傳感器供電不徹底斷電算法留在ISPU RAM中不丟失無需重新加載ISPU直接續(xù)跑低喚醒頻率較高待機電流可以接受C外掛SPI Flash統(tǒng)一管理算法包放獨立SPI Flash主控只負責搬運比A多一次Flash讀操作中高算法體積大、版本多、需要OTA升級先說結(jié)論絕大多數(shù)低功耗、間歇喚醒的振動節(jié)點我都推薦方案A也就是主控NVM存算法、上電后快速加載。方案B適合喚醒頻繁但又能接受“不徹底關(guān)斷”的場景方案C是算法體積和升級需求大到主控Flash裝不下時的備選。2.2 我最推薦的組合主控Flash加SPI DMA加載方案A的具體做法其實不復雜但有幾個細節(jié)決定能不能穩(wěn)定運行。算法工程在ST的ISE環(huán)境里編譯之后會生成一個二進制文件這個文件會嵌到主控MCU的固件里作為常量數(shù)組存在MCU的片內(nèi)Flash中。注意這里說的Flash是主控的Flash不是ISPU的——ISPU沒有但主控一定有。上電加載流程我一般是這樣安排的主控上電初始化自己的時鐘、GPIO和SPI外設(shè)。拉高傳感器的電源域等待傳感器內(nèi)部上電穩(wěn)定。對傳感器做一次軟復位確保它處于已知狀態(tài)。配置SPI接口把ISPU算法二進制分塊寫入傳感器的程序區(qū)。全部寫完后發(fā)送啟動或運行指令讓ISPU程序真正跑起來。通過狀態(tài)寄存器或者中斷信號確認ISPU已經(jīng)正常運行然后再初始化業(yè)務(wù)邏輯。這個流程里步驟4最容易被忽視的是“分塊寫入”和“傳輸校驗”。我見過有人直接把數(shù)千字節(jié)的數(shù)組一次性往SPI上懟結(jié)果因為主機緩沖不夠、或者SPI時鐘邊沿余量不足導致寫進去的數(shù)據(jù)錯位ISPU跑出來的完全是垃圾結(jié)果。正確的做法是把算法文件按256字節(jié)或512字節(jié)一塊一塊一塊地寫入每塊寫完都有明確的應答或寄存器狀態(tài)可查最后做一次整體校驗。在傳輸手段上強烈建議用DMA不要用CPU一個字節(jié)一個字節(jié)地搬。加載算法期間主控可以繼續(xù)做別的事或者干脆進入一個低功耗等待狀態(tài)直到DMA傳輸完成中斷再醒來。我用DMA加載40KB左右的算法實際CPU占用幾乎可以忽略整個過程由硬件自動完成這對功耗控制幫助很大。2.3 什么時候才需要外掛SPI Flash方案C我平時不太建議一上來就用除非你明確遇到了下面這些情況主控MCU片內(nèi)Flash太小塞不下多版本算法或一套完整的升級鏡像。算法體積已經(jīng)大到幾十上百KB而且還在不斷膨脹。產(chǎn)品需要支持現(xiàn)場OTA升級算法需要在本地暫存新版本固件。主控MCU過于低端內(nèi)部Flash本身就非常有限。外掛SPI Flash的缺點也很明顯成本增加、PCB面積增加、加載前要多一次“從Flash讀出來再寫進ISPU”的搬運啟動時間比方案A更久而且SPI Flash本身也是NVM一樣要考慮擦寫壽命。所以我的建議是預算和技術(shù)指標都允許的情況下先用主控Flash等確實不夠了再考慮外掛Flash。3. 啟動時序和功耗的賬要會算3.1 一次完整的冷啟動需要多長時間討論“推薦做法”的時候不能回避一個核心指標冷啟動到底要多久。這個指標直接影響節(jié)點是否能夠在可接受的窗口里完成一次數(shù)據(jù)采集也直接決定平均功耗。完整的冷啟動時間可以拆成幾段看傳感器電源域上電穩(wěn)定通常幾毫秒到十幾毫秒取決于電源開關(guān)器件和去耦電容。主控上電和SPI初始化幾毫秒。傳感器軟復位與會話建立幾毫秒。ISPU算法加載這是大頭取決于算法體積和SPI時鐘。ISPU啟動、初始化數(shù)據(jù)通路、FIFO開始填充幾毫秒。其中第4步是可以量化計算的。假設(shè)算法bin的實際大小在40KB左右SPI時鐘按10MHz跑理論傳輸時間大概是40 × 1024 × 8 / 10,000,000 ≈ 32.8毫秒但實際操作中有命令開銷、塊間切換、應答等待還要算上偶發(fā)的重傳所以實際加載時間落在40到60毫秒是很正常的。如果SPI時鐘能跑到20MHz理論時間可以砍半傳輸部分能做到16毫秒左右實際也就20到30毫秒。如果你按40KB算出來的加載時間比傳感器本身的測量周期還長那就要警惕了這種場景下每次喚醒都重載算法的代價可能比你想象的高得多。3.2 用數(shù)字說話加載一次ISPU到底值多少功耗功耗賬不能只看“時間短”要看“平均電流”。假設(shè)整個加載過程傳感器和主控都處于工作狀態(tài)整機電流取8mA左右加載時間按70毫秒算那么一次加載消耗的電量就是8mA × 0.07秒 ≈ 0.56毫安秒再換算成庫侖約等于0.56mAs。這個數(shù)字單獨看不嚇人但放到整個工作周期里算平均電流就很直觀了如果節(jié)點每60秒喚醒一次平均電流約 0.56mAs / 60s ≈ 9.3μA。如果節(jié)點每5秒喚醒一次平均電流約 0.56mAs / 5s ≈ 112μA。如果節(jié)點每1秒喚醒一次平均電流約 0.56mAs / 1s ≈ 560μA。注意這還只是加載算法這一件事的貢獻沒有算傳感器配置、數(shù)據(jù)采集、無線發(fā)射的電流。也就是說在喚醒不頻繁的節(jié)點里重新加載算法的功耗完全可以接受但喚醒頻率一旦上去加載本身就會變成最大的耗電黑洞。這也是為什么我說“推薦方案”不能脫離場景。低頻喚醒的軸承監(jiān)測節(jié)點方案A非常好70毫秒加載時間換來極低的待機電流電池壽命完全達標但如果你的節(jié)點需要每秒都判斷一次設(shè)備狀態(tài)那方案A就沒那么香了要么拉長休眠周期要么改用方案B讓ISPU一直保持供電。3.3 降低加載開銷的幾個實操技巧如果確認走方案A有幾個小技巧可以幫你把加載功耗壓下來。一是優(yōu)先用DMA傳輸。CPU在加載期間不用一直跑可以進入低功耗等待狀態(tài)等DMA完成中斷再喚醒這樣峰值電流的時間和幅度都更可控。二是按需初始化硬件。SPI外設(shè)、GPIO、DMA通道這些盡量在加載前一次性配置好不要在加載過程中反復開關(guān)外設(shè)時鐘那會引入額外的電流尖峰。三是檢查算法bin體積。每次編譯完都看一眼生成的二進制文件大小別讓它在不知不覺中膨脹。關(guān)掉調(diào)試輸出、縮減環(huán)形緩沖、精簡模型結(jié)構(gòu)能省下幾十KB就相當于省下了幾十毫秒加載時間和對應的功耗。四是把校準參數(shù)和用戶配置交給主控統(tǒng)一管理。傳感器內(nèi)部的用戶寄存器在掉電后同樣會丟所以像偏移校準、閾值設(shè)置、濾波器系數(shù)這些都應該存在主控Flash里每次加載算法后重新寫一遍。別指望ISPU自己能記住這些配置它沒有NVM做不到。3.4 喚醒頻率高時也許不該斷電這一點值得單獨拎出來說。不少團隊一提到低功耗就條件反射地想到“全斷”但全斷并不是唯一的省電路徑甚至不是最優(yōu)路徑。如果節(jié)點喚醒頻率超過每5秒一次或者更極端地需要持續(xù)監(jiān)測那每次喚醒都重新加載幾十毫秒的算法反而比讓ISPU保持在一個低功耗狀態(tài)更費電。這種場景我建議改用“偽power gating”傳感器電源不斷讓ISPU進入低功耗或睡眠模式中斷喚醒后它可以直接從RAM里繼續(xù)執(zhí)行程序不需要重新加載。代價是待機電流不再是零可能是幾十微安級別但換來的是微秒級的響應和完全不需要加載算法。在故障檢測類應用里很多時候“睡得淺一點但能快速響應”比“徹底關(guān)機但要花幾十毫秒才能醒”更劃算。這個取舍一定要寫在方案評審里別等到代碼寫完才改架構(gòu)。4. 加載失敗、掉電時序、Flash壽命這些坑我替你們踩過了4.1 ISPU程序加載失敗的常見原因ISPU程序加載失敗通常不會有什么明顯的報錯表現(xiàn)就是ISPU沒有按預期輸出結(jié)果或者傳感器狀態(tài)寄存器里的標志位不對。我排查過幾次最后定位到的主要原因就這幾個傳感器還沒就緒就開始寫程序。上電后立刻發(fā)SPI命令傳感器內(nèi)部還在復位命令全部被丟棄。SPI時鐘太快或信號完整性問題。飛線過長、上拉電阻不對、時鐘邊沿采樣點配置錯誤都可能導致寫入的數(shù)據(jù)錯位。加載過程中電源電壓跌落。電池節(jié)點上電瞬間電流沖擊大電源沒有穩(wěn)定導致加載中途失敗。算法bin版本與ISPU運行環(huán)境不匹配。比如用舊版本的IDE編譯的算法或者字節(jié)序配置錯誤。加載后沒有正確觸發(fā)啟動或者復位時序錯誤導致ISPU雖然收到了程序但并沒有運行起來。這些問題的排查方式我建議從軟件和硬件兩頭同時下手。軟件上在加載流程里加CRC校驗和狀態(tài)檢查每次寫一塊都確認寫成功再寫下一塊硬件上用邏輯分析儀抓一次SPI波形看看時鐘和數(shù)據(jù)是否對齊電源軌有沒有明顯跌落。4.2 MCU軟復位后的狀態(tài)一致性問題還有一個容易被忽略的坑MCU自己跑飛了軟件看門狗復位但傳感器的電源沒有斷過。這時候ISPU的程序其實還在RAM里還在繼續(xù)跑而主控MCU的SPI配置、DMA狀態(tài)、業(yè)務(wù)邏輯全部重新初始化了。兩邊處于“都知道對方存在但不知道對方狀態(tài)”的尷尬境地表現(xiàn)出來就是數(shù)據(jù)錯亂、中斷喚醒異常、莫名其妙多出很多垃圾中斷。所以我的建議是MCU的啟動流程里必須包含一個“傳感器復位并重新加載”的步驟即使傳感器看起來還在正常運行也要先把它軟復位掉然后重新加載ISPU算法保證整個系統(tǒng)回到一個確定性的初始狀態(tài)。這樣做雖然會讓啟動時間多幾十毫秒但換來的是系統(tǒng)狀態(tài)的一致性和可預期性在低功耗節(jié)點里這個代價是值得的。4.3 掉電順序與電源管理電路的配合既然做了power gating就繞不開掉電順序。最怕的情況是系統(tǒng)正在采集數(shù)據(jù)ISPU正在跑FFT主控突然把傳感器電源關(guān)了ISPU跑到一半掉電。下次上電時傳感器可能處于一個未定義狀態(tài)SPI通信拉不起來加載算法也遲遲不成功。合理的做法是在硬件設(shè)計時就規(guī)劃好掉電時序。傳感器的電源開關(guān)要保證有明確的上下電延遲不能和主控的reset共用同一個毛刺源軟件上主控在關(guān)斷傳感器電源之前應先把ISPU置于復位狀態(tài)或者至少讓它停止輸出中斷信號避免掉電瞬間ISPU給主控留下一個虛假的中斷。另外中斷線上最好加一個小的RC濾波或下拉避免掉電期間傳感器電源上的殘壓耦合出干擾脈沖把主控從低功耗狀態(tài)誤喚醒。這種問題在實驗室里很難復現(xiàn)一到現(xiàn)場就會變成“電池掉得特別快”的詭異Bug排查起來非常頭疼。4.4 Flash擦寫壽命、算法版本升級與現(xiàn)場維護如果算法放在主控Flash里就繞不開Flash壽命問題。算法本身是只讀的不會頻繁擦寫但OT A升級時如果設(shè)計得不好頻繁在同一個Flash分區(qū)寫入幾年下來就可能把片內(nèi)Flash寫穿。這不是危言聳聽現(xiàn)場的工程設(shè)備往往要服役五到十年。我的建議是算法存儲區(qū)與主程序存儲區(qū)在邏輯上分開算法區(qū)域使用雙備份結(jié)構(gòu)。當前正在運行的算法放一塊區(qū)域新升級的算法先寫入另一塊區(qū)域校驗通過后再切換激活。萬一升級過程中掉電下次啟動還能用舊版本算法繼續(xù)跑不會變磚。這套邏輯不復雜但對現(xiàn)場維護的可靠性提升非常大。給算法文件本身也建議帶一個版本號和CRC字段主控加載前讀出來校驗一遍避免Flash區(qū)域數(shù)據(jù)出錯ISPU跑了一個完全錯誤的算法。震動節(jié)點平時沒人看管一旦數(shù)據(jù)異常幾乎沒法遠程定位所以所有能自愈的機制都要盡量做在前面。4.5 程序保密性算法裸露在Flash里的風險還有一個很多人不會第一時間想到的點算法二進制放在主控Flash里本質(zhì)上就是明文存放的。如果現(xiàn)場的設(shè)備被人拆走通過調(diào)試接口把Flash讀出來你的振動診斷算法就完全暴露了。對很多做設(shè)備健康管理的公司來說算法模型本身就是核心資產(chǎn)。如果在意這個問題常見的做法是在主控側(cè)對算法二進制做加密存儲上電后解密再傳給ISPU。但要注意解密會占用主控RAM和CPU時間在超低功耗節(jié)點上需要評估是否劃算。對于比較敏感的工業(yè)客戶這個權(quán)衡值得提前和產(chǎn)品經(jīng)理對齊別等量產(chǎn)了再改加密方案。5. 回到標題我的recommended approach是什么5.1 一句話結(jié)論如果一定要用一句話回答標題里的問題我的答案是默認把ISPU算法二進制放在主控MCU的Flash里每次冷啟動通過SPI DMA分塊寫入ISPU配合CRC校驗和版本管理把加載時間控制在幾十毫秒量級當喚醒頻率高到重新加載的電量開銷無法接受時再切換為ISPU保電加低功耗運行的“偽power gating”方案只有當算法體積大到主控Flash放不下、或者需要頻繁O(jiān)TA升級時才去引入外部SPI Flash。這個思路的出發(fā)點很簡單在絕大多數(shù)電池供電的振動監(jiān)測場景里喚醒頻率并不高加載幾十毫秒的算法換來的低待機功耗才是收益最大的。而真正決定成敗的不是上電加載這個動作本身而是你為它設(shè)計的時序、校驗、掉電保護和版本管理機制。5.2 選型時真正該留意的兩件事第一件事是喚醒頻率。在項目最早期就要把“平均多久醒一次”這個參數(shù)定下來因為它直接決定ISPU的供電策略。喚醒頻率低于每30秒一次方案A幾乎無腦用喚醒頻率高于每5秒一次就要認真考慮方案B。第二件事是算法體積。哪怕現(xiàn)在只有20KB也要按未來增加故障類型、增加模型復雜度后的體積做評估看你選的主控Flash夠不夠用別等算法優(yōu)化到一半發(fā)現(xiàn)塞不下了再換芯片。5.3 一點經(jīng)驗做這類低功耗傳感器節(jié)點我個人的體會是不要怕ISPU沒有NVM真正怕的是系統(tǒng)設(shè)計時沒有把“冷啟動加載”當成一個一等公民來對待。只要你在架構(gòu)階段就給加載流程留好時序預算、功耗預算和異?;謴吐窂竭@個“缺點”完全不會成為瓶頸。另外再分享一個小建議在固件里保留一個加載耗時的性能探針每次上電都記錄一次從電源開啟到ISPU開始運行的毫秒數(shù)。這個數(shù)字在調(diào)試時價值極大能幫你快速識別是電源不穩(wěn)、SPI通信異常還是算法文件體積膨脹導致的問題。我在好幾個項目里都是靠這個數(shù)據(jù)定位到硬件問題的強烈建議你加上。