3、刷写会话控制:10 02编程会话、10 03扩展会话、会话切换时序与超时处理

会话控制,说白了就是告诉ECU:“我要干活了,你准备好没?”

UDS协议里定义了三种会话模式:默认会话、扩展会话、编程会话。刷写Bootloader时,我们最关心的是后两种。我个人习惯把会话切换看作是“敲门”的动作——你得先敲对门,ECU才会给你开门办事。

3.1 三种会话模式概述

ECU上电后,默认进入默认会话(Default Session)。这个模式下,很多诊断服务是被限制的。比如你想用34号服务(请求下载),ECU会直接拒绝你。

会话模式 SID + SubFunc 主要用途 可用的关键服务
默认会话 10 01 普通通信,低功耗 22(读数据)、2E(写数据)受限
扩展会话 10 03 诊断、配置、例程控制 2E、31(例程控制)、28(通信控制)
编程会话 10 02 Bootloader刷写 34(请求下载)、36(传输数据)、37(退出传输)

关键点:编程会话是刷写的“最高权限模式”。进入编程会话后,ECU会关闭应用层的正常通信,只响应诊断请求。你想想看,这时候如果网络上有其他报文干扰,刷写很可能失败。

3.2 10 02 编程会话

编程会话,是刷写流程的“入场券”。

发送10 02后,ECU会做两件事:

  • 切换到编程模式,禁用应用层任务
  • 启动一个内部定时器(S3Server),默认超时时间通常是5秒

我记得有一次,客户反馈刷写时总是超时。排查了半天,发现是CAN总线负载太高,10 02的响应报文被延迟了。ECU等不到响应,直接退出了编程会话。嗯,这里要注意:编程会话的超时时间很短,网络环境必须干净。

我的习惯:发送10 02后,我会立即启动一个5秒的看门狗定时器。如果5秒内没收到肯定响应(50 02),直接报错退出。不要傻等,嵌入式系统最怕死等。

3.3 10 03 扩展会话

扩展会话,是刷写前的“准备工作区”。

为什么需要扩展会话?因为有些刷写前的配置工作,比如解锁安全访问(27服务)、写入刷写密钥,这些操作在默认会话下是不允许的。你需要先切换到扩展会话,才能执行这些“敏感操作”。

扩展会话的超时时间通常比编程会话长,一般是10秒或更长。我个人习惯设置为15秒,给诊断仪留足操作时间。

避坑指南:我曾经遇到过一个项目,工程师在扩展会话里执行了27服务解锁,然后直接发送34服务请求下载。结果ECU返回了NRC 0x78(请求正确接收,但响应待定)。为什么?因为解锁成功后,会话模式没有切换回编程会话。记住:刷写必须在编程会话下进行。

3.4 会话切换时序

会话切换不是随意的,它有严格的时序要求。我画了一张流程图,帮你理清思路。

会话切换时序流程图 默认会话 (10 01) 10 03 扩展会话 (10 03) 10 02 编程会话 (10 02) 34/36/37 刷写操作进行中 超时 返回默认会话 说明: 1. 默认→扩展:10 03 2. 扩展→编程:10 02 3. 超时后自动返回默认 4. 编程会话不可直接跳转

从流程图可以看出,会话切换是单向的:默认→扩展→编程。你不能从默认会话直接跳到编程会话,也不能从编程会话跳回扩展会话。想回去?只能先超时或主动发送10 01回到默认会话,再重新切换。

实战经验:我建议你在刷写工具里实现一个“会话状态机”。每次发送诊断请求前,先检查当前会话状态。如果状态不对,先发送对应的10服务切换会话。这样可以避免很多“莫名其妙”的NRC错误。

3.5 超时处理机制

超时处理,是刷写稳定性的最后一道防线。

ECU内部有一个定时器叫S3Server。每次收到诊断请求(包括10服务本身),这个定时器就会重置。如果定时器超时了,ECU会自动回到默认会话。

为什么会这样设计?你想想看,如果刷写过程中诊断仪突然掉线了,ECU总不能一直卡在编程会话里吧?那应用层任务就永远跑不起来了。超时机制保证了ECU的“自救能力”。

会话模式 S3Server 典型超时时间 超时后的行为
默认会话 无(或很长) 保持默认会话
扩展会话 5~10秒 回到默认会话
编程会话 3~5秒 回到默认会话,中止刷写

避坑指南:我曾经遇到过一个案例,刷写过程中诊断仪每100ms发送一次34服务请求下载,但ECU总是在第3秒超时返回默认会话。排查后发现,34服务请求下载的响应时间超过了500ms,而诊断仪在等待响应期间没有发送任何其他诊断请求。S3Server在等待期间没有被重置,导致超时。解决方案:在等待34服务响应时,诊断仪需要定期发送“Tester Present”(3E 80)来保持会话。

3.6 保持会话的技巧:Tester Present

Tester Present(3E 80)是刷写时的“心跳包”。它的作用只有一个:重置S3Server定时器,防止会话超时。

我个人习惯的做法是:

  • 在刷写过程中,每隔2秒发送一次3E 80
  • 如果连续3次3E 80没有收到响应,认为通信中断,主动退出刷写
  • 在发送34/36/37等耗时服务时,等待响应期间也要保持3E 80的发送

小技巧:3E 80的响应是7E 80,不需要额外处理。你可以在刷写线程里单独开一个定时器任务,专门负责发送3E 80。这样即使主线程在等待34服务的响应,会话也不会超时。

3.7 会话切换的NRC错误处理

会话切换不是100%成功的。ECU可能会返回各种NRC错误。我整理了一些常见的错误码:

NRC 含义 常见原因
0x12 子功能不支持 发送了10 04(不存在的会话)
0x22 条件不满足 刷写条件未满足(如电压过低)
0x78 请求正确接收,响应待定 ECU正在处理其他任务,稍后重试
0x7F 服务不支持 当前会话下不支持10服务(极少见)

嗯,这里要注意:0x78不是错误,它只是告诉诊断仪“我收到了,但还没处理完”。遇到0x78时,不要立即放弃,等一段时间后重试即可。

总结一下:会话控制是刷写流程的“门禁系统”。门没开对,后面的所有操作都是白费。我个人建议你在开发刷写工具时,把会话切换做成一个独立的模块,包含超时处理、重试机制、状态机管理。这样即使项目换了ECU,这个模块也能复用。