KopherBit
診斷通訊

ASAM XCP on CAN:建構 ECU 線上標定與 DAQ 量測主機

從 A2L / ELF 解析、XCP session 建立、Calibration page 切換到動態 DAQ list 與 RAM-to-ROM Intel HEX 匯出,完整剖析 XCP-on-CAN master 在 ECU 標定流程中的角色與實作要點。

什麼是 XCP

XCP (Universal Measurement and Calibration Protocol) 是 ASAM MCD-1 XCP 標準定義的標定與量測協定,用以在開發、驗證與量產調校階段,對 ECU 內部的記憶體變數進行讀寫與週期性取樣。XCP 的設計刻意把協定層與實體層解耦:上層的 command 邏輯、Calibration page 切換、DAQ list 等概念與底層使用 CAN、CAN-FD、Ethernet、USB 還是 FlexRay 無關。

工程實務上最常見的部署仍是 XCP on CAN——CAN 物理層普及、車載開發環境本來就內建、訊框結構穩定,且大多數量產 ECU 已經預留了 XCP slave 的程式碼空間。本文以 KopherBit 自家的 KITE Calibrator 為例,整理一套 XCP-on-CAN master 的實作路徑:從 A2L / ELF 解析、session 建立、calibration page 寫入、動態 DAQ 量測,到最後的 RAM-to-ROM Intel HEX 匯出。

XCP-on-CAN 的封包與訊框結構

XCP 的訊息以 CTO (Command Transfer Object) 與 DTO (Data Transfer Object) 兩大類為主:

  • CTO 包含 master → slave 的 CMD、slave → master 的 RES / ERR / EV / SERV,承載 connect、上下傳、calibration 寫入、DAQ 配置等控制流量。
  • DTO 用於量測資料;每個 DTO 內含若干 ODT (Object Descriptor Table),由 PID (Packet Identifier) 對應到對應的 ODT 結構,slave 依 ODT 把 measurement 變數打包後送出。

在 CAN 上,XCP 通常使用一對 CAN ID:master → slave 的 CMD_ID 與 slave → master 的 RES_ID。標準 CAN 的 payload 上限為 8 bytes,因此 XCP MAX_CTO / MAX_DTO 在 CAN-only 配置下常被設為 0x08。在 CAN-FD 上限可放大到 64 bytes,但 master 與 slave 的 MAX_DLC 必須一致。

從 A2L + ELF 解析 characteristic / measurement 位址

A2L (ASAM MCD-2 MC) 是 ECU 內部變數的字典:每個 CHARACTERISTIC(標定參數)與 MEASUREMENT(量測訊號)都帶有名稱、資料型別、轉換規則、單位與位址欄位。但 A2L 中的位址常常以 link-time symbol address 表示,需要對應的 ELF / AXF / OUT 檔案,從 symbol table 解析出 ECU 編譯後的真實位址。

實作上 KITE Calibrator 內建 a2l-parserelf-parser,於 parse_a2l_file / parse_elf_file Tauri 指令中把兩者結果交叉合併,產出一個帶有完整位址的 in-memory 模型,再交給編輯器 (MapEditorPanelCurveEditorPanel) 與 DAQ 訊號樹 (DaqConfigPanel) 使用。

建立 XCP session:connect → CAL_PAGE → DAQ

一條典型的 XCP session 啟動序列如下:

master → slave : FF 00                          ; CONNECT
slave  → master: FF <RESOURCE> <COMM_MODE> <MAX_CTO> <MAX_DTO> ...
master → slave : FB                             ; GET_COMM_MODE_INFO
master → slave : FA <SEG> <PAGE> <MODE>         ; SET_CAL_PAGE → 切到 RAM page
master → slave : FE                             ; GET_CAL_PAGE 驗證

CONNECT 回應裡的 RESOURCE 位元告訴 master 該 slave 是否支援 CAL_PAG、DAQ、PGM 等子集;接下來的所有後續流程必須以這份能力宣告為準。Calibration 期間 master 通常會把 ECU 切到 RAM page (SET_CAL_PAGE MODE = ECU=RAM, XCP=RAM),讓寫入動作直接生效於 working memory,避免動到 ROM 區。

Calibration 與 RAM-to-ROM Intel HEX 匯出

Calibration 寫入透過 SET_MTA (set memory transfer address) + DOWNLOAD 完成。對單一 scalar 是一次寫入;對 CURVE / MAP / VAL_BLK 則由 master 將整塊資料切成 MAX_CTO - 2 大小的 chunk,連續呼叫 DOWNLOADDOWNLOAD_NEXT

每次寫入後 KITE Calibrator 會立即發出 SHORT_UPLOAD 進行 verification readback,把 ECU 真正存進 RAM 的位元組讀回來與寫入值比對。這一步看似繁瑣,但避免了「UI 顯示已改、ECU 實際未生效」的誤解,也能在第一時間發現位址錯位或 page 切換失誤。

調校完成後,save_cal_hex 從 ECU 的 RAM (calibration page) 把每個 segment 完整 upload 回 master,再把 RAM 來源位址重新對映成 flash (ROM) 目的位址,輸出帶有 :02 0000 04 extended linear address record 的 Intel HEX 檔。下游的 KITE Reflasher 或產線 flash 工具就可以拿這個 HEX 進行燒錄。

動態 DAQ list 設定

DAQ 是 XCP 在標定中的核心優勢:相較於 polling,它讓 slave 在自己的事件週期(例如 10 ms timer、CAN 收訊中斷)主動把訊號封裝成 ODT 推給 master,延遲低且採樣節拍穩定。

動態 DAQ 設定流程:

master → slave : D5 <COUNT>                     ; FREE_DAQ
master → slave : D4 <DAQ_COUNT>                 ; ALLOC_DAQ
master → slave : D3 <DAQ> <ODT_COUNT>           ; ALLOC_ODT
master → slave : D2 <DAQ> <ODT> <ENTRY_COUNT>   ; ALLOC_ODT_ENTRY
master → slave : E2 <DAQ> <ODT> <ENTRY> <BIT> <SIZE> <ADDR_EXT> <ADDR>
                                                ; WRITE_DAQ
master → slave : E0 <MODE> <DAQ> <EVENT> <PRESCALER> <PRIORITY>
                                                ; SET_DAQ_LIST_MODE
master → slave : DE 02 <DAQ>                    ; START_STOP_DAQ_LIST = START

KITE Calibrator 在 xcp_master.rs 中以 daq_decoder 解碼進來的 DTO frame,把每個 ODT 內的位元組依 A2L 的 conversion 規則還原成物理量,並以 Tauri event xcp-measurement 推送 {timestamp, values} 給前端的 MeasurementLogPanelWebGLChart

在 KITE Calibrator 上的實作

在 KITE Calibrator 內,所有 CAN I/O 都統一走共用的 kdp-network-driver crate,並在 build feature 上啟用 kvaserpcanvectorzlg。前端 HardwareConfigPanel 透過 scan_can_devices 列出可用裝置,使用者選擇後 start_xcp_server 才會把該 channel 綁定到 XCP master。

這樣的抽象有兩個好處:(1) 工程師在 Kvaser、PCAN、Vector、ZLG 之間切換不用換工具;(2) 同一份 XCP 協定層程式碼可以在不同實驗室的硬體配置上複用,而不會把 protocol stack 與某一家 driver 的 SDK 綁死。

常見問題

Verification readback 一直失敗怎麼辦? 先檢查 calibration page 是否切到 RAM;很多 ECU 在 ROM page 下寫入是被 silently dropped 的。再檢查 A2L 與 ELF 是否同一份 build——若 ELF 新編但 A2L 沒重新生成,位址會錯位,但寫入仍會「成功」,因為 slave 只是寫到了不該寫的記憶體。

Calibration page switch 後 measurement 數值跳動是正常的嗎? ECU 從 ROM page 切到 RAM page 時,RAM 通常會以 ROM 內容作為初始值複製過來;但若 RAM 已被前一次 session 修改而沒有重置,就會出現舊值殘留。建議 session 開始時明確執行 COPY_CAL_PAGE 把 ROM 複製到 RAM,再開始調校。

CAN-FD 何時可以用? ASAM XCP Part 2 (Transport on CAN) 已涵蓋 CAN-FD 的 DLC 對應與 BRS 行為,協定層本身不是阻礙;瓶頸通常在 ECU 端的 XCP slave 是否實作了 FD 相關的 MAX_DLC_REQUIRED 通報,以及 master 與 slave 的 MAX_CTO_FD / MAX_DTO_FD 協商。KITE Calibrator 目前的版本已預留 CAN-FD 結構但 fd_enabled 寫死為 false,啟用時間會與 KITE 系列的下一次 release window 對齊。