一.概述
UDS(UnifiedDiagnostic Services,统一诊断服务,有时也称增强诊断)是ISO-14229定义的基于OSI模型中应用层的协议。其中,ISO 14229-1定义了诊断服务,但不涉及网络层及实现手段,只有应用层的内容,因此可在不同的汽车总线(如CAN, LIN, Flexray, Ethernet和K-line等)上实现。
结合ISO 15765-3和ISO 14229-1则实现了基于CAN总线的UDS汽车统一诊断服务。如下图所示:
ISO15765-4规定排放相关的诊断内容
OSI各层 | 汽车制造商的增强诊断 | 法规要求的排放相关诊断(OBD) |
诊断应用 | 用户定义 | ISO 15031-5 |
应用层 | ISO 15765-3/ISO 14229-1 | ISO 15031-5 |
表示层 | 无 | 无 |
会话层 | ISO 15765-3 | ISO 15765-4 |
传输层 | 无 | 无 |
网络层 | ISO 15765-2 | ISO 15765-4 |
数据链路层 | ISO 11898-1 | ISO 15765-4 |
物理层 | 用户定义 | ISO 15765-4 |
UDS不是法规要求的,没有统一实现标准,其优势在于方便生产线检测设备的开发,同时更大的方便了售后维修保养和车联网的功能实现。
诊断通信的过程从用户角度来看非常容易理解,诊断仪发送诊断请求(request),ECU给出诊断响应(response),而UDS就是为不同的诊断功能的request和response定义了统一的内容和格式。
二.诊断服务交互方式
UDS本质上是一种定向的通信,是一种交互协议(Request/Response),即诊断方给ECU发送指定的请求数据(Request),ECU反馈给诊断方信息(Response)。
Diagnostic Request的格式:
DiagnosticRequest的格式可以分为两类:
一类是拥有sub-function的;
一类是没有sub-function的;
Service ID(以下简称SID)的长度固定为1个字节,代表了这条诊断命令执行的什么功能。Sub-function的长度也是1个字节,它通常表示对这个诊断服务的具体操作,比如是启动、停止还是查询这个诊断服务。而后面的Parameter则根据各个诊断服务的不同具有不同的内容,长度和格式并没有统一规格,它用于限定诊断服务执行的条件,比如某个诊断服务执行的时间等。Parameter的一个重要应用是作为标识符,标识诊断请求要读出的数据内容。
有一点要补充的是,其实Sub-function严格来说是7个bit,而不是1个byte,因为它的最高位bit被用于抑制正响应(Suppress Ppositive Response, SPR),如果这个bit被置1,则ECU不会给出正响应(PositiveResponse);如果这个bit被置0,则ECU会给出正响应。这样做的目的是可以告诉ECU不要发不必要的Response,从而节约通信资源。
Diagnostic Response的格式:
Diagnosticresponse分为positive和negative两类。
positive response意味着诊断仪发过来的诊断请求被执行了,而negativeresponse则意味着ECU因为某种原因无法执行诊断仪发过来的诊断请求,而无法执行的原因则存在于negative response报文中的NRC中
Positive response肯定响应的格式是由三部分组成,其中的response SID这个字节作为诊断请求的echo,回复[SID+0x40],例如请求10,响应50;请求22,响应62,回复的是一组数据。后面的两个字节分别为子功能及其他,视具体的诊断服务而定。
Negative response否定响应的格式固定为3个字节,回复[7F+SID+NRC],第一个字节为0x7F,第二个字节是被拒绝掉的SID,第三个字节是NRC否定响应码。比如,若ECU给出7F22 13这个negative response,则说明SID=22这个服务因为诊断请求数据长度不对(NRC=13)的原因而无法执行。NRC否定响应码如下图所示:
举例来说:
以CAN总线网络举例。八个帧数据字节,第一字节被网络层占用(ISO 15765-2)。
诊断端发送请求(Request):02 10 02 xx xx xx xx xx ; 02是网络层单帧SF,代表数据域有2个字节,10是SID,02是子功能。
若ECU的肯定响应(Positive Response):02 50 02 xx xx xxxx xx;02同上,10+40表示对SID的肯定回复,02是子功能(在下文进行详解)。
若ECU的否定响应(Negative Response):03 7F 10 22 xx xxxx xx;03同上,代表数据域有3个字节,7F表示否定响应,10是SID,22是NRC。
通俗来说,诊断通信的过程就是诊断仪和ECU交换数据,前者发的是request,后者发的是response,而UDS最重要的作用就是定义了这些request和response的格式和内容。
三.诊断服务内容
UDS协议共定义以下26种服务:
本文首先将针对上图中关于“诊断和通信管理类”“数据传输类”“存储数据传输”的服务进行解读。后续将在下文进行更新
诊断和通信管理类服务
1. DiagnosticSessionControl(0x10)
$10用于控制ECU在不同的session之间进行转换,session可以看作是ECU所处的一种软件状态,在不同的session中诊断服务执行的权限不同。其Request请求格式如下所示:
DiagnosticSessionControl诊断request的格式
第一个字节即SID,这里为0x10。第二个自己即$10服务的子功能,功能列表如下所示:
ECU上电时,进入的是默认会话0x01(Default)。如果您进入了一个非默认会话的状态,一个定时器会运转,如果一段时间内没有请求,那么到时间后,诊断退回到默认会话01。当然,我们有一个$3E的服务,可以使诊断保持在非默认的状态。
ECU上电之后,由于默认处在0x01 defaultSession中,而在这个session中很多诊断服务不可以执行,导致很多诊断相关的数据不能读取或写入。
一般的诊断仪启动之后,会给ECU发送10 03,即让ECU进入 extendedDiagnosticSession中,在这个session中可执行的诊断服务就很多了。
而如果要让ECU保持在non-defaultSession中,则需要诊断仪每隔固定的时间发送0x3E服务,ECU才会知道诊断仪有和自己通信的需求,从而保持在non-defaultSession中。
另一个常用的session是0x02 ProgrammingSession,在这个session中可以进行软件刷写的一系列诊断服务。
0x40 – 0x5F 这个范围中的session由整车厂自定义使用,比如,某些诊断服务或诊断数据的操作需要在生产线上执行,即所谓的End-Of-Line,整车厂可以从这个范围中选择一个值来表示EOL session;又或者在开发阶段需要某种“超级”session,则也可以从这里选一个值用来使ECU进入开发模式的session。
DiagnosticSessionControl这个服务非常简单,但是它却是ECU和诊断通信的第一条诊断命令。
ECUReset (0x11)
ECUReset 这条指令的用途是通过诊断请求使ECU重启。
ECUReset 诊断request的格式
第一个字节是SID,即0x11。第二个字节的低7bit是sub-function,用于指示ECU将模拟哪种方式进行重启。 常用的sub-function包括(只举2个例子,UDS还定义了很多其他的值)
0x01 hardReset 模拟KL30的重启
0x02 keyOffOnReset 模拟KL15的重启
当我们通过诊断命令改写了ECU的某些数据,或者对ECU进行了某些设置,只有将ECU重启才能将这些配置生效,所以就有了这个诊断命令。在ECUReset 执行之后,ECU会从Non-defaultsession回退到defaultsession中。
SecurityAccess(0x27)
厂家可能会为ECU定义某些安全级别稍微高一些的诊断服务,在执行此类服务之前,就需要执行SecurityAccess 这个诊断命令,进行一个简单的身份验证。
完成SecurityAccess 有以下步骤:
根据UDS对$27服务的定义:
0x03, 0x05, 0x07– 0x41 这个范围留给用于requestSeed的sub-function;
0x04, 0x06, 0x08– 0x42 这个范围留给用于sendKey的sub-function。
具体选择哪对值,由整车厂自己定义。整车厂也可以选择多对sub-function,用于不同等级的安全访问。
举例来说:
假设0x05用于requestSeed,0x06用于sendKey。
- 诊断仪发送 27 05;
- ECU响应 67 05 01 0101(seed是 01 01 01);
- 诊断仪发送 27 06 02 03 04(key值是02 03 04,seed是 01 01 01,假设本地密码为01 02 03,而算法就是将密码与seed相加);
- ECU验证成功 67 06;
此时ECU就处于unlocked的状态了,那些被保护起来的诊断服务和诊断数据可以被操作了。通常来说,如果ECU重启,或者回到了default session,unlocked状态就失效了,如果要执行相关诊断服务,则需要再次执行上面描述的过程。
CommunicationControl (0x28)
该服务用于打开/关闭某些类别的报文的发送/接收。它通常在刷写软件或大量数据的时候使用,因为在刷软件或参数的时候并不需要ECU进行与通信相关的功能,将通信关闭之后可以把所有通信资源都留给软件或参数的下载,当下载过程完成之后再利用该服务将通信恢复即可。
0x28服务的格式如下图所示
第一部分即SID,一个字节,值为0x28;
第二部分是sub-function,即对ECU的通信进行哪种控制,具体包括 :
第三部分表明这条诊断请求要对哪种报文进行控制,长度为1个字节,定义如下表所示:
这个字节中最常用的就是低2 bit,0x1代表普通应用报文,0x2代表网络管理报文,0x3代表普通应用报文和网络管理报文。
第四部分是optional的,只有当sub-functional等于0x04或0x05时才需要使用。
举例来说:
28 01 01 表示激活应用报文的接收并关闭应用报文的发送(网络管理报文不受影响)。
28 00 01 表示激活应用报文的接收和发送(网络管理报文不受影响)。
TesterPresent (0x3E)
这个诊断服务的用处可以通过它的名字很明显地得知,即告知ECU诊断仪还在连接着。在$10中提到了关于session的部分,如果没有诊断命令的发送和接收,ECU将从non-default session中回退到default session, 0x3E就是用于使ECU保持在当前session。
这应该是UDS中最简单的一个诊断服务了,它永远只有两个byte,格式如下:
当sub-function是0x00时,ECU要给出response;
当sub-function是0x80时,ECU不需要给出response。
一般来说主机厂会为这个服务定义两个时间参数,一个参数用于规定自己的诊断仪发送0x3E服务的间隔,另一个参数用于定义ECU收不到0x3E服务的timeout时间。
ControlDTCSetting (0x85)
该服务用于控制ECU的DTC(diagnostic trouble code,故障诊断码)存储,这个服务常常和前面提到的28服务一起使用,比如,在开始写参数之前,为了获得更快的传输速度,我们用28服务把所有ECU的通信关闭了,但此时因为收到不到相关的报文,ECU会没有必要地存储很多DTC,这时如果我们使用85服务把ECU存储DTC的功能暂时性地禁止掉,则不会造成这种麻烦。
0x85服务请求的格式
第一部分即SID,一个byte,值为0x85;
第二部分是sub-function,即是打开还是关闭ECU的DTC存储,包括 :
0x01 on
0x02 off
第三部分是optional的,由各家自己定义,比如,可以用FF FF FF 来表示这条诊断命令针对所有的DTC。
ResponseOnEvent (0x86)
尽管诊断通信过程是问答式的,诊断仪发请求,ECU给响应。0x86服务算是一个例外,在ECU收到这条0x86服务之后,当DTC产生时,它会自动地上报DTC及相关环境数据,直到用另一条0x86服务来关闭ECU的这个行为。
该功能主要用于ECU的前期开发阶段,在售后和生产中是不会用到的,而且该服务的格式复杂(即可变的参数很多),执行它还分为好几个步骤,在这里就不过多叙述。
LinkControl (0x87)
这个服务用于转化ECU数据链路层和物理层的状态,比如,在高速CAN上的ECU正常通信速率是500kbit/s,但它同时也支持1M bit/s的波特率,如果需要刷写大量数据,便可以利用这条诊断服务让ECU以1M bit/s的波特率进行通信。
这个诊断服务的执行分为两个步骤:
验证ECU是否支持要调整到的目标波特率
让ECU的数据链路层和物理层转到目标波特率的通信状态
只有当第一个步骤验证通过了,第二个步骤才可以成功执行。
数据传输类服务
在数据传输类服务,0x22和0x2E成对使用,0x23和0x3D成对使用,这几个服务用于诊断数据的基本读写操作。0x24,0x2A,0x2C是一些特殊操作。
ReadDataByIdentifier (0x22)
$22,即读数据
l Request(请求):22+DID(Data Identifier,通常是两个字节)
l Response(响应):62+DID+Data
DID有一部分已经被ISO 14229-1规定了。比如0xF186就是当前诊断会话数据标识符,0xF187就是车厂零件号数据标识符,0xF188就是车厂ECU软件号码数据ID,0xF189就是车厂ECU软件版本号数据标识符。
举例来说:
22 F1 87 (读取零件号,DID=F1 87)
62 F1 87 XX YYZZ KK MM NN(给出零件号)
WriteDataByIdentifier (0x2E)
l Request(请求):2E+DID+Data
l Response(响应):6E+DID
注意,比如0xF186这个DID不支持直接写入数据,需要用$10来进行会话转换。也就是说,对于写数据的请求,一般来说需要在一个非默认会话,和解锁的状态下才能进行。
举例来说:
2E F1 87 XX YY ZZ KK MM NN(写入零件号)
6E F1 87(给出positive response)
ReadMemoryByAddress (0x23)
0x23服务的请求格式
第一部分固定为1个byte, 0x23;
第二部分是格式信息,长度为1个byte,高4 bits用于指示memorySize的长度(字节数),低4 bits用于指示memoryAddress的长度(字节数)。比如,如果这个值为0x46,则后面的memorySize为6个byte,memoryAddress为4个byte。
第三部分是memoryAddress信息,它的长度由第二部分的AddressAndLengthFormatIdentifier指示。
第四部分是memorySize信息,它的长度由第二部分的AddressAndLengthFormatIdentifier指示。
如果这条命令的格式是 23 22 xx yy aa bb,则它的含义就是,读取xx yy地址的长度为aa bb的数据。
WriteMemoryByAddress (0x3D)
了解了0x23的用法,0x3D的用法就很好理解了,它标识memoryAddress和memorySize的方法与0x23相同,只是在诊断命令最后再加上一段需要写入的数据。
存储数据传输服务
存储数据传输服务,用于操作DTC(diagnostic trouble code,故障诊断码)
在 ISO15031-6 中对 DTC 的格式有明确的定义,该规范中定义了 DTC 共由三个字节组成,如下图所示
DTC格式
字节1 | 字节2 | 字节3 |
诊断故障代码高字节 | 诊断故障代码低字节 | 诊断故障代码失效类型字节 |
在 ISO15031-6 中对 DTC 格式中的字节 1 与字节 2 也做了具体的定义,通过这个定义可以很方便确定记录的 DTC 属于车上的那种类型。
至此,DTC故障码的概念解释完毕,下面将展开关于存储传输类服务的解读:
这类服务主要涉及到两条诊断命令,分别是:
0x14:ClearDiagnosticInformation
0x19:ReadDTCInformation
这两条服务用于操作存储在ECU中的DTC,使用频率很高,而且它们比较好地体现了“诊断”两个字的含义。
ClearDiagnosticInformation(0x14)
这条诊断命令的格式比较简单,用法也很好理解,即删除存储在ECU中的DTC。
第一个字节就是SID了,后边的三个字节用于标识将要被删除的DTC种类,UDS规定用FF FF FF表示所有种类的DTC,由厂家自定义代表Powertrain、Chassis、Body、NetworkCommunication等种类DTC的值。
举例来说
Request:14+FF+FF+FF;(删除掉ECU中的所有DTC)
Response:54 ;
ReadDTCInformation(0x19)
这条指令用于读取存储在ECU中的DTC,0x19服务的sub-function代表了各式各样读取DTC的方法,UDS给19服务的sub-function从0x00到0x19进行了明确定义,这里介绍其中常见4种。
- sub-function = 0x01(reportNumberOfDTCByStatusMask)
用于读取符合DTC状态掩码的DTC的数量,此时parameter为一个byte的Mask掩码,用于与DTC的Status进行“与”运算,而ECU返回的则是"与"运算之后结果不为0的DTC的数量。
DTC的Status用一个byte表示,其中的8个bit分别代表DTC的不同状态,比如,bit0 表示这个DTC是active的还是passive的,bit 4表示这个DTC是否已经被confirm了,如果DTC的状态是confirm,则说明该DTC已经被ECU存储下来了。
比如:19 01 08这个命令的用途,就是读取所有状态为confirm的DTC的数量。
- sub-function = 0x02(reportDTCByStatusMask)
用于读取符合特定条件的DTC列表,此时parameter仍然为一个byte的Mask,用于与DTC的Status进行“与”运算,而ECU返回的则是"与"运算之后结果不为0的DTC列表。
比如19 02 01这个命令的用途,就是读取所有状态为active的DTC的数量。此时ECU返回的格式应该是59 02 01 XX XX XX 01 YY YY YY 09......。返回的DTC列表中的每个条目为4个字节,前三个字节用于标识DTC,比如 XX XX XX,最后一个字节用于标识DTC状态,比如01,表示DTC是active的,09表示DTC是active且confirm的。
- sub-function = 0x06(reportDTCExtDataRecordByDTCNumber)
用于读取某个DTC及其相关的环境数据,此时parameter为4个byte,前三个byte用于标识我们要读取的DTC,第四个byte用于标识要读取的环境数据的范围,UDS规定使用FF来表示读取所有的环境数据,各厂家可以要根据自己的需求定义其他的值来代表要读取的环境数据的范围。环境数据包括DTC状态,优先级,发生次数,老化计数器,时间戳,里程等,厂家还可以根据自己的需求定义一些此DTC产生时的测量数据。
比如 19 06 XX XX XX FF就表示读取 XX XXXX这个DTC的所有环境数据,ECU的返回值应该是59 06 XX XX XX AA BB CC DD.....,其中AA BB CCDD...代表的就是XX XX XX这个DTC产生时所一起存储的环境数据。
- sub-function = 0x0E(reportMostRecentConfirmedDTC)
sub-function = 0x0E时,不需要parameter。0x0E表示,要求ECU上报最近的一条被置为confirm的DTC。上文介绍过0x86服务,sub-function = 0x0E的19服务通常被作为参数传递给86指令,要求ECU在发生DTC存储的时候进行自动上报,即19 0E这两个字节的指令被嵌入到86服务的命令中。这条命令在开发阶段会用到,比如验证某个故障路径是否生效。
- 小结
本文概述了UDS协议,交互方式及部分诊断服务内容(包括诊断和通信管理类”“数据传输类”“存储数据传输”)。
后续将继续更新余下的诊断服务内容(包括IO控制,例程控制,上传与下载)及其他相关内容,敬请期待!