3. 刷写流程核心服务:诊断会话控制(0x10)、安全访问(0x27)、诊断故障码读取(0x19)、写入数据(0x2E)、例程控制(0x31)
好,咱们直接进入正题。刷写流程里,有五个服务是绕不开的。我常说它们是Bootloader的“五虎上将”。少了哪一个,刷写流程都跑不起来。
这五个服务分别是:诊断会话控制(0x10)、安全访问(0x27)、诊断故障码读取(0x19)、写入数据(0x2E)、例程控制(0x31)。
今天我就把这五个服务的核心要点、实现细节、还有我踩过的坑,一次性给你讲透。
3.1 诊断会话控制 (0x10) —— 刷写的“入场券”
说白了,0x10服务就是告诉ECU:“我要开始干活了,你准备好没?”
ECU平时可能跑在默认会话里,只响应一些基本诊断请求。但刷写需要更高级的权限,比如解锁内存、执行擦除操作。这时候,你就得通过0x10服务切换到编程会话。
我个人习惯把会话切换分成三步:
- 请求切换:发送0x10 02,请求进入编程会话。
- ECU响应:ECU返回肯定响应或否定响应。
- 应用层准备:ECU内部会停止应用任务,初始化刷写环境。
核心要点:
- 编程会话下,ECU会禁用一些非必要的通信,比如CAN报文。
- 如果切换失败,ECU会返回NRC 0x12(子功能不支持)或0x22(条件不满足)。
- 我建议你在切换前,先检查ECU当前会话状态,避免重复切换。
嗯,这里要注意。有些ECU在编程会话下会关闭DTC存储功能。你想想看,刷写过程中产生一堆故障码,那多麻烦。
3.2 安全访问 (0x27) —— 刷写的“钥匙”
0x27服务,说白了就是一把锁。ECU不想让随便什么人都能刷写,所以你得先证明你是“自己人”。
安全访问的流程,我记得在项目里调试过无数次:
- 请求种子:发送0x27 01,请求种子。
- ECU返回种子:ECU返回一串随机数(种子)。
- 计算密钥:Tester用种子和算法算出密钥。
- 发送密钥:发送0x27 02,带上密钥。
- ECU验证:ECU比对密钥,通过则解锁。
避坑指南:
我曾经遇到过一个问题:种子请求次数过多,ECU会进入“锁定状态”。这时候你必须等待一段时间,或者断电重启才能继续。所以,我建议你在Tester端做好重试机制,比如最多尝试3次,失败后等待30秒。
为什么要有安全访问?说白了,就是防止误刷写。你想想看,如果随便一个诊断仪都能刷写,那ECU岂不是乱套了?
3.3 诊断故障码读取 (0x19) —— 刷写的“体检报告”
0x19服务,用来读取ECU的故障码。刷写前读一下,刷写后再读一下,对比一下,就知道刷写过程有没有产生新问题。
我个人习惯在刷写流程里加入两次0x19请求:
- 刷写前:读取当前故障码,记录状态。
- 刷写后:再次读取,确认没有新增故障码。
这里有个细节:刷写过程中,ECU可能会因为断电、通信中断等原因产生临时故障码。这些故障码在刷写完成后,应该被清除。所以,0x19服务通常和0x14(清除诊断信息)配合使用。
注意:
不要以为0x19只是读故障码那么简单。有些ECU在编程会话下,会屏蔽故障码存储。这时候你读到的故障码,可能不是真实状态。我建议你在刷写完成后,先切换到默认会话,再读取故障码。
3.4 写入数据 (0x2E) —— 刷写的“笔”
0x2E服务,用来写入数据到ECU。刷写过程中,你写入的是固件数据、配置参数、或者密钥。
写入数据的流程,其实很简单:
- 请求写入:发送0x2E,带上DID(数据标识符)和数据。
- ECU响应:ECU返回肯定响应或否定响应。
- 数据存储:ECU将数据写入指定地址。
嗯,这里要注意。0x2E服务写入的数据,通常是非易失性存储器(比如Flash或EEPROM)。所以,写入操作一定要小心,写错了可能导致ECU变砖。
核心要点:
- 写入数据前,最好先读取当前数据,确认状态。
- 写入完成后,再读取一次,验证数据是否正确。
- 我建议你在写入过程中,加入CRC校验,确保数据完整性。
我记得有一次,客户反馈刷写后ECU无法启动。排查了半天,发现是0x2E写入的配置参数错了。从那以后,我每次写入数据都会做两次校验:一次在写入前,一次在写入后。
3.5 例程控制 (0x31) —— 刷写的“执行器”
0x31服务,用来执行ECU内部的特定程序。刷写过程中,最常用的例程就是擦除Flash和检查编程完整性。
例程控制的流程:
- 请求启动例程:发送0x31 01,带上例程ID。
- ECU执行:ECU开始执行例程,比如擦除Flash。
- ECU返回结果:执行完成后,ECU返回肯定响应或否定响应。
我个人习惯把例程控制分成三类:
- 启动例程:开始执行。
- 停止例程:中断执行。
- 请求结果:查询执行状态。
避坑指南:
我曾经遇到过一个问题:擦除Flash的例程执行时间很长,超过了Tester的超时时间。结果Tester以为例程失败了,又发了一次擦除请求。这下好了,ECU同时执行两个擦除操作,直接死机。
所以,我建议你在Tester端设置合理的超时时间,或者在例程执行期间,定期发送“请求结果”来查询状态。
为什么例程控制这么重要?你想想看,刷写过程中,擦除Flash、写入数据、校验完整性,这些操作都需要ECU内部程序来执行。0x31服务就是用来调用这些程序的。
3.6 五个服务的协同工作
这五个服务不是孤立的。它们需要按照一定的顺序协同工作,才能完成一次完整的刷写流程。
我总结了一个典型的刷写流程:
- 会话控制 (0x10):切换到编程会话。
- 安全访问 (0x27):解锁ECU。
- 故障码读取 (0x19):记录刷写前的故障码。
- 例程控制 (0x31):擦除Flash。
- 写入数据 (0x2E):写入固件数据。
- 例程控制 (0x31):检查编程完整性。
- 故障码读取 (0x19):确认刷写后没有新增故障码。
核心要点:
这个流程不是固定的。有些ECU可能需要在写入数据前,先执行一些初始化例程。有些ECU可能需要在刷写完成后,重新上电才能生效。所以,你一定要根据具体的ECU规范来调整流程。
好了,这五个服务就讲到这里。下一章,我会带你深入刷写流程的细节,看看数据是怎么从Tester传到ECU的。