基于OEM《基于CAN的UDS服务》诊断工具要求规范,详解服务/会话矩阵、时序参数、DTC状态字节管理与刷写流程的ECU落地要点
UDS(统一诊断服务)车规诊断的工程落地,成败取决于四个容易被忽视的硬性细节:会话支持矩阵、时序参数、DTC 状态字节管理与刷写(重编程)流程。本文基于一份 OEM《OEM诊断工具要求:基于CAN的UDS服务》规范译文(引用 ISO 14229-1 / ISO 15765-2/3/4 标准族),将规范中 ECU 供应商必须满足的字节级、时序级要求整理为可直接执行的实现清单:诊断帧 DLC 必须恒为 8 且填充 0x00、OBD ECU 应用层响应 P2 上限 50ms、会话保活 S3 超时 5000ms、19 服务 DTC 状态字节 8 个 bit 的精确管理语义,以及 34→36→37 刷写流程中对闪存格式(Intel .hex / Motorola .s19)、波特率、电源锁定、烧录日志与重编程计数器的明确要求。对正在为商用车、工程机械、特种车辆开发 ECU 诊断固件的嵌入式团队,这份指南可直接对照自查。
整车厂(OEM)在项目定点后,会向 ECU 供应商签发一份《OEM诊断工具要求:基于CAN的UDS服务》规范文档,其目的明确:"为 OEM 车辆开发基于 CAN 协议上使用 UDS 的各类 ECU 的诊断测试软件所需的固件支持和文档要求"。这份规范基于 ISO 14229-1(UDS 应用层)、ISO 15765-2(CAN 网络层)、ISO 15765-3(基于 CAN 的 UDS)、ISO 15765-4(排放相关系统)标准族,并对标准中由 OEM 自行裁量的部分做了强制规定。关键点在于:规范第五条明确提出"ECU供应商应与 OEM 诊断团队确认本文件的最新版本""任何偏差都需诊断团队批准"——这意味着规范中的每一条(哪怕看似啰嗦的填充字节规则)都是审核项,未满足即无法通过 EOL(生产线末端)测试与售后诊断验收。
规范的约束范围覆盖五个层级:物理层与数据链路层(DLC、填充字节)、网络层(11 位/29 位 CAN ID、SF/FF/CF/FC 帧与时序)、会话层(S3 保活)、应用层(P2 响应时序、服务字节结构)以及工程交付物(附录 A 的 EOL 工具开发文档要求)。对于长期做工业物联网、以 MCU 为中心的嵌入式开发团队而言,这套体系既是车规项目的门槛,也是把工业设备诊断能力提升到车规水准的参照系。
对照规范逐条梳理,ECU 供应商在首轮交付中最常被 OEM 打回的四类问题分别是:
第一,帧级硬性规则执行不严。规范第 6 章与第 10 章明确规定:每个诊断 CAN 帧的 DLC 必须恒为 8,消息未填满时剩余字节填充 00h;同时"ECU 不得拒绝接收带有非零填充字节的诊断请求"。部分实现用 DLC 可变或截断帧传输,直接违反规范且无法通过网络层一致性测试。
第二,时序参数不达标或未按会话区分。规范第 7 章网络层规定:法定 OBD ECU 的接收侧响应时间 N_Ar 为 1ms、发送侧 N_As 为 21ms,接收连续帧 N_Cr 为 75/150ms;第 8 章会话层规定:测试仪在无其他请求时发送"测试仪存在"(0x3E)的周期建议 2000ms、超时 <5000ms,ECU 维持会话活跃的超时 S3 为 5000ms;第 9 章应用层规定:ECU 对请求的响应延迟 P2_CAN_ECU 为 0~50ms,收到 $78(请求已正确接收,等待响应)后最长 5s 内必须给出最终响应。时序不达标是 EOL 自动化测试失败的头号原因。
第三,DTC 状态字节管理语义混乱。规范第 11.5 章(19 服务)对 DTC 状态字节的 8 个 bit 给出了精确定义(测试失败/本循环失败/老化/已确认/自清除后未测试/自清除后失败/本循环未完成/警告指示灯),并要求 ECU 供应商正确定义 DTC 及其状态字节结构、响应最大数据长度需 OEM 批准。多数实现只维护 bit0 与 bit3,导致 14 服务清除后状态恢复、永久 DTC(子功能 15)等场景处理错误。
第四,刷写流程工程化不足。规范附录 A 对固件刷写提出了具体到"闪存文件格式、波特率、电源锁定时间、烧录日志、重编程计数器、失败后无限重试恢复"的交付要求,而不少 ECU 供应商只在开发环境里演示过刷写,从未按 OEM 规范组织过完整的 34→36→37 刷写时序与断电恢复设计。
问题的本质是:OEM 规范描述的是"必须满足什么",而 ECU 固件需要回答"如何用代码与状态机实现"。以下从四个维度给出可执行的落地设计,并以 C 语言给出关键实现片段。
规范第 11.1 章给出了 OEM 支持的 22 项诊断服务清单,第 11.3 章(表15)规定了每项服务在四种会话(默认 0x01 / 编程 0x02 / 扩展 0x03 / 固件无线升级 0x55)下的可用性。落地时第一件事就是按矩阵裁剪实现,避免"实现了多余服务反而暴露漏洞":
| 服务(SID) | 默认会话 0x01 | 编程会话 0x02 | 扩展会话 0x03 | 无线升级 0x55 | 寻址方式 |
|---|---|---|---|---|---|
| 10 启动诊断会话 | √ | √ | √ | √ | 物理 |
| 11 ECU复位 | √ | √ | √ | √ | 物理 |
| 27 安全访问 | √ | √ | √ | — | 物理 |
| 28 通信控制 | √ | — | — | — | 功能 |
| 3E 测试仪存在 | √ | √ | √ | √ | 物理 |
| 85 控制DTC设置 | √ | — | — | — | 功能 |
| 22 按标识符读数据 | √ | √ | √ | √ | 物理 |
| 2E 按标识符写数据 | √ | √ | √ | — | 物理 |
| 14 清除诊断信息 | √ | √ | — | — | 物理 |
| 19 读取DTC信息 | √ | √ | — | — | 物理 |
| 2F 输入输出控制 | √ | — | — | — | 物理 |
| 31 常规控制 | √ | √ | √ | — | 物理 |
| 34/35/36/37 上传下载 | — | √ | √ | — | 物理 |
实现要点:用一张"会话 × 服务"静态查表(而非散落的 if 判断)做会话准入控制,任何服务进入时先查表,不支持的组合直接回 NRC 0x7E(当前活动会话中不支持子功能)或 0x7F(活动会话中不支持该服务);同时在 0x10 切换会话时记录会话进入时间戳,供 S3 计时使用。
时序要求必须落地为三组定时器:会话保活定时器(S3=5000ms,超时自动回默认会话并复位安全访问状态)、应用层响应定时器(P2_CAN_ECU=50ms,超时前未处理完则回 $78 并启动 P2*_CAN_ECU=5000ms 定时器)、网络层发送/接收定时器(N_As/N_Ar/N_Bs/N_Cr 按 OBD ECU 的 21ms/1ms/75ms/75ms 配置)。规范强调"BS 强烈建议设为 0",即分段消息传输过程中不应再发流控帧,连续帧间隔 STmin 在正常诊断模式 <=5ms、引导加载模式 =0。
| 时序参数 | 符号 | OEM 要求 | 落地说明 |
|---|---|---|---|
| ECU 响应延迟 | P2_CAN_ECU | 0 ~ 50ms | 超时先回 $78,再启 P2*(最长 5s) |
| $78 后最终响应 | P2*_CAN_ECU | 0 ~ 5s | 用于例程执行/闪存擦写等耗时操作 |
| 会话保活超时 | S3_ECU | 5000ms | 超时回默认会话并注销安全访问 |
| 测试仪保活周期 | S3_DT | 建议 2000ms,<5000ms | 无请求时周期发 0x3E |
| 发送端传输时间 | N_As | OBD ECU 21ms | 普通 ECU 1000ms |
| 接收端传输时间 | N_Ar | OBD ECU 1ms | 普通 ECU 1000ms |
| 等待流控/连续帧 | N_Bs / N_Cr | OBD ECU 75/150ms | 普通 ECU 1000ms |
| 块大小 / 间隔时间 | BS / STmin | BS 建议 0;STmin 正常 ≤5ms,刷写 =0 | 分段传输期间不插流控帧 |
19 服务(0x19)子功能 02"按状态掩码报告 DTC"是售后诊断使用频率最高的功能,其核心是 DTC 状态字节。规范给出 8 个 bit 的精确定义,ECU 固件必须为每个 DTC 维护完整的 8 位状态机,而非只维护"有/无故障":
| Bit | 名称 | OEM 规范语义 | 置位条件 |
|---|---|---|---|
| 0 | testFailed | DTC 测试未完成,且在测试仪发出请求时失败 | 当前有故障且测试失败 |
| 1 | testFailedThisOperationCycle | 本操作循环内测试失败(循环结束清除) | 本次点火循环失败过 |
| 2 | pendingDTC | 挂起 DTC:循环内测试至少通过一次且从未失败才会被清除 | 一次及以上失败、未确认 |
| 3 | confirmedDTC | 已确认 DTC:检测次数足够,需存入长期存储器(如待处理 DTC 已设置一次或多次) | 按确认标准累计 |
| 4 | testNotCompletedSinceLastClear | 自上次清除后测试未完成 | 清除后未跑完监控 |
| 5 | testFailedSinceLastClear | 自上次清除后至少失败过一次 | 清除后失败过 |
| 6 | testNotCompletedThisOperationCycle | 本操作循环内测试未完成 | 本循环未跑完监控 |
| 7 | warningIndicatorRequested | 警告指示灯点亮条件由 OEM 定义;若灯亮,已确认 DTC 必须置 1 | 灯亮 → bit3 同步置 1 |
实现要点:为每个 DTC 维护 uint8_t status,监控函数每循环按上述条件更新;14 服务清除诊断信息时,仅清非永久 DTC,永久 DTC(子功能 15 可读)在对应监控成功通过前保留于非易失存储;19 服务子功能 02 请求中的状态掩码仅适用于 02/13 子功能,其余子功能(03 快照/04 扩展数据/14 检测计数/15 永久)无掩码字节,响应结构须按 OEM 批准的最大长度截断。状态字节更新代码如下:
/* DTC 状态字节更新(每监控循环调用,示意) */
#define DTC_TEST_FAILED 0x01u
#define DTC_FAIL_THIS_CYCLE 0x02u
#define DTC_PENDING 0x04u
#define DTC_CONFIRMED 0x08u
#define DTC_NOT_CLEARED 0x10u
#define DTC_FAIL_SINCE_CLEAR 0x20u
#define DTC_NOT_DONE_CYCLE 0x40u
#define DTC_WARN_LAMP 0x80u
void dtc_update_status(dtc_t *d, uint8_t test_failed, uint8_t cycle_end) {
if (test_failed) {
d->status |= DTC_TEST_FAILED | DTC_FAIL_THIS_CYCLE
| DTC_PENDING | DTC_FAIL_SINCE_CLEAR;
} else {
d->status &= ~(DTC_TEST_FAILED);
if (cycle_end) d->status |= DTC_NOT_DONE_CYCLE; /* 循环结束未跑完 */
}
/* 确认逻辑:挂起次数累计达到 OEM 确认标准 */
if ((d->status & DTC_PENDING) && (++d->pending_cnt >= CONFIRM_CNT)) {
d->status |= DTC_CONFIRMED;
dtc_store_nvm(d); /* 写入非易失存储 */
}
/* 永久 DTC:清除后监控未通过前不得清状态 */
if (d->permanent && !(d->status & DTC_CONFIRMED) && !test_failed)
d->status |= DTC_CONFIRMED;
}
规范第 11.8 章给出了覆盖全部诊断服务的通用否定响应码表(表2),从 0x10 普遍拒绝到 0x93 电压过低共 40+ 项,其中发动机工况类(0x81~0x93:转速过高/低、温度过高/低、车速、档位、刹车开关、电压等)是动力域 ECU 特有的条件类 NRC。落地时建议将 NRC 全表固化进固件枚举,并按 4.1 节矩阵为每个服务裁剪"支持的 NRC 列表",防止出现"规范要求支持 0x24 却返回 0x13"的审核问题。
| NRC | 名称 | 典型触发场景 | 常见实现错误 |
|---|---|---|---|
| 0x12 | 子功能不受支持 | 19 服务收到未实现子功能 | 误回 0x31 |
| 0x13 | 消息长度错误或格式无效 | 0x34 地址/长度格式标识符非法 | 长度校验缺失直接处理 |
| 0x22 | 条件不正确 | 刷写期间收到 0x22 读数据 | 未做会话/状态门禁 |
| 0x24 | 请求序列错误 | 未请求下载就发 0x36 传输数据 | 刷写状态机缺序列校验 |
| 0x31 | 请求超出范围 | 0x2F 控制不存在的 DID | DID 表越界访问 |
| 0x33 | 安全访问被拒绝 | 未解锁即发 0x2E 写数据 | 跳过 0x27 直接放行 |
| 0x7E/0x7F | 会话/服务不受支持 | 当前会话不允许该服务 | 未查会话矩阵 |
| 0x72/0x73 | 编程失败/块序列计数错误 | 0x36 块序号不连续、擦写失败 | 刷写容错与续传缺失 |
| 0x92/0x93 | 电压过高/过低 | 刷写时电源电压越界 | 未做刷写电压门限保护 |
刷写是规范附录 A 着墨最多的部分,直接决定 EOL 刷写与售后 OTA 的成败。完整流程为:0x10 03 进入编程会话 → 0x85 01 关闭 DTC 记录 → 0x27 安全访问解锁 → 0x28 通信控制静默 → 0x34 请求下载(携带数据格式标识符、地址和长度格式标识符、内存地址与大小)→ 0x36 传输数据(块序列计数器从 1 递增,每块最大长度由 0x34 响应的"块长度最大值"决定)→ 0x37 请求传输退出 → 0x11 01 硬复位。OEM 对 ECU 供应商的交付要求包括:
刷写状态机核心是序列校验与断点续传,伪代码示例如下:
/* 刷写状态机(简化) */
typedef enum { FLASH_IDLE, FLASH_AUTHED, FLASH_REQ_DL, FLASH_XFER, FLASH_EXIT } flash_state_t;
int uds_36_transfer(uint8_t seq, const uint8_t *data, uint16_t len) {
if (g_fs != FLASH_XFER) return NRC_SEQUENCE_ERROR; /* 0x24 */
if (seq != (g_block_seq + 1) % 256) {
return NRC_BLOCK_SEQ_ERROR; /* 0x73 */
}
g_block_seq = seq;
if (flash_write_block(g_addr, data, len) != OK) {
return NRC_GENERAL_PROG_FAIL; /* 0x72 */
}
g_addr += len; /* 按 0x34 响应块长度自动换页,支持续传 */
return NRC_NONE;
}
断电续刷的实现要点:每次成功写入一个块后,在非易失区记录"当前块序号 + 校验和",上电时若检测到刷写未完成且收到新的 0x34 请求,从记录块续传;同时依据规范"未使用的内存和可写位置应包含默认值 $FF",擦除后空区域必须以 0xFF 填充,避免残留数据被误判为有效固件。
OEM UDS 诊断规范的核心不是协议本身,而是对时序、状态与交付物的一整套强制要求:DLC 恒为 8、S3=5000ms、P2=50ms、DTC 状态字节 8 位完整语义、NRC 全表裁剪,以及 34→36→37 刷写流程中闪存格式、波特率、电源锁定、烧录日志与无限重试恢复等工程细节。建议 ECU 开发团队以"会话×服务矩阵 + 时序参数表 + DTC 状态机 + 刷写状态机"四张清单组织固件设计,并按附录 A 提前准备 EOL 工具开发文档,即可显著降低 OEM 审核驳回率与 EOL 测试返工成本。
本文基于 译文_OEM UDS Service required.pdf 技术资料整理优化。规范引用标准:ISO 14229-1(UDS)、ISO 15765-2/3/4(CAN 网络层与会话/应用层、OBD 排放相关要求)、SAE J1962/ISO 15031-3(OBD 连接器)、SAE J2012/ISO 15031-6(三字节 DTC 编码)。
沧州艾诺威电子 — 国家高新技术企业,20+项国家专利
嵌入式系统开发 · 物联网方案 · AI智能硬件 · 一站式交付
电话:13930711029 | 邮箱:tech@czinv.com | 24小时内响应