KopherBit
診断通信

ASAM XCP on CAN:ECU オンラインキャリブレーションと DAQ 計測マスターの構築

A2L / ELF のアドレス解決、XCP セッション立ち上げ、Calibration page 切替、動的 DAQ list、RAM-to-ROM Intel HEX 出力まで、ECU キャリブレーションフローにおける XCP-on-CAN マスター実装の要点を解説。

XCP とは

XCP (Universal Measurement and Calibration Protocol) は ASAM MCD-1 XCP 規格で定義されるキャリブレーション・計測プロトコルで、開発、検証、ライン調整の各フェーズにおいて ECU 内部のメモリ変数を読み書きし、周期的にサンプリングするために用いられます。XCP は意図的にプロトコル層を物理層から切り離しており、コマンドロジック、Calibration page 切替、DAQ list、アドレス解決といった上位概念は CAN、CAN-FD、Ethernet、USB、FlexRay のいずれの伝送路でも同一の意味を持ちます。

実務上もっとも普及しているのは依然として XCP on CAN です。CAN は車載ベンチに既に存在し、フレーム構造が安定しており、量産 ECU の多くは XCP slave のための小さなコード領域をすでに確保しています。本記事では KopherBit の KITE Calibrator を題材に、A2L / ELF 解析、セッション立ち上げ、calibration 書き込み、動的 DAQ 計測、RAM-to-ROM Intel HEX 出力までを通した XCP-on-CAN マスターの実装パスを整理します。

XCP-on-CAN のパケットとフレーム構造

XCP のメッセージは大きく CTO (Command Transfer Object) と DTO (Data Transfer Object) の 2 種類に分かれます。

  • CTO はマスターからスレーブへの CMD、スレーブからマスターへの RES / ERR / EV / SERV を含み、connect、アップロード / ダウンロード、calibration 書き込み、DAQ 設定などの制御トラフィックを運びます。
  • DTO は計測データを運びます。1 つの DTO の中には複数の ODT (Object Descriptor Table) が含まれ、PID (Packet Identifier) バイトがどの ODT レイアウトに従って measurement 変数がパックされているかを示します。

CAN 上では、XCP は通常 1 組の CAN ID 対を使用します(マスター → スレーブの CMD_ID、スレーブ → マスターの RES_ID)。Classic CAN のペイロード上限は 8 byte であるため、CAN-only 構成では XCP MAX_CTO / MAX_DTO0x08 に設定されることが一般的です。CAN-FD では 64 byte まで拡張できますが、MAX_DLC についてマスターとスレーブの合意が必要です。

A2L + ELF からの characteristic / measurement アドレス解決

A2L (ASAM MCD-2 MC) は ECU 内部変数の辞書です。各 CHARACTERISTIC(キャリブレーションパラメータ)と MEASUREMENT(計測信号)は、名前、データ型、変換規則、単位、アドレスフィールドを持ちます。ただし A2L のアドレスはしばしば link-time のシンボルアドレスであり、リンク後の実アドレスを得るには対応する ELF / AXF / OUT のシンボルテーブルとの照合が必要です。

KITE Calibrator は内蔵の a2l-parserelf-parser を備えており、parse_a2l_file / parse_elf_file Tauri コマンドが両者の出力をクロスマージして、アドレスが完全解決されたインメモリモデルを構築します。これがエディタ (MapEditorPanelCurveEditorPanel) や DAQ シグナルツリー (DaqConfigPanel) で利用されます。

XCP セッションの立ち上げ:connect → CAL_PAGE → DAQ

典型的な XCP セッションの起動シーケンスは以下のとおりです:

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 バイトは、スレーブが CAL_PAG、DAQ、PGM などのどのサブセットをサポートするかをマスターに伝えます。以降のすべての処理はこの能力宣言を尊重しなければなりません。キャリブレーション期間中、マスターは通常 ECU を RAM page に切り替え(SET_CAL_PAGE MODE = ECU=RAM, XCP=RAM)、書き込みが ROM に触れずにワーキングメモリへ即時反映されるようにします。

Calibration 書き込みと RAM-to-ROM Intel HEX 出力

Calibration 書き込みは SET_MTA (set memory transfer address) と DOWNLOAD の組合せで行います。スカラーは 1 回の書き込みで完結しますが、CURVE / MAP / VAL_BLK のようなブロック領域では、マスターがペイロードを MAX_CTO - 2 byte のチャンクに分割し、DOWNLOAD / DOWNLOAD_NEXT を連続発行します。

KITE Calibrator は各書き込みの直後に SHORT_UPLOAD を発行し、同じアドレスから値を読み戻して書いた値と比較する verification readback を実行します。冗長に見えるこのステップが「UI 上は更新済みなのに ECU が受け付けていなかった」という障害を排除し、アドレスのずれや page 切替の失敗を最も早い段階で検出します。

調整完了後、save_cal_hex は設定済みの calibration セグメントを RAM から完全アップロードし、RAM のソースアドレスを元の flash (ROM) 宛先アドレスへ再マッピングして、:02 0000 04 の extended linear address record を含む Intel HEX ファイルを出力します。下流の KITE Reflasher やライン書き込みツールがこの HEX をそのまま消費します。

動的 DAQ list の構成

DAQ は polling と比較した XCP の主要な利点です。マスターが値を毎回問い合わせる代わりに、スレーブが自身のイベントタイミング(例: 10 ms タイマー、CAN RX 割り込み)で設定済みの信号を ODT に詰めて push します。低レイテンシかつサンプル間隔が安定します。

動的 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 の変換規則と突き合わせて物理量に復元したうえで、Tauri イベント xcp-measurement として {timestamp, values} をフロントエンドへ発行します。MeasurementLogPanelWebGLChart がリアルタイムに描画します。

KITE Calibrator における実装

KITE Calibrator では CAN I/O はすべて共通の kdp-network-driver クレートに集約され、kvaserpcanvectorzlg の build フィーチャーが有効化されています。フロントエンドの HardwareConfigPanelscan_can_devices を呼んでホストの CAN ハードウェアを列挙し、ユーザーがベンダー / デバイス / チャネル / ボーレートを選択した時点で初めて start_xcp_server がそのチャネルを XCP マスターにバインドします。

この設計の利点は 2 つあります。(1) Kvaser、PCAN、Vector、ZLG のいずれにエンジニアが移っても同じツールが追従でき、ワークフローを変える必要がない。(2) プロトコルスタックは特定ベンダーの SDK や特定ベンチの配線に固着せず、可搬性を保てる。

よくある落とし穴

Verification readback が失敗し続ける場合 まず calibration page が確実に RAM へ切り替わっているか確認してください。多くの ECU は ROM page への書き込みを silently drop します。次に A2L と ELF が同じビルドから生成されたものか確認します。ELF を再ビルドしたのに A2L が再生成されていない場合、アドレスがずれた状態で書き込みが「成功」してしまい、スレーブは間違った正規のメモリ領域に書き込んでいます。

Calibration page 切替後に measurement の値が跳ねる 多くの ECU は最初の page 切替で ROM の内容を RAM にコピーして初期化しますが、前回のセッションで RAM が変更されたままリセットされていないと古い値が残ります。セッション開始時に明示的に COPY_CAL_PAGE を発行して ROM から RAM へコピーし、それから調整を開始するのが堅牢な運用です。

CAN-FD はいつ使えますか ASAM XCP Part 2 (Transport on CAN) はすでに CAN-FD の DLC マッピングと BRS の挙動を扱っており、プロトコル層がボトルネックになることはありません。実際の制約はスレーブ側の実装、すなわち XCP slave が MAX_DLC_REQUIRED を正しく報告するか、マスターとスレーブが MAX_CTO_FD / MAX_DTO_FD で合意できるかにかかっています。現行の KITE Calibrator は CAN-FD のスキャフォールディングを残したまま fd_enabledfalse に固定していますが、有効化のタイミングは KITE 系列の次回リリースウィンドウに合わせる予定です。