第4章:UDS诊断协议:ISO 14229-1概述,诊断会话控制(0x10),安全访问(0x27)

好,我们进入第四讲。这一章是Bootloader的灵魂所在——UDS诊断协议。说白了,没有UDS,你的ECU就是个黑盒子,没法跟外界通信。我最早接触UDS是在一个车身域控制器项目上,当时被一堆会话、子功能搞得晕头转向。后来摸透了,发现它其实就三件事:建立连接、验证身份、干活。

4.1 ISO 14229-1到底在讲什么?

ISO 14229-1,全称是“道路车辆——统一诊断服务”。它定义了一套标准化的诊断请求和响应机制。你想想看,不同厂家、不同型号的ECU,如果都用自己的一套协议,那诊断仪得装多少套软件?UDS就是来解决这个问题的。

它的核心思想很简单:请求-响应。诊断仪(Tester)发一个请求,ECU回一个响应。请求和响应都有固定的格式,包含服务ID(SID)、子功能、数据参数等。我习惯把SID看作“指令码”,比如0x10就是“切换会话”,0x27就是“我要验证身份”。

UDS报文结构(简版)

  • 请求:SID + 子功能 + 数据参数
  • 肯定响应:SID + 0x40 + 数据参数
  • 否定响应:0x7F + SID + NRC(否定响应码)

举个例子。你发一个0x10 02(请求切换到扩展会话),ECU如果同意,就回0x50 02。如果不同意,就回0x7F 10 78(0x78表示“请求正确接收,但正在处理中”)。这个0x78我遇到过,当时刷写时一直卡在“等待”状态,后来发现是ECU正在忙别的事。

4.2 诊断会话控制(0x10)——ECU的“工作模式”

ECU不是时刻都在听你指挥的。它有自己的工作模式,UDS用“会话”来管理。0x10服务就是用来切换这些会话的。

常见的会话有三种:

会话名称 子功能值 说明
默认会话 0x01 上电后的默认状态,功能受限
编程会话 0x02 用于刷写Bootloader或应用程序
扩展诊断会话 0x03 允许更多诊断功能,如读写数据

我个人习惯把默认会话比作“待机模式”,编程会话是“刷写模式”,扩展会话是“调试模式”。每个会话下,允许执行的UDS服务是不同的。比如,刷写相关的服务(0x34、0x36等)只能在编程会话下执行。

避坑指南

我曾经在一个项目中,发现ECU在编程会话下无法响应某些请求。查了半天,原来是Bootloader里没有实现“会话超时”处理。ECU在编程会话下待久了,自动跳回了默认会话。嗯,这里要注意:编程会话通常有超时时间,超时后会自动切回默认会话。所以刷写时,要定期发送“保持激活”报文(比如0x3E 0x80)。

切换会话的流程很简单:

  1. 诊断仪发送:0x10 + 目标会话子功能
  2. ECU响应:肯定响应(0x50 + 子功能)或否定响应(0x7F + 0x10 + NRC)

常见的否定响应码(NRC)有:

  • 0x12:子功能不支持(你发的会话ID不对)
  • 0x22:条件不满足(比如正在刷写时,不允许切回默认会话)
  • 0x78:请求正确接收,但正在处理中(ECU需要时间准备)

4.3 安全访问(0x27)——ECU的“门禁系统”

刷写Bootloader,说白了就是往ECU的Flash里写数据。这么敏感的操作,能随便让人干吗?当然不行。所以UDS定义了0x27服务——安全访问。它就像ECU的门禁系统,你得先证明你是“自己人”。

0x27服务的流程是“挑战-应答”机制:

  1. 请求种子(Seed):诊断仪发0x27 + 子功能(比如0x01表示请求种子)
  2. ECU返回种子:ECU回0x67 + 子功能 + 种子数据(比如4字节随机数)
  3. 发送密钥(Key):诊断仪根据种子,用特定算法计算出密钥,发0x27 + 子功能(0x02)+ 密钥
  4. ECU验证:ECU用同样的算法计算密钥,比对。一致则解锁,返回肯定响应;否则返回否定响应(NRC 0x35)

安全访问的典型报文交互

诊断仪 -> ECU: 02 27 01          // 请求种子(2字节长度)
ECU -> 诊断仪: 06 67 01 12 34 56 78  // 返回种子:0x12345678
诊断仪 -> ECU: 06 27 02 9A BC DE F0  // 发送密钥
ECU -> 诊断仪: 02 67 02          // 肯定响应,解锁成功

这里有个关键点:种子和密钥的算法是保密的。不同项目、不同ECU,算法可能完全不同。我见过用简单的异或、CRC,也见过用AES加密的。你想想看,如果算法泄露了,那安全访问就形同虚设。

注意事项

  • 解锁次数限制:很多ECU会限制连续解锁失败的次数。比如连续3次失败,ECU会锁定一段时间(比如10秒)。我曾经调试时,因为算法写错了,连续失败5次,ECU直接锁了半小时...嗯,那滋味不好受。
  • 会话依赖:安全访问通常只在扩展会话或编程会话下有效。默认会话下,0x27服务可能被禁用。
  • 超时处理:请求种子后,如果在一定时间内(比如5秒)没有收到密钥,ECU会认为超时,需要重新请求种子。

4.4 实战中的一点体会

讲到这里,我想分享一个实际案例。有一次,我在做Bootloader刷写测试,发现刷写到一半总是失败。抓了CAN报文一看,原来是安全访问的密钥算法里,有一个字节的移位方向搞反了。左移写成右移,导致密钥验证失败。ECU返回了0x7F 27 35(安全访问拒绝)。

所以,我建议你在实现0x27服务时,一定要做两件事:

  • 写单元测试:单独测试种子生成和密钥验证的逻辑,确保算法正确。
  • 加日志输出:在ECU端,把收到的种子、计算出的密钥、比对结果都打印出来。这样调试时,一眼就能看出问题在哪。

另外,关于会话切换,我有个小技巧:在刷写前,先切到扩展会话,再切到编程会话。为什么?因为有些ECU在编程会话下,某些诊断服务(比如读写DTC)是被禁用的。先切到扩展会话,可以做一些准备工作(比如清除DTC),再切到编程会话开始刷写。这样流程更顺畅。

4.5 小结

这一章我们聊了UDS诊断协议的核心:

  • ISO 14229-1:定义了标准化的诊断请求-响应机制。
  • 0x10服务:切换ECU的工作模式(默认、编程、扩展)。
  • 0x27服务:通过挑战-应答机制,验证诊断仪的合法性。

下一章,我们会深入0x34(请求下载)和0x36(数据传输),看看数据是怎么写进Flash的。到时候,我会结合一个具体的刷写流程,把报文一条条拆开讲。敬请期待。