4、XCP协议详解:XCP on CAN/Ethernet、传输层与协议层分离、MTA与DAQ列表、同步与异步通信
XCP 这个协议,说实话,是咱们标定工程师吃饭的家伙。它全称是 Universal Measurement and Calibration Protocol,但大家更习惯叫它 XCP。为什么叫 X?因为它是从 CCP 进化来的,那个 X 代表「可扩展」—— 你想想看,从 CAN 到 Ethernet,从同步到异步,它都能搞定。
我最早接触 XCP 是在 2010 年左右,那时候还在用 CCP。后来项目要求标定数据量越来越大,CCP 那 8 字节的报文实在扛不住了。换到 XCP 之后,感觉就像从 56k 拨号升级到了光纤。嗯,今天我们就来好好聊聊这个协议的核心设计。
4.1 传输层与协议层分离:XCP 最聪明的设计
XCP 最让我佩服的一点,就是它把传输层和协议层彻底分开了。说白了,协议层只关心「我要读哪个地址、写哪个参数」,而传输层只关心「怎么把数据包发出去」。这两层之间通过一个标准接口对接,互不干扰。
核心思想: 协议层定义命令和响应,传输层定义数据怎么打包、怎么纠错、怎么流控。换传输介质,协议层代码一行都不用改。
我在一个项目中遇到过这种情况:前期用 CAN 做原型验证,后期要切换到 Ethernet 做高速采集。因为代码里把协议层和传输层分得清楚,改起来只换了底层驱动,上层标定工具完全没动。要是当初写在一起,估计得重写大半年。
XCP 的协议层定义了这么几类报文:
- CMD(命令报文): 主设备发给从设备,比如 CONNECT、GET_ID、SET_MTA
- RES(响应报文): 从设备回复主设备,携带状态码或数据
- ERR(错误报文): 出错了,比如命令不支持、地址越界
- EV(事件报文): 从设备主动上报,比如 DAQ 溢出警告
- SERV(服务报文): 用于时间同步等特殊功能
而传输层呢,负责把这些报文塞进具体的物理通道里。CAN 的话,一帧最多 8 字节,所以需要分片重组。Ethernet 就好多了,UDP 一包能装 1400 多字节,大块数据一次搞定。
| 特性 | XCP on CAN | XCP on Ethernet |
|---|---|---|
| 最大 PDU 长度 | 8 字节 | 1492 字节(典型) |
| 传输速率 | 500 kbps ~ 1 Mbps | 100 Mbps ~ 1 Gbps |
| 分片机制 | 必须分片(CTO/DTO) | 通常不分片 |
| 典型延迟 | ~1 ms | ~0.1 ms |
| 适用场景 | 低速标定、OBD 诊断 | 高速采集、大数据量标定 |
我的习惯: 做原型阶段先用 CAN,因为调试工具便宜、抓包方便。等系统稳定了再切 Ethernet 做性能验证。两层分离的设计让这种切换几乎没有成本。
4.2 MTA 与 DAQ 列表:两种数据访问模式
XCP 提供了两种数据访问方式,我管它们叫「点菜模式」和「自助餐模式」。
4.2.1 MTA:点菜模式
MTA 全称 Memory Transfer Address,就是你要读写的内存地址。主设备先设置 MTA,然后发读写命令。每次只能操作一个地址或一段连续地址。
举个例子:
// 设置 MTA 到 0x8000A000
SET_MTA(0x8000A000, EXT)
// 从该地址读取 4 字节
READ(4)
// 响应:返回 0x41200000(比如是某个标定系数)
RES: 0x41 0x20 0x00 0x00
这种方式的好处是简单直接,适合标定参数的读写。但缺点也很明显 —— 一次只能操作一个地址,效率低。
我曾经踩过的坑: 有一次用 MTA 模式采集 100 个信号,每个信号 2 字节,循环读取。结果总线负载率直接飙到 80%,影响了其他 CAN 报文。后来改成 DAQ 模式,负载率降到 5%。记住:MTA 适合标定,DAQ 适合采集。
4.2.2 DAQ 列表:自助餐模式
DAQ 全称 Data Acquisition。主设备先配置好一个列表,告诉从设备「我要采集哪些地址、多大字节、什么触发条件」。然后从设备按照配置自动发送数据,主设备只管收。
DAQ 列表的核心概念:
- ODT(Object Descriptor Table): 每个 ODT 包含一组地址偏移和长度,最多 7 个元素(CAN 场景)
- DAQ List: 由多个 ODT 组成,一个 DAQ List 对应一个采集任务
- Event Channel: 触发条件,比如曲轴转角、时间周期、某个信号过阈值
配置流程大致是这样:
- 主设备发送 FREE_DAQ 释放之前的配置
- ALLOC_DAQ 分配 DAQ List 数量
- ALLOC_ODT 分配每个 List 的 ODT 数量
- SET_DAQ_PTR 设置每个 ODT 的地址
- WRITE_DAQ 写入具体的地址偏移和长度
- SET_DAQ_EVENT 绑定触发事件
- START_STOP_SYNCH 启动采集
听起来步骤多,但实际上一套配置可以反复用。我习惯在标定工具里把常用信号的 DAQ 列表存成模板,换项目时改改地址就行。
4.3 同步与异步通信:什么时候该用哪种?
XCP 支持两种通信模式,这个选择直接影响你的采集质量。
4.3.1 同步模式(Synchronous)
主设备发一个命令,从设备必须回复。一来一回,严格配对。MTA 读写、DAQ 配置、标定写入,这些都用同步模式。
特点:
- 可靠性高,每个命令都有确认
- 延迟大,因为要等回复
- 适合标定操作,不适合高速采集
4.3.2 异步模式(Asynchronous)
从设备按照自己的节奏发数据,主设备只管收。DAQ 模式就是典型的异步通信。从设备在事件触发时自动发送 DTO(Data Transfer Object),主设备不需要每包都确认。
特点:
- 吞吐量高,没有握手开销
- 延迟低,数据实时性更好
- 可能丢包,需要上层做校验
经验之谈: 同步模式用来「问问题」,异步模式用来「听广播」。标定参数用同步,采集信号用异步。混着用的时候要注意总线优先级 —— 我见过有人把 DAQ 报文优先级设得太低,结果被标定命令堵住,采集数据全是毛刺。
4.4 XCP 协议栈结构图
下面这张图是我自己画的一个 XCP 协议栈分层结构,能帮你直观理解各层的关系:
你看,从应用层到底层物理层,每一层各司其职。协议层不关心底下是 CAN 还是 Ethernet,传输层也不关心上面传的是标定命令还是采集数据。这种设计让 XCP 活了二十多年还能继续用。
4.5 实战中的选择建议
最后,我根据自己的项目经验,给几个实际选择建议:
选 CAN 还是 Ethernet?
- 信号数 < 50,更新周期 > 10ms → CAN 就够了,成本低、工具多
- 信号数 > 200,更新周期 < 1ms → 必须上 Ethernet,CAN 带宽不够
- 混合场景:标定用 CAN,采集用 Ethernet,两条总线并行
我曾经犯过的错: 在一个项目中,我把 DAQ 列表配了 30 个 ODT,每个 ODT 塞了 7 个信号。结果从设备 CPU 负载过高,DAQ 报文发送不及时,主设备那边看到的数据全是断断续续的。后来把 DAQ 拆成两个列表,分别绑定不同的事件通道,问题就解决了。记住:DAQ 列表不是越大越好,要留给从设备喘气的空间。