診斷通訊

UDS Reflash 流程|從 0x10 到 0x37

詳解 UDS (ISO 14229) 燒錄完整序列:0x10 session 切換、0x27 Security Access、0x31 erase routine、0x34/0x36/0x37 區塊下載與 0x11 ECU Reset 的實作細節與常見 NRC。

重點摘要

UDS reflashISO 14229ISO 15765-2RequestDownload 0x34TransferData 0x36RequestTransferExit 0x37Security Access 0x27VBF firmware
分類
診斷通訊
關鍵字
10

為什麼 reflash 需要這條完整序列

ECU reflash 不是「把一段 binary 寫進 flash」這麼簡單。bootloader 必須先確認:對方是合法工具、應用程式已被妥善停用、flash 已被抹除、待寫入的位址範圍與大小被正確協商、每一段 payload 的順序沒有遺漏,最後資料完整性也經過 CRC 驗證。UDS (ISO 14229) 把這整個流程以服務 ID 的方式標準化,跑在 ISO-TP (ISO 15765-2) 之上,讓不同 OEM、不同工具、不同 ECU 都能以同一套流程互通。本篇按照 KITE Reflasher 在實機上實際執行的順序,逐步拆解 0x10 → 0x27 → 0x31 → 0x34 / 0x36 / 0x37 → 0x31 → 0x11 這條完整序列。

0x10 Diagnostic Session Control:從 default 到 programming

序列的第一步是切換到具備燒錄權限的 session。一般作法是先進入 extended diagnostic session (0x03) 做前置準備(如關閉非診斷通訊),再切到 programming session (0x02),這時 ECU 會跳到 bootloader 端執行。

# 進 extended session
Tx: 02 10 03 00 00 00 00 00
Rx: 06 50 03 00 32 01 F4 00      ; P2=50ms, P2*=5000ms

# 進 programming session
Tx: 02 10 02 00 00 00 00 00
Rx: 06 50 02 00 32 01 F4 00

切換完成後,KITE Reflasher 會啟動 TesterPresent (0x3E) 週期性回報,以避免 P2 timeout。

0x27 Security Access:seed → DLL → key

進入 programming session 後,bootloader 不會接受任何寫入要求,直到 Security Access 完成。流程是:工具向 ECU 要 seed (0x27 01),拿到 seed 後交給外部 DLL 計算對應的 key,再以 0x27 02 送回。

# 要 seed
Tx: 02 27 01 00 00 00 00 00
Rx: 06 67 01 11 22 33 44 00      ; seed = 11 22 33 44

# (本機) 呼叫 compute_key_from_dll(seed) → key
# 送 key
Tx: 06 27 02 AA BB CC DD 00
Rx: 02 67 02 00 00 00 00 00

KITE Reflasher 透過 libloading 載入 Security DLL,並支援 computeKeyFromSeed 與常見的 GenerateKeyEx 匯出慣例,方便接入 OEM 提供的 Seed / Key 演算法。

0x31 Routine Control:pre-programming、erase、check、CRC

0x31 是一個服務 ID 但用途多元,bootloader 通常會註冊四到六個 routine identifier (RID),例如:

  • Pre-programming — 應用程式先做關機/saveNV 動作。
  • Dependency check — 確認硬體版本、Bootloader 版本相容。
  • Erase memory — 由工具指定起始位址與長度進行抹除。
  • Check programming dependencies — 寫完後檢查映像完整性。
  • CRC check — 對下載完的區段做 CRC 比對。

以 erase 為例(子功能 01 = startRoutine,RID FF 00,參數為 address[4] | size[4]):

Tx: 0F 31 01 FF 00 00 02 00 00 00 00 80 00 00 00 00 00
Rx: 04 71 01 FF 00 00 00 00      ; routine 完成,no data

抹除耗時較長,bootloader 可能回 0x78 (RequestCorrectlyReceived-ResponsePending) 暫拖時間,此時工具不可放棄、必須等待最終的 positive response。

0x34 RequestDownload:位址、大小、format identifier

接著要協商每一段 download。0x34 帶有:

  • dataFormatIdentifier:高 nibble = 壓縮、低 nibble = 加密(通常是 0x00)。
  • addressAndLengthFormatIdentifier:高 nibble = size 長度、低 nibble = address 長度,常見 0x44 表示 4 + 4 bytes。
  • memoryAddress(4 bytes)+ memorySize(4 bytes)。
# 在 0x00020000 寫入 0x00010000 bytes
Tx: 0B 34 00 44 00 02 00 00 00 01 00 00
Rx: 04 74 20 04 02 00            ; lengthFormatId=0x20, maxBlockLen=0x0402

ECU 回覆中的 maxNumberOfBlockLength 告訴工具「下一階段每一段 TransferData 最多能裝多少 bytes(含 SID 與 BSC)」。KITE Reflasher 會以此為上限切割 payload。

0x36 TransferData:block sequence counter 與分段

每一段資料都用 0x36 送出,第一個 byte 是 block sequence counter (BSC),從 01 開始,每次 +1,溢位後回到 00。

Tx: ... 36 01  <payload bytes>
Rx: 02 76 01 00

Tx: ... 36 02  <payload bytes>
Rx: 02 76 02 00
...

如果 ECU 回覆 BSC 與工具預期不一致,代表中間掉包;此時應以原 BSC 重送。一個 block 必然由多個 ISO-TP CF (Consecutive Frame) 組成,工具端的 ISO-TP 層會自動處理 flow control(stmin / BS)。

0x37 RequestTransferExit:結束本段下載(可帶 CRC)

當這一段的全部資料送畢,送 0x37 結束。0x37 後面可以選擇性附帶 transferRequestParameter,常見作法是傳入工具端算好的 CRC-32,讓 bootloader 確認接收到的 binary 正確。

# 不帶參數
Tx: 01 37 00 00 00 00 00 00
Rx: 01 77 00 00 00 00 00 00

# 帶 CRC-32
Tx: 05 37 12 34 56 78 00 00 00
Rx: 01 77 00 00 00 00 00 00

如要寫多個 sector,則回到 0x34 重新協商下一段。

0x11 ECU Reset:套用新韌體

所有 segment 寫完、最後再以 0x31 執行 CRC check 與 dependency check 通過後,送 0x11 01 觸發 hard reset。bootloader 會跳回應用程式,reflash 完成。

Tx: 02 11 01 00 00 00 00 00
Rx: 02 51 01 00 00 00 00 00

HEX / S-record / VBF 在這條序列中的角色

工具端拿到的 HEX、S-record、VBF 並不是「一條線性的 binary」,而是多段帶位址的區塊(records)。KITE Reflasher 在進入 0x34 階段之前,會先做 memory-aware merge:

  • 解析 HEX 的 ULBA + data record,或 S-record 的 S1/S2/S3,或 VBF 的 erase regions + data blocks。
  • 依照使用者在 MemoryConfigPanel 設定的 sector layout,把連續的 record 合併成單一 block。
  • 空隙以 0xFF 填充(Pad 旗標),避免下載階段過度分段。
  • 合併後的 binary 同時以 Intel HEX 落地,作為 audit artifact。

這樣每個 0x34 對應一個合併後的 sector;0x36 則只是把該 sector 的 bytes 依 maxBlockLen 切片送出。

在 KITE Reflasher 上的實作:序列器逐步組合

在 UdsSequencerPanel 上,工程師逐項插入步驟:

  1. Diagnostic Session Control(0x03)
  2. Diagnostic Session Control(0x02)
  3. Security Access(0x27 level=01) — 此步骤会自动呼叫 compute_key_from_dll
  4. Routine Control(0x31 startRoutine, RID=Pre-programming)
  5. Routine Control(0x31 startRoutine, RID=EraseMemory, params=addr|size)
  6. Download Step — 載入 .hex/.vbf,選取要寫入的區塊,工具自動展開為 0x34 → 0x36×N → 0x37
  7. Routine Control(0x31 startRoutine, RID=CheckProgrammingDependencies)
  8. Routine Control(0x31 startRoutine, RID=CRCCheck)
  9. ECU Reset(0x11 01)

每一步驟在 UI 顯示 idle / running / success / error,執行迴圈可中止。整段流程儲存為 .udss,EOL 工裝可重播相同序列。

常見 NRC

只要哪一步出錯,bootloader 會以 7F <SID> <NRC> 回覆。最常見的是:

NRC 名稱 多半發生在
0x10 generalReject 服務組合錯誤
0x11 serviceNotSupported 工具發了 ECU 沒實作的 SID
0x12 subFunctionNotSupported session 或 routine subfunction 不存在
0x22 conditionsNotCorrect 沒進 programming session 就送 0x34
0x33 securityAccessDenied DLL 算錯 key,或 level 不對
0x35 invalidKey seed 對應的 key 計算錯誤
0x37 requiredTimeDelayNotExpired Security Access 連錯後的延遲未到
0x71 transferDataSuspended 上一筆 0x36 還沒收齊
0x72 generalProgrammingFailure flash 寫入硬體錯誤
0x78 requestCorrectlyReceivedResponsePending erase / CRC 等耗時操作中,工具須繼續等待

0x78 不是錯誤 — 它是「請等我」的意思,工具要 reset P2 timer 並繼續等待最終的 positive response。在 KITE Reflasher 中,這由 ISO-TP 層自動處理,不會中斷整段序列。

結語

理解這條序列的關鍵不是任何單一 SID,而是步驟之間的依賴關係:沒有 0x10 進不到 0x27、沒有 0x27 進不到 0x31、沒有 0x31 erase 就直接 0x34 會被 NRC 0x22 擋下。把序列以可重現的方式留在 .udss 與 ASC 紀錄裡,bring-up 與量產驗證都能基於同一份 ground truth 進行。

技術來源與適用範圍

以下原始來源用於核對本文的標準、元件與通訊原理。KopherBit 產品功能、數值與交付範圍屬公司規格,仍須以指定型號、版本及專案驗證為準;引用標準不代表產品已取得認證。

來源核對:2026-10-03

需要可量產的整車控制器平台?

查看 KopherBit 針對商用電動車、電動巴士、卡車與特種車提供的 VCU 平台與工程服務。