:手動為 J-Link 添加不支持的 MCU)
SEGGER 這次把 Open Flash Loader 能力拉到 J-Link、J-Trace、Flasher 三款產(chǎn)品線上對搞單片機開發(fā)的兄弟來說確實是個好消息。尤其是用非主流 MCU、剛流片回來還沒拿到官方燒錄算法的團隊以前碰到J-Link 不支持這顆料基本就是卡死狀態(tài)現(xiàn)在 Open Flash Loader 給了一條完全不同的路。這篇文章結(jié)合我最近的項目經(jīng)歷把 Open Flash Loader 是什么、怎么配、怎么在 J-Link 里手動添加一顆不在支持列表里的 IC以及 J-Link、J-Trace、Flasher 三者在這種情況下分別怎么用一次說清楚。順手把網(wǎng)上問得最多的J-Link 點位和 S32DS 調(diào) J-Link 時報 GDB Server 超時的坑也一并聊了。1. Flash 編程的底層邏輯與 Open Flash Loader 的定位1.1 傳統(tǒng) Flash 編程是怎么工作的要理解 Open Flash Loader 到底解決了什么問題得先看傳統(tǒng) J-Link 燒錄 Flash 的過程。J-Link 通過 SWD 或 JTAG 連上目標芯片之后并不會直接把燒錄指令一點點塞進 Flash。原因是 Flash 的寫操作有嚴格時序要求比如需要先擦除扇區(qū)、再按頁編程、寫完還要做校驗這些操作如果靠調(diào)試接口一條條指令去驅(qū)動速度會慢到?jīng)]法用。所以 J-Link 的做法是把一段燒錄程序?qū)I(yè)叫法是 flash algorithmFlash 算法下載到目標芯片的 RAM 里然后讓 CPU 運行這段程序通過它去操作片內(nèi) Flash 控制器完成擦除和寫入。燒錄完成后再通過調(diào)試接口讀取 Flash 內(nèi)容做校驗。這套思路本身沒問題問題出在flash algorithm 從哪來。傳統(tǒng)上每款芯片都需要 SEGGER 官方針對內(nèi)核、Flash 控制器、RAM 地址空間做適配編譯好之后集成到 J-Link 軟件里。也就是說芯片廠商必須先跟 SEGGER 對接用戶才能用 J-Link 燒錄這顆芯片。你要是用了一顆很小眾的 MCU或者芯片還在工程樣品階段官方適配列表里沒有那 J-Link 就完全沒辦法幫你燒錄。1.2 為什么 Open Flash Loader 能破局Open Flash Loader 是 ARM 在 CMSIS-Pack 體系里定義的一套開放標準。它的核心思路是把Flash 算法從 J-Link 軟件內(nèi)部剝離出來變成一個個獨立的 ELF 格式文件由芯片廠商或者用戶自己來維護。J-Link 只負責把這份 ELF 加載到目標 RAM然后調(diào)用里面約定的函數(shù)完成燒錄至于 Flash 控制器具體怎么操作完全由 ELF 文件里的代碼決定。SEGGER 把 Open Flash Loader 支持加入到 J-Link、J-Trace、Flasher 之后意味著三件事同時發(fā)生第一J-Link 對第三方 Flash 算法的兼容邊界被徹底打開了。以前只能用 SEGGER 官方適配好的算法現(xiàn)在只要你有 ELF 格式的 loader 文件不管芯片多小眾都可以燒。第二用戶手里有了一顆新芯片的工程樣片想先評估或者燒個 bootloader 做 bring-up不用再干等官方支持自己花半天時間就能把 loader 配好。第三公司里如果有多款芯片需要統(tǒng)一燒錄平臺Open Flash Loader 讓團隊可以自己維護一套算法文件不依賴外部廠商供應(yīng)鏈上更可控。1.3 什么人最需要關(guān)注這個能力我列一下最典型的幾類場景你可以對號入座使用國產(chǎn)或小眾 MCU 的團隊。很多國產(chǎn)芯片廠商的 SEGGER 適配進度滯后經(jīng)常出現(xiàn)芯片已經(jīng)量產(chǎn)、J-Link 軟件里還沒有的情況。芯片原廠的 FAE 或嵌入式工程師。給客戶提供燒錄支持時Open Flash Loader 是最高效的方式不綁定特定燒錄器品牌。做板級 bring-up 的硬件工程師。新板子回來Flash 算法不對所有調(diào)試都做不了自己配 loader 能省出好幾天的等待時間。產(chǎn)線燒錄相關(guān)工程師。Flasher 是獨立的離線燒錄設(shè)備支持 Open Flash Loader 之后能掛載的芯片范圍大大擴展。2. Open Flash Loader 的運行機制與配置原理2.1 核心文件與目錄結(jié)構(gòu)Open Flash Loader 落到文件層面主要有兩種東西一是loader 算法的 ELF 文件一般以.elf或.flm結(jié)尾。FLM是 Keil MDK 那套 Flash 算法的老格式本質(zhì)上也是 ELF 的變種。里面的代碼不依賴任何操作系統(tǒng)通過固定的導(dǎo)出函數(shù)接口和 J-Link 通信。二是設(shè)備映射 XML 文件SEGGER 管它叫JLinkDevices.xml。這個文件的作用是告訴 J-Link某顆芯片屬于哪個內(nèi)核、RAM 空間在哪、Flash 起始地址在哪、用的 loader 文件又放在哪個路徑。J-Link 軟件啟動時會掃描這個 XML把芯片信息加載進支持列表。SEGGER 推薦的做法是把這些文件統(tǒng)一放在一個業(yè)務(wù)目錄下。比如我的工作目錄是這樣的C:\Work\FlashLoaders\ ├── Devices\ │ └── MyVendor\ │ ├── MyMCU\ │ │ ├── FlashLoader.elf │ │ └── flash_device.h └── JLinkDevices.xml實際配置的時候JLinkDevices.xml里的條目長這樣DataBase Device ChipInfo VendorMyVendor NameMyMCU-100 CoreJLINK_CORE_CORTEX_M4 WorkRAMAddr0x20000000 WorkRAMSize0x00010000/ FlashBankInfo NameInternal Flash BaseAddr0x08000000 MaxSize0x00080000 LoaderDevices/MyVendor/MyMCU/FlashLoader.elf LoaderTypeFLASH_ALGO_TYPE_OPEN/ /Device /DataBase這里的路徑是相對 J-Link 安裝目錄來說的所以Loader一項要注意路徑寫對。SEGGER 新版本也已經(jīng)支持從 CMSIS-Pack 的安裝目錄里直接引用 loader這種情況下路徑可以指向%PACK_FOLDER%之類的通配位置。2.2 關(guān)鍵配置項逐一拆解在JLinkDevices.xml里幾個關(guān)鍵屬性的含義一定要搞清楚配錯了會非常痛苦。Core目標芯片的內(nèi)核類型。必須是 J-Link 認識的表達方式比如JLINK_CORE_CORTEX_M4、JLINK_CORE_CORTEX_M33、JLINK_CORE_RISCV等。這一項決定 J-Link 用什么寄存器訪問方式來初始化 CPU 和下載 loader 程序。WorkRAMAddr / WorkRAMSizeloader 程序要放到目標芯片的哪塊 RAM 里運行。這個地址必須是你芯片上真實存在的可讀可寫 RAM而且燒錄期間不能有別的程序占用它。很多芯片的 RAM 是分塊的比如 0x20000000 開頭的 SRAM 和 0x10000000 開頭的 CCM RAM 就完全不同一定要選 loader 能正常訪問的區(qū)域。BaseAddr / MaxSizeFlash 的起始地址和最大容量。起始地址一般看數(shù)據(jù)手冊里的 Flash 基地址Cortex-M 芯片通常是 0x08000000 或者 0x00000000如果你開啟了 BOOT 映射。容量按芯片型號填比如 512KB 就填0x00080000。Loaderloader 算法文件的路徑。LoaderType這是 Open Flash Loader 支持的關(guān)鍵字段填FLASH_ALGO_TYPE_OPEN表示走開放格式。如果你的 loader 是老式的 SEGGER 私有格式就不該用這個類型。2.3 loader 程序的導(dǎo)出符號Open Flash Loader 的 ELF 文件不是隨便編譯一個固件就能用它必須導(dǎo)出 5 個固定的函數(shù)符號J-Link 靠這些符號來調(diào)用算法int Init(uint32_t clk); int UnInit(uint32_t fnc); int EraseChip(void); int EraseSector(uint32_t addr); int ProgramPage(uint32_t addr, uint32_t size, uint8_t *buf);你可以把Init理解成開機自檢對 Flash 控制器做時鐘使能和解鎖操作EraseSector按照地址擦除一個扇區(qū)ProgramPage往某個頁里寫入指定長度的數(shù)據(jù)。每個函數(shù)返回 0 表示成功非 0 表示失敗。J-Link 在燒錄過程中會調(diào)用EraseChip或循環(huán)調(diào)用EraseSector然后一頁頁調(diào)ProgramPage寫入數(shù)據(jù)。這個接口非常簡潔芯片廠商的 SDK 里通常都會給參考模板照著改就行。我見過不少團隊在這個環(huán)節(jié)踩坑函數(shù)名大小寫不對、沒有做好符號導(dǎo)出、編譯時加了優(yōu)化導(dǎo)致參數(shù)傳遞被改壞這些都會讓 J-Link 在加載 loader 后直接報錯或者卡住。3. 手動為 J-Link 添加一顆不在列表里的 IC3.1 第一步從數(shù)據(jù)手冊里撈出 Flash 參數(shù)拿一顆 J-Link 原本不支持的 MCU 來舉例。假設(shè)芯片是 Cortex-M33 內(nèi)核內(nèi)部集成 1MB Flash 和 256KB RAM。要配 Open Flash Loader需要從數(shù)據(jù)手冊里找到這些信息內(nèi)核型號Cortex-M33支持 ARMv8-M Mainline 指令集Flash 基地址0x08000000容量 0x00100000Flash 扇區(qū)大小前 16 個扇區(qū)每個 8KB后面每個 64KBRAM 基地址0x20000000容量 0x00040000編程頁大小256 字節(jié)扇區(qū)和頁大小這兩個參數(shù)直接決定你看待擦除和寫入的最小單位。如果手冊里寫的是雙 Bank 結(jié)構(gòu)半頁編程之類記得把 Bank 切換邏輯在 loader 里實現(xiàn)。這里我建議你先別急著寫 XML。先用 J-Link 自帶的命令行工具做一次最小驗證。SEGGER 的JLink.exe允許直接指定要連接的芯片試一下能不能通過 SWD 正常連接到這顆芯片JLink.exe -device Cortex-M33 -if SWD -speed 4000如果這一步能連上說明 J-Link 的調(diào)試鏈路沒問題問題只在 Flash 算法層如果連不上那是接線或電源問題先排查完再繼續(xù)。3.2 第二步編譯 or 獲取 loader 文件如果芯片原廠已經(jīng)提供了 CMSIS-Pack里面通常會有 Open Flash Loader 的.flm或.elf文件直接找出來用。如果原廠沒有給就得自己編譯一個。最常見的做法是從 Keil MDK 的FlashOS模板工程改起因為FlashOS工程本身就是按 Open Flash Loader 接口寫的你只需要根據(jù)芯片手冊修改底層的 Flash 操作函數(shù)重新編譯生成.flm文件。以我做過的某顆國產(chǎn) M33 內(nèi)核芯片為例只需要改動 4 處FlashDev.c里的器件描述結(jié)構(gòu)體填寫 Flash 大小、起始地址、扇區(qū)大小、頁大小、FlashOS.c里的 Init/UnInit/EraseSector/ProgramPage 函數(shù)體、啟動文件里的棧空間設(shè)置、以及鏈接腳本里的加載地址。編譯參數(shù)里記得把目標內(nèi)核選成 Cortex-M33并開啟 Hardware FPU 支持如果芯片帶 FPU 的話。3.3 第三步在 J-Link 中注冊新器件有了 ELF 文件接下來注冊就有兩條路改JLinkDevices.xml或者用 J-Flash 的圖形界面。改 XML 的方式適合批量維護我把一個真實可用的例子放出來Device ChipInfo VendorMyVendor NameMyM33-1000 CoreJLINK_CORE_CORTEX_M33 WorkRAMAddr0x20000000 WorkRAMSize0x00040000/ FlashBankInfo NameInternal Flash BaseAddr0x08000000 MaxSize0x00100000 LoaderDevices/MyVendor/MyM33/MyM33_1M.elf LoaderTypeFLASH_ALGO_TYPE_OPEN/ /Device把這段寫進 J-Link 安裝目錄下的JLinkDevices.xml或者你自己維護的新 XML 文件保存后重啟 J-Link 軟件。用JLink.exe測試時-device參數(shù)會多出MyM33-1000這個選項。J-Flash 的圖形界面方式更適合單次操作打開 J-Flash文件菜單里新建工程在設(shè)備選擇界面點擊Add創(chuàng)建自定義器件把內(nèi)核類型、RAM 地址、Flash Bank 地址、loader 文件路徑填進去保存為*.jflash工程文件。以后每次直接用 J-Flash 打開這個工程就能燒錄。3.4 第四步第一次燒錄驗證與調(diào)優(yōu)配置完成后先用最小的 bin 文件測試比如一個 256 字節(jié)的啞數(shù)據(jù)只做擦寫和校驗不要上來就刷整個固件。我常用的驗證流程是JLink.exe -device MyM33-1000 -if SWD -speed 4000 -CommanderScript burn_simple.jlinkburn_simple.jlink腳本里寫的是connect erase loadbin C:\Work\test.bin, 0x08000000 verifybin C:\Work\test.bin, 0x08000000 exit如果loadbin和verifybin都通過說明流程通了。接下來可以嘗試燒錄真實固件同時觀察燒錄速度。Open Flash Loader 的編程性能通常會比官方適配算法慢一些如果慢得離譜比如一個 1MB 固件要燒 5 分鐘就要檢查ProgramPage函數(shù)里的緩沖實現(xiàn)和時鐘配置。4. J-Link、J-Trace、Flasher 的定位與 Open Flash Loader 的協(xié)作4.1 三款設(shè)備到底誰是誰很多人分不清 J-Link、J-Trace 和 Flasher簡單說J-Link 是日常軟件開發(fā)調(diào)試用的調(diào)試探針支持下載、單步、斷點、變量監(jiān)視通過 USB 連接電腦配合 IDE 使用。J-Trace 是 J-Link 的加強版主要多出了指令跟蹤功能支持 ETM 等 trace 接口可以完整記錄 CPU 執(zhí)行過程對分析復(fù)雜崩潰問題、代碼覆蓋率評估、實時性能分析非常有用。Flasher 則是產(chǎn)線用的獨立編程燒錄器可以完全脫離電腦工作通過 SD 卡或網(wǎng)口存儲固件按一個按鈕就批量燒錄追求的是生產(chǎn)效率和穩(wěn)定性。這三款設(shè)備在 Flash 燒錄這個動作上的底層邏輯是完全一致的都需要把算法加載到目標 RAM 里執(zhí)行。Open Flash Loader 支持加入后三款設(shè)備都能加載同一份 ELF 格式 loader也就是說你花時間配好的算法文件開發(fā)、測試、產(chǎn)線三端通用不需要為不同工具各維護一份。4.2 在 J-Trace 上使用 Open Flash Loader 的注意事項J-Trace 運行 Open Flash Loader 的機制和 J-Link 相同但 J-Trace 多了 trace 相關(guān)的硬件資源。實際調(diào)試中有一個容易被忽略的問題如果你在 Open Flash Loader 里配置的WorkRAMAddr恰好覆蓋了 trace 數(shù)據(jù)要用的 RAM 緩沖區(qū)地址燒錄完成后 trace 功能可能異常。因為 loader 程序被下載到 RAM 里去執(zhí)行燒錄時 CPU 要跑這段程序trace 硬件也在持續(xù)監(jiān)控總線活動。某些芯片的 ETM trace 對 RAM 地址有優(yōu)先級要求或者 trace buffer 設(shè)在了運行 loader 的同一塊 RAM這時候燒錄過程會讓 trace 數(shù)據(jù)被覆蓋。我的建議是給 loader 單獨保留一塊 RAM不要和 trace buffer 共用。如果芯片 RAM 足夠大把 loader 用的 WorkRAM 放在不沖突的地址范圍如果 RAM 緊張至少保證燒錄時 trace buffer 的地址被排除在 loader 的 RAM 范圍之外。4.3 Flasher 生產(chǎn)模式下的 Loader 配置Flasher 和 J-Link 的燒錄流程走的是不同的軟件鏈。Flasher 的固件配置是通過 SEGGER 的 J-Flash 軟件或者 Flasher 自帶的命令行工具來完成的配置內(nèi)容主要包括通信接口SWD/JTAG、目標器件加載 Open Flash Loader、固件文件、是否自動校驗、是否加密等。生產(chǎn)環(huán)境下Flasher 會把整個燒錄配置連同 loader 算法一起打包進 Flasher 的存儲空間?,F(xiàn)場操作員只需要把目標板通過排線連到 Flasher按一下 Start 按鈕設(shè)備就自動完成連接、擦除、寫入、校驗的完整流程。這個過程完全不依賴電腦也就避免了生產(chǎn)現(xiàn)場 USB 驅(qū)動、病毒、權(quán)限等因素的干擾。我建議在 Flasher 上線之前先做一次完整的試燒錄驗證重點檢查Open Flash Loader 里 Init 函數(shù)對目標芯片時鐘的初始化是否穩(wěn)定擦除整個 Flash 所需時間是否在產(chǎn)線期望范圍內(nèi)編程一頁數(shù)據(jù)之后的 ACK 等待時間是否足夠長多塊板卡連測確認 loader 不會在反復(fù)擦寫后出現(xiàn)內(nèi)存泄漏Open Flash Loader 的 ELF 文件在 Flasher 上的兼容性一般不會有問題但我見過有些 loader 依賴了 C 庫的初始化邏輯這類 loader 在 J-Link 上跑得挺好放到 Flasher 上反而會死機因為 Flasher 的 loader 加載環(huán)境更裸。所以產(chǎn)線用 loader 寫完之后一定要在 Flasher 上單獨驗證。5. 高頻問題與排查實錄5.1 J-Link 點位到底怎么確認網(wǎng)上搜j-link 點位的人大多數(shù)是剛接觸 J-Link 的新手想知道 JLINK 探針上的引腳定義和接線方法。J-Link 最常見的物理接口有兩種20-pin JTAG 接口和 10-pin 的 SWD 排針。20-pin 接口里做 SWD 接線只需要關(guān)注這幾根信號引腳名稱方向說明VTref輸入J-Link 檢測目標板電壓用于電平匹配GND-地線SWDIO雙向數(shù)據(jù)線對應(yīng) TMSSWCLK輸出時鐘線對應(yīng) TCKRESET輸出復(fù)位信號可接可不接接線口訣其實就一句VTref 接目標板 3.3VSWDIO 接 SWDIOSWCLK 接 SWCLKGND 共地。很多連接不上問題出在沒接 VTref導(dǎo)致 J-Link 不知道目標電壓是多少電平匹配不工作。如果你用的是 10-pin 排針定義跟 20-pin 是兼容的只是去掉了大部分不用的 JTAG 信號。接好之后先用 J-Link Commander 驗證JLink.exe命令提示符出現(xiàn)后輸入connect再選設(shè)備類型和接口如果能看到Static RAM Base Address: 0x20000000之類的信息說明連接正常。常見錯誤Cannot connect to target或No target connected第一反應(yīng)查接線第二反應(yīng)查目標板供電第三反應(yīng)降低 SWD 速度試試比如從 4000kHz 降到 1000kHz。5.2 S32DS 啟動 GDB Server 超時的排查思路S32DS error in services launch sequence starting j-link gdb server timed out這個問題主要出現(xiàn)在 NXP S32 Design StudioS32DS里用 J-Link 調(diào)試時Eclipse 生態(tài)的調(diào)試插件要啟動一個 J-Link GDB Server 進程然后通過 TCP 端口轉(zhuǎn)發(fā) GDB 和 J-Link 之間的通信。如果這個啟動過程在限定的超時時間內(nèi)沒有完成就會報這個錯。這個報錯可以說有四個最常見的誘因第一個是端口被占用。J-Link GDB Server 默認監(jiān)聽的是 2331 端口有的版本是 2332。如果你之前跑過 JLinkGDBServer 或者別的調(diào)試會話沒有正常退出端口就還占著。檢查辦法netstat -ano | findstr 2331看到有 LISTENING 記錄直接到任務(wù)管理器里把對應(yīng) PID 的進程結(jié)束掉。第二個是 J-Link 驅(qū)動版本和 S32DS 自帶的 GDB Server 版本不匹配。S32DS 內(nèi)置的調(diào)試插件會調(diào)用它自己認識的 JLinkGDBServer 版本如果你電腦上安裝了新版本的 J-Link 軟件插件卻還在找舊的執(zhí)行文件就容易發(fā)生啟動失敗。這種情況去 S32DS 的調(diào)試配置里手動指定 GDB Server 的可執(zhí)行文件路徑讓它指向當前 J-Link 安裝目錄里的JLinkGDBServerCLExe.exe就能解決。第三個是接口參數(shù)不對。調(diào)試配置里如果選擇了 SWD但目標板實際只接了 JTAG或者反過來GDB Server 啟動時會卡在建立連接階段直到超時。檢查Debugger配置頁里的 Interface 設(shè)置確保跟實際接線一致。第四個是目標板沒上電或復(fù)位電路有問題。GDB Server 啟動時會對目標做一次連接檢測如果芯片沒反應(yīng)它不會立刻報錯而是等超時。從 S32DS 的 Console 視圖里拉出 J-Link GDB Server 的完整日志看看連接階段的最后一句輸出是什么基本就能定位到哪一步卡住。我當時排查這個問題的順序是先 netstat 看端口再檢查 J-Link 驅(qū)動版本然后用 J-Link Commander 單獨驗證連接最后回到 S32DS 重新指定 GDB Server 路徑。整個流程十分鐘左右就能定位問題。5.3 常見問題速查表問題現(xiàn)象可能原因解決方案J-Link 報 Cannot connect to targetSWD 接線錯誤VTref 接電壓、SWDIO/SWCLK 不可接反連接成功但 loadbin 失敗WorkRAMAddr 配置錯誤改為目標芯片空閑 RAM 區(qū)域燒錄時 loader 加載失敗ELF 路徑錯誤相對路徑在 XML 里寫相對于 J-Link 安裝目錄的路徑S32DS 啟動 GDB Server 超時端口 2331 被占用netstat 找 PID 并結(jié)束進程Open Flash Loader 燒錄性能差ProgramPage 未做緩沖寫入按 Flash 頁大小整頁寫入避免逐字節(jié)寫Flasher 連接不上目標板排線過長、信號質(zhì)量差縮短線纜長度降低速度檢查連接器焊接J-Trace 燒錄后 trace 異常loader RAM 與 trace buffer 沖突為 loader 單獨分配 RAM5.4 幾條個人經(jīng)驗最后分享幾條我在實際項目中攢下來的經(jīng)驗這些細節(jié)通常文檔里不會寫。第一Open Flash Loader 的 ELF 文件編譯時盡量關(guān)掉重定位選項讓代碼加載到固定地址。有些編譯器默認生成位置無關(guān)代碼J-Link 加載起來雖然也能跑但在特定芯片上偶爾會有詭異問題比如擦除到一半死機。固定地址編譯更像傳統(tǒng) MCU 固件行為可預(yù)期得多。第二loader 里的 Init 函數(shù)不要只配 Flash 控制器還要把 CPU 的時鐘、總線等待狀態(tài)一起考慮進去。很多芯片 Flash 讀取有 wait state 要求loader 運行在 RAM 上不涉及 Flash 讀但 ProgramPage 時 Flash 控制器需要穩(wěn)定的時鐘如果你沒初始化好時鐘源寫入極不穩(wěn)定。最保險的做法是在 Init 里顯式配置 Flash 編程所需的時鐘頻率。第三一定要保留 loader 源碼的版本管理。我見過有團隊直接拿原廠給的 ELF 文件用結(jié)果芯片出了新版底層 Flash 指令時序變了原廠 ELF 不對又找不到當初編譯的源碼只能重新逆向非常痛苦。從一開始就把 FlashLoader 工程納入 Git每次出板子版本都重建 loader產(chǎn)線燒錄的 ELF 文件和固件版本捆綁記錄能省掉很多后續(xù)麻煩。Open Flash Loader 這套體系讓我最滿意的一點就是它的開放性和可遷移性不管你是用 J-Link 做開發(fā)調(diào)試還是用 J-Trace 做深度跟蹤分析或者用 Flasher 做產(chǎn)線量產(chǎn)同一個 loader 文件從頭用到底。配好第一個不支持的芯片之后后面再遇到任何冷門型號心里就有底了無非是拿手冊、寫 Flash 驅(qū)動、編譯、驗證這套流程走一遍。