4、UDS诊断协议入门:ISO 14229概述、诊断会话控制(0x10)、安全访问(0x27)、例程控制(0x31)
各位同学,今天我们来聊聊UDS诊断协议。说实话,这是BootLoader开发中最绕不开的一环。你想想看,没有诊断协议,ECU就是个黑盒子,你没法跟它对话,更别提升级了。
UDS的全称是Unified Diagnostic Services,统一诊断服务。它定义在ISO 14229标准里。说白了,它就是一套汽车电子设备之间沟通的“普通话”。不管你是哪个供应商做的ECU,只要支持UDS,大家就能用同样的指令去访问它。
我个人习惯把UDS理解成“ECU的API接口”。你发送一个请求,ECU给你一个响应。就这么简单。但背后的细节,嗯,咱们得好好捋一捋。
4.1 ISO 14229概述
ISO 14229是一个大家族,它定义了26种诊断服务。每个服务都有一个唯一的SID(Service Identifier,服务标识符)。比如0x10是诊断会话控制,0x27是安全访问,0x31是例程控制。
这些服务被分成了六大类:
- 诊断和通信管理类:包括0x10(诊断会话控制)、0x11(ECU复位)、0x3E(测试仪在线)等。这些是基础服务,用来建立和管理诊断连接。
- 数据传输类:包括0x22(读取数据)、0x2E(写入数据)、0x23(读取内存)等。用来读写ECU内部的数据。
- 存储数据传输类:包括0x14(清除诊断信息)、0x19(读取DTC信息)等。用来管理故障码。
- 输入输出控制类:包括0x2F(输入输出控制)。用来强制控制ECU的输入输出引脚。
- 远程激活类:包括0x31(例程控制)。用来执行ECU内部的特定程序。
- 上传下载类:包括0x34(请求下载)、0x35(请求上传)、0x36(传输数据)、0x37(请求传输退出)。这些是BootLoader升级的核心服务。
这里有个小经验:在BootLoader开发中,最常用的服务其实就那几个——0x10、0x27、0x31、0x34、0x36、0x37。其他的服务,说实话,用得不多。但作为基础,你都得了解。
4.2 诊断会话控制(0x10)
0x10服务,用来切换ECU的诊断会话状态。ECU上电后,默认处于默认会话(Default Session)。在这个会话里,很多诊断服务是被禁用的。比如你想刷写程序,ECU会直接拒绝你。
为什么会这样?这是安全考虑。你想想看,如果随便一个诊断仪都能刷写ECU,那车还不得乱套?
0x10服务支持三种会话:
| 子功能 | 会话名称 | 说明 |
|---|---|---|
| 0x01 | 默认会话 | 上电后的初始状态,功能受限 |
| 0x02 | 编程会话 | 允许刷写操作,BootLoader升级时使用 |
| 0x03 | 扩展会话 | 允许更多诊断功能,如读写配置参数 |
请求格式很简单:
请求:0x10 + 子功能
例如:0x10 0x02 // 请求切换到编程会话
响应格式:
肯定响应:0x50 + 子功能 + P2_Server_Max + P2*_Server_Max
例如:0x50 0x02 0x32 0x00 0x64
// 0x32 = 50ms(P2_Server_Max,即最大响应时间)
// 0x00 0x64 = 100ms(P2*_Server_Max,即扩展响应时间)
我在项目中遇到过一个问题:有些ECU在切换会话后,会重置一些内部状态。比如你正在做安全访问,突然切了会话,安全状态就丢了。所以,我建议你在切换会话前,先确认当前状态,避免踩坑。
4.3 安全访问(0x27)
0x27服务,用来解锁ECU的安全保护。说白了,就是“对暗号”。你发送一个种子(Seed),ECU给你一个密钥(Key),你算对了,它就让你进去。
为什么需要这个?因为有些操作太危险了。比如刷写程序、修改配置参数,这些操作如果被误操作,可能导致ECU变砖。所以,ECU会要求你先通过安全访问验证。
安全访问的流程是这样的:
- 请求种子:诊断仪发送0x27 + 子功能(奇数),ECU返回种子。
- 发送密钥:诊断仪计算密钥,发送0x27 + 子功能(偶数)+ 密钥,ECU验证。
- 验证通过:ECU返回肯定响应,解锁成功。
举个例子:
// 步骤1:请求种子(安全等级1)
请求:0x27 0x01
响应:0x67 0x01 0xAA 0xBB 0xCC 0xDD
// 种子是 0xAA 0xBB 0xCC 0xDD
// 步骤2:发送密钥(假设算法结果是 0x11 0x22 0x33 0x44)
请求:0x27 0x02 0x11 0x22 0x33 0x44
响应:0x67 0x02 // 肯定响应,解锁成功
这里有个关键点:安全算法是OEM(主机厂)定义的,每个项目都不一样。有的用简单的异或,有的用AES加密,有的用自定义算法。我曾经遇到过一个项目,算法里还混了时间戳,搞得我调试了好几天。
4.4 例程控制(0x31)
0x31服务,用来让ECU执行一段预定义的程序。你可以把它理解成“ECU的API调用”。比如擦除Flash、检查CRC、执行自检,这些都可以通过例程控制来实现。
0x31服务有三个子功能:
| 子功能 | 名称 | 说明 |
|---|---|---|
| 0x01 | 启动例程 | 开始执行例程 |
| 0x02 | 停止例程 | 中断正在执行的例程 |
| 0x03 | 请求例程结果 | 获取例程的执行状态或结果 |
请求格式:
请求:0x31 + 子功能 + 例程ID + 可选参数
例如:0x31 0x01 0xFF 0x00 // 启动例程ID为0xFF00的例程
响应格式:
肯定响应:0x71 + 子功能 + 例程ID + 可选结果
例如:0x71 0x01 0xFF 0x00 0x00 // 例程启动成功
在BootLoader中,0x31服务用得特别多。比如:
- 擦除Flash:启动一个擦除例程,传入要擦除的地址和大小。
- 检查编程条件:比如检查电压是否正常、点火开关是否打开。
- 验证程序完整性:刷写完成后,启动CRC校验例程,检查数据是否正确。
我个人习惯把例程控制设计成“原子操作”。什么意思?就是例程一旦启动,要么成功,要么失败,中间不能被打断。你想想看,如果擦除Flash擦到一半,突然来个复位,那ECU就真的变砖了。
- 0x10用来切换会话,是诊断的“大门”。
- 0x27用来安全验证,是诊断的“钥匙”。
- 0x31用来执行程序,是诊断的“工具”。
- 这三个服务是BootLoader升级的基石,必须熟练掌握。
好了,这一章的内容就到这里。下一章我们会深入讲解0x34、0x36、0x37这三个上传下载服务,也就是真正的刷写流程。到时候我会结合一个实际项目,带大家走一遍完整的升级过程。