4、UDS协议入门:UDS(ISO 14229)概述、诊断会话控制、安全访问机制

UDS,全称 Unified Diagnostic Services,统一诊断服务。说白了,它就是汽车电子世界里的一套通用语言。不管你是哪个供应商的ECU,只要它支持UDS,就能用同样的指令去跟它对话、读故障码、刷写软件。

我刚开始接触UDS时,觉得这玩意儿协议栈又长又复杂。后来做Bootloader项目多了才发现,真正核心的就那么几个服务。你只要把会话控制、安全访问、读写数据、例程控制这几个玩明白了,刷写功能基本就能跑通。

4.1 UDS协议栈概览

UDS基于OSI模型,但咱们做嵌入式的不需要把七层全背下来。你只需要关注三层:

  • 应用层:定义具体的诊断服务,比如0x10(诊断会话控制)、0x27(安全访问)。
  • 会话层/表示层:UDS自己把这层叫时间参数和分组打包,咱们一般直接跳过。
  • 传输层:CAN总线上的传输协议,ISO 15765-2(俗称CAN TP)。它负责把超过8字节的诊断报文拆包、重组。

核心要点: UDS的请求/响应格式是固定的——服务ID(SID)+ 子功能 + 数据参数。响应分两种:肯定响应(SID+0x40)和否定响应(0x7F + 请求SID + 否定码)。

举个例子。你发0x10 01请求进入编程会话,ECU如果回0x50 01,那就是肯定响应。如果回0x7F 10 78,意思就是“我收到了,但你再等等”(响应待决,NRC 0x78)。

UDS 诊断通信基本流程 诊断仪(Tester) ECU(Server) 请求(Request) 0x10 01 → 0x50 01 响应(Response) 否定响应:0x7F 10 78(响应待决) P2_max / P2*_max 超时控制

4.2 诊断会话控制(0x10服务)

ECU不可能一直开着所有诊断功能。你想想看,如果车辆在高速行驶时,有人通过诊断口把ECU切到刷写模式,那得多危险。所以UDS定义了三种标准会话:

会话类型 子功能ID 典型用途 安全等级
默认会话 0x01 上电后的初始状态,只读基本数据 最低
编程会话 0x02 Bootloader刷写、Flash擦除/编程 最高
扩展会话 0x03 读写标定数据、执行例程 中等

我个人习惯把会话理解成ECU的“工作模式”。默认会话就像Windows的安全模式,功能受限但稳定。编程会话则是刷写专用模式,在这个模式下,ECU会关闭大部分应用功能,专心听诊断指令。

避坑指南: 我曾经在一个项目里遇到ECU在编程会话下超时自动跳回默认会话,导致刷写到一半中断。后来查协议才发现,ECU内部有个S3定时器(默认5秒),如果在编程会话下连续收不到诊断请求,就会自动回退。解决方案是诊断仪必须在S3超时前发送“保持激活”报文(0x3E 0x00)。

4.3 安全访问机制(0x27服务)

安全访问,说白了就是ECU的“门锁”。你想进编程会话?可以,先回答一个只有合法诊断仪才知道的密码。这个机制防止了非授权设备随意刷写ECU。

流程其实不复杂:

  1. 请求种子:诊断仪发0x27 01(请求种子),ECU回0x67 01 + 种子数据(通常4字节)。
  2. 计算密钥:诊断仪用种子通过特定算法算出密钥。
  3. 发送密钥:诊断仪发0x27 02 + 密钥数据,ECU验证。
  4. 解锁成功:ECU回0x67 02,之后就可以执行受保护的服务了。

注意: 种子和密钥的算法是OEM自定义的。有的用简单的异或+移位,有的用AES加密。我见过最坑的是某OEM把算法写在诊断仪里,但ECU里用的却是另一套——结果就是永远解不了锁。所以做Bootloader时,一定要跟OEM确认算法实现,最好做一次联调。

安全访问还有几个关键点:

  • 失败计数器:ECU会记录连续解锁失败的次数。通常允许3-5次,超过后ECU会锁定一段时间(比如10秒)。
  • 种子时效性:种子通常有有效期(比如1秒),超时后种子失效,需要重新请求。
  • 会话关联:安全解锁状态通常只在当前会话有效。一旦会话切换或ECU复位,就需要重新解锁。
安全访问(0x27)交互流程 诊断仪 ECU ① 0x27 01(请求种子) ② 0x67 01 + Seed(4字节) 计算密钥 ③ 0x27 02 + Key(4字节) 验证密钥 ④ 0x67 02(解锁成功) 失败:0x7F 27 35(无效密钥)→ 计数器+1

4.4 否定响应码(NRC)速查

做UDS开发,一半时间都在跟NRC打交道。ECU不会直接告诉你“我错了”,而是给你一个否定响应码。下面这几个是Bootloader开发中最常见的:

NRC 含义 常见场景
0x10 一般拒绝 请求格式错误,或当前状态不支持该服务
0x22 条件不满足 没解锁就尝试刷写,或没切到编程会话
0x31 请求超出范围 内存地址越界、数据长度不对
0x33 安全访问被拒绝 密钥错误,或解锁次数超限被锁定
0x35 无效密钥 安全访问时密钥与种子不匹配
0x37 超时 诊断仪没在规定时间内完成安全访问流程
0x78 响应待决 ECU正在处理(比如擦Flash),让诊断仪等等
0x7E 子功能不支持 比如0x27只支持01/02,你发了03

个人经验: 调试阶段,我习惯在ECU的UDS驱动里加一个NRC日志打印。每次收到否定响应,就把NRC和当前会话状态一起打出来。这招帮我快速定位过好几次“条件不满足”的问题——往往是忘了先切会话就直接发刷写指令了。

4.5 小结

UDS入门其实就三件事:会话控制告诉ECU你要干什么,安全访问证明你有权限干,NRC告诉你为什么干不了。这三个基础打牢了,后面学0x34(请求下载)、0x36(数据传输)就顺理成章了。

嗯,这里要注意一点:不同OEM对UDS的实现有细微差异。比如有的要求编程会话下必须先解锁才能擦Flash,有的则允许先擦后解锁。所以拿到OEM的诊断规范后,第一件事就是把会话状态机和安全访问的时序图画出来,别想当然。