RK3588平台三路MCP2515 SPI CAN + 双网卡Linux系统适配深度解析
聚焦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-rxid和rgmii-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-mode(rgmii-rxidvsrgmii-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波特率),双网卡可实现内外网隔离或链路聚合。”
更多推荐

所有评论(0)