一、概述
目前 SemiDrive X9H 的 SDK 中,在 Safety 域运行 Freertos,在 AP 域运行 Linux。而对于 CAN 资源来说, SemiDrvie X9H 只有两路 CAN 资源,并且都分配到 Safety 域。对于物理 CAN 的收发都在 Safety,芯驰自行研发了 CAN Service,使得 AP 想要访问 CAN 通过 CAN Service,CAN Service 在 Linux 操作系统创建设备节点,X9H 的核间通信架构提供 Linux 设备节点和 Safety 域的物理节点之间的通信,在 linux 端 映射 CAN 成 /dev/vircan 设备文件,用户层可以按照标准 unix 文件方式访问。
二、使用环境
硬件:SemiDrive SD003_X9H REF_A03 DEMO Board
软件:X9 PTG3.9
工具:USBCANFD-200U
三、连接图
PC 端的 CAN 收发器 USBCANFD-200U 与板端的 CAN 总线连接图。
四、CAN Service 主要功能
CAN service 是由芯驰自行开发、运行在 Safety Island 上的服务,主要功能如下:
1、接收来自 CAN 总线的数据;
2、兼并接收来自外部 MCU 的数据;
3、转发来自 CAN 总线或外部 MCU 的数据并发送到远端 AP;
4、接收来自远端 AP 的数据并转发到 CAN 或外部 MCU。
代码路径:/buildsystem/rtos/freertos_safetyos/framework/service/can_proxy
五、代码修改
在 SemiDrive SDK 中,CAN 的初始化是以 4 路CAN 为模型的,但是 SemiDrive X9H 只有 2 路 CAN 资源,所以修改代码成 2 路资源的,以下是代码的修改:
路径:/buildsystem/rtos/lk_boot/chipdev/can/flexcan/Can.c
static const struct can_sleep_scr gCanSleepSCR[MAX_FLEXCAN_CH] = { [CAN1] = {APB_SCR_SAF_BASE + (0x600U << 10), 4U, 5U}, [CAN2] = {APB_SCR_SAF_BASE + (0x604U << 10), 4U, 5U}, //2022.12.9 Ryan xiugai //[CAN3] = {APB_SCR_SAF_BASE + (0x608U << 10), 4U, 5U}, //[CAN4] = {APB_SCR_SAF_BASE + (0x60CU << 10), 4U, 5U}, |
路径:/buildsystem/rtos/lk_boot/chipdev/can/flexcan/can_cfg.c
struct Can_ControllerConfig gCan_CtrllerConfig[CAN_CTRL_CONFIG_CNT] = { { .controllerId = CAN1, .baseAddr = (uint32)APB_CAN1_BASE, .irq_num = CANFD1_IPI_INT_MBOR_NUM, .flexcanCfg = { .clkSrc = FLEXCAN_ClkSrcPeri, /* 80MHz */ .maxMbNum = 14U, .enableSelfWakeup = true, .enableIndividMask = true, .enableCANFD = true, BAUDRATE_1M_5M, .can_fd_cfg = { .enableISOCANFD = true, .enableBRS = true, .enableTDC = true, .TDCOffset = 8U, .r0_mb_data_size = CAN_FD_64BYTES_PER_MB, .r1_mb_data_size = CAN_FD_64BYTES_PER_MB } } },
{ .controllerId = CAN2, .baseAddr = (uint32)APB_CAN2_BASE, .irq_num = CANFD2_IPI_INT_MBOR_NUM, .flexcanCfg = { .clkSrc = FLEXCAN_ClkSrcPeri, /* 80MHz */ .maxMbNum = 14U, .enableSelfWakeup = true, .enableIndividMask = true, .enableCANFD = true, BAUDRATE_1M_5M, .can_fd_cfg = { .enableISOCANFD = true, .enableBRS = true, .enableTDC = true, .TDCOffset = 8U, .r0_mb_data_size = CAN_FD_64BYTES_PER_MB, .r1_mb_data_size = CAN_FD_64BYTES_PER_MB } } }, #if 0 { .controllerId = CAN3, .baseAddr = (uint32)APB_CAN3_BASE, .irq_num = CANFD3_IPI_INT_MBOR_NUM, .flexcanCfg = { .clkSrc = FLEXCAN_ClkSrcPeri, /* 80MHz */ .maxMbNum = 14U, .enableSelfWakeup = true, .enableIndividMask = true, .enableCANFD = true, BAUDRATE_1M_5M, .can_fd_cfg = { .enableISOCANFD = true, .enableBRS = true, .enableTDC = true, .TDCOffset = 8U, .r0_mb_data_size = CAN_FD_64BYTES_PER_MB, .r1_mb_data_size = CAN_FD_64BYTES_PER_MB } } },
{ .controllerId = CAN4, .baseAddr = (uint32)APB_CAN4_BASE, .irq_num = CANFD4_IPI_INT_MBOR_NUM, .flexcanCfg = { .clkSrc = FLEXCAN_ClkSrcPeri, /* 80MHz */ .maxMbNum = 14U, .enableSelfWakeup = true, .enableIndividMask = true, .enableCANFD = true, BAUDRATE_1M_5M, .can_fd_cfg = { .enableISOCANFD = true, .enableBRS = true, .enableTDC = true, .TDCOffset = 8U, .r0_mb_data_size = CAN_FD_64BYTES_PER_MB, .r1_mb_data_size = CAN_FD_64BYTES_PER_MB } } }, |
路径:/buildsystem/rtos/lk_boot/chipdev/can/rules.mk
ifneq ($(filter g9%, $(CHIPVERSION)), ) GLOBAL_DEFINES += MAX_FLEXCAN_CH=20 else ifeq ($(CHIPVERSION), v9t) GLOBAL_DEFINES += MAX_FLEXCAN_CH=8 else GLOBAL_DEFINES += MAX_FLEXCAN_CH=2//Ryan add 原本 4 endif |
路径:/buildsystem/rtos/lk_boot/framework/communication/include/ipcc_config.h
/* global flag to enable ipcc-rpmsg */ #ifndef CONFIG_IPCC_RPMSG #define CONFIG_IPCC_RPMSG (1) //Ryan add 原本 0 #endif |
路径: /buildsystem/rtos/lk_boot/framework/service/can_proxy/interface/can/can_port.c
int can_if_init(struct cp_if_t *cpif) { extern const Can_ConfigType gCan_Config; Can_Init(&gCan_Config); if(cpif->if_id <= 1) Can_SetControllerMode(cpif->if_id, CAN_CS_STARTED); cpif->if_state = cpifStateRunning; return 0; |
上面的修改都会自动同步 rtos/freertos_safetyos 的相关文件修改。
六、测试
1、物理 CAN 通信验证
SDK 提供了can_test 和 can_sample 两个应用,测试需要把这两个编进去,同时,由于FreeRTOS 验证 CAN 需要把 can_proxy 这个关掉,不然会冲突,无法编译通过。
路径:/buildsystem/rtos/freertos_safetyos/project/safety-x9-ref-serdes.mk
SUPPORT_CAN_SAMPLE_CODE := true SUPPORT_CAN_TEST := true ########################## #library define ########################## SUPPORT_DCF := true SUPPORT_3RD_RPMSG_LITE := true SUPPORT_RPC := false |
编译烧录后在 Safety 串口直接运行 can_sample,会发送一帧 CAN 数据到 PC 端。
以上表示 PC 端正常接收一帧数据。
之后从 PC 端发一帧数据
可以看出,板端也接收成功了,并且 ID 和数据都是准确的,说明物理 CAN 可以正常通信。
2、Linux 端 vircan 通信
Linux 端的 /dev/vircan 就是 Vircan 设备,SDK 代码提供了 candump 和 cansend 两个工具用来测试 Vircan 设备,在测试前需要先把 cluster 应用关掉,不然该应用会占用 Vircan,同时需要把 can_proxy 这个服务打开,不然会一直报错:
关闭 cluster 可以直接先用 ps 查看进程,之后用 kill 掉,也可以在以下文件,删除这个应用:
路径:/buildsystem/yocto/meta-semidrive/conf/distro/cluster-qt.conf
之后在 Linux 终端下,输入
candump /dev/vircan |
之后进入等待 PC CAN 的数据发送,PC CAN 发送数据
如下,表示接收成功
之后在 LINUX 终端下输入
cansend /dev/vircan -i 0x55 0x11 0x12 0x13 0x14 0x15 |
之后在 PC CAN 可以看到
以上表示PC CAN 成功接收,至此,Linux 端的 vircan 正常通信。
七、参考文献
《SemiDrive高性能车载处理器核间通信应用指南_Rev00.04.pdf》
《Semidrive_X9_V9_CAN应用指南_Rev0.3.pdf》
八、预告
实现 X9H 的 CAN 通信,预计接下会将写一篇关于在 AP 端通过 CAN 将固件包发送给 MCU 的文章,感兴趣可以在评论区留下评论或关注。
评论
Topone
2023年9月7日