好久没有更新了,这一期来说说刚刚领悟的新技能,那就是XCP,嘿嘿嘿,我是新手,有错勿喷。参考资料:XCP协议规范2003。
XCP:Universal Calibration Protocol,通用标定协议,主要用于直接在软件上更改某些参数。那么这个XCP是为了解决什么什么问题呢?
XCP的爸爸是CCP,它由CCP发展变化而来,而CCP就是CAN标定协议,CCP是针对CAN总线来定的协议,后来由于通信形式和系统的多样化和复杂化,XCP就被搞出来了,而那个X就是****的意思,它可以是CAN,Ethernet,FlexRay,USB,SPI,LIN等等等,非严格意义上来讲,它可以在任何通信协议存活,But,嘿嘿,需要你的努力适配。
XCP的应用场景最重要的就是调参数!如果你是工科出生,那一定知道大名鼎鼎的PID算法,就PID那三个参数调起来都能要了你半条命,想想当年学生时代调PID参数,改个参数,然后编译下载然后运行看效果,我改我编,我再改我再编,熟练的让人心疼。这才3个参数就让人恶心,更别说那种复杂的系统,动不动就几百个参数,而XCP就是针对这种场景,它可以在线更改参数,实时观察结果变化,这样就可以非常的便捷的凑出一组宇宙无敌适合的参数。
为了实现这种实时改变参数的功能,XCP将操作对象放在了参数的地址上,在MCU的世界中,一切皆地址,那些重要的参数都有一个独立的运行地址,XCP协议就是根据运行地址直接找到并修改参数的值,通过这种方法,就可以让用户快速实现标定,这简直是又Low又夸张。
这个时候有些小朋友就要问了,如果是这样的话,那我也能整出一个类似的协议,阁下该如何应对?XCP最牛逼的地方不在它的协议上,而是在它发展到如今的上位机生态,现在很多常用的XCP上位机的功能非常强大,最具代表性的还是Vector(维克多)的CANape,还有ETAS(一坨屎)的INCA,这些上位机不仅可以实现测量量和标定量的图形化,还可以使用各种脚本来实现数据分析,那简直把标定玩出一朵花出来了,我觉得就没有CANape标定不了的系统,如果有,那就是你的系统很烂。
XCP的功能有:随机读取ECU中RAM和ROM数据;测量数据采样;标定数据采样和传输;同时处理多个ECU系统;Flash编程技术。
其工作模式也是非常常见的主从通信模式,XCP协议中,主节点为XCP上位机,被测量点又称“XCP从节点;主结点发送命令连接并开始,从结点在接收到后,再向主结点发送应答,可以采用一主多从的通信形式。提到主从模式,那就来到了我们所熟知的,协议命令环节。
XCP协议组成如下:
其通信包按照功能分成CTO(Command Transfer Object)和DTO(Data Transfer Object),CTO中分别有Command,Response,Error,Event,Service Request;DTO中有Data Acquisition和Stimulation Data,从名字中其实就可以看出来CTO和DTO的功能用途,一个是用来进行XCP控制,一个则用来进行数据传输。
其中CMD包为主节点发送给从节点,从节点需要立即回复RES包或者ERR包,而其他类型包则为自主发送包,主从节点满足条件时则可自发发送,不属于那种传统意义上的一问一答制通信,但是这些自主发送包都是受主节点控制的,也就是说这些自主包发送之前,主节点必须要发送CMD进行相关的操作配置。
至于上面的各种包有什么作用,现在不用关心,后面会一一说明。
XCP的通信模式有三种分别是Standard communication model, Block Transfer communication model, Interleaved communication model。在CAN上的XCP为标准模式和块传输模式。
XCP帧格式如下:
在CAN上的XCP来说,XCP Header和XCP Tail是不需要的,然后上面的格式又要根据是CTO和DTO又要进行一点点变化,对于CTO来说,帧结构则变成了:
其中Identification Field只有PID,没有Timestamp Field,剩下就是Data Field。其中PID为Packet IDentifier,其中所代表的内容是CTO Packet Code,可以根据其判断出CTO的类型,长度固定为1个字节,而DATA则是根据不同的PID而变化了。
对于DTO来说,帧结构则变成了:
DTO的格式就比较随意多变了,它会根据不同的PID进行变化。
首先来看看Identification Field,可以根据PID来判断帧的DTO类型,其中包含的信息为Absolute ODT Number或者Relative ODT Number,长度固定一个字节,如果PID包含的信息为Relative ODT Number,那么则需要DAQ参数,DAQ则包含了Absolute DAQ list Number(这些名词后面会解释)。如果XCP有字节对齐要求,则还需要添加一个FILL来进行字节对齐。
Timestamp区域在DTO中是可选的,主节点可通过SET_DAQ_LIST_MODE命令来开启和关闭TS,如果从节点的TIMESTAMP_FIXED flag为1(主节点可通过GET_DAQ_RESOLUTION_INFO获取),则代表主节点不可以设置TS,TS的长度可以是1,2,4字节。
在学习XCP之前,一定要搞清楚其中几个非常重要的定义,这是入门的基础,理解的越透彻,XCP学习的越快。
同步数据传输,也有的叫它同步数据测量,主要功能其实就是完成大量数据的读写。
(1) Element,ODT_Enrey和ODT
上面在介绍XCP的时候,提到过XCP的操作对象是数据地址,而在XCP中,这样一个数据则被称为一个Element元素。
而描述Element信息的描述被称为ODT_Entry。它是XCP的基本数据操作单元,其中包含了Element的地址,扩展地址,大小,所在位以及位偏移。XCP其实也就是根据ODT_Entry来去进行数据的读写,有没有发现XCP突然也变得非常可爱和简单啊。而这几个参数则就需要去了解一下了:
1. ADDRESS_GRANULARITY: 一般简写成AG,表示数据整合方式,即BYTE, WORD, DWORD,也就是1,2,4。也就代表了在后面的数据读写过程中数据的最小单位。
2. GRANULARITY_ODT_ENTRY_SIZE_x:表示数据对齐方式,可以是1,2,4,8。所以Element的地址和大小必须可以被其整除。而它也必须可以被ADDRESS_GRANULARITY整除。
3. MAX_ODT_ENTRY_SIZE_x:表示Element的最大长度
4. ODT_ENTRY_NUMBER:是ODT_Enrey的编号,即索引。
很多个ODT_Enrey就可以组成的一个ODT,然后通过ODT_ENTRY_NUMBER去索引到每一个Element。对于ODT也有几个参数需要了解一下:
1. MAX_ODT_ENTRIES:ODT所能容纳的最大ODT_Entry数量。
2. ODT_NUMBER:是ODT的编号,即索引。
所以Element,ODT_Enrey和ODT这三者的关系如下图所示:
(2) DAQ-list
很多个ODT就组成了一个DAQ-list,然后通过ODT_NUMBER去索引到每一个ODT。所以ODT和DAQ-list的关系如下图所示:
从节点可预定义DAQ-list,也就是ECU固有的,而主节点也可以动态定义DAQ-list。DAQ-list分为静态DAQ-list和动态DAQ-list两种,静态DAQ-list表示其所包含的ODT数量一定,而动态DAQ-list则就表示其包含的ODT数量可以变化,其起始值为0。下面有几个参数需要了解:
1. MAX_ODT:表示一个DAQ-list包含的ODT数量,静态DAQ-list不变,动态DAQ-list可变。
2. MAX_DAQ:表示从节点所能支持的最大的DAQ-list数量。
3. MIN_DAQ:表示从节点的预定义的DAQ-list数量。
4. DAQ_COUNT:表示主节点动态定义的DAQ-list数量。
(3) Event channels
上面介绍了DAQ-list,如果主从节点需要周期性的采样和传输一个DAQ-list中所有Element,那么就需要一个周期性事件来激活这个DAQ-list的采样和传输,而这个用来触发DAQ-list的事件在XCP中被称为Event channels,一个DAQ-list对应一个Event channel,同一个时间可激活多个DAQ-list。
从节点需要在本地事先定义好Event channels,然后主节点需要发送CMD将相关的DAQ-list和Event channels绑定,这样当从节点的Event channels发生时就会激活绑定的DAQ-list,这就完成了对DAQ-list中的所有Element完成采样和传输。这个流程其实就是上面提到的DTO包中的DAQ,也被称为同步测量。
(4) DAQ和STIM
DAQ(Synchronous data acquisition)的工作流程在上面已详细说明,当Event channels发生时就会激活其绑定的DAQ-list,然后从节点就会去对其所包含的所有Element进行采样并且将其使用DTO包传输给主节点。
STIM的流程则恰恰与DAQ相反,DAQ是读取Element数据,而STIM是主节点向从节点写Element数据,也是非常的好理解。
Online Calibration,在线标定是XCP的核心功能,就是完成相关参数的校准。
(1) SECTOR, SEGMENT和PAG
下图显示了SECTOR, SEGMENT和PAG三者的关系:
其中SECTOR指的是ECU中的物理SECTOR, 即RAM和FLASH的物理存储空间。SEGMENT则是XCP定义的逻辑映射空间,而一个SEGMENT则至少有一个或多个PAGE,每个PAGE中的内容是一样的,同一时间只有一个PAGE可以被ECU访问,同一时间只有一个PAGE可以被主节点访问,这两个激活的PAGE是单独管理的,这样多PAGE管理模式是为了避免一个PAGE同时被XCP和ECU访问的数据同步问题。在定义SEGMENT时,可以定义它的地址,大小以及访问权限。当XCP访问相关地址数据时,这个数据必须符合SEGMENT定义。
主节点可通过GET_CAL_PAGE命令CMD读取当前能被XCP访问的PAGE以及能被ECU访问的PAGE,通过SET_CAL_PAGE命令CMD设置能被XCP访问和能被ECU访问的PAGE。主节点还可通过COPY_CAL_PAGE命令CMD进行一个SEGMENT的两个PAGE的拷贝。
一般来说,标定数据分为工作页和参考页,两个标定页当中存放着两套不同的标定数据。工作页一般位于 RAM 中,在标定过程中,可随时修改其值;参考页一般位于 Flash中,标定时不能直接修改。标定过程中, Master 可使用 SET_CAL_PAGE 指令在标定页和参考页之间进行切换。同一时间只有当前页的标定值可以反应在 ECU 的算法中,参考页一般用于对比标定量修改前后的效果。常见的标定流程如下:
XCP除了标定之外,还有一个非常重要的功能就是Flash programming了,XCP FLASH变成的大致流程如下:
然后Flash programming分成两种,分别是绝对地址访问模式和相对地址访问模式。
(1) Absolute Access Mode
Absolute Access Mode其实就是根据实际物理地址进行数据的下载,即access by address。流程如下图所示:
上图中的MTA为Memory Transfer Address,ECU获取到MTA后直接就将其应用到FLASH的物理地址,然后进行接下来的编程操作。这个模式一般应用下载一些PAR数据,进行小数据量的FLASH读写。
(2) Functional Access Mode
Functional Access Mode就是不需要啥地址,那它需要啥呢?其流程如下图所示:
首先其起始编程地址由PROGRAMM_CLEAR决定,然后呢,ECU里面有个Counter,每进行一次下载,那么这个counter就会累加,然后ECU每次会根据这个counter去计算每次的下载绝对物理地址,这样就可以慢慢的将每一次写的Block写到正确的地址处。这种下载模式通常应用于下载很大的软件镜像。
这个模式是为了实现这样一个功能,Master将DAQ配置好后,DAQ配置保存到Slave的本地,Master然后激活RESUME Mode,等Slave重启后,检测RESUME Mode是否打开,如果打开,就会自动进入XCP的RESUME Mode,就会读取保存在本地的DAQ配置进行初始化,随后就可以自动进行DAQ数据传输了。即ECU一上电就会进行XCP的DAQ数据测量。