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的控制状态强烈绑定于诊断会话:一旦会话结束,这个“横向权限“必须立即收回。
四种控制类型——你可以制定精准的通信隔离规则
你能控制的不只是“说还是不说“——而是精确到收发方向:
| 控制类型 | 值 | 含义 | 应用场景 | 医生比喻 |
|---|---|---|---|---|
| enableRxAndTx | 0x00 | 收发全部开放 | 恢复正常——解除之前所有限制 | 把手术台的隔离帘拉开——病人回到普通病房 |
| enableRxAndDisableTx | 0x01 | 可听不可说 | 刷写固件的核心模式——ECU接收你的下载块但不往外发数据 | 给病人戴上氧气面罩——他还能吸氧但说不出话 |
| disableRxAndEnableTx | 0x02 | 不可听只能说 | 特殊故障模拟——ECU忽略外来指令但继续往外广播信号 | 病人被麻醉——他自己没意识但在无意识地说梦话 |
| disableRxAndTx | 0x03 | 完全静默 | 极端隔离——ECU与整条总线断开,既不听也不说 | 手术台上的深麻醉——病人对任何刺激均无反应 |
在刷写场景中,几乎一定选用 enableRxAndDisableTx (0x01)——你需要ECU能收到你的0x36传输块,但它的嘴巴必须封上——不能和你争抢CAN总线的时间片。
通信类型——你要屏蔽的是应用消息还是网络管理消息
你在CAN总线上会看到两种截然不同语义的帧。一种是“发动机水温92°C“这样的普通应用数据,另一种是“本ECU还活着,不要让我休眠“这样的网络管理消息。它们由ECU内部完全不同的模块产生——应用数据来自SW-C的周期任务,NM消息来自CanNm/AUTOSAR NM栈的独立调度。
0x28允许你分别控制这两类消息:
| communicationType | 值 | 控制的消息类型 | 关闭后的副作用 |
|---|---|---|---|
| normalCommunicationMessages | 0x01 | 普通应用消息 | ECU不再广播传感器数据的CAN帧——总线负载大幅下降 |
| networkManagementCommunicationMessages | 0x02 | 网络管理消息 | ECU停止发送NM PDU——其他ECU可能误判此ECU“已掉线“或“已休眠“ |
| normalAndNM | 0x03 | 两类同时控制 | 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的粗糙开关细化为精准的“方向×类型“二维控制矩阵。
本篇小结
-
0x28 CommunicationControl是CAN总线诊断的必要前奏——在刷写固件或大数据读取前关闭非诊断通信以释放总线带宽,避免应用帧与诊断帧的仲裁碰撞。
-
四种控制类型enableRxAndTx/enableRxAndDisableTx/disableRxAndEnableTx/disableRxAndTx精确对应“全开/只收/只发/全关“四个隔离级别,刷写场景固定使用enableRxAndDisableTx。
-
communicationType的普通消息(0x01)/网络管理消息(0x02)/全部(0x03)区分映射到整车功能安全——NM消息关闭可能引发整网误判ECU掉线,必须在理解后果的前提下使用。
-
0x28的状态绑定在诊断会话上——切换会话或超时自动恢复通信——这是防止“刷写崩溃后ECU永久哑巴“的兜底安全设计。
-
标准刷写编排必须遵循0x10→0x28→0x85→0x27→0x34的顺序——0x28必须出现在下载块之前而不是之后,否则总线仲裁会大幅拖慢刷写效率。
【下集预告】:通信静默了——DTC暂停了——安全解锁了——会话已编程。还缺最关键的一步:把4.2MB的固件数据拆解成一个个编号的传输块,通过诊断通道灌进ECU的Flash目标地址。0x34请求下载→0x36传输数据→0x37退出传输(加上上传方向0x35,共四个SID),这是UDS上传下载的核心流程——每一个块都有它自己的生命线——块序号、最大块长度、流控窗口——我们下一章拆解这个手术台上最精密的数据搬运过程。