海思平台移植 CAN 通信全攻略:从硬件到应用
在工业控制、车载电子等领域,CAN(Controller Area Network)总线因其高可靠性和实时性被广泛应用。海思芯片(如 Hi3516、Hi3559 等)作为嵌入式领域的主流方案,常需移植 CAN 通信功能以满足场景需求。本文将从硬件选型、内核配置、驱动适配到应用测试,详细讲解海思平台 CAN 通信的移植过程。
设备驱动调试和硬件具有强关联性,一定要和硬件工程师沟通清楚,原理图上的不一定是实际的接线关系,一定要问清楚!!!问清楚!!!问清楚!!!
1.硬件方案选择
海思芯片本身大多不内置 CAN 控制器,需通过外部芯片扩展。常见方案有两种:
1.1 SPI 转 CAN
核心芯片:Microchip MCP2515(支持 CAN 2.0A/B 协议,SPI 接口)
硬件连接:
- SPI 接口:连接海思的 SPI 控制器(如 SPI0、SPI1),需接 SCK(时钟)、MOSI(主发从收)、MISO(主收从发)、CS(片选,GPIO 控制)
- 中断引脚:MCP2515 的 INT 引脚连接海思的 GPIO(用于中断通知)
- 电源:通常需 3.3V 供电(注意与海思 GPIO 电平匹配)
优势:电路简单,成本低,适配性强,适合多数海思平台。
1.2 串口转 CAN
核心芯片:周立功 ZLG CAN transceiver(如 CANalyst-II 模块)
硬件连接:通过 UART 接口连接海思的 UART 控制器,无需中断引脚。
劣势:实时性稍差,不适合高频率通信场景。
本文以MCP2515 + 海思 HI3519 为例,讲解 SPI 转 CAN 的移植过程。
2. 内核配置与驱动适配
2.1 内核配置参数
通过make menuconfig
开启 CAN 相关支持,关键配置如下:
# CAN核心协议栈
CONFIG_CAN=y
CONFIG_CAN_RAW=y # 启用原始CAN协议(用户态必备)
CONFIG_CAN_BCM=y # 广播管理模块(可选)
CONFIG_CAN_GW=y # CAN网关功能(可选)# SPI转CAN驱动
CONFIG_CAN_MCP251X=y # MCP251x系列驱动
CONFIG_CAN_MCP251X_SPI=y # SPI接口支持
内核配置信息如下:
Networking support --->[*] CAN bus subsystem support --->--- CAN bus subsystem support<*> Raw CAN Protocol (raw access with CAN-ID filtering)<*> Broadcast Manager CAN Protocol (with content filtering)<*> CAN Gateway/Router (with netlink configuration)[*] CAN Gateway: Allow to route CAN frames between CAN interfaces--- CAN Device Drivers<*> Platform CAN drivers with Netlink support<*> CAN USB interfaces ---><*> CAN SPI interfaces ---><*> Microchip MCP251x SPI CAN controllers
如果需要can设备开机自动挂载,可勾选<*> Microchip MCP251x SPI CAN controllers,本人的硬件比较特殊(这个可爱的硬件),因此我选择迎难而上,在用户层挂载can设备并通信。
2.2 设备树配置
本人的can是挂载在spi2下,因此修改spi3节点:
clocks {clk8m: clk8m {compatible = "fixed-clock";#clock-cells = <0>;clock-frequency = <8000000>;clock-output-names = "clk8m";};};&spi_bus3{status = "okay";/*spidev@0 {compatible = "rohm,dh2228fv";reg = <0>;pl022,interface = <0>;pl022,com-mode = <0>;spi-max-frequency = <25000000>;};*/can0: can@0 {compatible = "microchip,mcp2515";reg = <0>;clocks = <&clk20m>;spi-max-frequency = <8000000>;interrupt-parent = <&gpio_chip6>;interrupts = <5 IRQ_TYPE_EDGE_FALLING>;status = "okay";};
};
这部分解释一下,clocks = <&clk8m> 是配置2515的外部时钟,这个需要根据我们可爱的硬件工程师们的选择进行配置,不可自行发挥。
interrupt-parent = <&gpio_chip5> 和 interrupts = <6 IRQ_TYPE_EDGE_FALLING> 是我们的2515芯片的INT脚和soc的gpio管脚的配置,需要硬件确认。
2.3 管脚复用
如果阁下想在自启时就挂载can设备,那么可以选择在uboot中配置对应管脚,可以在reg配置Excel参考如下:

我的是在用户层自己挂载,因此我的是在sys_config 中配置管脚复用信息:
static void spi3_pin_mux(void)
{void *iocfg2_base = sys_config_get_reg_iocfg2();sys_writel(iocfg2_base + 0x0110, 0x01b3); /* SPI3_SCLK */sys_writel(iocfg2_base + 0x0108, 0x0153); /* SPI3_SDO */sys_writel(iocfg2_base + 0x0104, 0x0203); /* SPI3_SDI */sys_writel(iocfg2_base + 0x010C, 0x0203); /* SPI3_CSN */
}
3.手动编译MCP/XL2515驱动
只需将2515的源代码,编译为ko文件,以便在用户层手动加载,以下是我的编译脚本:
海思SPI-CAN驱动程序
如果遇到内核需要鉴权的,可以添加鉴权指令,否则无法加载。
编译完成可以在板子上,手动挂载:insmod mcp2515.ko,挂载成功会提示:
mcp251x spi0.0: MCP2515 successfully initialized.
4.通信测试
4.1 中断测试
# 查看中断注册状态
cat /proc/interrupts | grep can0
# 触发中断后检查计数是否增长
watch -n 1 "cat /proc/interrupts | grep can0"
4.2 CAN 接口配置:
# 设置波特率(500kbps为工业常用)
ip link set can0 type can bitrate 500000 sample-point 0.875
ip link set can0 up# 检查接口状态
ip -details link show can0
4.2 通信性能测试:
# 后台持续发送数据
cansend can0 123#DEADBEEFDEADBEEF &# 统计接收情况(检查丢包率)
candump -tA can0 | pv -r > /dev/null
4.3 用户态编程接口
// 创建CAN原始套接字
int s = socket(PF_CAN, SOCK_RAW, CAN_RAW);// 绑定到CAN接口
struct sockaddr_can addr;
struct ifreq ifr;
strcpy(ifr.ifr_name, "can0");
ioctl(s, SIOCGIFINDEX, &ifr);
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
bind(s, (struct sockaddr *)&addr, sizeof(addr));// 发送CAN帧
struct can_frame frame = {.can_id = 0x123,.can_dlc = 8,.data = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}
};
write(s, &frame, sizeof(frame));// 接收CAN帧
read(s, &frame, sizeof(frame));
5.调试总结
本次移植测试共耗时1.5天,遇到中断无法响应和时钟信号失真的情况,后亲切的咨询硬件兄弟后成功解决,因此,没有硬件软件工程师啥都不是,请对硬件工程师好一点!!!!