2. 汽车电子基础

好,咱们正式开始聊刷写协议。很多刚入行的朋友一听到「UDS」就觉得头大,觉得这是套很玄乎的东西。其实说白了,它就是ECU和诊断仪之间沟通的一套「黑话」——你问一句,它答一句,仅此而已。

我个人习惯把UDS理解成「汽车界的HTTP协议」。你想想看,浏览器和服务器怎么通信?发请求、收响应、有状态码。UDS也一样,只不过它跑在CAN总线上,报文更短,实时性要求更高。

UDS协议简介

UDS的全称是 Unified Diagnostic Services,统一诊断服务。它定义了一套标准化的服务ID(SID),用来做诊断、刷写、标定这些事儿。

我记得刚做Bootloader那会儿,总把UDS和KWP2000搞混。KWP2000是上一代标准,报文结构更复杂,而且只支持单帧。UDS最大的改进就是引入了多帧传输机制,能传几兆甚至几十兆的刷写文件。

核心要点:UDS不是协议栈,而是一套服务规范。具体怎么在CAN、LIN、以太网上跑,由下层传输协议决定。咱们做ECU刷写,最常用的是基于CAN的UDS,也就是ISO 15765-2(DoCAN)。

ISO 14229标准

ISO 14229就是UDS的官方标准文档。它定义了所有诊断服务的格式、时序、状态机。标准分好几部分,咱们做刷写最关心的是 ISO 14229-1(应用层)和 ISO 14229-3(统一诊断服务在CAN上的实现)。

这里有个坑,我当年踩过。ISO 14229-1里定义的请求/响应格式是通用的,但具体到每个OEM,他们会做裁剪。比如某德系厂商只支持20个服务,另一家美系厂商可能支持30个。千万别以为标准里写的所有服务ECU都得支持——实际项目里,OEM会给你一张「支持服务列表」,照着那个做就行。

标准编号 内容 刷写相关度
ISO 14229-1 应用层规范,定义服务ID、格式、时序 ★★★★★
ISO 14229-2 会话层服务,用于建立/管理诊断会话 ★★★★☆
ISO 14229-3 CAN总线上的UDS实现(DoCAN) ★★★★★
ISO 14229-5 LIN总线上的UDS实现 ★★☆☆☆
ISO 14229-7 UDS over Ethernet(DoIP) ★★★☆☆

我的建议:新手先啃ISO 14229-1和ISO 14229-3就够了。其他部分等用到再查,别一上来就想通读全标准——那玩意儿一千多页,看完黄花菜都凉了。

刷写相关的诊断服务

做Bootloader开发,你真正需要掌握的UDS服务其实就10个左右。我把它们分成三组:会话控制、安全访问、数据传输。

1. 会话控制服务

  • 10 服务(DiagnosticSessionControl):切换诊断会话。刷写前必须切换到扩展会话(0x03)或编程会话(0x02)。
  • 11 服务(ECUReset):复位ECU。刷写完成后通常需要硬复位让新程序跑起来。

我曾经遇到一个项目,ECU死活进不了编程会话。查了两天,发现是Bootloader里会话状态机没处理好——从默认会话切到编程会话时,中间必须经过扩展会话。标准里写得很清楚,但实现时容易漏掉这个中间态。

2. 安全访问服务

  • 27 服务(SecurityAccess):安全解锁。刷写前必须通过种子-密钥验证,防止非法刷写。

安全访问这块,不同OEM的算法差异很大。有的用简单的异或,有的用AES。我建议在Bootloader里预留算法接口,方便后期适配不同客户的需求。

3. 数据传输服务

  • 34 服务(RequestDownload):请求下载。告诉ECU你要刷写的数据大小和起始地址。
  • 36 服务(TransferData):传输数据。实际的数据块发送,支持多帧传输。
  • 37 服务(RequestTransferExit):请求传输退出。刷写完成后关闭传输通道。
  • 31 服务(RoutineControl):例程控制。刷写前后用来擦除Flash、校验完整性、执行跳转。

注意:34服务的请求下载地址必须是物理地址,不能是逻辑地址。我见过有人把Flash驱动地址写错了,结果刷写时把Bootloader自己给覆盖了——ECU直接变砖。嗯,那哥们后来被客户骂得很惨。

刷写流程中的服务调用顺序

一个典型的UDS刷写流程,服务调用顺序是这样的:

  1. 10 03 → 切换到扩展会话
  2. 27 01/02 → 安全解锁(种子-密钥交换)
  3. 31 01 FF00 → 例程控制:擦除Flash
  4. 34 00 44 → 请求下载(指定地址和大小)
  5. 36 xx → 传输数据(循环发送,直到数据传完)
  6. 37 00 → 请求传输退出
  7. 31 01 FF01 → 例程控制:校验完整性
  8. 11 01 → 复位ECU

这个顺序是标准推荐的,但实际项目中OEM可能会调整。比如有些厂商要求先擦除再请求下载,有些则把擦除放在请求下载之后。做Bootloader时,最好把每个步骤做成独立模块,方便按需组合。

UDS刷写流程(服务调用顺序) 10 03 扩展会话 27 01/02 安全解锁 31 01 FF00 擦除Flash 34 00 44 请求下载 36 xx 传输数据(循环) 37 00 传输退出 31 01 FF01 校验完整性 11 01 复位ECU 说明: • 蓝色:会话/安全控制 • 红色:Flash擦除操作 • 绿色:数据传输阶段 • 紫色/橙色:收尾与复位

UDS报文结构

UDS的报文结构其实不复杂。一个标准的UDS请求帧包含:

  • 服务ID(1字节):比如0x10、0x27、0x34
  • 子功能(1字节,可选):比如0x03(扩展会话)、0x01(请求种子)
  • 数据参数(N字节):比如地址、长度、数据块

响应帧的结构类似:

  • 响应ID(1字节):服务ID + 0x40,比如0x50是0x10的响应
  • 子功能/状态码(1字节):0x00表示肯定响应,其他值表示否定响应
  • 数据参数(N字节):根据服务不同而变化

关键点:否定响应码(NRC)是调试刷写问题的重要线索。常见的NRC有:0x12(子功能不支持)、0x22(条件不满足)、0x31(请求超出范围)、0x35(安全访问被拒绝)。我调试时第一件事就是抓CAN报文看NRC,能省一半排查时间。

多帧传输机制

刷写文件动辄几兆,CAN单帧最多传8字节数据,所以必须用多帧传输。ISO 15765-2定义了四种帧类型:

帧类型 PCI字节 作用
单帧(SF) 0x00-0x07 数据长度 ≤ 7字节
首帧(FF) 0x10-0x1F 多帧传输的第一帧,包含总长度
连续帧(CF) 0x20-0x2F 后续数据帧,带序列号
流控帧(FC) 0x30-0x3F 接收方控制发送速率(BS、STmin)

这里有个细节容易忽略:流控帧的BS(块大小)和STmin(最小间隔时间)直接影响刷写速度。我见过一个项目,BS设成0(表示不限制),结果ECU接收缓冲区溢出,刷写频繁失败。后来把BS改成16,STmin设成10ms,问题就解决了。

我的经验:做Bootloader时,多帧接收缓冲区至少分配256字节。有些ECU Flash驱动要求数据对齐到4字节,所以36服务的数据长度最好是4的倍数。嗯,这些小细节不注意,刷写时就会莫名其妙地卡住。

总结一下

UDS协议是ECU刷写的基石。你不需要背下所有服务ID,但必须理解:

  • 会话控制、安全访问、数据传输这三类服务的配合关系
  • 多帧传输的握手流程(FF→FC→CF)
  • 否定响应码的含义和排查方法