1. 功能概述¶
1.1. 软件架构说明¶
J6X芯片位于MCU域的CAN控制器负责完成雷达、底盘和车身等CAN数据收发。由于感知等应用位于Acore,因此部分CAN数据需要通过IPC核间通信机制转发到Acore。
为保证传输可靠性,转发机制需要实现数据正确性检测、丢包检测和传输超时检测等机制。此外,还需要规避MCU侧高频转发小数据块导致CPU占用率过高,造成MCU实时性降低等性能问题。
J6X CAN转发方案的核心流程如下:
首先通过MCU侧CAN2IPC模块将CAN通道映射到对应IPC通道,然后通过Acore侧CanHal模块将IPC通道反映射为虚拟CAN设备通道。最后用户通过CanHal提供的API接口获取虚拟CAN设备中的数据。其中,CAN2IPC模块为MCU侧服务,CanHal模块为Acore侧提供给应用程序的动态库。
CAN2IPC模块周期性采集MCU侧CAN数据,按照指定传输协议进行打包,然后通过IPC核间通信转发到Acore。Ipc instance 0中的channel0~channel7默认分配给CAN转发使用。
CanHal模块获取来自MCU侧的IPC数据,按照指定的传输协议解析数据,并支持业务软件通过API获取原始CAN帧。
Acore与MCU之间透传CAN数据架构图

数据流如上图所示:
雷达、底盘等外设数据通过CAN的PHY和控制器器件被MCU域CAN驱动接收后,CAN驱动将数据上报并缓存在hobot CANIF模块。
CAN2IPC Service周期性从CANIF模块取出CAN帧,按照可靠传输协议进行打包,然后通过IPC核间通信机制转发给Acore。
CanHal模块获取来自MCU侧的IPC数据,按照指定的传输协议解析数据,Acore 应用程序通过CanHal Lib库提供的API获取CAN帧。
方案特性说明:
支持数据透传正确性校验。
支持数据透传丢包检测。
支持传输超时检测。MCU侧CAN2IPC转发数据时将数据包打上MCU侧的时间戳,Acore CanHal接收到数据后会读取Acore的时间戳,如果传输超时会报警。注意,需要提前启动时间同步完成MCU RTC时间和Acore 网卡phc0的时间同步。
支持多个CAN通道并行传输。MCU侧多个CAN控制器的数据可同时被转发给Acore,Acore应用程序通过CanHal从不同通道号读出CAN数据。
由于CanHal底层通过ipc核间通信进行传输,而ipc目前不支持多个进程或者线程读写同一个通道,因此CanHal也不支持该特性。
透传协议如下所示:
Filed | Len(Byte) | Introduction |
|---|---|---|
startFlag0 | 1 | 0xa5 |
startFlag1 | 1 | 0x3c |
startFlag2 | 1 | 0x96 |
startFlag3 | 1 | 0x5a |
startFlag4 | 1 | 0xa5 |
frameType | 1 | can=0, canfd=1, can/canfd=3 |
reserved | 1 | Reserved |
reserved | 1 | Reserved |
length | 2 | Msg data length in byte. Use Big Endian Eg: length = 0x1234, byte[0]=0x12,byte[1]=0x34 |
data | N | can/canfd data. |
crc | 2 | range: from startFlag0 to data filed. Use Big Endian Eg: crc= 0x1234, byte[0]=0x12,byte[1]=0x34 |
endFlag0 | 1 | ‘\n’ |
endFlag1 | 1 | ‘\n’ |
endFlag2 | 1 | ‘\n’ |
endFlag3 | 1 | ‘\n’ |
每次透传以包为单位,每个包中包含多个CAN帧。为保证可靠传输,包的传输协议如上表所示。
startFlag0~startFlag4字段为固定的包头分隔符,endFlag0~endFlag4字段为固定的包尾分隔符。
frameType字段为MCU侧透传过来的CAN帧类型,包括CAN、CANFD以及两者混合型,具体由MCU侧CAN2IPC指定。
count字段为rolling counter,每传输1包就递增1,达到最大值255后从0开始循环计数。
length字段为CAN数据长度,crc字段对前面所有数据进行正确性校验。data区域存放多帧CAN数据,CAN帧格式如下文所示。
Filed | Len(Byte) | Introduction |
|---|---|---|
time_stamp | 8 | unit: ms use Big Endian |
id | 4 | frame ID Use Big Endian |
count | 1 | count from 0-255 |
frameType | 1 | CanIdFormat type: CAN_STANDARD=0 CAN_FD_STANDARD=1 CAN_EXTENDED=2 CAN_FD_EXTENDED=3 |
channel | 1 | can controller channel |
length | 1 | can frame length |
data | N | can data. No more than 64 byte. |
上表中,time_stamp字段为CAN帧在MCU侧打上的时间戳,id字段为CAN帧id。
count字段为该包中所有CAN帧的rolling counter,用于丢帧检测。frameType表示CAN帧类型。channel字段用于表示CAN帧来自哪一个CAN控制器。
length字段表示CAN帧数据长度,data区域为CAN帧数据。
由于CAN转发核心模块分别为Acore侧的CanHal模块和MCU侧的CAN2IPC模块,下文具体介绍两个模块。
1.2. 代码位置与目录结构¶
MCU侧CAN2IPC源码目录:mcu/Service/HouseKeeping/can_ipc/hb_CAN2IPC.c
源码中hb_CAN2IPC_MainFunction函数被OS周期性调用,其内部通过调用hb_CAN2IPC_Proc 函数将指定的CAN控制器数据通过IPC转发到Acore。
hb_CAN2IPC_Proc 函数中三个传入参数分别为:CAN控制器、ipc instance、ipc 指定instance下的虚拟chennel。
如下示例代码将CAN4和CAN6分别通过ipc intance0的channel4和 intance0的channel6分别转发给Acore。
Acore CanHal使用可参考sample源码目录:test/samples/platform_samples/source/S83_Sample/S83E02_Communication/canhal_sample
sample 目录结构如下:
注意,etc目录下为json配置文件,默认已经有底盘和雷达CAN接入的json配置文件。json文件配置主要包括3个json配置文件:node.json、ipcf_channel.json、channels.json。目前为了支持多进程,各个进程都会去当前路径下的config目录下寻找这3个配置文件。
node.json负责创建虚拟CAN设备节点给CanHal API访问。关键配置选项包括:
channel_id字段指定该虚拟CAN设备从ipc配置文件ipcf_channel.json中哪一个节点获取数据。
target字段表示该虚拟CAN设备节点的名称,CanHal API通过该名称访问指定的节点。
enable字段表示该节点是否使能。
ipcf_channel.json将node.json中用到的ipc节点映射到具体的instance和channel。
channels.json指定ipc配置文件,用户一般不需要更改。
1.3. API说明¶
CanHal API接口基本特性:
支持多通道并行传输,CanHal通过target参数决定获取哪一个CAN通道的数据
支持多进程,各个进程可以分别读取不同通道CAN数据。但是不支持多个进程或者线程读取同一个CAN通道数据。
支持用户通过传入target参数获取CAN frame数据(核心功能)
支持用户通过传入target参数获取raw数据(调试功能,暂不启用)
支持用户通过传入target参数发送raw数据(调试功能,暂不启用)
支持用户通过传入target参数发送CAN frame数据(调试功能,暂不启用)
支持CAN/CANFD类型的数据
由于转发数据来自于MCU侧,因此Acore CanHal与MCU侧固件配合使用。MCU固件指定转发哪些CAN通道、转发周期等配置。
Acore应用程序通过CanHal获取MCU侧CAN帧的流程伪代码如下:
首先执行canInit()完成初始化,然后调用 canRecvMsgFrame()从指定通道获取当前传输过来的一包CAN数据,其中target参数为json文件中配置好的通道。
其中,pack信息包含这一包数据的信息,包括CAN帧数量、mcu侧的时间戳以及Acore侧的monotic时间戳等信息。
CanHal会从这一包ipc数据中解析出CAN帧,用户通过frame指针读取出所有CAN帧。
最后执行canDeInit()释放资源。
CanHal 各个API具体介绍如下:
1.3.1. canInit¶
【函数声明】
int canInit();
【参数描述】
N/A
【返回值】
0:成功
非0:失败,返回错误码
【功能描述】
任务的初始化,申请相关的资源
【示例代码】
1.3.2. canDeInit¶
【函数声明】
void canDeInit();
【参数描述】
[IN] N/A
【返回值】
N/A
【功能描述】
功能注销,释放相关资源
【示例代码】
1.3.3. canRecvMsgRaw¶
【函数声明】
int canRecvMsgRaw(const char *target, uint8_t *rx_buf, hobot::canhal::Pack_Info *pack);
【参数描述】
[IN] target:目标节点
[OUT] rx_buf:接收数据指针
[OUT] pack:包信息指针
【返回值】
0:成功
非0:失败,返回错误码
【功能描述】
接收原始数据(调试功能,暂不启用)
【示例代码】
1.3.4. canSendMsgRaw¶
【函数声明】
int canSendMsgRaw(const char *target, uint8_t *tx_buf, hobot::canhal::Pack_Info *pack);
【参数描述】
[IN] target:目标节点
[IN] tx_buf:发送数据指针
[IN] pack:包信息指针
【返回值】
0或者正数:成功发送的数据量
负数:失败
【功能描述】
发送原始数据(调试功能,暂不启用)
【示例代码】
1.3.5. canRecvMsgFrame¶
【函数声明】
int canRecvMsgFrame(const char *target, hobot::canhal::CanFrame *frame, hobot::canhal::Pack_Info *pack);
【参数描述】
[IN] target:目标节点
[OUT] frame:can帧地址
[OUT] pack:包信息指针
【返回值】
0:成功
非0:失败,返回错误码
【功能描述】
接收CAN帧数据
【示例代码】
1.3.6. canSendMsgFrame¶
【函数声明】
int canSendMsgFrame(const char *target, struct canframe *frame, hobot::canhal::Pack_Info *pack);
【参数描述】
[IN] target:目标节点
[IN] tx_buf:发送数据指针
[IN] pack:包信息指针
【返回值】
0或者正数:成功发送的数据量
负数:失败
【功能描述】
发送CAN帧数据(调试功能,暂不启用)
【示例代码】
1.3.7. CanHal API Error code¶
2. 编译¶
2.1. 编译环境¶
2.2. 编译说明¶
执行如下编译命令即可单独编译出Acore CanHal sample程序。
3. 运行¶
3.1. 支持平台¶
J6X Matrix
3.2. 板端部署及配置¶
需要做好如下准备工作:
完成MCU和Acore之间的时间同步:CAN转发具有传输超时检测机制,即MCU给CAN帧打上MCU域的时间戳后,Acore Canhal接收到CAN帧时会读取本地网卡phc0的时间,并比较两者时间差,若高于阈值则API返回传输超时错误码。超时报警阈值默认为28毫秒,如需修改,可在node.json中为各个节点添加max_delay配置项,单位为毫秒。
将MCU的CAN4和CAN6分别与底盘和雷达连接(也可以使用tsmaster或者canoe提供回灌数据)。
3.3. 运行指南¶
3.3.1. 运行方法¶
在Acore进入控制台,执行如下操作。
完成时间同步:
如果MCU侧的CAN帧时间戳使用RTC软件时间戳方案,则执行如下步骤将RTC时间同步到Acore phc0:
如果MCU侧的CAN帧时间戳使用xgmac硬件时间戳方案,则使用如下命令将xgmac时间同步到phc0(以下假设上述xgmac对应的eth索引为eth3)
获取底盘数据:
获取雷达数据:
3.3.2. 运行结果说明¶
如上打印获取到一次IPC传输包中的多个CAN帧数据。pack中ength字段表示CAN帧数量,soc_ts字段为Linux monotic时间,mcu_ts为CAN帧在MCU侧打上的时间戳。
3.3.3. 注意事项¶
Acore获取到CAN帧中的MCU时间戳在什么时刻被打上?MCU CAN模块使用RTC软件时间戳时,CAN2IPC软件在每个转发周期到来时,从Canif模块获取到CAN帧后再打上时间戳并转发数据到Acore;若使用xgmac硬件时间戳,则CAN帧到达CAN控制器时,会由硬件自动打上xgmac硬件时间戳。
如何配置转发周期?过小的转发周期导致MCU CPU开销过大,过大的转发周期导致实时性降低。用户需要根据业务需求决定转发周期,OS调度 CAN2IPC模块的hb_CAN2IPC_MainFunction API周期即是转发周期。
传输超时检测机制如何工作?完成时间同步后,CAN帧在MCU侧会被打上MCU域时间戳ts1,当报文转发到Acore后CanHal获取网卡phc0的时间戳ts2,当ts1和ts2差值超过阈值(默认是28ms)时会产生”Exceed max delay!”报警。
是否支持多进程?支持多个进程或者线程读取不同的通道数据,但是不支持多个进程或者线程读取同一个通道数据。
Acore json配置文件需要放在哪里?目前集成CanHal动态库的进程会在当前目录下寻找Config目录中的channels.json、ipcf_channel.json、nodes.json这3个配置文件。因此用户需要在进程当前目录下创建Config目录,并存放上述3个配置文件。为便于用户使用,后续更新版本后会将各个进程的配置文件统一放在特定配置目录下。