戰(zhàn):ISO15765多幀傳輸原理與VIN讀取報(bào)文解析)
干過幾年車載總線測(cè)試的人都知道只要跟UDS診斷打交道CANoe基本是繞不開的家伙。ISO15765這幾個(gè)字聽起來挺唬人但它本質(zhì)上解決一個(gè)問題CAN總線一幀只能塞8個(gè)字節(jié)診斷數(shù)據(jù)動(dòng)不動(dòng)就是幾十個(gè)字節(jié)怎么傳ISO15765規(guī)定了一套“拆包-打包”的規(guī)則業(yè)內(nèi)常叫它ISO-TP。很多人第一次在Trace里看到一堆以 10、21、30 開頭的幀直接懵掉——明明我發(fā)的是個(gè)讀VIN的請(qǐng)求怎么總線上回了一大串這篇文章就專門把這層窗戶紙捅破。我會(huì)用CANoe作為分析工具從ISO15765多幀傳輸?shù)膸Y(jié)構(gòu)講起再到如何配置CANoe的傳輸層最后用一次讀取VIN17字節(jié)數(shù)據(jù)的真實(shí)報(bào)文逐字節(jié)拆給你看。無論你是剛接觸ECU測(cè)試的應(yīng)屆生還是被診斷報(bào)文折磨過的老同志照著走一遍下次再看到帶多幀傳輸?shù)腡race心里會(huì)踏實(shí)很多。1. 多幀傳輸?shù)降自诮鉀Q什么問題1.1 為什么會(huì)有ISO15765CAN總線最早是給控制信號(hào)設(shè)計(jì)的像轉(zhuǎn)速、油門、剎車這類量一幀8字節(jié)綽綽有余。但后來車廠開始做診斷和刷寫要把“讀取故障碼”“寫入配置”“更新固件”這種動(dòng)輒幾十上百字節(jié)的數(shù)據(jù)塞進(jìn)CAN8字節(jié)顯然不夠用??偛荒転榱艘淮卧\斷就前前后后發(fā)十幾幀原始數(shù)據(jù)吧接收方怎么知道哪些幀屬于同一個(gè)消息哪一幀在前、哪一幀在后中間斷了怎么辦于是ISO 15765-2成了事實(shí)標(biāo)準(zhǔn)它定義了一種傳輸協(xié)議也就是我們常說的ISO-TP。它把上層的數(shù)據(jù)拆成多幀加上標(biāo)識(shí)信息按順序發(fā)出去接收方再把這些幀拼成完整數(shù)據(jù)。CANoe里很多診斷報(bào)文顯示成一條“Diagnostic”消息底層其實(shí)是ISO-TP在背后自動(dòng)拆裝。1.2 四種幀類型的“角色分工”ISO-TP用四種幀類型完成整個(gè)多幀流程單幀SF數(shù)據(jù)長度不超過7字節(jié)經(jīng)典CAN直接用一幀傳完。首幀F(xiàn)F數(shù)據(jù)長度超過7字節(jié)時(shí)第一幀先發(fā)出去里面帶著總長度和首段數(shù)據(jù)。流控幀F(xiàn)C接收方收到首幀后返回一個(gè)“允許發(fā)送”的指令里面攜帶BS、STmin等參數(shù)。連續(xù)幀CF發(fā)送方按流控幀的指示一幀一幀把剩余數(shù)據(jù)發(fā)完。這四種幀靠第一個(gè)字節(jié)的PCI協(xié)議控制信息區(qū)分。PCI高四位是幀類型標(biāo)識(shí)例如0x0代表單幀0x1代表首幀0x2代表連續(xù)幀0x3代表流控幀。在CANoe的Trace窗口里你往往會(huì)看到“SF/FF/FC/CF”的縮寫要能一眼認(rèn)出來。1.3 物理尋址與功能尋址ISO15765的尋址通常分兩種物理尋址點(diǎn)對(duì)點(diǎn)比如測(cè)試儀發(fā)給某個(gè)ECU請(qǐng)求ID一般是0x7E0響應(yīng)ID是0x7E8。這種最常用。功能尋址廣播一個(gè)請(qǐng)求發(fā)給多個(gè)ECU常用ID是0x7DF。功能尋址一般只用于請(qǐng)求不用于響應(yīng)。CANoe里配置傳輸層的時(shí)候要分清這兩種尋址對(duì)應(yīng)的CAN ID。很多人配置錯(cuò)誤導(dǎo)致收不到響應(yīng)多半是物理尋址ID沒配對(duì)。2. 實(shí)戰(zhàn)前必須搞定的CANoe環(huán)境配置2.1 我推薦的CANoe配置方式先說一下環(huán)境。我用的是CANoe 16/17系列接口有VN1640和虛擬CAN通道。如果你只是想學(xué)多幀報(bào)文分析不一定非要真實(shí)硬件CANoe自帶的虛擬CAN總線也能跑通整個(gè)流程。安裝的時(shí)候務(wù)必確認(rèn)裝了“Diagnostics”相關(guān)組件部分功能需要授權(quán)沒授權(quán)的話診斷窗口會(huì)用不了。新建工程時(shí)選擇CAN總線配置兩條虛擬通道Channel1和Channel2。用CANoe的“Simulation Setup”把通道連接起來再加上一個(gè)DBC文件定義好節(jié)點(diǎn)和報(bào)文。沒有DBC也可以先裸發(fā)CAN幀但解析不出ISO-TP消息所以建議老老實(shí)實(shí)建一個(gè)基礎(chǔ)DBC。DBC我用CANdbVector自帶的數(shù)據(jù)庫編輯器創(chuàng)建。典型配置是定義兩個(gè)節(jié)點(diǎn)Tester測(cè)試儀和ECU然后定義物理請(qǐng)求報(bào)文ID0x7E0物理響應(yīng)報(bào)文ID0x7E8。ISO-TP本身不強(qiáng)制這些ID具體是什么值但UDS診斷領(lǐng)域約定俗成大部分OEM都沿用這套邏輯。2.2 配置傳輸層的關(guān)鍵步驟DBC建好后在CANoe的“Diagnostics/ISO TP”區(qū)域右鍵添加一個(gè)ISO TP傳輸對(duì)象。這里要設(shè)置發(fā)送ID和接收ID請(qǐng)求ID 0x7E0響應(yīng)ID 0x7E8。尋址類型物理尋址。協(xié)議類型ISO 15765-2CAN。處理模式可以把“對(duì)完整幀進(jìn)行重組”打開這樣在Diagnostic窗口里看到的是一條完整診斷響應(yīng)而不是一堆拆分后的裸CAN幀。這一步最容易踩的坑是“診斷描述文件CDD”。CANoe診斷控制臺(tái)加載CDD后可以直接用服務(wù)名發(fā)診斷請(qǐng)求非常方便。但如果手頭沒有CDD也可以手動(dòng)發(fā)送CAN幀靠CANoe的TP層去拆包。兩種方式我都會(huì)在實(shí)戰(zhàn)里覆蓋到。2.3 Trace窗口和過濾技巧ISO-TP報(bào)文在Trace里非常刷屏尤其是發(fā)送幾十個(gè)字節(jié)的多幀響應(yīng)一秒鐘可能幾十條CF幀。我的習(xí)慣是先把Trace窗口的默認(rèn)列配置好查看CAN ID、數(shù)據(jù)場(chǎng)、幀類型、絕對(duì)時(shí)間、相對(duì)時(shí)間這幾列再打開設(shè)置里的“右鍵過濾”功能。點(diǎn)擊Trace窗口工具欄上的“Display Filter”圖標(biāo)可以只顯示請(qǐng)求ID和響應(yīng)ID或者只顯示ISO-TP相關(guān)報(bào)文。不要在一堆其他網(wǎng)絡(luò)管理、應(yīng)用報(bào)文里找診斷幀效率太低。還可以在“Write Window”里用CAPL腳本打印關(guān)鍵信息比如打印收到的完整多幀數(shù)據(jù)分析速度更快。3. 手把手實(shí)戰(zhàn)用VIN讀取把多幀報(bào)文拆明白3.1 一個(gè)真實(shí)的讀取VIN全過程我以一個(gè)ECU返回VIN碼的場(chǎng)景為例。UDS服務(wù)是22讀數(shù)據(jù)DID是F190VIN。請(qǐng)求數(shù)據(jù)是22 F1 90只有3個(gè)字節(jié)CAN單幀完全能裝下所以請(qǐng)求幀只發(fā)一個(gè)單幀方向幀類型CAN IDData請(qǐng)求SF0x7E002 22 F1 9002是單幀PCI代表單幀且數(shù)據(jù)長度為2字節(jié)后邊跟22 F1 90。這個(gè)請(qǐng)求沒有任何懸念一幀就完事了。重點(diǎn)在響應(yīng)。假設(shè)ECU返回的VIN是ABC123XYZ45678901ASCII碼一共17個(gè)字節(jié)。UDS響應(yīng)數(shù)據(jù)為62 F1 902字節(jié)DID 1字節(jié)服務(wù)響應(yīng)再加上17字節(jié)VIN總共20字節(jié)。20字節(jié)超過了7字節(jié)所以必須走ISO-TP多幀。3.2 首幀F(xiàn)F怎么解析ECU發(fā)送的第一幀如下方向幀類型CAN IDData響應(yīng)FF0x7E810 14 62 F1 90 41 42 43首幀PCI的格式是第一個(gè)字節(jié)高四位為1表示首幀低四位是完整數(shù)據(jù)長度的bit11~bit8第二個(gè)字節(jié)是完整數(shù)據(jù)長度的bit7~bit0。所以10 14拼接得到長度0x014也就是20字節(jié)正好是將來重組后的完整響應(yīng)長度。首幀數(shù)據(jù)區(qū)只有6字節(jié)放的是完整響應(yīng)最前面的6個(gè)字節(jié)62響應(yīng)服務(wù)ID與請(qǐng)求的22服務(wù)對(duì)應(yīng)。F1 90DID字段。41、42、43就是VIN里最前面的三個(gè)字符A B C。所以這條首幀的完整含義就是我要傳20字節(jié)數(shù)據(jù)前6字節(jié)我已經(jīng)發(fā)給你了下面是后面14字節(jié)等我收到流控幀再安排節(jié)奏。3.3 流控幀F(xiàn)C怎么解析ECU發(fā)完首幀后正常不會(huì)立刻繼續(xù)發(fā)連續(xù)幀。它必須先等測(cè)試儀Tester回一個(gè)流控幀告訴它“你按這個(gè)節(jié)奏來發(fā)”。測(cè)試儀收到首幀后回一個(gè)流控幀方向幀類型CAN IDData請(qǐng)求FC0x7E030 00 00流控幀PCI的第一個(gè)字節(jié)高四位是3代表流控幀。低四位叫FSFlow Status0Continue繼續(xù)發(fā)。1Wait先等著。2Overflow接收緩沖區(qū)溢出丟棄本次傳輸。示例里的FS0表示可以繼續(xù)。第二個(gè)字節(jié)是BSBlock Size表示允許發(fā)送方連續(xù)發(fā)送的連續(xù)幀數(shù)量。BS0是個(gè)特殊值表示“不限幀數(shù)一口氣發(fā)完”。第三個(gè)字節(jié)是STminSeparation Time min表示兩個(gè)連續(xù)幀之間的最小時(shí)間間隔。STmin0x00代表不強(qiáng)制額外延時(shí)但很多工具還是會(huì)留一點(diǎn)間隔避免CAN發(fā)送緩沖溢出。3.4 連續(xù)幀CF的序號(hào)和數(shù)據(jù)拼接收到FC后ECU開始連發(fā)剩余的連續(xù)幀。完整響應(yīng)的20字節(jié)中首幀已經(jīng)帶了6個(gè)還剩14個(gè)字節(jié)剛好分成兩個(gè)連續(xù)幀每個(gè)7字節(jié)第一幀CF方向幀類型CAN IDData響應(yīng)CF0x7E821 31 32 33 58 59 5A 34PCI第一個(gè)字節(jié)高四位是2表示連續(xù)幀低四位是序列號(hào)SN。第一個(gè)連續(xù)幀的SN通常是1部分協(xié)議棧也有從0開始的后續(xù)會(huì)聊到。數(shù)據(jù)區(qū)放的是后續(xù)7個(gè)字節(jié)31 32 33 58 59 5A 34也就是ASCII字符1 2 3 X Y Z 4。第二幀CF方向幀類型CAN IDData響應(yīng)CF0x7E822 35 36 37 38 39 30 31SN2數(shù)據(jù)區(qū)是剩余7個(gè)字節(jié)35 36 37 38 39 30 31也就是5 6 7 8 9 0 1。接收方拿到FFCF1CF2后按順序把數(shù)據(jù)區(qū)拼接起來FF數(shù)據(jù)6字節(jié)62 F1 90 41 42 43CF1數(shù)據(jù)7字節(jié)31 32 33 58 59 5A 34CF2數(shù)據(jù)7字節(jié)35 36 37 38 39 30 31拼起來就是62 F1 90 41 42 43 31 32 33 58 59 5A 34 35 36 37 38 39 30 31轉(zhuǎn)成ASCII就是ABC123XYZ45678901。到這里一次完整的多幀響應(yīng)就解析完了。3.5 傳輸參數(shù)的計(jì)算邏輯有人會(huì)問BS和STmin怎么選簡單說BS決定“發(fā)幾幀停一下”。BSN表示發(fā)送方每發(fā)N個(gè)連續(xù)幀后必須等接收方重新發(fā)一個(gè)FC才繼續(xù)。STmin決定“幀與幀之間的最小時(shí)間”。如果ECU接收處理速度慢STmin就要給大一點(diǎn)如果太快又會(huì)造成總線負(fù)載升高。STmin的具體含義還要注意單位。0x00到0x7F表示0到127ms0x80到0xF0時(shí)單位變成100us比如0xFA其實(shí)不是標(biāo)準(zhǔn)值。常見的10是1ms32是5ms64是10ms。實(shí)際項(xiàng)目中STmin會(huì)根據(jù)ECU底層驅(qū)動(dòng)能力來確定。CANoe的診斷傳輸層配置里可以直接選配置完它會(huì)自動(dòng)生成對(duì)應(yīng)的FC參數(shù)。4. 多幀傳輸常見的坑現(xiàn)象與排查做過幾輪診斷測(cè)試后你會(huì)發(fā)現(xiàn)多幀傳輸?shù)膯栴}翻來覆去就那么幾個(gè)。我整理了一份在CANoe環(huán)境下的避坑經(jīng)驗(yàn)按出現(xiàn)頻率排序。4.1 看不見首幀或連續(xù)幀Trace里全是裸CAN幀很多時(shí)候明明發(fā)了20字節(jié)的響應(yīng)Trace窗口里卻看不到帶有10、21、30的報(bào)文反而看到一串完整的原始數(shù)據(jù)被拆成8字節(jié)一條的CAN幀。這是CANoe把ISO-TP層“幫助”了它默認(rèn)重組了完整消息并且在Diagnostics窗口和Trace里只展示重組后的結(jié)果。解決方法是到Trace窗口的“Display”里打開ISO-TP的詳細(xì)模式或者直接在報(bào)文列表里看“CAN TP”列。如果你希望看到傳輸層的裸幀可以右鍵“ISO TP”選項(xiàng)選擇“show transport protocol frames”。不要誤以為ECU沒發(fā)多幀其實(shí)數(shù)據(jù)早就到了。4.2 發(fā)完FF后一直沒有FC響應(yīng)典型的故障是ECU發(fā)完首幀后測(cè)試儀不回復(fù)流控幀。排查順序如下檢查故障注入是不是CAPL腳本或者DBC里把流控幀屏蔽了。檢查地址ID確認(rèn)請(qǐng)求ID和響應(yīng)ID配對(duì)是否正確。檢查診斷協(xié)議配置CANoe的ISO TP傳輸層如果發(fā)送ID和接收ID設(shè)置反了收到的FF會(huì)被當(dāng)成無效幀丟棄。檢查超時(shí)時(shí)間CANoe默認(rèn)的N_As/N_Bs超時(shí)是1秒如果測(cè)試儀沒來得及解析也會(huì)出現(xiàn)超時(shí)。這個(gè)坑最隱蔽的地方在于很多新手用CDD和診斷窗口發(fā)送請(qǐng)求時(shí)CANoe會(huì)自動(dòng)幫你回FC但如果你直接用“CAN IG”面板手動(dòng)發(fā)送幀CANoe不會(huì)自動(dòng)回流控幀此時(shí)ECU發(fā)完FF就一直等最終超時(shí)報(bào)N_Bs超時(shí)。所以我建議純學(xué)習(xí)階段就用診斷窗口或CAPL來走完整流程別用手動(dòng)CAN發(fā)送去模擬測(cè)試儀。4.3 CF序號(hào)為什么不是從0開始我在拿到首幀之后見過很多人在Trace里盯著第一個(gè)連續(xù)幀的SN看。有人收到21開頭的幀就會(huì)問為什么不是20ISO15765標(biāo)準(zhǔn)里SN是一個(gè)4位循環(huán)計(jì)數(shù)器從0到15循環(huán)。但在標(biāo)準(zhǔn)實(shí)現(xiàn)中首幀之后第一個(gè)連續(xù)幀的SN通常從1開始后續(xù)依次遞增。部分工具或協(xié)議棧會(huì)從0開始這個(gè)在判斷時(shí)會(huì)有歧義。我的經(jīng)驗(yàn)是不要糾結(jié)起始值重點(diǎn)檢查連續(xù)幀的SN是否連續(xù)。如果中間出現(xiàn)跳號(hào)比如前面是SN3后面直接SN5那基本可以判定丟幀需要做重傳處理。CANoe在重組時(shí)如果發(fā)現(xiàn)SN不連續(xù)會(huì)在Trace里顯示錯(cuò)誤或者直接超時(shí)。你可以在診斷窗口的“Trace Filter”里勾選“Protocol errors”快速定位這類問題。4.4 BlockSize與STmin搭配出問題有時(shí)候首幀發(fā)完流控幀也回得很快但連續(xù)幀發(fā)了幾幀就停了。這時(shí)候排查BS和STmin的取值。BS3代表每發(fā)3個(gè)CF就要等接收方再發(fā)一次FC。如果接收方遲遲不發(fā)第二個(gè)FC傳輸就卡住。BS0雖然不限次數(shù)但工程上不建議在復(fù)雜的CAN網(wǎng)絡(luò)中無腦設(shè)0因?yàn)橐坏┛偩€擁堵要么出錯(cuò)誤幀要么接收方緩沖區(qū)溢出。STmin設(shè)置太小時(shí)比如0x00連續(xù)幀之間幾乎沒有間隔。如果ECU底層寫Flash或者做校驗(yàn)可能來不及處理導(dǎo)致后續(xù)CF被丟棄。一般項(xiàng)目里STmin至少設(shè)到0x0A10ms。在CANoe里可以通過“CAN Statistics”窗口看到總線負(fù)載和錯(cuò)誤幀情況如果錯(cuò)誤幀多先懷疑STmin。4.5 常見問題速查表現(xiàn)象可能原因解決方向Trace只顯示重組后的診斷消息CANoe默認(rèn)合并TP層開啟“show transport protocol frames”發(fā)完FF后無FC手動(dòng)發(fā)送幀導(dǎo)致無流控響應(yīng)改用診斷窗口或CAPL報(bào)文接收超時(shí)N_BsFC未返回或超時(shí)參數(shù)過短檢查ID、協(xié)議配置和超時(shí)時(shí)間連續(xù)幀SN跳變丟幀或總線錯(cuò)誤檢查STmin和BS查看錯(cuò)誤幀響應(yīng)長度與實(shí)際不符FF中的長度計(jì)數(shù)錯(cuò)對(duì)照FF的12位長度字段重新計(jì)算功能尋址收不到響應(yīng)功能尋址不能用于響應(yīng)請(qǐng)求用0x7DF響應(yīng)必須物理尋址0x7E85. 進(jìn)階玩法與個(gè)人心得5.1 用CAPL腳本自動(dòng)發(fā)送并校驗(yàn)多幀手動(dòng)發(fā)一次UDS請(qǐng)求沒有問題但做壓力測(cè)試和自動(dòng)化回歸時(shí)就要用CAPL來跑。我常用的套路是用diagSetP2Parameter設(shè)置超時(shí)。用diagSendRequest發(fā)送CDD里定義好的診斷請(qǐng)求。通過on diagResponse回調(diào)接收完整響應(yīng)。在回調(diào)里用diagGetParameter解析響應(yīng)中的VIN字節(jié)并比對(duì)預(yù)期值。用CAPL的好處是你不需要關(guān)心底層拆包拼包邏輯CANoe的協(xié)議棧已經(jīng)把FF/CF/FC全部處理好了。它會(huì)給你一個(gè)完整響應(yīng)的字節(jié)數(shù)組直接用MemCmp做結(jié)果校驗(yàn)。批量刷寫、反復(fù)讀寫DID的自動(dòng)化腳本基本都是這個(gè)思路。5.2 與Python聯(lián)合測(cè)試的擴(kuò)展有些團(tuán)隊(duì)習(xí)慣用Python控制CANoe做集成測(cè)試??梢杂肅ANoe的COM接口啟動(dòng)工程、發(fā)送診斷請(qǐng)求、讀取響應(yīng)。比如調(diào)用CANoe.Application對(duì)象再通過Diagnostic對(duì)象觸發(fā)請(qǐng)求這樣就能在Python測(cè)試框架里跑診斷自動(dòng)化。不過這種方案對(duì)CANoe版本依賴較強(qiáng)COM接口偶爾會(huì)因?yàn)榘姹静黄ヅ涑鲧鄱曜?。如果是學(xué)習(xí)階段先用CAPL把邏輯調(diào)通再考慮Python封裝。5.3 一個(gè)調(diào)試小技巧最后分享一個(gè)我壓箱底的小技巧。排查多幀傳輸問題時(shí)我習(xí)慣在Trace窗口添加兩列Ack和Error。當(dāng)某個(gè)CF幀出現(xiàn)CRC或ACK錯(cuò)誤時(shí)這兩列會(huì)標(biāo)紅立刻能定位到物理層干擾。很多時(shí)候你以為ISO-TP配置不對(duì)其實(shí)是總線上丟幀。另外CANoe的“Graphics Window”配合ISO-TP層可以把BS和STmin的時(shí)序可視化。調(diào)了幾次參數(shù)后你會(huì)對(duì)“STmin1ms和5ms的實(shí)際總線效果”有直觀感覺。這些參數(shù)的變化用肉眼很難看出來但圖形曲線騙不了人。根據(jù)我個(gè)人經(jīng)驗(yàn)ISO15765多幀傳輸真正難的不是協(xié)議本身而是你第一次面對(duì)一堆看似雜亂幀時(shí)的心態(tài)。記住每類幀的角色FF是報(bào)幕員FC是交通指揮CF是跑腿的SF是一句話能說完的事。用CANoe多看幾次真實(shí)報(bào)文多拆幾輪字節(jié)這個(gè)坎很快就能邁過去。