4. 刷写流程设计:预编程-主编程-后编程三阶段、会话切换、DTC处理

刷写流程,说白了就是给域控“换脑子”的标准操作流程。我见过不少工程师,上来就怼数据,结果刷到一半域控“死”了,还得拆盒子用调试器救。嗯,这其实完全可以避免。

UDS 规范里把刷写拆成了三个阶段:预编程、主编程、后编程。每个阶段都有明确的任务,少一步都不行。今天我就把这三阶段的细节、会话怎么切、DTC 怎么处理,一次性讲清楚。

4.1 三阶段总览

先看整体流程。我习惯用一张图来记,你想想看,刷写就像做手术:术前准备、手术操作、术后恢复。

核心原则:预编程负责“清场”,主编程负责“换件”,后编程负责“验收”。任何一步出错,都要能回滚到安全状态。

刷写三阶段流程总图 预编程阶段 主编程阶段 后编程阶段 子任务 • 会话切换 (10 → 03) • 禁用 DTC 存储 • 停止通信 (NM) • 安全访问解锁 子任务 • 写入数据 (34/36) • 检查完整性 • 编程验证 • 复位 子任务 • 恢复 DTC 存储 • 恢复通信 • 检查应用状态 • 会话切回默认 ⚠ 关键点: 每个阶段都有对应的超时监控。预编程超时 → 自动回默认会话;主编程超时 → 进入编程会话异常处理。 刷写成功 → 后编程 → 正常行驶

4.2 预编程阶段:把环境打扫干净

预编程的目的只有一个:让域控进入可刷写的安静状态。我遇到过最坑的情况,就是刷写过程中网络管理报文还在乱飞,结果域控一边刷一边响应网络请求,直接超时失败。

4.2.1 会话切换:从默认到编程

第一步,把会话从 默认会话 (0x01) 切到 编程会话 (0x02)。注意,不是扩展会话 (0x03),是编程会话。

// 请求:10 02
// 响应:50 02 00 32 00 64
// 其中 00 32 = 50ms 是 P2_Server_max
//      00 64 = 100ms 是 P2*_Server_max

// 实际报文示例
Tx: 10 02
Rx: 50 02 00 32 00 64

我的经验:编程会话的 P2 时间通常比默认会话长。默认会话 P2 一般是 50ms,编程会话可以放宽到 500ms 甚至 1s。为什么?因为刷写时域控很忙,响应慢是正常的。我曾经在某个项目里把 P2 设成 200ms,结果域控在擦除 Flash 时超时了,后来改成 1s 就稳了。

4.2.2 禁用 DTC 存储

刷写过程中,域控会执行各种非常规操作。比如断电、复位、通信中断。这些操作在正常行驶时都是故障,但在刷写时是正常的。如果不关 DTC 存储,刷一次写能报几十个故障码。

步骤 服务 说明
1. 禁用 DTC 存储 85 02 告诉域控:接下来发生的异常不要存 DTC
2. 停止非诊断通信 28 03 停止网络管理报文,避免总线干扰
3. 读取刷写条件 22 F1 00 检查电压、温度等是否满足刷写条件
4. 安全访问解锁 27 01/02 请求种子、发送密钥,解锁刷写权限

注意:85 服务禁用的是 DTC 的存储,不是 DTC 的检测。域控仍然会检测故障,只是不存。刷写完成后必须用 85 01 恢复存储功能。我曾经见过有人忘了恢复,结果客户跑了一个月才发现 DTC 一个都没存。

4.3 主编程阶段:核心操作

主编程阶段,说白了就是往 Flash 里写数据。但怎么写、写什么、写完怎么验证,这里面的门道不少。

4.3.1 数据写入流程

标准流程是:请求下载 (34) → 传输数据 (36) → 请求退出传输 (37)。每次传输的数据块大小由域控决定。

// 请求下载 - 告诉域控我要写数据了
// 34 00 44 00 00 00 10 00 00 00 00 00
// 参数:数据格式=00, 地址长度=4字节, 地址=0x00100000, 内存大小=4字节, 大小=0x00000000

// 传输数据 - 每次最多 4096 字节
// 36 01 [数据块]

// 请求退出传输
// 37

这里有个关键点:数据块大小。域控会在 34 服务的响应里告诉你它一次能收多少字节。

避坑指南:我曾经在某个项目里,域控返回的块大小是 1024 字节,但我们的刷写工具默认发 4096。结果域控每次收到数据都报错,刷写进度卡在 0%。后来查了三天才发现是块大小没对齐。所以,一定要解析 34 服务的响应,动态调整块大小。

4.3.2 完整性检查

数据写完后,必须做完整性检查。常用的方式有两种:

  • CRC 校验:刷写工具计算整个文件的 CRC,写入后让域控自己算一遍,对比是否一致。
  • 逐块校验:每写完一块数据,域控立即回读并校验。这种方式更安全,但速度慢。

我个人更推荐先写后验的方式。先快速写完所有数据,最后做一次整体 CRC 校验。这样既保证了速度,又保证了完整性。

4.3.3 编程验证与复位

校验通过后,执行 31 01 FF 00 服务,让域控做一次编程验证。这个服务会检查 Flash 里的数据是否完整、应用是否可启动。

验证通过后,发送 11 01 硬复位,让域控重启加载新程序。

4.4 后编程阶段:恢复与确认

后编程阶段,很多人觉得不重要,随便做做就行。其实不然。我见过刷写成功后,域控因为通信没恢复,导致整车网络瘫痪的案例。

4.4.1 恢复通信与 DTC 存储

复位后,域控会回到默认会话。这时候需要:

  1. 恢复通信:发送 28 01,让域控重新参与网络管理。
  2. 恢复 DTC 存储:发送 85 01,恢复故障码存储功能。
  3. 清除历史 DTC:发送 14 FF FF FF,把刷写过程中产生的临时故障码清掉。

我的习惯:清除 DTC 时,不要只清特定的 DTC,直接清所有 DTC (14 FF FF FF)。因为刷写过程中可能产生各种意想不到的故障码,一次性清干净最省事。当然,前提是你已经恢复了 DTC 存储功能。

4.4.2 检查应用状态

最后一步,检查域控是否正常运行。我通常用 22 F1 00 读取域控的编程状态,确认应用已经激活。

// 读取编程状态
Tx: 22 F1 00
Rx: 62 F1 00 01  // 01 表示编程成功,应用已激活

如果返回的是 02 或 03,说明编程失败或应用未激活。这时候需要进入故障处理流程,比如回滚到备份区。

4.5 会话切换的细节

会话切换看起来简单,就是发一条 10 服务。但实际项目中,我踩过不少坑。

会话 ID 用途 超时时间
默认会话 01 正常行驶时的会话 无超时
编程会话 02 刷写专用会话 通常 5s
扩展会话 03 诊断、标定、调试 通常 5s

注意:编程会话有超时机制。如果 5 秒内没有收到任何诊断请求,域控会自动切回默认会话。这意味着,如果你在刷写过程中停顿太久(比如等待用户确认),域控可能已经切回默认会话了。这时候再发 36 传输数据,域控会回复 NRC 0x22(条件错误)。

解决办法有两个:

  • 发送 3E 80 保持会话:每 2-3 秒发一次,告诉域控“我还活着”。
  • 调整超时时间:在预编程阶段,通过 10 02 的响应参数,把 P2 时间设长一些。

4.6 DTC 处理策略

DTC 处理是刷写流程里最容易出问题的环节。我总结了几条原则:

  1. 刷写前禁用存储:85 02 必须在所有操作之前执行。
  2. 刷写后恢复存储:85 01 必须在所有操作之后执行。
  3. 刷写后清除 DTC:14 FF FF FF 清除所有历史故障码。
  4. 不要清除正在发生的故障:如果域控当前有故障(比如电压低),清除 DTC 后它会立即重新报出。所以要先排除故障,再清 DTC。

我曾经踩过的坑:有一次刷写完成后,我忘了发 85 01 恢复 DTC 存储。结果客户反馈说车辆报“通信故障”,但读不出任何 DTC。查了两天,才发现 DTC 存储功能还关着。从那以后,我把恢复 DTC 存储写进了刷写脚本的强制步骤里,少一步就报错。

4.7 总结

刷写流程设计,说白了就是三个字:稳、准、狠。

  • 稳:预编程把环境打扫干净,避免干扰。
  • 准:主编程按部就班,数据块大小对齐,校验到位。
  • 狠:后编程恢复彻底,不留隐患。

会话切换和 DTC 处理是细节中的细节。你想想看,一个 85 服务没恢复,可能导致整个售后诊断系统瘫痪。一个会话超时没处理,可能导致刷写失败需要拆盒子救。这些坑,我替你们踩过了,希望你们别再踩。