UDS定义的服务从逻辑上分为6类,在上一篇文章中已经对诊断和通信管理类”“数据传输类”“存储数据传输“进行了解读。本文将介绍余下3类UDS服务,即“IO控制服务”“例行程序服务”“上传与下载服务”。
1. InputOutputControlByIdentifier (0x2F)
$2F这个服务即利用ID对ECU的输入输出进行控制,经常会在生产线上使用来验证零部件的功能。比如,在总装阶段,工人需要验证车上的各种功能是否正常,例如四个车窗的升降是否正常,如果挨个开关去按,那效率很低,如果通过一个诊断命令就能够观察到车窗升降的情况,效率则高得多。
比如,ECU接收一个输入信号A,我们就可以利用2F给这个A赋个我们需要的值;ECU对某个执行器B进行控制,我们就可以利用2F服务再配上某些特定的参数来实现对B的控制,例如门控对车窗升降、后视镜折叠等的控制。
$2F服务的request由4部分组成
第一个字节:SID=0x2F
第二三个字节:dataIdentifier(2 byte),用于标识被控制的IO对象,例如下文举例0x9B00(进气口门位置)
第四个字节:controlOptionRecord,用于标识控制类型,以及若干byte由厂家自定义使用的controlState。UDS明确定义了四种控制类型
0x00 将控制权还给ECU,即结束控制
0x01 将DID标识的对象的输入信号、内部参数、输出信号等设为默认值
0x02 将DID标识的对象的的输入信号、内部参数、输出信号等冻结住
0x03 将DID标识的对象的的输入信号、内部参数、输出信号进行设置,其实就相当于开始了对ECU的控制,这种控制类型其后会跟着第五个字节,可以表示控制对象的数字量或模拟量。
举例来说:
使用2F控制Air Inlet Door Position (进气口门位置),用DID(标识符)=0x9B00来标识进气口门的位置。
Air Inlet Door Position [%] = decimal(Hex) * 1 [%] ,即用一个百分比来表示这个位置。
step1:
tester 发送22 9B 00读取当前进气口门的位置,这里22即SID,0x9B00即第二三字节DID。
ECU返回62 9B 00 0A ,这里 0x0A = 10(dec),即表示当前位置是10%
(UDS定义可以用22服务读取2F服务中使用的dataIdentifier,返回值是状态信息,具体的状态信息是什么,则由使用者自定义了。)
step2:
tester 发送2F 9B 00 03 3C ,表示要将进气口门的位置调整到60%,0x3C = 60(dec)表示要将控制对象的模拟量设定为60%。
ECU返回6F 9B 00 03 0C,表示接受控制,当前进气口门的位置为12%。因为ECU收到请求后是立刻响应的,而门的位置调节需要时间,所以还没有达到60%。
step3:
过一段时间后tester 发送22 9B 00读取当前进气口门的位置
ECU返回62 9B 00 3C , 0x3C = 60(dec),表示当前位置已经到了60%
step4:
tester 发送2F 9B 00 00,将控制权交还给ECU
ECU返回6F 9B 00 00 3A,表示接受请求,当前位置为58%
step5:
tester 发送2F 9B 00 02,冻结9B 00这个ID所代表的进气口门位置这个状态
ECU返回6F 9B 00 02 32,表示接受请求,当前位置保持在50%
此外,2F服务存在一个问题(引自知乎作者“心灵之花”),如果通过2F服务修改了某个值,后续也不把控制权还给ECU,那么这个修改的有效时间是一直持续下去?正确的做法是如果扩展会话超时,即切回默认会话,此时控制权应还给ECU,毕竟 2F的03子功能是"暂时接管控制权"。
RoutineControl (0x31)
$31服务是调用ECU内置的一些操作序列的接口,这个服务的应用很灵活,因为厂家可以根据自己的需要为ECU定义各种各样的内部操作,而要执行这些操作只需要调用31服务就好了。典型的用途包括检查边界条件、清除闪存、对数据进行较验、对软硬件依赖性进行校验等,甚至有需要的话可以进行恢复出厂设置的操作,还有很多与ECU自身逻辑功能相关的操作也可以定义。
31服务的request由4部分组成
SID=0x31
sub-function,子功能,启动(0x01)、停止(0x02)、查询结果(0x03)
routineIdentifier,即任务ID,用于标识要执行的routine
routineControlOptionRecord,这是一个可选参数,用于标识routine执行时所需要的参数,由各家自定义它的内容
举个例子:
假设用0x0809这个ID来代表检查ECU是否满足软件刷写条件(比如车速、转速为0,KL15接通等)的routine。
tester发送31 01 08 09来启动0x0809这个routine
如果所有条件都满足,则ECU返回71 01 08 09作为echo即可,如果条件不满足,则ECU返回71 01 08 09 XX YY ZZ,后边的XX YY ZZ则表明哪些条件不满足,具体的内容就由厂家自己定义了。
关于ECU升级数据的传输,是通过34(请求下载)、36(传输数据)、37(请求退出传输)等服务来完成的。由于汽车ECU中用于缓存诊断服务数据的buffer大小有限,所以当我们需要读取或写入超过buffer大小的数据时,就无法简单地使用2E和22服务了,因此UDS据此定义了几个将大块数据写入或读出的服务,即数据下载和上传。
Upload Download functional unit总共定义了5个诊断服务,分别是:
RequestDownload (0x34):诊断仪向ECU请求下载数据
RequestUpload (0x35)诊断仪向ECU请求上传数据
TransferData(0x36) 诊断仪向ECU传数据(下载),或者服务器向客户端传数据(上传)
RequestTransferExit(0x37)数据传输完成,请求退出
RequestFileTransfer(0x38) 传输文件的操作,可以用于替代上传下载的服务。
下图是数据下载的简略过程,用到了34,36,37这三个服务,如果是上传的话,34服务被35服务替换,数据传输方向变一下,就可以了。
step1:
诊断仪通过34服务传输该块的起始地址、该块的数据长度信息;进行下载请求;
ECU收到34服务的下载请求后,通过74肯定响应报文通知诊断仪,其(诊断仪)接下来的每个数据传输的报文中(36服务)应包含多少数据字节。诊断仪则根据该返回的参数对自身的发送能力进行调整;
step2:
诊断仪通过36服务传输该块的数据,每个36服务传输的数据量大小由ECU返回的34服务(即SID=0x74)中的参数确定,详情见下文。
ECU对36服务返回肯定响应;
通过36服务依次将该数据进行拆分发送,期间每完成一次36服务的发送,ECU进行肯定响应的回复。直到该块数据全部发送完;
step3:
诊断仪通过发送37服务进行传输退出的请求;
ECU进行肯定响应回复。
各服务说明如下所示:
各服务说明如下所示:
RequestDownload (0x34):
0x34服务用于启动下载传输,作用是告知ECU准备接受数据,ECU则通过0x74 response告诉诊断仪自己是否允许传输,以及自己的接受能力是多大。
0x34服务的请求格式包括5个部分
第一部分:1个byte的SID=0x34
第二部分:1个byte的dataFormatIdentifier,用于指示数据压缩和加密的方法。其中,第7-4位定义了压缩方法;第3-0位定义了加密方法。该字节为0x00时则表示既没有使用压缩方法也没有使用加密方法。0x00外的其他值的定义是由车产自行规定的。
第三部分:1个字节的addressAndLengthFormatIdentifier,用于指示后面两个部分所占用的字节数,高4bit表示memorySize所占的字节长度,低4bit表示memoryAddress所占的字节长度。在这个例子中我将这两个值分别设置为n和m。
第四部分:m个字节的memoryAddress,由addressAndLengthFormatIdentifier中的低4bit指示。含义是要写入数据在ECU中的逻辑地址。
第五部分:n个字节的memorySize,由addressAndLengthFormatIdentifier中的高4bit指示。含义是要写入数据的字节数。
ECU收到请求之后,如果允许传输的话,会给出如下response
第一部分:1个byte的 Response SID=0x74
第二部分:1个byte的dataFormatIdentifier作为echo
第三部分:maxNumberOfBlockLength,长度不定,表示可以通过0x36服务一次传输的最大数据量。
TransferData(0x36):
如果34服务得到了正确响应,tester就要启动数据传输过程了,使用的就是36服务。36服务的格式如下。
第一部分:1个byte的 SID=0x36。
第二部分:1个byte的blockSequenceCounter,标识当前传输的是第几个数据块,即帧序号,或者简单地说就是第几次调用36服务。
第三部分:transferRequestParameterRecord,传输的数据。第次传输数据量的上限就是34服务响应中的maxNumberOfBlockLength。
举例:如果ECU告知tester,maxNumberOfBlockLength = 20(来自$34服务的echo),也就是说tester每次通过36服务只能发送最多20个字节,其中还包括了SID和blockSequenceCounter,所以实际上每次可传的数据信息只有18个字节。如果tester要传的数据为50个字节,则需要传输三次,每次分别传输18,18,14个字节,即调用3次36服务。
36的响应很简单,就是一个字节的Response SID再加一个字节的blockSequenceCounter作为echo。
RequestTransferExit(0x37):
$37服务用于退出上传下载,如果之前的34和36服务都顺利执行完成,那么37服务就可以得到ECU的positive response。
格式很简单,请求就是37,正确响应就是77,都是一个字节。
如果前面的36服务没有执行完成,以我前面举的例子来说,比如这个数据块有50个字节,但是tester只发了两次36服务传了36个字节,那么这次传输对于ECU来说是失败的,所以ECU应该给出NRC 0x7F 37 24,表示诊断序列执行有错误。
在UDS诊断产品中知名度最高,应用最广泛的是德国Vector公司的CAN卡 VN1630/1640 配合其CANoe 软件,Vector 产品功能齐全,适合系统级汽车总线开发,被大部分汽车厂商采用。通常工程师先用Vector的CANdela进行cdd文件的开发,之后将该cdd文件导入CANoe.diva中进行功能测试。下面的链接是Vector提供的全套解决方案,里面的CANdesc是UDS代码生成软件。
Vector 产品很好用,节省开发时间,不开放API,且价格昂贵,不适用于硬件开发团队和生产线的自动化测试。目前市面上有很多CAN 厂商(如Kvaser, ZLG 等)能提供低成本、体积小、驱动简单、开放API 的设备,很适合进行二次开发。
至此,关于UDS诊断协议更新完毕,UDS协议晦涩复杂, 需要真切体验才能加深记忆,在使用过程中加深理解,欢迎大家随时交流。