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控制器驱动加载过程

设备树配好了,内核启动时怎么把驱动拉起来?流程其实很清晰:

  1. 内核解析设备树,生成platform_device
  2. 驱动匹配:compatible字符串对上号
  3. probe函数执行:申请资源、注册中断、初始化硬件
  4. 注册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操作,每一步都环环相扣:

CAN设备节点配置与驱动加载流程 CAN设备节点配置与驱动加载流程 设备树配置 compatible/reg/irq 内核解析设备树 生成platform_device 驱动匹配 of_match_table比对 probe函数执行 申请资源/初始化 注册net_device 创建can0接口 ip link操作 设置波特率/up 💡 关键检查点 1. 设备树status必须为"okay" 2. 驱动编译进内核或加载模块后,dmesg应有注册信息 3. ip link set up成功后,用ip -details确认波特率和状态 完整链路:设备树 → 内核解析 → 驱动匹配 → probe → net_device → ip link 任何一个环节出问题,CAN接口都无法正常工作

嗯,这一章的内容就这些。设备树配置是基础,驱动加载是桥梁,ip link操作是工具。三者缺一不可。你只要把这张图里的链路走通,CAN接口就能正常工作。