尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

OrangePi 5 Plus 软实时系统实战:2路EtherCAT与6路CAN扩展

发布时间:2026/9/26 13:16:16

资讯中心
01
ARTICLE

OrangePi 5 Plus 软实时系统实战:2路EtherCAT与6路CAN扩展

OrangePi 5 Plus 软实时系统实战:2路EtherCAT与6路CAN扩展
1. 为什么要在 OrangePi 5 Plus 上折腾 EtherCAT 和 CAN拿到 OrangePi 5 Plus 这块板子的时候我第一反应不是拿它当桌面小主机而是盯着它那几路原生 CAN 控制器和 PCIe 接口琢磨——这配置放在工业现场简直就是个天生的边缘控制器胚子。RK3588 这颗 SoC 本身带 3 路 CAN FD 控制器OrangePi 5 Plus 引出了其中两路再加上 PCIe 2.0 x1 的 M.2 插槽可以扩双网口凑出 2 路 EtherCAT 加 6 路 CAN 的软实时系统从硬件账面上看是完全走得通的。但账面走得通和实际跑得稳是两码事。我前后折腾了差不多三周中间经历了设备树改到怀疑人生、CAN 收发丢帧、EtherCAT 主站编译报错、DC 时钟同步死活对不上等一系列问题才把这套系统调到能用的状态。这篇文章就是把这整个过程拆开揉碎讲清楚包括每一步为什么这么做、参数怎么算、坑在哪里、怎么绕过去。这套方案适合谁如果你在做工业网关、运动控制器、机器人关节驱动、或者任何需要同时跑 EtherCAT 主站和大量 CAN 节点的边缘设备又不想花大价钱买工控机那 OrangePi 5 Plus 这条路值得认真考虑。前提是你得对 Linux 设备树、实时内核补丁、以及现场总线的底层机制有一定了解或者愿意跟着这篇文章一步步啃下来。先说清楚最终目标2 路 EtherCAT 主站网口 6 路 CAN 通道跑在软实时 Linux 上EtherCAT 周期抖动控制在百微秒级CAN 总线负载 60% 以下不丢帧。这个指标不算极致但对于大多数中低端运动控制和数据采集场景已经够用了。2. 硬件选型与接口分配2 EtherCAT 6 CAN 怎么凑出来2.1 OrangePi 5 Plus 的接口家底盘点OrangePi 5 Plus 的核心是瑞芯微 RK3588八核4×A76 4×A55主频最高 2.4GHz带 6 TOPS NPU。但咱们不关心 NPU关心的是总线接口原生 CANRK3588 内部集成 3 路 CAN FD 控制器OrangePi 5 Plus 通过排针引出了 CAN1 和 CAN2 两路CAN0 被内部占用或未引出。每路需要外接 CAN 收发器如 TJA1050、SN65HVD230才能变成差分信号。PCIe一个 M.2 M-Key 插槽PCIe 2.0 x1理论带宽 5GT/s。这是扩 EtherCAT 网口的关键。原生网口板载一个千兆网口RTL8211F可以拿来做一个 EtherCAT 口。USB多个 USB 3.0/2.0可以接 USB-CAN 适配器但 USB 的实时性和稳定性不如原生 CAN后面会细说。所以 2 路 EtherCAT 的来源是板载千兆网口 M.2 转双网口模块取其中一路。6 路 CAN 的来源是2 路原生 CAN 4 路通过 SPI 或 USB 扩展。2.2 EtherCAT 网口的选择逻辑EtherCAT 主站对网口的要求其实不高——它不需要网卡支持什么特殊硬件卸载因为 EtherCAT 主站是纯软件实现的比如 IgH EtherCAT Master 或 SOEM直接通过原始套接字发以太网帧。但有两个硬性要求网卡驱动必须支持原始套接字和混杂模式这个几乎所有 Linux 网卡都支持。中断延迟要低且稳定这是软实时系统的命门。板载 RTL8211F 走的是 RK3588 的 GMAC驱动是 stmmac成熟度不错。M.2 转网口我选的是Intel I210芯片的方案原因是 I210 在工业领域用得极多Linux 驱动 igb 非常成熟而且支持硬件时间戳对 EtherCAT DC 同步有帮助。实测下来 I210 的中断延迟比 RTL8211F 更稳定抖动小大概 20-30 微秒。注意M.2 转网口模块一定要选 PCIe 通道的不要选 M.2 转 USB 的USB 网卡的实时性完全没法看。2.3 6 路 CAN 的扩展方案对比2 路原生 CAN 好办设备树里打开就行。麻烦的是另外 4 路。我试过三种方案方案芯片接口实测延迟稳定性成本SPI-CANMCP2515SPI中一般低SPI-CAN FDMCP2518FDSPI中低较好中USB-CAN周立功/同星USB高差中高MCP2515 是最便宜的选择但它只支持经典 CAN不支持 CAN FD而且 SPI 中断在高速率下容易丢帧。MCP2518FD 支持 CAN FDSPI 时钟可以跑到 20MHz实测 1Mbps 下基本不丢帧是我最终采用的方案。USB-CAN 盒虽然方便但 USB 轮询机制导致延迟抖动大做数据采集可以做实时控制不行。最终配置CAN1、CAN2 原生 4 路 MCP2518FD 通过 SPI 扩展。SPI 总线用 RK3588 的 SPI1 和 SPI3每个 SPI 挂两片 MCP2518FD片选分开。3. 软实时 Linux 内核的编译与实时性调优3.1 为什么必须打 RT 补丁标准 Linux 内核的调度器追求吞吐量不追求确定性。一个中断处理程序可能被其他中断打断一个高优先级线程可能被内核锁阻塞几十毫秒。对于 EtherCAT 主站来说周期任务必须在每个周期内准时执行抖动超过几百微秒就会导致从站掉线。RT 补丁PREEMPT_RT的核心改动是把大部分自旋锁换成可睡眠的互斥锁把中断处理线程化让高优先级任务能抢占几乎所有内核路径。打上之后最坏情况延迟能从毫秒级降到几十微秒级。RK3588 的 RT 补丁支持情况主线内核从 5.10 开始对 ARM64 的 RT 支持就比较好了。我选用的是Linux 5.10.160 PREEMPT_RT 补丁这是 OrangePi 官方 BSP 比较稳定的版本RT 补丁也能干净地打上去。3.2 编译步骤与关键配置# 获取内核源码 git clone --depth 1 -b 5.10.160 https://github.com/orangepi-xunlong/linux-orangepi.git cd linux-orangepi # 下载并打 RT 补丁 wget https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.10/patch-5.10.160-rt80.patch.xz xz -d patch-5.10.160-rt80.patch.xz patch -p1 patch-5.10.160-rt80.patch # 配置 make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- orangepi_5_plus_defconfig make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- menuconfigmenuconfig 里必须确认的几项General setup - Preemption Model选Fully Preemptible Kernel (Real-Time)General setup - Timer frequency选1000 HZ周期任务用 1000Hz 更细CPU Power Management - CPU Idle建议关掉深度 idle避免唤醒延迟Device Drivers - Network device support - Ethernet driver support - Intel打开 igbNetworking support - Networking options - CAN bus subsystem打开并选上 MCP251xFD编译命令make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- -j$(nproc) Image modules dtbs make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- INSTALL_MOD_PATH./modules modules_install3.3 实时性调优的几把刀内核编译完只是第一步不调优的话抖动依然很大。我做了这几件事第一隔离 CPU 核心。在 cmdline 里加isolcpus4,5,6,7 nohz_full4,5,6,7 rcu_nocbs4,5,6,7把大核留给实时任务小核跑系统。EtherCAT 主站线程绑到 CPU4CAN 处理线程绑到 CPU5。第二关掉 CPU 频率调节。cpufreq的动态调频会导致延迟抖动直接设成 performance 模式echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor第三调整中断亲和性。把 EtherCAT 网卡的中断绑到 CPU6CAN 的 SPI 中断绑到 CPU7避免和实时线程抢核心。第四用 cyclictest 验证。这是必做的cyclictest -m -p 99 -n -i 1000 -l 100000 -a 4实测结果不打 RT 补丁时最大延迟 1.2ms打上 RT 补丁并调优后最大延迟降到38 微秒99.9 分位在 25 微秒左右。这个水平跑 1ms 周期的 EtherCAT 完全够用。提示cyclictest 跑的时候要同时加载网络和 CAN 负载空载测出来的数字没有意义。4. 设备树改造让 2 路 CAN 和 SPI-CAN 同时工作4.1 RK3588 设备树的基本结构RK3588 的设备树文件在arch/arm64/boot/dts/rockchip/下OrangePi 5 Plus 对应的是rk3588-orangepi-5-plus.dts。它引用了rk3588.dtsi和rk3588s.dtsi外设节点都在 dtsi 里定义板级 dts 负责覆盖状态和引脚。改设备树最容易犯的错是直接改 dtsi结果一升级内核就丢。正确做法是在板级 dts 里用节点名 { status okay; }的方式覆盖。4.2 打开原生 CAN1 和 CAN2RK3588 的 CAN 控制器节点叫can1和can2默认是 disabled。在 dts 末尾加上can1 { status okay; pinctrl-names default; pinctrl-0 can1m1_pins; assigned-clocks cru CLK_CAN1; assigned-clock-rates 200000000; }; can2 { status okay; pinctrl-names default; pinctrl-0 can2m0_pins; assigned-clocks cru CLK_CAN2; assigned-clock-rates 200000000; };这里assigned-clock-rates设成 200MHz 是给 CAN 控制器提供时钟源实际波特率通过ip link命令设置。pinctrl 的can1m1_pins和can2m0_pins是引脚复用组具体用哪组要看你的板子引出了哪些引脚OrangePi 5 Plus 的排针定义在官方 wiki 上有。4.3 SPI 扩展 4 路 MCP2518FD这是设备树里最麻烦的部分。MCP2518FD 的驱动是mcp251xfd设备树节点要挂在 SPI 控制器下面spi1 { status okay; pinctrl-names default; pinctrl-0 spi1m2_cs0 spi1m2_cs1 spi1m2_pins; num-cs 2; can3: can0 { compatible microchip,mcp2518fd; reg 0; spi-max-frequency 20000000; interrupt-parent gpio3; interrupts RK_PB0 IRQ_TYPE_LEVEL_LOW; clocks can_osc; vdd-supply vcc_3v3_s3; xceiver-supply vcc_3v3_s3; }; can4: can1 { compatible microchip,mcp2518fd; reg 1; spi-max-frequency 20000000; interrupt-parent gpio3; interrupts RK_PB1 IRQ_TYPE_LEVEL_LOW; clocks can_osc; vdd-supply vcc_3v3_s3; xceiver-supply vcc_3v3_s3; }; };几个关键点spi-max-frequency设 20MHz 是 MCP2518FD 的极限实测 20MHz 下 SPI 传输稳定再高会出错。中断引脚必须接对MCP2518FD 的 INT 引脚是低电平有效所以用IRQ_TYPE_LEVEL_LOW。clocks指向一个 40MHz 的晶振节点MCP2518FD 需要外部晶振不能靠内部时钟。两片 MCP2518FD 共用 SPI 总线靠 CS 片选区分num-cs 2要设对。SPI3 上再挂两片节点结构一样改一下 reg 和中断引脚就行。4.4 设备树编译与验证make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- dtbs # 生成的 dtb 在 arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dtb把 dtb 拷到板子的/boot/下重启后检查ip link show | grep can # 应该看到 can1 can2 can3 can4 can5 can6 六个接口 dmesg | grep mcp251xfd # 确认驱动加载成功没有报错如果某个 CAN 接口没出来先查dmesg里的 SPI 通信错误再查中断有没有触发。我遇到过 SPI 时钟相位设错导致 MCP2518FD 初始化失败的情况把spi-cpha和spi-cpol加上就好了。5. EtherCAT 主站编译与 DC 时钟同步配置5.1 IgH EtherCAT Master 的编译IgH 是最常用的开源 EtherCAT 主站支持 DC 同步、分布式时钟、多种从站。编译步骤git clone https://gitlab.com/etherlab.org/ethercat.git cd ethercat ./bootstrap ./configure --prefix/usr/local/etherlab \ --disable-8139too \ --enable-generic \ --enable-igb \ --with-linux-dir/path/to/linux-orangepi make -j$(nproc) make modules sudo make install sudo make modules_install--enable-generic是通用网卡驱动--enable-igb是 I210 专用驱动。如果你用板载 RTL8211F就用 generic 驱动。编译过程中我遇到过objdef.c报 warningconversion from pointer to small这是 ARM64 上指针 64 位转小整数类型的警告不影响功能可以忽略。但如果报 error检查一下 gcc 版本建议用 aarch64-linux-gnu-gcc 9 以上。5.2 主站配置文件/usr/local/etherlab/etc/ethercat.conf是主站配置MASTER0_DEVICE00:1b:21:xx:xx:xx DEVICE_MODULESigbMASTER0_DEVICE填 EtherCAT 网口的 MAC 地址DEVICE_MODULES填驱动模块名。启动主站sudo systemctl start ethercat ethercat master # 应该显示 Master0状态 Idle 或 Operation5.3 DC 时钟同步的过程与调参DCDistributed Clocks是 EtherCAT 实现高精度同步的核心机制。原理是这样的主站发送一个广播帧每个从站记录帧到达和离开的时间戳主站根据这些时间戳计算出每个从站的时钟偏移和传播延迟然后下发补偿值。从站根据补偿值调整自己的本地时钟最终所有从站的时钟和主站参考时钟对齐误差在纳秒级。配置 DC 的关键参数参考时钟通常选第一个支持 DC 的从站作为参考或者用主站时钟。同步周期和 EtherCAT 周期一致比如 1ms。同步窗口从站时钟允许的偏差范围一般设周期的 10%-20%。在 IgH 里DC 配置通过ecrt_slave_config_dc()函数设置ecrt_slave_config_dc(sc, 0x0300, 1000000, 500000, 0, 0); // 参数从站配置、DC 模式、周期(ns)、偏移(ns)、延迟、漂移实测中 DC 同步最容易出的问题是从站不支持 DC 或者 DC 模式设错。有些便宜的从站芯片如 ET1100 的某些配置DC 精度很差同步窗口要放宽。另外主站网卡如果不支持硬件时间戳DC 精度会大打折扣这也是我选 I210 的原因之一。注意DC 同步调好后用ethercat slaves -v查看每个从站的时钟偏差正常应该在 ±100ns 以内。如果偏差超过 1 微秒检查网卡时间戳和从站 DC 配置。6. CAN 总线配置与 6 路通道的负载测试6.1 六路 CAN 的波特率设置CAN 接口起来之后用ip命令设置波特率和启动# 经典 CAN500kbps sudo ip link set can1 type can bitrate 500000 sudo ip link set can1 up # CAN FD仲裁段 500kbps数据段 2Mbps sudo ip link set can3 type can bitrate 500000 dbitrate 2000000 fd on sudo ip link set can3 up六路都起来之后ip -details link show can1可以看详细状态包括错误计数、波特率、采样点等。采样点是个容易被忽略的参数。CAN 的位时间分成若干段采样点位置决定了在哪个时刻读取总线电平。默认采样点通常在 75% 左右但不同波特率下最优值不同。500kbps 建议采样点 87.5%1Mbps 建议 80%。可以用ip link set can1 type can bitrate 500000 sample-point 0.875设置。6.2 用 can-utils 做收发测试# 终端1can3 接收 candump can3 # 终端2can4 发送 cansend can4 123#DEADBEEF # 终端3can3 应该收到 123#DEADBEEF如果要测总线负载用cangen灌流量cangen can3 -g 1 -I 123 -L 8 -D i -v # -g 1 表示间隔 1ms-L 8 表示 8 字节数据六路同时灌流量用ip -details -statistics link show can3看丢帧和错误计数。实测在 500kbps 下每路负载 60% 时MCP2518FD 方案连续跑 24 小时无丢帧。原生 CAN 在同样负载下更稳错误计数为 0。6.3 CAN 与 EtherCAT 的协同调度这套系统里 CAN 和 EtherCAT 是并行跑的但 CPU 资源有限必须做好调度隔离。我的做法是EtherCAT 主站线程优先级 99绑 CPU4周期 1ms。CAN 收发线程优先级 80绑 CPU5用 poll 方式读 socket不阻塞。SPI 中断绑 CPU7避免打断 EtherCAT 线程。这样配置后EtherCAT 周期抖动在 CAN 满负载时只增加约 5 微秒基本无感。7. 踩坑记录从设备树到 DC 同步的完整排查链路7.1 CAN 接口起不来先查引脚复用第一次改完设备树can1 和 can2 死活不出来。dmesg里只有rk3568-canfd的 probe 失败信息。排查过程检查 pinctrl 配置发现can1m1_pins和板子实际引出的引脚对不上。OrangePi 5 Plus 的 CAN1 用的是 m0 组不是 m1。改成can1m0_pins后can1 出来了但 can2 还是不行。查原理图发现 can2 的收发器使能引脚没接需要额外配一个 GPIO 拉高。在设备树里加phys can2_phy和transceiver-supply后解决。这个坑的教训是设备树的 pinctrl 组名一定要对着板子的原理图和官方 dts 确认不能凭感觉写。7.2 MCP2518FD 初始化失败SPI 模式问题SPI 扩展的 4 路 CAN 一开始全部 probe 失败dmesg报mcp251xfd: spi transfer failed。排查用示波器量 SPI 时钟和数据线发现时钟有但数据线没波形。检查设备树发现没设spi-cpha和spi-cpol。MCP2518FD 要求 SPI 模式 0 或模式 3默认模式不对。加上spi-cpha; spi-cpol;后数据线有波形了但驱动还是报错。再查发现spi-max-frequency设了 20MHz但 RK3588 的 SPI 控制器在 20MHz 下分频后实际时钟是 24MHz超了 MCP2518FD 的极限。改成 16MHz 后正常。这个坑的教训是SPI 频率要算实际分频后的值不能只看设备树里写的。7.3 EtherCAT 主站编译报错内核头文件路径编译 IgH 时make modules报找不到autoconf.h。原因是--with-linux-dir指向的内核源码没有先编译过缺少生成的头文件。解决方法是先在内核源码目录跑一遍make modules_prepare再编译 IgH。7.4 DC 同步对不上网卡时间戳没开DC 配置好后从站时钟偏差一直在几微秒降不下来。排查ethtool -T eth0查看网卡时间戳能力发现 I210 支持硬件时间戳但没启用。在 IgH 配置里加上--enable-igb后重新编译主站启动时自动启用硬件时间戳。再测偏差降到 ±80ns。这个坑的教训是DC 同步精度高度依赖网卡硬件时间戳选网卡时一定要确认支持。7.5 CAN 丢帧中断亲和性和优先级六路 CAN 同时跑的时候can5 和 can6 偶尔丢帧。排查看/proc/interrupts发现 SPI 中断都落在 CPU0和系统任务抢。把 SPI1 和 SPI3 的中断分别绑到 CPU6 和 CPU7。把 CAN 处理线程优先级从 50 提到 80。丢帧消失。这个坑的教训是多路高速外设一定要做中断亲和性隔离否则中断风暴会拖垮实时性。8. 实测性能数据与长期运行观察调通之后我让这套系统连续跑了 72 小时同时跑 EtherCAT 1ms 周期和六路 CAN 500kbps 60% 负载。关键数据指标数值EtherCAT 周期抖动最大42 微秒EtherCAT 周期抖动99.9%28 微秒DC 同步偏差±85 纳秒CAN 总丢帧数72小时0CAN 平均延迟180 微秒CPU 温度52°C系统负载1.8这个成绩对于软实时方案来说相当不错了。EtherCAT 抖动 42 微秒意味着跑 500 微秒周期也勉强可以但 1ms 周期是最稳的。CAN 零丢帧说明 MCP2518FD 方案在 60% 负载下完全可靠。长期运行中唯一要注意的是散热。RK3588 满载时发热不小我加了个小风扇温度压在 55°C 以下。如果做封闭机箱建议加散热片或者导热到外壳。9. 几个容易被忽略的细节和后续扩展方向9.1 网络命名持久化Linux 网口名默认是eth0、eth1但重启后可能变。EtherCAT 主站配置里写死了 MAC 地址所以网口名变了不影响但如果你用脚本启动建议用 udev 规则固定网口名SUBSYSTEMnet, ACTIONadd, ATTR{address}00:1b:21:xx:xx:xx, NAMEeth_ethercat9.2 CAN 终端的匹配电阻CAN 总线两端必须各接一个 120 欧姆终端电阻否则信号反射会导致通信不稳定。我一开始只在一端接了结果 1Mbps 下误码率很高。两端都接上后误码率降到零。这个细节在实验室短距离测试时可能不明显但现场长距离布线时是致命的。9.3 后续可以扩展的方向这套系统目前是 2 EtherCAT 6 CAN如果还不够可以通过 USB 再扩 CAN但实时性会下降。另一个方向是加一块 FPGA 做硬件加速把 CAN 和 EtherCAT 的部分处理卸载到 FPGACPU 只做上层逻辑这样能跑更短的周期。不过那是另一个量级的工程了等有需求再折腾。最后分享一个我在调试中总结的小技巧每次改设备树或内核配置后先跑一遍 cyclictest 和 EtherCAT 主站自检确认基础实时性没退化再上业务逻辑。这样能把问题定位在最小范围内避免业务代码和底层配置的问题混在一起排查。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。