Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

2.15 通信控制(0x28)——屏蔽打扰

CAN总线上有一群永远停不下嘴的ECU

凌晨两点二十三分,你面前摆着一辆需要紧急刷写发动机ECU的故障车。你用诊断仪通过CAN总线进入了编程会话,安全解锁完毕,新固件4.2MB已经在诊断仪的内存里准备就绪。你点击“开始刷写“。

第一块数据通过0x34 RequestDownload发出去——正响应收到。

第二块——0x36 TransferData——发送失败。NRC 0x13(incorrectMessageLengthOrInvalidFormat)。

你重新发一遍——失败。再发——失败。

不是车的问题。是你忘了关掉其他ECU的通信。

此时同一条CAN总线上,车身控制模块(BCM)每10ms发出一个“车门状态:关闭“、变速箱控制单元(TCU)每20ms一个“当前挡位:P“、仪表盘ECU每50ms一个“车速:0km/h“……而你的诊断仪正通过同一根双绞线试图以密集速率发0x36传输块——这些应用帧和诊断帧的优先级碰撞导致你的多帧序列被CAN仲裁打断,整个15765-2的Flow Control状态机被撕碎。

你会疯掉的。你需要让除了你和被刷ECU之外的这个总线段落上,所有噪声都消失。

此时你需要的就是0x28 CommunicationControl——UDS的“禁言手术室“开关


为什么ECU不能自己闭嘴——刷写模式≠通信静默

你很可能会想:ECU切换到编程会话(0x10 0x02)之后,它不是知道自己正在被刷写吗?为什么它不能自己停止发送应用帧?

答案在于ECU的软件架构分层。诊断栈(Dcm)和应用层(SW-C)是两个独立的调度实体。当你通过诊断仪把ECU踢进编程会话时,Dcm层的状态机确实切换到了编程模式。但Dcm无法控制应用层SW-C的周期发送调度——在AUTOSAR体系里,SW-C的周期发送由ComM(通信管理器)和CanIf(CAN接口)模块管控,Dcm没有权限跨模块叫停这些业务总线流量。

这就是0x28存在的根本原因——它不是一个Dcm内部的变量翻转,而是通过协议强制触发ComM/PduR/CanIf全栈层面的通信开关。0x28在协议层做了“诊断栈可以叫停应用栈的通信“这个越权操作——因为此时正在诊断的你需要这个权力。

核心洞察:0x28是诊断协议中唯一的“横向权限“——它允许一个ECU的诊断子系统对整个ECU的通信子系统发出控制命令。这在AUTOSAR的分层模型中是一个异常——正常情况下各模块独立自治,0x28在协议层打开了一个自诊断优先通道。这就是为什么0x28的控制状态强烈绑定于诊断会话:一旦会话结束,这个“横向权限“必须立即收回。


四种控制类型——你可以制定精准的通信隔离规则

你能控制的不只是“说还是不说“——而是精确到收发方向:

控制类型含义应用场景医生比喻
enableRxAndTx0x00收发全部开放恢复正常——解除之前所有限制把手术台的隔离帘拉开——病人回到普通病房
enableRxAndDisableTx0x01可听不可说刷写固件的核心模式——ECU接收你的下载块但不往外发数据给病人戴上氧气面罩——他还能吸氧但说不出话
disableRxAndEnableTx0x02不可听只能说特殊故障模拟——ECU忽略外来指令但继续往外广播信号病人被麻醉——他自己没意识但在无意识地说梦话
disableRxAndTx0x03完全静默极端隔离——ECU与整条总线断开,既不听也不说手术台上的深麻醉——病人对任何刺激均无反应

在刷写场景中,几乎一定选用 enableRxAndDisableTx (0x01)——你需要ECU能收到你的0x36传输块,但它的嘴巴必须封上——不能和你争抢CAN总线的时间片。


通信类型——你要屏蔽的是应用消息还是网络管理消息

你在CAN总线上会看到两种截然不同语义的帧。一种是“发动机水温92°C“这样的普通应用数据,另一种是“本ECU还活着,不要让我休眠“这样的网络管理消息。它们由ECU内部完全不同的模块产生——应用数据来自SW-C的周期任务,NM消息来自CanNm/AUTOSAR NM栈的独立调度。

0x28允许你分别控制这两类消息:

communicationType控制的消息类型关闭后的副作用
normalCommunicationMessages0x01普通应用消息ECU不再广播传感器数据的CAN帧——总线负载大幅下降
networkManagementCommunicationMessages0x02网络管理消息ECU停止发送NM PDU——其他ECU可能误判此ECU“已掉线“或“已休眠“
normalAndNM0x03两类同时控制ECU完全静默——最高隔离级别

为什么需要分开控制NM和普通消息?请看这个场景:

你要对发动机ECU做在线诊断(不是刷写,只是在扩展会话下读取数据)。你不想让非必要的应用帧争抢总线,于是你发0x28 0x01 0x01——只关闭普通应用消息,保留NM。

发动机ECU还在发NM消息——告诉全车:“我还没休眠,别关我的供电。“变速箱ECU看到这个NM信号,维持唤醒,继续正常工作。

如果你鲁莽地发0x28 0x01 0x03——连NM一起关——变速箱ECU在三秒内没等到发动机ECU的NM,触发“DTC U0100——与发动机ECU失联“,点亮故障灯,进入跛行模式。你本来只想做一次诊断,结果制造了一个新故障。

NM消息和普通消息在整车的功能安全中承担完全不同的角色,这就是通信类型区分存在的根本原因。


请求格式与增强子功能

标准请求

Byte 0:   0x28                        — SID
Byte 1:   SubFunction                 — bit7=suppressPosRsp, bit6-0=controlType (0x00~0x03)
Byte 2:   communicationType           — 0x01(normal) / 0x02(NM) / 0x03(both)

标准正响应

Byte 0:   0x68                        — SID+0x40
Byte 1:   controlType回声             — ECU确认的控制类型

增强子功能请求(当controlType的bit6-0取值为0x04~0x7F时):

Byte 0:   0x28
Byte 1:   SubFunction                 — 增强子功能值
Byte 2:   communicationType
Byte 3~4: nodeIdentificationNumber    — 双字节,指定子网内的目标节点(如0x1234)

nodeIdentificationNumber是DoIP引入的概念——当诊断仪通过网关到达一个内部CAN网段,这个网段上挂了多个ECU,你需要通过nodeId精确指定“让这个节点通信静默“而不是“让网关后的整条子网都静默“。在纯CAN诊断中这个字段通常不出现——你通过CAN ID的物理寻址已经锁定了唯一的目标ECU。


刷写准备序列——0x10→0x28→0x85→0x34的完整编排

刷写固件是一个多服务协作的严格次序。任何一步顺序错了,后面的流控都会崩溃。标准编排如下:

步骤1:进入编程会话——ECU进入"可以接受刷写"的状态
诊断仪 → ECU:  0x10 0x02
ECU → 诊断仪:   0x50 0x02 0x0032 0x00FA
               P2=50ms, P2*=250ms — ECU保证在此时间内响应

步骤2:通信控制——关闭ECU的非诊断通信
诊断仪 → ECU:  0x28 0x01 0x03
               controlType=0x01(enableRxDisableTx)
               communicationType=0x03(普通+NM全关)
ECU → 诊断仪:   0x68 0x01
               ECM确认——"我已进入安静模式

步骤3:暂停DTC记录——刷写期间不要产生误故障码
诊断仪 → ECU:  0x85 0x02
ECU → 诊断仪:   0xC5 0x02
               "DTC记录已暂停——刷写过程中的电压波动不会被误存为历史故障

步骤4:安全解锁——刷写是破坏性操作,需要高安全等级
诊断仪 → ECU:  0x27 0x03 — requestSeed
ECU → 诊断仪:   0x67 0x03 0x12 0x34 0x56 0x78
诊断仪 → ECU:  0x27 0x04 0xAB 0xCD 0xEF 0x01
ECU → 诊断仪:   0x67 0x04 — 解锁成功

步骤5:现在开始刷写——此时总线完全干净,DTC暂停,安全已解锁
诊断仪 → ECU:  0x34 0x00 0x44 <addressAndLength>  — RequestDownload
ECU → 诊断仪:   0x74 <maxBlockLength>
诊断仪 → ECU:  0x36 <blockSeq> <data[0..maxBlockLength-1]>  — 重复数百次
ECU → 诊断仪:   0x76
诊断仪 → ECU:  0x37 — RequestTransferExit
ECU → 诊断仪:   0x77

步骤6:恢复通信——刷写完成,让ECU重新开口
诊断仪 → ECU:  0x28 0x00 0x03  — enableRxAndTx, both
ECU → 诊断仪:   0x68 0x00

步骤7:恢复DTC记录
诊断仪 → ECU:  0x85 0x01
ECU → 诊断仪:   0xC5 0x01

步骤8:ECU硬复位——新固件需要从启动入口重新运行
诊断仪 → ECU:  0x11 0x01
ECU → 诊断仪:   0x51 0x01 — 复位确认——ECU即将重启

如果某个ECU的实现不严谨——比如在步骤1后就发0x34而跳过0x28——你会观察到什么?刷写速度从预期的8KB/s掉到2KB/s甚至更低。不是代码写错了,是CAN总线的仲裁延迟在蚕食你的带宽——每隔几个0x36块就被应用帧挤掉一次,导致FC流控窗口被耗尽后整块重传。


会话绑定的安全逻辑——为什么切换会话自动恢复通信

0x28的通信控制状态不是一个全局变量。它只在当前的诊断会话内有效——诊断会话发生任何切换(10 02→10 01、或者S3超时回到默认),ECU自动清除0x28的控制状态,恢复全部通信。

这不是设计缺陷——这是最核心的安全设计。

假设刷写过程中你的诊断仪蓝屏崩溃了。诊断仪的TCP连接掉了,CAN线上不再有TesterPresent帧。经过S3超时(通常5秒),ECU诊断栈自动切回默认会话。同时0x28的控制状态被清除——ECU恢复全部通信——发动机ECU重新开始发送“转速1160rpm“、“水温92°C”、“车速0“这些关键数据。其他ECU收到这些消息后恢复正常运行。

如果0x28是全局持久化开关——刷写期间诊断仪崩溃——发动机ECU永远闭嘴——全车ECU在几分钟后集体因“发动机ECU失联“点亮满屏故障灯——车主第二天打开车门——迎接他的是整车故障码的狂欢。

会话绑定就是退路——它保证无论刷写过程中发生什么灾难,在最坏的情况下,S3超时自动恢复一切。


历史溯源:KWP2000没有0x28——过去的刷写是怎么活下来的

在KWP2000时代(1990年代中后期至2000年代初),K-Line是点对点的单主多从总线——只有一根K线连接诊断仪和ECU。问题根本不存在——当诊断仪在K-Line上狂发刷写块时,总线上没有其他ECU在说话——因为K-Line是主从架构,只有被诊断仪点名的那个ECU才有权回话。

到了CAN时代,这个问题突然变成了灾难。CAN是多主总线——任何ECU在任何时刻都可能发起仲裁。UDS设计委员会在2004~2006年间讨论ISO 14229时,整车厂的代表们发现:原来K-Line时代从未需要过的“通信隔离“在CAN上变成了必须项。于是0x28 CommunicationControl作为UDS的全新服务诞生——它的四个控制类型明确对应了CAN总线上的方向性隔离需求。

KWP2000中的对应项是StopCommunication/StartCommunication(KWP2000的SID 0xA7/0xA8),但它们是ECU级别的整体开关——不区分收发方向,不区分消息类型。0x28把KWP2000的粗糙开关细化为精准的“方向×类型“二维控制矩阵。


本篇小结

  1. 0x28 CommunicationControl是CAN总线诊断的必要前奏——在刷写固件或大数据读取前关闭非诊断通信以释放总线带宽,避免应用帧与诊断帧的仲裁碰撞。

  2. 四种控制类型enableRxAndTx/enableRxAndDisableTx/disableRxAndEnableTx/disableRxAndTx精确对应“全开/只收/只发/全关“四个隔离级别,刷写场景固定使用enableRxAndDisableTx。

  3. communicationType的普通消息(0x01)/网络管理消息(0x02)/全部(0x03)区分映射到整车功能安全——NM消息关闭可能引发整网误判ECU掉线,必须在理解后果的前提下使用。

  4. 0x28的状态绑定在诊断会话上——切换会话或超时自动恢复通信——这是防止“刷写崩溃后ECU永久哑巴“的兜底安全设计。

  5. 标准刷写编排必须遵循0x10→0x28→0x85→0x27→0x34的顺序——0x28必须出现在下载块之前而不是之后,否则总线仲裁会大幅拖慢刷写效率。


【下集预告】:通信静默了——DTC暂停了——安全解锁了——会话已编程。还缺最关键的一步:把4.2MB的固件数据拆解成一个个编号的传输块,通过诊断通道灌进ECU的Flash目标地址。0x34请求下载→0x36传输数据→0x37退出传输(加上上传方向0x35,共四个SID),这是UDS上传下载的核心流程——每一个块都有它自己的生命线——块序号、最大块长度、流控窗口——我们下一章拆解这个手术台上最精密的数据搬运过程。