刷写流程概览:预编程、主编程、后编程三个阶段
大家好,我是你们的嵌入式工程师老友。今天咱们聊聊UDS刷写的整体流程。说实话,很多刚入行的朋友一上来就盯着具体的诊断服务看,比如0x34、0x36、0x37这些。但我个人习惯,先看大局。
刷写一个ECU,说白了就是三个阶段:预编程、主编程、后编程。这三个阶段就像盖房子——先拆旧、再盖新、最后验收。你想想看,少了哪一步都不行。
核心要点:刷写流程不是简单的数据搬运,而是一套严谨的状态机管理。每个阶段都有明确的目标和退出条件。
一、预编程阶段:准备工作
预编程阶段,我习惯叫它“清场阶段”。为什么要清场?因为ECU在正常工作时,有很多功能在跑——网络通信、应用任务、故障诊断等等。你直接刷写,可能会出大问题。
我记得有一次在项目中,客户反馈刷写后ECU死机了。排查了半天,发现是预编程阶段没把DTC(诊断故障码)存储功能关掉。刷写过程中触发了故障,ECU一直在写故障码,把Flash操作给打断了。嗯,从那以后,我再也不敢跳过预编程的任何一个步骤。
预编程阶段主要做三件事:
- 关闭DTC存储:通过0x85服务(ControlDTCSetting)告诉ECU:“兄弟,先别记故障码了,我要干活了。”
- 停止非刷写相关的通信:比如一些应用层的报文,避免干扰刷写数据流。
- 检查刷写条件:比如电压是否正常、安全访问是否通过、ECU是否处于可编程状态。
我的小技巧:预编程阶段最好做一个“刷写前置检查清单”。把电压、温度、安全访问状态都列出来。我在项目中就用过一张Excel表,每次刷写前逐项确认,省了不少排查时间。
二、主编程阶段:核心数据传输
主编程阶段,这才是真正的“重头戏”。说白了,就是把新的固件数据写到ECU的Flash里。这个阶段涉及的服务最多,也最容易出问题。
主编程阶段的标准流程是这样的:
- 0x10 03(诊断会话控制):切换到扩展会话或编程会话。这是刷写的前提条件。
- 0x27(安全访问):解锁ECU。没有这一步,后面的操作都会被拒绝。
- 0x31(例程控制):执行擦除例程。把旧的固件区域清空。
- 0x34(请求下载):告诉ECU:“我要开始传数据了,准备好接收。”
- 0x36(数据传输):真正的数据搬运。一包一包地发,每包通常1KB左右。
- 0x37(请求退出传输):告诉ECU:“数据传完了,你检查一下完整性。”
- 0x31(例程控制):执行校验例程,比如CRC校验。
这里我要特别强调一下0x36数据传输。很多新手觉得这就是个循环发送,没什么技术含量。其实不然。你想想看,如果网络不稳定,丢了一包数据怎么办?ECU的Flash写入是有时序要求的,你发得太快,ECU处理不过来;发得太慢,又可能超时。
注意:我曾经遇到过一个坑——刷写过程中突然断电。ECU的Flash只擦了一半,数据没写完。重启后ECU变砖了。后来我们在主编程阶段加了“恢复机制”,每次写入前先备份关键信息。嗯,这个后面会详细讲。
三、后编程阶段:收尾与验证
后编程阶段,我管它叫“打扫战场”。数据写完了,不代表刷写成功了。你得让ECU恢复正常工作状态,并且确认新固件能跑起来。
后编程阶段的核心任务:
- 恢复DTC存储:通过0x85服务重新开启故障码记录功能。
- 恢复通信:让ECU重新发送应用报文,回到正常网络状态。
- 执行软复位:通过0x11服务(ECUReset)让ECU重启,加载新固件。
- 验证固件版本:通过0x22服务(ReadDataByIdentifier)读取软件版本号,确认刷写成功。
关键点:后编程阶段最容易忽略的是“验证”。很多工程师刷完就走,结果ECU跑起来发现功能异常。我建议至少做三件事:读版本号、读DTC状态、读一些关键信号值。确认一切正常再收工。
四、三个阶段的时间分配
在实际项目中,三个阶段的时间占比大概是这样的:
| 阶段 | 时间占比 | 典型耗时 | 常见问题 |
|---|---|---|---|
| 预编程 | 10% | 1-3秒 | 安全访问失败、电压异常 |
| 主编程 | 80% | 30秒-5分钟 | 数据传输超时、Flash写入失败 |
| 后编程 | 10% | 1-3秒 | 复位后ECU无响应、版本不匹配 |
你看,主编程占了绝大部分时间。所以优化刷写速度,主要就是优化主编程阶段的数据传输效率。比如增大单包数据量、减少握手次数等等。这些后面会有专门的章节讲。
五、一个完整的刷写时序示例
为了让大家更直观地理解,我画一个简化的时序图(用文字描述):
Tester ECU
| |
|-- 0x10 03 ------------>| 切换到编程会话
|<-- 0x50 03 00 32 01 ---| 响应:成功,P2=50ms,P2*=5000ms
| |
|-- 0x27 01 ------------>| 请求种子
|<-- 0x67 01 12 34 56 ---| 返回种子:0x123456
| |
|-- 0x27 02 ------------>| 发送密钥
|<-- 0x67 02 ------------| 安全访问通过
| |
|-- 0x31 01 FF 00 ------->| 擦除Flash
|<-- 0x71 01 FF 00 01 ---| 擦除完成
| |
|-- 0x34 00 44 00 10 ---->| 请求下载,地址0x1000,大小0x10000
|<-- 0x74 20 00 10 ------>| 同意,最大包长0x1000字节
| |
|-- 0x36 01 [数据] ------>| 发送第一包
|<-- 0x76 01 ------------| 确认
|-- 0x36 02 [数据] ------>| 发送第二包
|<-- 0x76 02 ------------| 确认
| ... | 循环直到数据发完
| |
|-- 0x37 ---------------->| 请求退出传输
|<-- 0x77 ---------------| 确认
| |
|-- 0x31 01 FF 01 ------->| 执行CRC校验
|<-- 0x71 01 FF 01 00 ---| 校验通过
| |
|-- 0x11 01 ------------>| 请求复位
|<-- 0x51 01 ------------| 确认,ECU重启
| |
|-- 0x22 F1 00 ---------->| 读取软件版本
|<-- 0x62 F1 00 01 02 ---| 版本号:1.2
这个时序图,说白了就是刷写的“标准答案”。我在项目中调试刷写工具时,就是拿着这个时序图一帧一帧地对。哪一步没响应,哪一步超时了,一眼就能看出来。
避坑指南:我曾经遇到过一个ECU,在0x34请求下载后返回了0x7F 0x34 0x78(请求超出范围)。查了半天,发现是地址参数写错了。ECU的Flash地址不是从0x0000开始的,而是从0x8000开始的。嗯,所以一定要先看ECU的Memory Map。
六、总结
好了,刷写流程概览就讲到这里。三个阶段的划分,其实是为了让刷写过程更可控、更安全。预编程做准备工作,主编程做数据传输,后编程做收尾验证。每一步都有明确的服务和状态机。
下一章,我会详细讲预编程阶段的具体实现,包括如何关闭DTC、如何检查刷写条件。到时候我会带一个实际项目的代码示例,大家记得来看。
最后说一句:刷写流程看似简单,但每个细节都可能成为坑。我见过太多因为跳过预编程步骤导致ECU变砖的案例。所以,别嫌麻烦,一步一步来。