4、CAN设备节点:设备树配置、CAN控制器驱动加载、ip link与ifconfig操作
好,咱们进入第四章。前面几章我们把CAN协议基础、硬件接口和内核编译环境都捋了一遍。从这章开始,就要真正跟硬件打交道了——让Linux系统“认识”你的CAN控制器。
说白了,这一步就是给内核递一张“名片”,告诉它:这里有个CAN控制器,挂在哪个总线上,中断号是多少,时钟频率多少。这张“名片”就是设备树(Device Tree)。
核心流程:设备树配置 → 驱动匹配加载 → 网络设备注册 → ip link操作
4.1 设备树中的CAN节点配置
我个人习惯,拿到一块新板子,第一件事就是看原理图和芯片手册,找到CAN控制器的寄存器基地址和中断号。然后打开设备树文件(.dts或.dtsi),开始配节点。
一个典型的CAN设备树节点长这样:
&ecan0 {
status = "okay";
compatible = "bosch,m_can";
reg = <0x0 0x20900000 0x0 0x1000>,
<0x0 0x20910000 0x0 0x8000>;
reg-names = "m_can", "message_ram";
interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MQ_CLK_CAN0>,
<&clk IMX8MQ_CLK_CAN0_OSC>;
clock-names = "hclk", "cclk";
bosch,mram-cfg = <0x0 0 0 32 0 0 0 1>;
};
这里有几个关键字段,我解释一下:
| 字段 | 含义 | 常见坑点 |
|---|---|---|
compatible |
驱动匹配字符串 | 必须与驱动中of_match_table一致 |
reg |
寄存器地址和大小 | 地址对齐、长度别写错 |
interrupts |
中断号和触发方式 | SPI号查芯片手册确认 |
clocks |
时钟源 | 频率不对会导致波特率偏差 |
bosch,mram-cfg |
M_CAN消息RAM配置 | 不同芯片差异大,照手册填 |
我曾经在一个项目里,reg字段的地址长度少写了0x100,结果驱动probe成功,但访问寄存器时直接挂死。查了两天才发现是设备树地址范围不够。嗯,这种低级错误最折磨人。
4.2 CAN控制器驱动加载过程
设备树配好了,内核启动时怎么把驱动拉起来?流程其实很清晰:
- 内核解析设备树,生成platform_device
- 驱动匹配:compatible字符串对上号
- probe函数执行:申请资源、注册中断、初始化硬件
- 注册net_device:创建can0/can1网络接口
驱动加载成功后,你会在内核日志里看到类似这样的信息:
[ 2.345678] m_can 20900000.can: CAN0 registered, irq=118
[ 2.345712] m_can 20900000.can: device registered (base=0x20900000)
如果没看到,别慌。先检查设备树status是不是"okay",再确认驱动有没有编译进内核。我见过有人把驱动编成模块,但没放到文件系统里,结果啥都没有。
小技巧:用ls /sys/bus/platform/devices/可以查看所有platform设备。如果能看到你的CAN节点名,说明设备树解析成功了;如果看不到,那就是设备树本身有问题。
4.3 ip link与ifconfig操作
驱动加载完,CAN接口就出现了。但这时候它还是“down”状态,不能收发数据。你需要用ip link把它激活。
我个人更推荐用ip命令,功能比ifconfig强太多。来看几个常用操作:
# 查看所有网络接口
ip link show
# 设置CAN接口为up状态,并配置波特率500k
ip link set can0 up type can bitrate 500000
# 查看接口状态
ip -details link show can0
# 关闭接口
ip link set can0 down
执行ip -details link show can0后,你会看到类似这样的输出:
3: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UP mode DEFAULT group default qlen 10
link/can promiscuity 0 minmtu 0 maxmtu 0
can state ERROR-ACTIVE restart-ms 0
bitrate 500000 sample-point 0.875
tq 125 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1
m_can: version 3.2.0, clock 40000000, max tx 1
这里的信息量很大:
- state ERROR-ACTIVE:控制器状态正常
- bitrate 500000:当前波特率
- clock 40000000:CAN控制器时钟频率
- sample-point 0.875:采样点位置
避坑指南:ifconfig也能看到can0,但它不会显示CAN特有的参数。你想想看,用ifconfig配CAN接口,连波特率都设不了。所以,请忘掉ifconfig,用ip命令。
4.4 常见问题与排查思路
我在项目中遇到过几次“设备树配对了,驱动也加载了,但can0死活起不来”的情况。这里总结几个排查点:
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| ip link set up失败 | 时钟配置错误 | 检查clocks频率,用clk_get_rate确认 |
| can0不显示 | 设备树status不是okay | 检查dts文件,确认节点使能 |
| 中断不触发 | 中断号或触发方式错误 | cat /proc/interrupts看中断计数 |
| 波特率不准 | 时钟源不对或分频参数错 | 用ip -details看实际采样点 |
我曾经在一个项目里,设备树配的时钟是40MHz,但实际晶振是20MHz。结果波特率设500k,实际只有250k。对端设备死活收不到数据。后来用示波器一看,位时间完全不对。嗯,从那以后我每次都会用示波器确认一下实际波形。
4.5 本章知识体系
下面这张图把整个流程串起来了,从设备树到ip link操作,每一步都环环相扣:
嗯,这一章的内容就这些。设备树配置是基础,驱动加载是桥梁,ip link操作是工具。三者缺一不可。你只要把这张图里的链路走通,CAN接口就能正常工作。