2、刷写协议基础:UDS协议简介、基于UDS的刷写流程、诊断会话控制
好,咱们进入正题。刷写这件事,说白了就是给ECU换“脑子”——把新的固件程序写进它的Flash里。但ECU不是U盘,你不能直接拖拽文件进去。它得遵循一套严格的“对话规则”,这套规则就是UDS协议。
我刚开始做刷写时,总觉得UDS很复杂。后来发现,你只要抓住几个核心概念,剩下的就是按套路出牌。今天咱们就把这层窗户纸捅破。
2.1 UDS协议简介
UDS,全称是 Unified Diagnostic Services,统一诊断服务。它定义在ISO 14229标准里。你可以把它理解成ECU和诊断仪(比如你的刷写工具)之间的一套“外交辞令”。
为什么需要它?因为ECU很脆弱。你随便发个指令,它可能就死机了。UDS规定了:
- 谁可以说话(会话控制)
- 说什么话(服务ID,比如读数据、写数据)
- 怎么说话(请求/响应的格式)
UDS的通信模型很简单:请求-响应。诊断仪发一个请求,ECU回一个响应。如果ECU执行成功,回正响应;如果失败,回负响应(NRC,Negative Response Code)。
核心要点:UDS不是刷写专属协议,它是通用的诊断协议。刷写只是它众多应用场景中的一个。但刷写对UDS的依赖最深,因为刷写过程中需要频繁切换会话、读写数据、执行程序。
UDS的报文格式,我简单说一下。一个典型的UDS请求包含:
- 服务ID(SID):1个字节,标识要执行什么操作。比如0x10是诊断会话控制,0x34是请求下载。
- 子功能(Sub-function):可选,1个字节,进一步细化操作。比如0x10服务下的0x01表示默认会话,0x02表示编程会话。
- 数据参数(Data):根据服务不同,长度可变。
举个例子,请求进入编程会话的报文:
请求:02 10 02
解释:
02 - 报文长度(2个字节)
10 - 服务ID:诊断会话控制
02 - 子功能:编程会话
ECU的响应:
响应:02 50 02 00 00 00 00
解释:
02 - 报文长度
50 - 正响应(服务ID + 0x40,即0x10 + 0x40 = 0x50)
02 - 子功能:编程会话
00 00 00 00 - 扩展信息(这里表示成功)
嗯,这里要注意:正响应的SID = 请求SID + 0x40。这是UDS的一个固定规则,别搞混了。
2.2 基于UDS的刷写流程
刷写不是一步到位的。它像做手术,得先消毒、开刀、换零件、缝合、观察。UDS刷写流程也类似,一般分为三个阶段:
- 预编程阶段:让ECU进入“待手术”状态。
- 编程阶段:真正传输数据。
- 后编程阶段:检查、复位、收尾。
我画个简化的流程图,你感受一下:
+----------------+ +----------------+ +----------------+
| 预编程阶段 | --> | 编程阶段 | --> | 后编程阶段 |
| - 进入扩展会话 | | - 请求下载 | | - 检查完整性 |
| - 禁用DTC记录 | | - 传输数据 | | - 复位ECU |
| - 停止通信 | | - 请求退出传输 | | - 验证功能 |
+----------------+ +----------------+ +----------------+
2.2.1 预编程阶段
这个阶段的目标是:让ECU“安静下来”,别在刷写过程中捣乱。
- 进入扩展会话(0x10 03):默认会话下,很多诊断服务是禁用的。你得先切换到扩展会话,才能执行后续操作。
- 禁用DTC记录(0x85 02):刷写过程中,ECU可能会检测到一些异常(比如电压波动),从而记录故障码。我们得先关掉这个功能,避免误报。
- 停止通信(0x28 03):让ECU停止发送周期性报文(比如CAN报文),减少总线负载。
个人经验:我曾经在一个项目里,因为忘了禁用DTC记录,刷写过程中ECU报了一堆“通信丢失”的故障码。刷完后还得花时间清码,非常麻烦。所以预编程阶段,千万别偷懒。
2.2.2 编程阶段
这是核心阶段,数据真正开始传输。主要用到三个服务:
- 请求下载(0x34):告诉ECU:“我要开始写数据了,你准备好接收。” 你需要指定数据的起始地址和长度。
- 传输数据(0x36):把固件数据分包发送。每包大小通常由ECU决定(比如每包4096字节)。
- 请求退出传输(0x37):数据发完了,告诉ECU:“传输结束,你可以处理了。”
一个典型的传输数据请求:
请求:36 01 00 01 A5 A5 A5 A5 ...
解释:
36 - 服务ID:传输数据
01 - 块序列号(第1块)
00 01 - 数据长度(2字节,这里表示256字节)
A5 A5 ... - 实际固件数据
ECU每收到一包,都会回一个正响应。如果超时没收到响应,你得重发。我建议设置一个重试机制,比如最多重试3次。
注意:传输数据时,ECU可能会因为Flash写入速度慢而延迟响应。别急着超时重发,给ECU一点时间。我一般把超时时间设为500ms到1秒。
2.2.3 后编程阶段
数据写完了,但工作还没结束。你得检查一下:
- 检查完整性(0x31 01):让ECU计算一下刚写入的固件的CRC或哈希值,和你的原始值对比。确保数据没写错。
- 复位ECU(0x11 01):让ECU重启,加载新固件。
- 验证功能:复位后,再读一下ECU的版本号,确认刷写成功。
2.3 诊断会话控制
诊断会话控制(0x10服务)是刷写流程的“门禁”。ECU有多个会话状态,不同状态下能执行的服务不同。
常见的会话有:
| 会话名称 | 子功能值 | 说明 |
|---|---|---|
| 默认会话 | 0x01 | 上电后的默认状态,只能执行基本诊断服务(如读版本号)。 |
| 编程会话 | 0x02 | 刷写专用会话,可以执行0x34、0x36、0x37等刷写服务。 |
| 扩展会话 | 0x03 | 允许执行一些高级诊断服务(如读写内存、禁用DTC)。 |
| 安全系统会话 | 0x04 | 用于安全相关操作,比如解锁安全访问。 |
刷写时,你通常需要这样切换:
- 从默认会话(0x01)切换到扩展会话(0x03),执行预编程操作。
- 从扩展会话切换到编程会话(0x02),执行数据传输。
- 刷完后,回到默认会话(0x01),或者直接复位。
为什么不能直接从默认会话跳到编程会话?因为ECU的设计者认为,编程会话太“危险”了,必须经过扩展会话的“热身”才能进入。这是一种安全保护机制。
避坑指南:我曾经遇到过一个ECU,它要求必须在扩展会话下先执行一次“安全访问解锁”(0x27服务),才能进入编程会话。否则,ECU会直接拒绝0x10 02的请求。所以,别想当然地认为所有ECU都按标准套路来。多看ECU的刷写规范文档。
会话切换还有一个重要特性:会话超时。ECU不会永远待在编程会话里。如果一段时间内没有收到任何诊断请求,ECU会自动切回默认会话。这个超时时间通常是5秒到30秒。所以,刷写过程中,你得保持“心跳”——定期发送一些空请求(比如0x3E 00,测试仪在线),防止会话超时。
嗯,说到这,我想起一个教训。有一次我在刷写一个大型固件,数据传输时间比较长。我忘了发心跳,结果ECU在传输中途切回了默认会话。后面的0x36请求全部被拒绝,刷写失败。从那以后,我养成了一个习惯:在每次传输数据之前,先发一个0x3E 00请求,确保会话还在。
总结一下今天的核心:
- UDS是刷写的“语言”,请求-响应模式是基础。
- 刷写分三个阶段:预编程、编程、后编程。每个阶段都有固定的服务序列。
- 会话控制是门禁,刷写必须进入编程会话。别忘了心跳和超时。
下一章,我们会深入讲解安全访问(0x27服务)和密钥管理。那是刷写中最容易出问题的地方,也是很多工程师头疼的环节。咱们到时候细聊。