
1. 先說結(jié)論為什么一個國產(chǎn)芯片的USB-CAN卡值得你這么折騰我玩USB-CAN分析儀已經(jīng)好幾年了從最初買的幾十塊錢的“裸板”到后來幾千塊的商用設(shè)備手里前前后后過了不下十塊卡。但這個標(biāo)題里涉及的東西——給一片APM32F072主控的USB-CAN卡刷入moonglow/kvaser開源固件——是我這幾年折騰下來覺得最值回票價的玩法沒有之一。先給還不清楚的朋友捋一下這幾樣?xùn)|西到底是個啥。USB-CAN是USB轉(zhuǎn)CAN總線的協(xié)議轉(zhuǎn)換設(shè)備電腦通過USB口連上它就能直接收發(fā)CAN總線上的報文調(diào)試車載ECU、工業(yè)設(shè)備、機(jī)器人控制器都離不開它。APM32F072是極海半導(dǎo)體推出的一款Cortex-M0內(nèi)核MCU和意法半導(dǎo)體的STM32F072管腳兼容、外設(shè)兼容度很高很多國產(chǎn)USB-CAN分析儀用的就是這顆芯片或者它的近親STM32F072。而moonglow是Github上一個開源固件項目能讓廉價的USB-CAN硬件跑起接近商用分析儀的固件功能kvaser則是瑞典一家老牌CAN總線工具廠商它的軟件生態(tài)和驅(qū)動在行業(yè)內(nèi)認(rèn)可度很高moonglow項目的一個重要目標(biāo)就是讓低成本的國產(chǎn)硬件兼容kvaser的通信協(xié)議從而用上kvaser的Windows軟件和SDK。說人話就是你有一塊一百多塊錢買來的USB-CAN小板內(nèi)部芯片是APM32F072通過刷入一個開源固件可以讓它被電腦識別成幾千塊錢的商用設(shè)備并且能跑商用的上位機(jī)軟件。這事兒要是放幾年前想都不敢想但現(xiàn)在開源社區(qū)把這條路徹底鋪平了。這篇文章適合誰看第一類是手里正好有這類USB-CAN板子、想挖掘更多功能的人第二類是做嵌入式開發(fā)、需要多個CAN通道但又暫時不想買昂貴設(shè)備的人第三類是純粹想研究固件移植、了解MCU內(nèi)部Bootloader機(jī)制的人。全文會從硬件原理講到刷機(jī)實操再到坑點排查手把手帶你把這套流程走通。2. 硬件底子拆解APM32F072怎么就成了USB-CAN的“完美胚子”2.1 認(rèn)識這塊板子的核心主控、收發(fā)器、電源一個都別少要做USB-CAN分析儀主控芯片必須同時具備兩個能力一是要有CAN控制器外設(shè)二是要有USB設(shè)備控制器。這兩樣缺一不可否則就得外掛芯片成本和復(fù)雜度都會上去。APM32F072這顆芯片恰好就是這個定位Cortex-M0內(nèi)核主頻48MHz內(nèi)置了USB 2.0 Full-Speed設(shè)備控制器和一路CAN 2.0B控制器。和STM32F072相比雖然寄存器有些細(xì)微差異但引腳定義和整體架構(gòu)幾乎一致這意味著市面上大量為STM32F072寫的USB-CAN開源方案理論上都可以通過適配移植到APM32上。除了主控板上還有一個CAN收發(fā)器芯片最常見的是TJA1050或者TJA1051它的作用是把MCU內(nèi)部CAN控制器輸出的差分信號轉(zhuǎn)換成總線上的物理電平。有些便宜板子用的是國產(chǎn)兼容料比如SIT1050功能上沒區(qū)別但需要注意供電電壓是5V還是3.3V這會影響你在接線時的判斷。電源部分同樣不能小看。USB-CAN板子一般有兩種供電方式一種是直接從USB的5V取電板上用一顆LDO降到3.3V給MCU供電另一種是板上有隔離電源模塊CAN側(cè)用單獨的隔離電壓常見的是B0505S這種小功率的DC-DC隔離模塊。有隔離的板子抗干擾能力好很多在車上調(diào)試時不容易被共模干擾打掛價格自然也就貴一些。我之前拆過一塊板子走線非常精簡主控、晶振、收發(fā)器、LDO、接口全部加起來十幾個元件。這種極簡設(shè)計的板子反而很適合刷機(jī)研究因為變數(shù)少、問題容易排查。如果你拿到手的板子結(jié)構(gòu)更復(fù)雜還帶TVS管、共模電感、防靜電芯片這些保護(hù)器件那就更好了刷機(jī)過程中不太容易因為靜電或者接線失誤把板子弄壞。2.2 Bootloader的秘密為什么“能刷機(jī)”本身就是一種設(shè)計很多朋友第一次聽說可以給USB-CAN刷固件時第一反應(yīng)是這玩意兒不是出廠就寫死程序了嗎怎么還能刷這里面的關(guān)鍵在于很多USB-CAN板子在出廠時就預(yù)置了一段Bootloader程序。Bootloader本身不干CAN的活兒它的作用是在上電時檢查特定條件決定是進(jìn)入固件升級模式還是直接跳轉(zhuǎn)到用戶應(yīng)用程序。常見的進(jìn)入Bootloader的方式有幾種按住板上的按鍵再插USB上電短接BOOT0跳線后上電通過上位機(jī)軟件發(fā)送特定命令重啟進(jìn)Bootloader檢測到USB總線有特定請求時自動進(jìn)入moonglow固件的刷入往往就要用到這種出廠Bootloader。因為Bootloader占據(jù)的是MCU的System Memory或Flash的起始區(qū)域它通過USB DFU協(xié)議或者自定義的CAN命令來接收新固件然后寫入到應(yīng)用區(qū)。這就意味著你不需要買ST-Link或者J-Link調(diào)試器一根USB線就能完成刷機(jī)門檻大幅降低。但也要提前打個預(yù)防針不是所有USB-CAN板子都有USB DFU引導(dǎo)功能。有些特別廉價的板子出廠只燒錄了應(yīng)用固件沒有預(yù)置Bootloader或者Bootloader的通訊協(xié)議和moonglow項目預(yù)期的不一樣。這種情況下你就得祭出SWD調(diào)試接口用調(diào)試器直接連芯片燒錄了。所以在你下單買板子之前最好先查清楚手里的板子具體是什么型號、有沒有公開的刷機(jī)教程別盲目照搬別人的步驟。2.3 兼容性分析Kvaser、PCAN等商用設(shè)備到底有什么“過人之處”聊到刷固件就繞不開一個問題憑什么一個開源固件就能讓廉價硬件變身商用設(shè)備商用設(shè)備和廉價設(shè)備之間差距到底在哪里先看硬件層。商用CAN分析儀的核心器件選擇其實并不神秘很多用的也是Cortex-M0/M3級別的MCU加CAN收發(fā)器單看物料成本并不高。但這幾年用下來我發(fā)現(xiàn)商用設(shè)備的真正優(yōu)勢在軟件生態(tài)和驅(qū)動穩(wěn)定性上——比如kvaser的驅(qū)動支持非常完善Windows、Linux、macOS全平臺覆蓋還有CANopen、J1939、UDS等協(xié)議棧的SDK可以直接調(diào)用。這些軟件層面的積累才是幾千塊差價的來源。moonglow這個開源項目思路很有意思它通過模擬kvaser的USB通訊協(xié)議讓計算機(jī)端原本為kvaser硬件寫的驅(qū)動和軟件以為插上來的就是一塊真正的kvaser設(shè)備。等于說開源固件在USB這一層“偽裝”成了商用設(shè)備而上位機(jī)軟件完全不需要改動。這有點類似打印機(jī)領(lǐng)域的“兼容墨盒”思路——硬件不同沒關(guān)系接口協(xié)議對齊了就能無縫使用。這個方案能成立的前提是kvaser的USB協(xié)議格式被逆向分析得足夠透徹。開源社區(qū)花了大量精力抓取、分析、復(fù)現(xiàn)了kvaser設(shè)備的USB描述符、端點配置、命令格式和應(yīng)答機(jī)制。這里面很多細(xì)節(jié)非常微妙比如USB端點緩沖區(qū)大小、一次傳輸能攜帶多少條CAN報文、錯誤幀如何上報、時間戳是32位還是64位……任何一處對不上上位機(jī)可能就會報錯或者干脆識別不了設(shè)備。當(dāng)你了解這一層邏輯后就會明白刷固件其實是“站在巨人肩膀上”的活把別人逆向好的通信協(xié)議直接拿來用硬件本身只需要關(guān)心CAN收發(fā)性能就夠了。3. 刷機(jī)前的準(zhǔn)備工作工具、備份、環(huán)境一個都不能漏3.1 從零搭建刷機(jī)工作臺你需要準(zhǔn)備這些動手之前先把工具備齊不然刷到一半缺這缺那會非常難受。我建議按下面的清單準(zhǔn)備每一件都有它的用途別嫌麻煩USB-CAN硬件板卡一塊確認(rèn)主控是APM32F072或STM32F072一根質(zhì)量靠譜的Micro USB或Type-C數(shù)據(jù)線注意必須是帶數(shù)據(jù)功能的不是純充電線一臺Windows電腦推薦Win10或Win11驅(qū)動兼容性最好ST-Link V2或者J-Link調(diào)試器備用萬一塊上沒預(yù)置Bootloader就要靠它救磚萬用表一塊排查供電異常、判斷板卡是否上電鑷子、杜邦線若干短接跳線、飛線時用這里面最容易忽略的是數(shù)據(jù)線。我吃過好幾次虧手邊隨便抓一根線插上去電腦一點反應(yīng)都沒有。后來用萬用表一量發(fā)現(xiàn)那根線只有電源針腳數(shù)據(jù)針腳壓根沒接。所以建議大家固定一根專門用來刷機(jī)的數(shù)據(jù)線不要換來換去。軟件環(huán)境方面基本就是三件套USB驅(qū)動工具如Zadig用于替換USB驅(qū)動、固件燒錄工具STM32CubeProgrammer或者自制刷機(jī)腳本、以及moonglow源碼編譯工具鏈。3.2 固件備份這是刷機(jī)前最重要的一步?jīng)]有之一很多人拿到板子第一件事就是直接刷入新固件結(jié)果刷完發(fā)現(xiàn)功能不對或者完全變磚想還原又找不到原廠固件只能干瞪眼。我一開始也是這樣后來學(xué)乖了刷機(jī)前一定會先備份原始固件。備份方法取決于你的板子類型。如果板子上有SWD調(diào)試接口直接用ST-Link配合STM32CubeProgrammer選“Read Out”功能把整個Flash內(nèi)容讀出來存成bin文件。如果板子只能通過USB連接那備份的難度會高一些需要先確認(rèn)板子的出廠Bootloader是否支持固件導(dǎo)出——大部分只支持寫入不支持導(dǎo)出這時候你只能碰運氣看網(wǎng)上有沒有人分享同型號的原始固件。備份數(shù)據(jù)出來后妥善保存到網(wǎng)盤或者本地文件夾里標(biāo)注好對應(yīng)的板卡型號和版本。這個習(xí)慣救過我兩次一次是刷了一個測試版固件導(dǎo)致USB枚舉失敗另一次是改配置時把CAN通道弄亂了都是靠恢復(fù)備份固件才讓板子重新工作。所以無論你多急著想刷入新固件請一定先花五分鐘做備份。3.3 認(rèn)識你的板卡怎么確認(rèn)具體型號和控制器版本市面上USB-CAN板卡型號五花八門但底層芯片就那么幾種。刷機(jī)之前最好先把板卡徹底看清楚主要確認(rèn)三點。第一看主控絲印。如果板子上芯片絲印清晰可以直觀看到APM32F072或者STM32F072的字樣。APM32F072的標(biāo)志很好認(rèn)通常是“APM32F072RBT6”或者“APM32F072CBT6”封裝不同但flash大小一樣都是128KB。第二看板卡有沒有按鍵、跳線、測試點。很多可刷機(jī)的板卡都會預(yù)留一個BOOT按鍵方便用戶進(jìn)Bootloader如果你手頭板子上有這個按鍵刷機(jī)就會非常方便。第三看PCB板上的版本絲印或廠商Logo有些廠商會把硬件版本號印在板上這個信息在查資料時非常有用。如果這些信息都不明確還有一個辦法把USB插上電腦打開設(shè)備管理器看設(shè)備枚舉出來的PID和VID。不同廠商的PID/VID不一樣moonglow項目里通常會列出它支持的所有PID/VID列表你可以對照這個列表判斷自己的板卡是否在支持范圍內(nèi)。3.4 為什么有人刷完沒有反應(yīng)先檢查驅(qū)動和USB枚舉狀態(tài)當(dāng)你把準(zhǔn)備工作都做完了滿懷信心地把USB插上電腦卻發(fā)現(xiàn)設(shè)備管理器里什么都沒有出現(xiàn)這時候別慌八成是驅(qū)動問題。Windows系統(tǒng)默認(rèn)不會認(rèn)識這種非標(biāo)準(zhǔn)的USB設(shè)備尤其是刷機(jī)之前設(shè)備還處于Bootloader模式下系統(tǒng)可能只會提示“未知USB設(shè)備”或者“設(shè)備描述符請求失敗”。這時候需要用到Zadig工具把該設(shè)備的驅(qū)動手動替換為WinUSB或者libusb驅(qū)動。moonglow刷機(jī)腳本通常會依賴WinUSB來和硬件通信所以這個步驟躲不掉。Zadig用起來不難打開后選擇目標(biāo)設(shè)備在驅(qū)動列表里選WinUSB點擊“Replace Driver”就行。但有一個坑是界面里可能同時列出多個設(shè)備你一定要確認(rèn)選中的是USB-CAN那個設(shè)備別手滑把別的設(shè)備驅(qū)動給換了。如果在設(shè)備管理器里完全看不到設(shè)備那就把USB線拔了重插同時短按一下板上的復(fù)位鍵讓設(shè)備重新枚舉。還不行就換一個USB口盡量用電腦后置面板的USB口前置USB口供電不穩(wěn)定偶爾會出現(xiàn)枚舉失敗。4. 編譯固件并刷入手把手帶你跑通整個流程4.1 獲取源碼從GitHub拉取moonglow項目moonglow的源碼托管在GitHub上項目本身是基于libopencm3這個開源庫開發(fā)的支持多種主控平臺其中就包括F072系列。在拉取代碼之前先確認(rèn)你的電腦上已經(jīng)安裝了git、make、arm-none-eabi-gcc交叉編譯工具鏈這些都是編譯環(huán)境的基本要求。打開終端執(zhí)行g(shù)it clone https://github.com/linux-can/moonglow.git cd moonglow git submodule update --init --recursive第二行拉取子模塊尤其重要因為libopencm3是作為子模塊引用的如果漏了這步編譯時會報找不到頭文件的錯誤。整個項目拉下來后目錄結(jié)構(gòu)大致是src/固件主代碼libopencm3/底層驅(qū)動庫scripts/刷機(jī)腳本firmware/預(yù)編譯固件或配置模板4.2 選擇正確的目標(biāo)板和配置文件moonglow項目支持多種硬件型號編譯前需要通過Makefile參數(shù)指定目標(biāo)板。常見的配置有make BOARDapm32f072cbt6或者如果你用的是STM32F072make BOARDstm32f072cbt6這里有個很容易踩的坑很多開源工程默認(rèn)的BOARD是STM32F072如果你用APM32F072需要先確認(rèn)Makefile里是否定義了對應(yīng)的board target。有些版本的moonglow并未單獨區(qū)分APM32F072直接用STM32F072的配置也能編譯通過因為兩者的外設(shè)寄存器地址基本一致但個別時鐘配置參數(shù)可能不同。如果編出來的固件刷進(jìn)去后USB無法正常工作大概率就是時鐘樹配置不一致導(dǎo)致的需要手動調(diào)整PLL參數(shù)。我自己的做法是編譯前先看一眼Makefile里BOARD相關(guān)的宏定義確認(rèn)時鐘源是HSI還是HSE再對照APM32F072數(shù)據(jù)手冊里推薦的48MHz時鐘配置方案進(jìn)行調(diào)整。4.3 編譯從源碼到可以燒錄的bin文件編譯過程本身不復(fù)雜無非是make命令。但環(huán)境問題可能會折磨人尤其是arm-none-eabi-gcc的版本太老或者太新都可能導(dǎo)致編譯報錯。我建議的編譯流程是cd moonglow make BOARDapm32f072cbt6 clean make BOARDapm32f072cbt6編譯順利的話最終會在build/目錄下生成三個文件一個.bin、一個.hex、一個.elf。其中.bin是最常用的燒錄文件體積一般在幾十KB左右。如果編譯報錯最常見的幾類錯誤和解決辦法是找不到libopencm3頭文件說明子模塊沒拉全重新執(zhí)行g(shù)it submodule update --init --recursive編譯器版本太老導(dǎo)致-fno-diagnostics-show-caret等參數(shù)不識別升級gcc-arm-none-eabi到最新穩(wěn)定版報錯說某個寄存器的宏定義不存在可能是這個版本的moonglow對F072支持不完整切換到master分支或者issue區(qū)推薦的穩(wěn)定tag版本編譯通過后不建議著急燒錄先用文本編輯器查看一下生成的.bin文件大小如果大于90KB就要小心了APM32F072雖然有128KB flash但Bootloader或者出廠固件會占用掉一部分空間應(yīng)用固件太大可能會覆蓋Bootloader區(qū)導(dǎo)致刷完直接變磚。4.4 刷機(jī)實操進(jìn)入Bootloader并寫入新固件刷機(jī)方式有兩種我分別講一下大家根據(jù)自己手里的硬件靈活選擇。方式一USB DFU刷機(jī)。這個方式需要有出廠Bootloader支持。操作流程是先拔掉USB線按住板上的按鍵如果有的話保持按住狀態(tài)把USB插上電腦看到電腦提示新設(shè)備接入后松開按鍵。此時設(shè)備應(yīng)該被枚舉成一個DFU設(shè)備設(shè)備管理器里會出現(xiàn)“STM32 BOOTLOADER”或者類似的名稱。接下來用STM32CubeProgrammer燒錄STM32_Programmer_CLI.exe -c portUSB1 -w build/moonglow.bin 0x08000000 -v這里的0x08000000是應(yīng)用固件的起始地址。如果順利幾秒鐘之內(nèi)就會提示燒錄成功。刷完后拔掉USB重新插上設(shè)備會自動運行新的固件。方式二SWD調(diào)試器刷機(jī)。如果你手里的板子沒有Bootloader或者Bootloader無法正常進(jìn)入那就只能用ST-Link這類調(diào)試器直接刷了。連接方法很簡單ST-Link的SWDIO、SWCLK、GND分別對應(yīng)板子上的SWD測試點VCC可以不用接因為板子可以通過USB供電。連接后用STM32CubeProgrammer選ST-Link接口讀取芯片ID然后再執(zhí)行寫入操作STM32_Programmer_CLI.exe -c portSWD modeunder-reset -w build/moonglow.bin 0x08000000 -vSWD刷機(jī)的可靠性比USB DFU更高因為不依賴出廠Bootloader是否存在也不受USB枚舉狀態(tài)影響。如果你手邊有調(diào)試器我推薦優(yōu)先用這種方式。4.5 修改配置參數(shù)的進(jìn)階技巧如何定義設(shè)備名、序列號、CAN速率刷完基本固件后的默認(rèn)配置其實已經(jīng)能用了但如果你想讓它更像一個“自己的”設(shè)備moonglow支持通過源碼中的配置項定制設(shè)備信息。在src/目錄下有一個類似config.h的頭文件里面定義了設(shè)備名稱字符串、PID、VID、序列號格式等參數(shù)。比如#define USB_DEVICE_NAME My CAN Analyzer #define USB_VID 0x0c72 #define USB_PID 0x1301修改后重新編譯燒錄設(shè)備管理器里顯示的就是你自定義的名字。這個功能對于設(shè)備量比較大的工作室或者實驗環(huán)境非常有用免得每次都糾結(jié)插的到底是哪塊板子。CAN速率的支持范圍也挺寬常見的是125kbps、250kbps、500kbps、1Mbps這些都是上位機(jī)軟件里動態(tài)配置的固件本身不需要針對每個速率單獨編譯。如果要修改默認(rèn)定時器參數(shù)可以在src/can.c里調(diào)整波特率相關(guān)的分頻系數(shù)但一般不建議動除非你是在做非標(biāo)的低速總線調(diào)試。5. 刷完之后怎么確認(rèn)成功不只看燈亮不亮5.1 USB枚舉驗證這一步能揭示絕大多數(shù)問題刷完固件之后第一步驗證就是重新插上USB在電腦的設(shè)備管理器里看能否正確枚舉。moonglow固件模擬的是kvaser設(shè)備所以正常枚舉后設(shè)備管理器里應(yīng)該出現(xiàn)一個“CANbus”或者“Kvaser”字樣的設(shè)備并且不會帶黃色感嘆號。剛插上時Windows可能會嘗試自動安裝驅(qū)動如果你的系統(tǒng)里之前裝過kvaser官方驅(qū)動這里經(jīng)常能直接成功因為設(shè)備識別到的VID和PID和真正的kvaser設(shè)備一致。如果設(shè)備管理器里顯示的還是“未知USB設(shè)備”那就要回溯排查了。最常見的原因是USB驅(qū)動沒對用Zadig重新安裝WinUSB驅(qū)動后重啟再試其次是固件刷入的起始地址不對導(dǎo)致MCU跳轉(zhuǎn)時壓根沒跑新固件再有就是APM32芯片的某些USB上拉電阻配置和STM32不完全一致這時候就需要改代碼里的USB上拉控制引腳定義。設(shè)備管理器看到正常設(shè)備后接下來要確認(rèn)的就是上位機(jī)軟件能否正常打開。5.2 用kvaser官方軟件驗證功能打開CanKing的那一刻裝好kvaser官方驅(qū)動后建議先用它的免費測試軟件CanKing連接設(shè)備。打開CanKing如果固件模擬的kvaser設(shè)備被正常識別軟件會顯示一個CAN通道你可以在設(shè)置里選擇不同的波特率。然后做一個最基本的回環(huán)測試把USB-CAN板子上的CANH接到另一個設(shè)備的CANHCANL接CANL再在CanKing里周期性發(fā)送一幀數(shù)據(jù)看對端能不能收到。沒有對端設(shè)備的話可以把板子自身變成回環(huán)模式looback模式但這只能驗證CAN控制器本身的工作狀態(tài)測不了收發(fā)器。這里有個細(xì)節(jié)很多人會忽略CAN總線兩端必須各有一個120Ω的終端電阻否則信號反射會導(dǎo)致通信不穩(wěn)定。好多調(diào)試現(xiàn)場都是這個原因報錯的人還以為固件有問題。拿萬用表量一下CANH和CANL之間的阻值正常情況下應(yīng)該在60Ω左右因為兩側(cè)各有一個120Ω電阻并聯(lián)了。如果量出來是120Ω說明有一端的終端電阻沒接。5.3 多通道板卡的特別注意事項通道順序和映射關(guān)系有些USB-CAN板卡有雙通道硬件上其實是主控芯片的兩路CAN外設(shè)分別接了兩路收發(fā)器。刷完固件后兩個通道在軟件里顯示的編號和物理接口的對應(yīng)關(guān)系需要確認(rèn)清楚——很多時候通道0對應(yīng)的是板子上標(biāo)注為“CAN1”的那個接口但也有反過來的情況。我建議拿到新固件之后先做一次通道映射測試在通道0上發(fā)一個特定ID的報文看另一臺設(shè)備從哪個物理接口收到數(shù)據(jù)記錄下來后面用的時候就不會出現(xiàn)一直往錯誤通道上發(fā)數(shù)據(jù)的情況。5.4 指示燈狀態(tài)與日志輸出固件運行狀態(tài)最直觀的表征刷完固件的板子如果原廠固件和moonglow固件對LED燈的定義不一樣你也別見怪。moonglow固件一般會在初始化完成后讓LED閃幾下然后進(jìn)入空閑狀態(tài)時保持常亮收發(fā)數(shù)據(jù)時LED閃爍頻率會明顯變化。如果板子上壓根沒有LED那也沒關(guān)系通過上位機(jī)軟件的收發(fā)包統(tǒng)計也能判斷固件是否正常運行。CanKing這類軟件會實時顯示TX/RX計數(shù)器只要計數(shù)在跳動固件就是活著的。想進(jìn)一步確認(rèn)固件內(nèi)部狀態(tài)可以在編譯時打開調(diào)試串口輸出moonglow支持把日志信息從USART打印出來接一個USB轉(zhuǎn)TTL小板就能看到詳細(xì)日志包括USB枚舉過程、CAN控制器初始化參數(shù)等。不過這個功能默認(rèn)是關(guān)閉的需要在config.h里開啟DEBUG_PRINT相關(guān)宏。6. 踩坑記錄這些坑我?guī)缀醵继婺悴冗^了6.1 刷完USB無響應(yīng)設(shè)備管理器的“未知設(shè)備”問題這個是最常見的問題沒有之一?,F(xiàn)象是刷機(jī)過程報成功但重新插USB后系統(tǒng)只提示“Unknown Device”設(shè)備管理器里顯示設(shè)備描述符請求失敗。排查順序是這樣的先換一個USB口排除供電和接觸問題然后用Zadig強(qiáng)行給這個未知設(shè)備裝WinUSB驅(qū)動看能否恢復(fù)枚舉都不行的話用萬用表測量板子上3.3V電壓是否正常如果電壓偏低可能是板上LDO過載或者短路。最后再低概率懷疑固件本身刷壞了重新用SWD方式燒錄一次燒錄前先執(zhí)行全片擦除。我自己的經(jīng)驗是這個問題的根源九成是驅(qū)動不是硬件也不是固件。Windows的USB驅(qū)動緩存機(jī)制偶爾會搞出一些莫名其妙的狀態(tài)徹底卸載設(shè)備管理器里相關(guān)的“未知設(shè)備”條目后重新掃描硬件改動往往能解決。6.2 編譯報錯找不到libopencm3頭文件這個問題在第一次拉取源碼時就可能遇到。原因很明確子模塊沒有正確拉取。解決辦法很簡單rm -rf libopencm3 git submodule update --init --recursive如果你在拉取子模塊時遇到網(wǎng)絡(luò)問題導(dǎo)致拉取不完整也可以直接去libopencm3的GitHub倉庫手動下載對應(yīng)版本的源碼放到目錄里并重命名成libopencm3效果一樣。6.3 APM32和STM32的時鐘配置差異導(dǎo)致的USB不工作這是讓我折騰最久的一個問題。APM32F072和STM32F072雖然管腳兼容、寄存器大體一致但在USB時鐘配置上有細(xì)微差異。moonglow工程默認(rèn)使用的是STM32的48MHz時鐘生成配置直接刷到APM32上有可能出現(xiàn)USB設(shè)備枚舉時好時壞的情況?,F(xiàn)象很典型刷完后第一次插USB正常識別拔掉再插就識別不出來了反復(fù)插拔偶爾又正常。這種和插拔次數(shù)相關(guān)的詭異問題基本就是時鐘不穩(wěn)定導(dǎo)致的。解決方法是去APM32官方SDK里找到它的USB時鐘初始化代碼對比moonglow里的實現(xiàn)把PLL分頻和倍頻參數(shù)調(diào)整成APM32對應(yīng)的數(shù)值。具體來說APM32F072的USB設(shè)備需要48MHz的USB時鐘這個48MHz是通過PLL從HSE或者HSI倍頻得到的檢查PLL的倍頻系數(shù)N與分頻系數(shù)M是否產(chǎn)生了偏差即可發(fā)現(xiàn)問題所在。6.4 原廠驅(qū)動和新驅(qū)動沖突設(shè)備被識別成原廠型號如果你之前裝過這款USB-CAN板的原廠驅(qū)動再刷moonglow固件后Windows可能會把新設(shè)備識別成原廠型號而不是期望的kvaser設(shè)備。這是因為Windows驅(qū)動庫里緩存了舊設(shè)備的PID/VID對應(yīng)關(guān)系。解決辦法是去設(shè)備管理器里把該設(shè)備卸載同時勾選“刪除此設(shè)備的驅(qū)動程序軟件”然后拔掉USB重新插讓系統(tǒng)重新識別并搜索匹配驅(qū)動。如果還不行就要去C:\Windows\System32\drivers里手動清理殘留的舊驅(qū)動文件這一步需要管理員權(quán)限操作時小心別刪到系統(tǒng)文件了。6.5 固件燒錄后運行不穩(wěn)定、報文丟幀嚴(yán)重刷機(jī)成功后如果出現(xiàn)報文丟幀、間歇性卡頓等現(xiàn)象先別懷疑固件問題。優(yōu)先級最高的是CAN收發(fā)器的終端電阻和接線質(zhì)量其次看USB線纜是否過長或者線材質(zhì)量太差USB線材對高速通信的穩(wěn)定性影響非常大。一般建議USB線不超過1米且盡量使用帶磁環(huán)的線。排除掉物理因素后再考慮固件本身的中斷優(yōu)先級和緩沖區(qū)配置問題。moonglow工程默認(rèn)參數(shù)在大多數(shù)場景下是夠用的但如果你在高負(fù)載下長時間跑可以嘗試調(diào)整src/目錄下FIFO緩沖區(qū)的大小把發(fā)送緩沖區(qū)和接收緩沖區(qū)都改成深度更大的環(huán)形隊列。刷完之后的一點心里話折騰USB-CAN刷機(jī)這個項目給我?guī)淼淖畲笫斋@其實不是省了那幾千塊設(shè)備錢而是把USB設(shè)備枚舉、CAN控制器初始化、Bootloader機(jī)制、開源協(xié)議棧這些之前零散的知識串成了一條線。以前用CAN分析儀就像用黑盒出了問題只能找廠商現(xiàn)在固件是開源的上位機(jī)是開放的總線出了問題我能從鏈路層一步步往前查這種掌控感是花錢買不來的。如果你想在這個項目基礎(chǔ)上繼續(xù)延伸后面還可以做幾件事一是把moonglow固件移植到APM32F303這種性能更強(qiáng)的芯片上獲得更快的報文處理能力二是基于libopencm3自己寫一個支持CANopen協(xié)議的固件讓USB-CAN板變成一個小型的協(xié)議轉(zhuǎn)換節(jié)點三是把固件刷入過程徹底腳本化做到一鍵備份、一鍵刷機(jī)、一鍵還原方便團(tuán)隊內(nèi)部大規(guī)模部署設(shè)備。每一塊USB-CAN板子背后其實都藏著一套完整的嵌入式系統(tǒng)設(shè)計思路刷機(jī)只是打開了這扇門。后面的路怎么走就看你自己的需求了。