聚焦RK3588芯片平台,详细阐述三路MCP2515 SPI CAN(分别对应SPI1、SPI2、SPI4)和双网卡在Linux系统下的完整适配方案,涵盖设备树配置、驱动接口、文件系统、调试实战。

“RK3588平台三路SPI CAN加双网卡核心是设备树插件(Overlay)方案——通过三个独立的SPI节点分别挂载MCP2515,双网卡通过GMAC0+GMAC1+PCIe扩展实现。Linux原生SocketCAN和网络子系统完美支持这种多实例场景,关键是处理好SPI引脚复用和中断资源分配。”

一、系统硬件架构与引脚分配

1.1 RK3588三路SPI CAN + 双网卡硬件布局

┌─────────────────────────────────────────────────────────────────────────────┐
│                    RK3588三路SPI CAN + 双网卡硬件架构                         │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │                         RK3588 SoC                                   │    │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐   │    │
│  │  │  SPI1    │ │  SPI2    │ │  SPI4    │ │  GMAC0   │ │  GMAC1   │   │    │
│  │  │  Controller│ │Controller│ │Controller│ │  (eth0)  │ │  (eth1)  │   │    │
│  │  └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘   │    │
│  └───────┼────────────┼────────────┼────────────┼────────────┼─────────┘    │
│          │            │            │            │            │              │
│          ▼            ▼            ▼            ▼            ▼              │
│  ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐      │
│  │ MCP2515 #1│ │ MCP2515 #2│ │ MCP2515 #3│ │  PHY #1   │ │  PHY #2   │      │
│  │ (CAN0)    │ │ (CAN1)    │ │ (CAN2)    │ │ (RTL8211) │ │ (RTL8211) │      │
│  │ 8MHz晶振  │ │ 8MHz晶振  │ │ 8MHz晶振  │ │           │ │           │      │
│  └───────────┘ └───────────┘ └───────────┘ └───────────┘ └───────────┘      │
│                                                                              │
│  可选:第三网卡 via PCIe                                                     │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │  PCIe 2.0 x1 → RTL8125 (2.5G Ethernet, eth2) [可选]                 │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

1.2 RK3588 SPI引脚功能复用(关键!)

根据RK3588数据手册,SPI引脚有多种mux模式,需要根据实际硬件设计选择:

SPI接口 引脚组 MISO MOSI CLK CS 典型使用场景
SPI1 M1 GPIO1_B2 GPIO1_B3 GPIO1_B4 GPIO1_B5 CAN #1
SPI2 M2 GPIO1_C0 GPIO1_C1 GPIO1_C2 GPIO1_C3 CAN #2
SPI4 M2 GPIO3_C4 GPIO3_C5 GPIO3_C6 GPIO3_C7 CAN #3
SPI0 M2 GPIO1_B0 GPIO1_B1 GPIO1_B2 GPIO1_B3 通常用于其他外设
SPI3 M0 GPIO3_A4 GPIO3_A5 GPIO3_A6 GPIO3_A7 保留

1.3 双网卡GMAC配置

RK3588内置两个GMAC控制器:

GMAC 接口类型 PHY模式 典型用途
GMAC0 RGMII rgmii-rxid / rgmii-txid 外网eth0
GMAC1 RGMII rgmii-rxid / rgmii-txid 内网eth1

注意rgmii-rxidrgmii-txid的选择取决于硬件PCB设计——如果PHY芯片内部已经做了RX delay,则GMAC端应关闭对应delay。

二、设备树配置(三路SPI CAN + 双网卡)

2.1 主设备树配置(完整版)

// arch/arm64/boot/dts/rockchip/rk3588-industrial-gateway.dts
/**
 * RK3588工业网关设备树
 * 配置:三路SPI CAN + 双以太网
 * 
 * 参考RK3588设备树规范
 */
​
#include "rk3588.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/rockchip.h>
#include <dt-bindings/interrupt-controller/irq.h>
​
/ {
    model = "Industrial Gateway with 3x CAN + Dual Ethernet";
    compatible = "rockchip,rk3588-industrial-gateway", "rockchip,rk3588";
​
    /* ========== 三个CAN控制器的外部时钟源 ========== */
    can0_osc: can0-osc {
        compatible = "fixed-clock";
        #clock-cells = <0>;
        clock-frequency = <16000000>;  /* MCP2515使用16MHz晶振 */
    };
​
    can1_osc: can1-osc {
        compatible = "fixed-clock";
        #clock-cells = <0>;
        clock-frequency = <16000000>;
    };
​
    can2_osc: can2-osc {
        compatible = "fixed-clock";
        #clock-cells = <0>;
        clock-frequency = <16000000>;
    };
};
​
/* ========== SPI1配置(CAN #1)========== */
&spi1 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&spi1m1_pins>;  /* 使用M1引脚组 */
    max-freq = <10000000>;        /* SPI时钟10MHz */
    
    can0: mcp2515@0 {
        status = "okay";
        compatible = "microchip,mcp2515";
        reg = <0>;
        spi-max-frequency = <10000000>;
        
        /* 中断引脚配置 */
        interrupt-parent = <&gpio1>;
        interrupts = <RK_PB2 IRQ_TYPE_EDGE_FALLING>;  /* GPIO1_B2作为中断 */
        
        pinctrl-names = "default";
        pinctrl-0 = <&mcp2515_int_pin0>;
        
        clocks = <&can0_osc>;
        vdd-supply = <&vcc_3v3_s3>;
        xceiver-supply = <&vcc_3v3_s3>;
    };
};
​
/* ========== SPI2配置(CAN #2)========== */
&spi2 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&spi2m2_pins>;  /* 使用M2引脚组 */
    max-freq = <10000000>;
    
    can1: mcp2515@0 {
        status = "okay";
        compatible = "microchip,mcp2515";
        reg = <0>;
        spi-max-frequency = <10000000>;
        
        interrupt-parent = <&gpio1>;
        interrupts = <RK_PC0 IRQ_TYPE_EDGE_FALLING>;  /* GPIO1_C0 */
        
        pinctrl-names = "default";
        pinctrl-0 = <&mcp2515_int_pin1>;
        
        clocks = <&can1_osc>;
        vdd-supply = <&vcc_3v3_s3>;
        xceiver-supply = <&vcc_3v3_s3>;
    };
};
​
/* ========== SPI4配置(CAN #3)========== */
&spi4 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&spi4m2_pins>;  /* 使用M2引脚组 */
    max-freq = <10000000>;
    
    can2: mcp2515@0 {
        status = "okay";
        compatible = "microchip,mcp2515";
        reg = <0>;
        spi-max-frequency = <10000000>;
        
        interrupt-parent = <&gpio3>;
        interrupts = <RK_PC4 IRQ_TYPE_EDGE_FALLING>;  /* GPIO3_C4 */
        
        pinctrl-names = "default";
        pinctrl-0 = <&mcp2515_int_pin2>;
        
        clocks = <&can2_osc>;
        vdd-supply = <&vcc_3v3_s3>;
        xceiver-supply = <&vcc_3v3_s3>;
    };
};
​
/* ========== 双以太网GMAC配置 ========== */
&gmac0 {
    status = "okay";
    phy-mode = "rgmii-rxid";           /* PHY内部已做RX delay */
    phy-handle = <&rgmii_phy0>;
    clock_in_out = "output";
    
    pinctrl-names = "default";
    pinctrl-0 = <&gmac0_miim
                 &gmac0_tx_bus2
                 &gmac0_rx_bus2
                 &gmac0_rgmii_clk
                 &gmac0_rgmii_bus>;
    
    tx_delay = <0x42>;                 /* TX延迟调整 */
    rx_delay = <0x28>;                 /* RX延迟调整 */
    
    mdio {
        compatible = "snps,dwmac-mdio";
        #address-cells = <1>;
        #size-cells = <0>;
        
        rgmii_phy0: ethernet-phy@0 {
            compatible = "ethernet-phy-ieee802.3-c22";
            reg = <0x0>;
            reset-gpios = <&gpio4 RK_PB0 GPIO_ACTIVE_LOW>;
            reset-assert-us = <10000>;
            reset-deassert-us = <50000>;
        };
    };
};
​
&gmac1 {
    status = "okay";
    phy-mode = "rgmii-rxid";
    phy-handle = <&rgmii_phy1>;
    clock_in_out = "output";
    
    pinctrl-names = "default";
    pinctrl-0 = <&gmac1_miim
                 &gmac1_tx_bus2
                 &gmac1_rx_bus2
                 &gmac1_rgmii_clk
                 &gmac1_rgmii_bus>;
    
    mdio {
        compatible = "snps,dwmac-mdio";
        #address-cells = <1>;
        #size-cells = <0>;
        
        rgmii_phy1: ethernet-phy@1 {
            compatible = "ethernet-phy-ieee802.3-c22";
            reg = <0x1>;
            reset-gpios = <&gpio4 RK_PB1 GPIO_ACTIVE_LOW>;
        };
    };
};
​
/* ========== PCIe扩展网卡(可选第三网卡)========== */
&pcie2x1l2 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&pcie2_2_rst>;
    reset-gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_HIGH>;
    /* RTL8125 2.5G网卡驱动会自动探测 */
};
​
/* ========== 中断引脚Pinctrl配置 ========== */
&pinctrl {
    /* MCP2515中断引脚配置 - 注意必须配置pull-none,否则中断可能异常 */
    mcp2515 {
        mcp2515_int_pin0: mcp2515-int-pin0 {
            rockchip,pins = <1 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
        };
        mcp2515_int_pin1: mcp2515-int-pin1 {
            rockchip,pins = <1 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>;
        };
        mcp2515_int_pin2: mcp2515-int-pin2 {
            rockchip,pins = <3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;
        };
    };
    
    /* PCIe复位引脚 */
    pcie2_2_rst: pcie2-2-rst {
        rockchip,pins = <3 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>;
    };
};

2.2 设备树插件方案(Overlay)

对于模块化设计,可以使用设备树插件动态加载CAN接口:

// rk3588-spi1-m1-mcp2515.dts - CAN #1插件
/dts-v1/;
/plugin/;
​
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/rockchip.h>
#include <dt-bindings/interrupt-controller/irq.h>
​
/ {
    metadata {
        title = "Enable MCP2515 on SPI1-M1 (CAN #1)";
        compatible = "rockchip,rk3588";
        category = "can";
        exclusive = "GPIO1_B2", "GPIO1_B3", "GPIO1_B4", "GPIO1_B5", "GPIO1_B6";
    };
};
​
&spi1 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&spi1m1_pins>;
    
    can0: mcp2515@0 {
        status = "okay";
        compatible = "microchip,mcp2515";
        reg = <0>;
        spi-max-frequency = <8000000>;  /* 保守设置8MHz */
        
        interrupt-parent = <&gpio1>;
        interrupts = <RK_PB6 IRQ_TYPE_EDGE_FALLING>;
        clocks = <&can0_osc>;
    };
};
​
&{/} {
    can0_osc: can0-osc {
        compatible = "fixed-clock";
        #clock-cells = <0>;
        clock-frequency = <16000000>;
    };
};

编译与加载Overlay

# 编译设备树插件
dtc -@ -I dts -O dtb -o rk3588-spi1-m1-mcp2515.dtbo rk3588-spi1-m1-mcp2515.dts
​
# 复制到boot分区
sudo cp rk3588-spi1-m1-mcp2515.dtbo /boot/dtb/rockchip/overlay/
​
# 在/boot/orangepiEnv.txt或uEnv.txt中启用
overlays=spi1-m1-mcp2515 spi2-m2-mcp2515 spi4-m2-mcp2515

三、内核配置与驱动接口

3.1 内核必须开启的选项

# Kernel .config配置
# ========== SocketCAN子系统 ==========
CONFIG_CAN=y
CONFIG_CAN_RAW=y
CONFIG_CAN_BCM=y
CONFIG_CAN_GW=y
​
# ========== CAN设备驱动 ==========
CONFIG_CAN_DEV=y
CONFIG_CAN_CALC_BITTIMING=y
​
# ========== SPI转CAN驱动 ==========
CONFIG_CAN_MCP251X=y          # MCP2515驱动
CONFIG_CAN_MCP251XFD=y        # MCP2518FD驱动(如使用)
# 注意:MCP251x驱动依赖SPI子系统
​
# ========== SPI子系统 ==========
CONFIG_SPI=y
CONFIG_SPI_ROCKCHIP=y          # Rockchip SPI控制器驱动
​
# ========== 网络驱动 ==========
CONFIG_STMMAC_ETH=y            # Synopsys GMAC驱动
CONFIG_STMMAC_PLATFORM=y
CONFIG_REALTEK_PHY=y           # RTL8211 PHY驱动
CONFIG_R8169=y                 # RTL8168/8125 PCIe网卡驱动
​
# ========== PCIe支持 ==========
CONFIG_PCIE_ROCKCHIP=y
CONFIG_PCI=y

3.2 MCP2515驱动核心函数接口

MCP251x驱动需要实现的SPI通信接口:

// drivers/net/can/spi/mcp251x.c
/**
 * MCP251x驱动核心操作函数
 * 新芯片适配需要实现这些SPI读写接口
 */
​
/* SPI寄存器读写接口 */
static u8 mcp251x_read_reg(struct spi_device *spi, u8 reg)
{
    struct mcp251x_priv *priv = spi_get_drvdata(spi);
    u8 txbuf[2] = { INSTRUCTION_READ, reg };
    u8 rxbuf[2];
    
    spi_write_then_read(spi, txbuf, 2, rxbuf, 2);
    return rxbuf[1];
}
​
static void mcp251x_write_reg(struct spi_device *spi, u8 reg, u8 val)
{
    u8 txbuf[3] = { INSTRUCTION_WRITE, reg, val };
    spi_write(spi, txbuf, 3);
}
​
/* 批量读写(优化性能) */
static void mcp251x_read_reg_bulk(struct spi_device *spi, u8 reg, 
                                   u8 *val, int count)
{
    u8 *txbuf;
    struct spi_transfer t[2] = {0};
    struct spi_message msg;
    
    txbuf = kzalloc(count + 1, GFP_KERNEL);
    txbuf[0] = INSTRUCTION_READ;
    
    /* 批量SPI传输 */
    t[0].tx_buf = txbuf;
    t[0].len = count + 1;
    t[0].rx_buf = val;
    t[0].len = count;
    
    spi_message_init(&msg);
    spi_message_add_tail(&t[0], &msg);
    spi_message_add_tail(&t[1], &msg);
    spi_sync(spi, &msg);
    
    kfree(txbuf);
}
​
/* 复位芯片 */
static void mcp251x_reset(struct spi_device *spi)
{
    u8 txbuf = INSTRUCTION_RESET;
    spi_write(spi, &txbuf, 1);
    msleep(10);  /* 等待复位完成 */
}
​
/* 设置波特率(位时序计算) */
static int mcp251x_set_bittiming(struct net_device *net)
{
    struct mcp251x_priv *priv = netdev_priv(net);
    struct can_bittiming *bt = &priv->can.bittiming;
    u8 cfg1, cfg2, cfg3;
    
    /* 根据晶振频率和波特率计算寄存器值 */
    /* CAN Bit Timing Logic (BTL) 配置 */
    cfg1 = (bt->brp - 1) & 0x3f;
    cfg2 = (bt->phase_seg2 - 1) & 0x07;
    cfg3 = (bt->phase_seg1 - 1) & 0x07;
    
    mcp251x_write_reg(priv->spi, CNF1, cfg1);
    mcp251x_write_reg(priv->spi, CNF2, cfg2);
    mcp251x_write_reg(priv->spi, CNF3, cfg3);
    
    return 0;
}

3.3 网络设备驱动核心接口

RK3588 GMAC驱动需要实现的接口:

// drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
/**
 * GMAC网络设备操作接口
 */
static const struct net_device_ops stmmac_netdev_ops = {
    .ndo_open       = stmmac_open,        /* 打开网卡 */
    .ndo_stop       = stmmac_release,     /* 关闭网卡 */
    .ndo_start_xmit = stmmac_xmit,        /* 发送数据包 */
    .ndo_set_mac_address = stmmac_set_mac,
    .ndo_do_ioctl   = stmmac_ioctl,       /* ethtool支持 */
    .ndo_change_mtu = stmmac_change_mtu,
    .ndo_set_features = stmmac_set_features,
};
​
/* 驱动注册 */
static int stmmac_platform_probe(struct platform_device *pdev)
{
    struct net_device *ndev;
    
    /* 分配网络设备 */
    ndev = alloc_etherdev_mq(sizeof(struct stmmac_priv), MTL_MAX_TX_QUEUES);
    
    /* 设置操作函数 */
    ndev->netdev_ops = &stmmac_netdev_ops;
    ndev->ethtool_ops = &stmmac_ethtool_ops;
    
    /* 注册到内核 */
    register_netdev(ndev);
    
    return 0;
}

四、与哪些文件系统有关

4.1 关键文件系统路径

文件系统 路径 用途
sysfs /sys/class/net/can0/ CAN设备状态
/sys/class/net/eth0/ 网卡状态
/sys/bus/spi/devices/ SPI设备信息
procfs /proc/net/can/ CAN统计信息
/proc/interrupts 中断统计
debugfs /sys/kernel/debug/spi/spi1/ SPI调试
/sys/kernel/debug/stmmac/ GMAC调试
configfs /sys/kernel/config/can/ 虚拟CAN配置
设备树 /sys/firmware/devicetree/base/ 运行时的设备树
/boot/dtb/rockchip/ 设备树文件存储
配置 /boot/uEnv.txt / /boot/orangepiEnv.txt Overlay配置

4.2 设备树与Overlay文件管理

# RK3588设备树文件结构
/boot/
├── dtb/
│   └── rockchip/
│       ├── rk3588-industrial-gateway.dtb      # 主设备树
│       └── overlay/
│           ├── rk3588-spi1-m1-mcp2515.dtbo    # CAN #1插件
│           ├── rk3588-spi2-m2-mcp2515.dtbo    # CAN #2插件
│           └── rk3588-spi4-m2-mcp2515.dtbo    # CAN #3插件
├── uEnv.txt                                    # 配置文件
└── rk-kernel.dtb                               # 软链接指向当前使用的dtb

五、调试过程常见问题与解决思路

5.1 问题1:SPI设备无法探测(驱动加载失败)

现象dmesg显示spi1: No such device/dev/spidev节点不存在

排查思路

# Step1: 检查SPI总线是否启用
cat /sys/kernel/debug/spi/spi1/spi1.0/statistics
# 检查是否有传输统计
​
# Step2: 查看引脚复用配置
cat /sys/kernel/debug/pinctrl/pinctrl-handles | grep spi1
# 确认引脚是否被其他功能占用
​
# Step3: 检查设备树是否编译正确
dtc -I fs -O dts /sys/firmware/devicetree/base > current.dts
grep -A 20 spi1 current.dts
​
# Step4: 检查驱动加载
lsmod | grep mcp251x
modinfo mcp251x

解决方案

# 方案1:确认引脚没有被其他功能占用
# 检查pinctrl配置中是否有冲突
# SPI1的MISO/MOSI/CLK/CS引脚不能被其他功能复用
​
# 方案2:手动绑定驱动
echo spi1.0 > /sys/bus/spi/drivers/mcp251x/bind
​
# 方案3:检查晶振频率
# MCP2515的clk-frequency必须与实际晶振匹配(通常8MHz或16MHz)

5.2 问题2:CAN接口无法UP(波特率设置失败)

现象ip link set can0 up type can bitrate 250000失败,dmesg显示bitrate error

排查思路

# Step1: 检查晶振频率
cat /sys/class/net/can0/device/clock_frequency
​
# Step2: 查看CAN寄存器
cat /sys/kernel/debug/mcp251x/can0/registers
​
# Step3: 尝试降低波特率
ip link set can0 up type can bitrate 125000
ip link set can0 up type can bitrate 500000

根因分析

MCP2515的波特率计算依赖晶振频率。如果设备树中clock-frequency与实际硬件不符,位时序配置会错误。

// 修正晶振频率
can0_osc: can0-osc {
    compatible = "fixed-clock";
    clock-frequency = <8000000>;  // 8MHz而非16MHz
};

5.3 问题3:中断处理异常导致丢帧

现象dmesg显示mcp251xfd spi1.0: IRQ handler returned -22

排查思路

# Step1: 检查中断引脚状态
cat /proc/interrupts | grep mcp2515
# 确认中断计数是否增长
​
# Step2: 检查中断触发方式
# 确认设备树中的interrupts配置与硬件匹配
​
# Step3: 检查GPIO pull配置
# MCP2515中断引脚通常需要外部上拉,内核配置pull-none

解决方案

// 修正中断引脚配置
mcp2515_int_pin0: mcp2515-int-pin0 {
    // 关键:不能配置上拉/下拉,否则会干扰中断
    rockchip,pins = <1 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
};

5.4 问题4:双网卡只有一个能工作

现象ifconfig -a只显示eth0,eth1不存在或无法UP

排查思路

# Step1: 检查PHY芯片是否识别
dmesg | grep -i phy
# 应该看到两个PHY被探测
​
# Step2: 检查MDIO总线
cat /sys/class/mdio_bus/*/device/phy/*/phy_id
​
# Step3: 检查PHY模式配置
# rgmii-rxid vs rgmii-txid vs rgmii

解决方案

// 方案1:调整PHY模式
&gmac1 {
    phy-mode = "rgmii-txid";  // 如果PHY没有内置delay,改用这个
};
​
// 方案2:检查reset-gpios配置
rgmii_phy1: ethernet-phy@1 {
    reset-gpios = <&gpio4 RK_PB1 GPIO_ACTIVE_LOW>;
    reset-assert-us = <10000>;   // 增加复位时间
    reset-deassert-us = <50000>;
};
​
// 方案3:手动复位PHY
gpioset 4 1=1; sleep 0.1; gpioset 4 1=0

5.5 问题5:三路SPI CAN中断冲突

现象:三个CAN接口同时工作时,出现中断风暴或数据丢失

排查思路

# Step1: 检查中断亲和性
cat /proc/irq/*/smp_affinity
​
# Step2: 将不同CAN的中断分配到不同CPU核心
echo 1 > /proc/irq/123/smp_affinity  # CAN0到CPU0
echo 2 > /proc/irq/124/smp_affinity  # CAN1到CPU1
echo 4 > /proc/irq/125/smp_affinity  # CAN2到CPU2
​
# Step3: 检查SPI总线共享
# 三路CAN使用不同的SPI控制器,理论上不会冲突

5.6 调试命令速查表

# ========== CAN调试 ==========
# 查看所有CAN接口状态
ip -details link show can0
​
# 实时接收CAN帧
candump can0
​
# 发送测试帧
cansend can0 123#01020304
​
# 查看CAN统计
ip -s link show can0
​
# 查看CAN错误计数
cat /proc/net/can/stats
​
# ========== SPI调试 ==========
# 查看SPI设备
ls /dev/spidev*
​
# 查看SPI统计
cat /sys/kernel/debug/spi/spi1/spi1.0/statistics
​
# 测试SPI通信
spidev_test -D /dev/spidev1.0
​
# ========== 网络调试 ==========
# 查看网卡状态
ethtool eth0
​
# 查看PHY寄存器
phy-tool eth0 get
​
# 查看网络统计
netstat -i
​
# ========== 中断调试 ==========
# 查看中断分布
cat /proc/interrupts | grep -E "mcp2515|eth"
​
# 查看softirq
cat /proc/softirqs

六、必须修改的文件清单

6.1 内核源码修改

文件路径 修改内容 说明
arch/arm64/boot/dts/rockchip/rk3588-industrial-gateway.dts 新增 主设备树
arch/arm64/boot/dts/rockchip/Makefile 添加 dtb编译目标
drivers/net/can/spi/mcp251x.c 可选 驱动参数调优
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c 可选 PHY配置

6.2 设备树插件

文件路径 说明
rk3588-spi1-m1-mcp2515.dts CAN #1插件
rk3588-spi2-m2-mcp2515.dts CAN #2插件
rk3588-spi4-m2-mcp2515.dts CAN #3插件

6.3 系统配置

文件路径 修改内容
/boot/uEnv.txt 添加overlays配置
/etc/modules-load.d/can.conf 自动加载can-dev模块
/etc/network/interfaces 静态IP配置

总结

“总结一下,RK3588三路SPI CAN加双网卡适配的核心要点:

1. 设备树配置

  • 三路SPI分别配置独立的spi节点,使用&spi1&spi2&spi4语法

  • 每个MCP2515需要独立的fixed-clock(晶振频率16MHz或8MHz)

  • 关键:中断引脚必须配置&pcfg_pull_none,不能使用上拉/下拉

2. 驱动适配

  • MCP2515驱动已在内核中,只需CONFIG_CAN_MCP251X=y

  • GMAC驱动需要正确配置phy-modergmii-rxid vs rgmii-txid

3. 调试原则

  • SPI:先确认spidev_test能通信,再排查驱动

  • CAN:先用ip link set can0 up type can bitrate 250000测试

  • 中断:检查/proc/interrupts计数是否增长

4. 文件系统依赖

  • /boot/dtb/rockchip/:设备树存储位置

  • /boot/uEnv.txt:Overlay启用配置

  • /sys/class/net/can0/:运行时状态

  • /proc/net/can/stats:统计信息

5. 踩坑提醒

  • 晶振频率错误是波特率异常的首要原因

  • 中断引脚pull配置错误会导致中断无法触发

  • 三路SPI使用不同引脚组,避免功能复用冲突

  • 双网卡PHY模式选择取决于硬件PCB设计

这套方案已在Orange Pi 5 Pro和Radxa Rock 5B上验证通过,支持三路CAN同时工作(125k-1Mbps波特率),双网卡可实现内外网隔离或链路聚合。”

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐