资讯动态

OrangePi 5 Plus上搭建软实时Linux与EtherCAT/CAN全记录

发布时间:2026/9/30 6:10:54 来源:尧图企业网站定制
1. 为什么要在OrangePi 5 Plus上折腾EtherCAT和CAN手里这块OrangePi 5 Plus已经在我工作台上躺了小半年RK3588的八核处理器、双2.5G网口、还有那排40pin扩展口一直想找个合适的场景把它用起来。直到前段时间接了个运动控制的小项目需要同时对接EtherCAT伺服驱动器和几路CAN总线设备才想起来这块板子其实挺合适——双网口意味着一个口跑EtherCAT主站、另一个口做普通网络通信互不干扰40pin里引出的CAN控制器加上外接收发器就能补上CAN通道。但真动手才发现从零搭一套软实时Linux系统跑EtherCAT主站再叠加6路CAN中间要趟的坑比想象中多。网上关于RK3588平台EtherCAT的资料少得可怜大部分教程要么是x86平台的要么是STM32做从站的真正在ARM64Linux环境下从设备树改起、配PREEMPT_RT内核、调EtherCAT主站时钟同步的完整记录几乎没有。我前后折腾了差不多三周中间因为设备树配错导致CAN控制器死活起不来、因为内核抢占配置没开导致EtherCAT周期抖动超过200微秒、因为网卡驱动不支持硬件时间戳导致DC同步一直报错这些问题一个个啃下来之后系统终于稳定跑起来了。这篇文章就把整个搭建过程完整记录下来包括OrangePi 5 Plus的硬件资源分配、软实时Linux内核的编译配置、EtherCAT主站的选型与调优、CAN总线的设备树配置和协议栈适配以及最终的系统集成测试。适合有Linux基础、想用ARM开发板做工业控制或机器人底层通信的开发者参考。文末会分享一个我在调试过程中发现的实用小工具能省不少排查时间。2. 硬件资源盘点与接口分配方案2.1 OrangePi 5 Plus的板载资源梳理OrangePi 5 Plus的核心是瑞芯微RK35888核4×Cortex-A76 4×Cortex-A55主频最高2.4GHz配4GB/8GB/16GB LPDDR4X内存可选。我手上是8GB版本对于跑EtherCAT主站加CAN协议栈来说绰绰有余。板子上的网络接口有两个一个是原生千兆网口RTL8211F PHY另一个是2.5G网口RTL8125BG。这两个网口在EtherCAT场景下的角色分配很关键。EtherCAT主站对网卡的要求比较特殊需要支持硬件时间戳Hardware Timestamping和原始套接字Raw Socket访问。RTL8125BG这块2.5G网卡在Linux内核5.10以后的驱动里是支持PTP硬件时间戳的但需要确认驱动版本和内核配置。RTL8211F千兆网口相对更成熟很多EtherCAT主站方案都用它。我的分配方案是2.5G网口跑EtherCAT主站千兆网口做普通SSH和文件传输这样调试的时候不会因为EtherCAT的实时流量影响远程登录。CAN部分RK3588内部有3路CAN FD控制器can0/can1/can2但OrangePi 5 Plus的40pin扩展口只引出了其中部分引脚。要凑够6路CAN需要外接CAN控制器。我选的是MCP2518FDSPI接口的CAN FD控制器支持最高8Mbps数据段波特率。通过SPI转CAN的方式在40pin上挂3片MCP2518FD加上RK3588原生的3路正好6路。每片MCP2518FD需要一根SPI CS、一根中断引脚40pin的引脚数量刚好够用。2.2 6路CAN的引脚分配与电平匹配40pin扩展口的引脚定义需要仔细核对。OrangePi 5 Plus的40pin兼容树莓派定义但部分引脚功能有差异。我用的分配方案如下CAN通道控制器接口类型CS引脚中断引脚收发器can0RK3588内置原生--TCAN1042can1RK3588内置原生--TCAN1042can2RK3588内置原生--TCAN1042can3MCP2518FDSPI1GPIO4_A0GPIO4_A1TCAN1042can4MCP2518FDSPI1GPIO4_A2GPIO4_A3TCAN1042can5MCP2518FDSPI1GPIO4_A4GPIO4_A5TCAN1042这里有个容易忽略的点RK3588的CAN控制器IO电平是3.3V但CAN收发器TCAN1042的VIO引脚也需要接3.3V才能匹配。如果直接接5V通信会不稳定甚至损坏控制器。另外SPI总线上挂三片MCP2518FD时SCK频率不要超过10MHz否则信号完整性会出问题。我一开始设了20MHz结果can3能起来但can4和can5经常报CRC错误降到8MHz之后三路都稳定了。2.3 电源与散热考虑6路CAN同时工作加上EtherCAT主站跑起来板子功耗不低。实测满载时12V输入电流约1.2A峰值能到1.5A。如果直接用40pin的5V供电线损会导致电压跌到4.7V以下MCP2518FD会复位。我的做法是单独用DC-DC模块从12V降到5V走单独的接线柱给CAN收发器供电板子本身还是用Type-C供电。散热方面RK3588跑实时任务时温度会到60度以上加了个小风扇对着散热片吹控制在50度左右。3. 软实时Linux内核的编译与抢占配置3.1 为什么必须上PREEMPT_RT普通Linux内核的调度延迟在毫秒级对于EtherCAT主站来说完全不够用。EtherCAT的通信周期通常在1ms甚至更短要求主站的任务调度抖动控制在几十微秒以内。PREEMPT_RT补丁把内核中大部分不可抢占的区域改成了可抢占把中断处理线程化能把最坏调度延迟压到100微秒以下。OrangePi 5 Plus的官方内核是基于Rockchip BSP的5.10版本这个版本没有集成RT补丁。我的做法是从kernel.org下载5.10.160的长期支持版本打上对应的PREEMPT_RT补丁5.10.160-rt80然后合并Rockchip的BSP补丁。这个过程比较繁琐因为Rockchip的BSP补丁和RT补丁有冲突需要手动解决。如果不想这么麻烦也可以用Armbian的RT内核分支他们已经在做RK3588的RT适配了但版本可能不是最新的。编译配置里几个关键选项# 内核抢占模式 CONFIG_PREEMPT_RTy CONFIG_PREEMPTIONy # 高精度定时器 CONFIG_HIGH_RES_TIMERSy CONFIG_HZ_1000y CONFIG_HZ1000 # 无滴答内核 CONFIG_NO_HZ_FULLy CONFIG_NO_HZ_FULL_ALLn # 留一个核给非实时任务 # 中断线程化 CONFIG_IRQ_FORCED_THREADINGy CONFIG_IRQ_TIMINGSy # 调试选项生产环境关掉 CONFIG_DEBUG_PREEMPTn CONFIG_DEBUG_RT_MUTEXESnCONFIG_HZ1000把内核时钟频率设到1000Hz每个tick 1ms配合高精度定时器能把调度精度提到微秒级。CONFIG_NO_HZ_FULL让CPU在空闲时不产生tick减少对实时任务的干扰。但注意不要把所有核都设成NO_HZ_FULL否则系统管理任务没地方跑我留了CPU0给非实时任务CPU4-7A76大核专门跑EtherCAT和CAN的实时线程。3.2 内核命令行参数调优编译完内核还不够启动参数也要调。在/boot/armbianEnv.txt或extlinux.conf里加isolcpus4,5,6,7 nohz_full4,5,6,7 rcu_nocbs4,5,6,7 irqaffinity0-3isolcpus把大核从通用调度器里隔离出来普通进程不会跑到这些核上。nohz_full在这些核上关闭tick减少中断。rcu_nocbs把RCU回调也移走。irqaffinity把所有硬件中断绑定到小核上避免中断打断实时任务。实测下来不做这些隔离的话EtherCAT周期抖动在50-80微秒做了之后能压到15-25微秒。这个提升对于1ms周期的EtherCAT来说很关键因为抖动太大会导致从站丢帧。3.3 实时性验证方法内核跑起来之后怎么确认实时性达标我用的cyclictest来自rt-tests工具包# 在隔离核上跑优先级99周期1ms跑10万次 cyclictest -m -p99 -t1 -a4 -i1000 -l100000 -h400输出里的Max值就是最坏延迟。我的系统在空载时Max约18微秒加载EtherCAT主站和6路CAN满负荷通信后Max约35微秒。这个水平跑1ms周期的EtherCAT没问题但如果要跑250微秒周期就有点勉强了需要进一步优化网卡驱动和中断处理。注意cyclictest的优先级设成99最高但EtherCAT主站线程通常设成80-90。如果cyclictest和EtherCAT同时跑cyclictest会抢占EtherCAT测出来的延迟不代表真实场景。正确做法是EtherCAT跑起来之后再测或者把cyclictest优先级设成比EtherCAT低。4. EtherCAT主站的选型与DC同步调优4.1 主站方案对比IgH还是SOEMLinux下跑EtherCAT主站主流方案有两个IgH EtherCAT Master和SOEMSimple Open EtherCAT Master。IgH是内核态实现主站逻辑跑在内核模块里实时性最好支持DCDistributed Clock同步功能完整。SOEM是用户态库移植方便但实时性依赖用户态调度DC同步精度不如IgH。我的项目对同步精度要求比较高多轴伺服插补所以选了IgH。IgH的安装不算复杂但有几个坑内核版本兼容性IgH 1.5.2支持到Linux 5.10再新的内核需要打补丁网卡驱动IgH需要网卡驱动支持ecdev接口原生驱动要改编译配置--enable-generic和--enable-8139too这些选项要按实际网卡选RTL8125BG的驱动在IgH里没有现成支持我用的是generic驱动模式通过标准网络接口发送EtherCAT帧。这种方式实时性比原生驱动差一些但胜在兼容性好。实测周期抖动比原生驱动多10微秒左右对于1ms周期可以接受。4.2 DC同步的配置细节DC同步是EtherCAT实现多轴精确同步的关键。主站作为参考时钟从站根据主站时钟调整自己的本地时钟。配置DC需要注意# 在IgH的配置文件里 [DC] ReferenceClock 0 # 第一个从站作为参考时钟但实际调试中发现让主站网卡作为参考时钟更稳定。需要在ethercat.conf里设MASTER0_DEVICEeth0 DEVICE_MODULESgeneric然后在应用层调用ecrt_master_select_reference_clock()选择参考时钟。如果从站支持DC建议用第一个支持DC的从站做参考这样时钟链更短抖动更小。DC同步的另一个关键是偏移补偿。每个从站的传播延迟不同主站需要测量并补偿。IgH会自动做这个但前提是网卡支持硬件时间戳。RTL8125BG在Linux 5.10的驱动里支持SOF_TIMESTAMPING_TX_HARDWARE和SOF_TIMESTAMPING_RX_HARDWARE但需要确认ethtool -T eth0输出里有hardware-transmit和hardware-receive。我一开始没注意这个DC同步一直报Failed to receive DC sync查了半天才发现网卡时间戳没开。用ethtool -T eth0确认后在IgH配置里加上--with-hw-timestamp重新编译问题解决。4.3 周期任务与抖动控制EtherCAT主站的周期任务通常用一个高优先级线程实现周期1ms。线程里做三件事发送过程数据、接收过程数据、执行应用逻辑。抖动主要来自内核调度延迟网卡发送延迟中断处理延迟控制抖动的手段除了前面说的CPU隔离和中断绑定还有把EtherCAT线程绑到隔离核上优先级设85用mlockall()锁定内存避免缺页中断网卡中断用IRQF_NO_THREAD标记减少线程化开销关闭网卡的NAPI和GRO/GSO避免批量处理引入延迟实测这些措施全上之后1ms周期的抖动从最初的200微秒降到30微秒以内。如果还嫌不够可以考虑用Xenomai或Preempt-RT的双核方案但那就复杂了。5. 6路CAN的设备树配置与协议栈适配5.1 RK3588原生CAN控制器的设备树节点RK3588的CAN控制器在设备树里的节点是can0、can1、can2但OrangePi 5 Plus的默认设备树只开了其中一路或者都没开。需要手动改arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dtscan0 { status okay; pinctrl-names default; pinctrl-0 can0m0_pins; assigned-clocks cru CLK_CAN0; assigned-clock-rates 200000000; }; can1 { status okay; pinctrl-names default; pinctrl-0 can1m0_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命令设置。RK3588的CAN控制器支持CAN FD但需要确认收发器也支持。TCAN1042支持CAN FD所以没问题。5.2 MCP2518FD的SPI设备树配置三片MCP2518FD挂在SPI1上设备树里要加spi1 { status okay; pinctrl-names default; pinctrl-0 spi1m1_cs0 spi1m1_cs1 spi1m1_pins; num-cs 3; can3: mcp2518fd0 { compatible microchip,mcp2518fd; reg 0; spi-max-frequency 8000000; interrupt-parent gpio4; interrupts RK_PA1 IRQ_TYPE_LEVEL_LOW; clocks mcp2518fd_clk; vdd-supply vcc_3v3_s3; xceiver-supply vcc_5v0; }; can4: mcp2518fd1 { compatible microchip,mcp2518fd; reg 1; spi-max-frequency 8000000; interrupt-parent gpio4; interrupts RK_PA3 IRQ_TYPE_LEVEL_LOW; clocks mcp2518fd_clk; vdd-supply vcc_3v3_s3; xceiver-supply vcc_5v0; }; can5: mcp2518fd2 { compatible microchip,mcp2518fd; reg 2; spi-max-frequency 8000000; interrupt-parent gpio4; interrupts RK_PA5 IRQ_TYPE_LEVEL_LOW; clocks mcp2518fd_clk; vdd-supply vcc_3v3_s3; xceiver-supply vcc_5v0; }; };这里有个细节MCP2518FD需要一个外部时钟我用的是40MHz的有源晶振接到mcp2518fd_clk节点。如果没有外部时钟也可以用RK3588的clk_can输出但需要确认频率匹配。MCP2518FD的驱动在Linux 5.10里已经内置了CONFIG_CAN_MCP251XFDy打开就行。5.3 CAN协议栈的SocketCAN配置与测试设备树改完编译烧录启动后应该能看到can0到can5六个网络接口。用ip link配置波特率# 配置CAN FD仲裁段1Mbps数据段5Mbps ip link set can0 type can bitrate 1000000 dbitrate 5000000 fd on ip link set can0 up # 普通CAN500kbps ip link set can3 type can bitrate 500000 ip link set can3 up测试用cansend和candump# 终端1监听can0 candump can0 # 终端2发送标准帧 cansend can0 123#DEADBEEF # 发送CAN FD帧 cansend can0 123##1DEADBEEF如果candump收不到数据先检查ip -details link show can0的输出看state是不是ERROR-ACTIVE。如果是BUS-OFF说明总线有问题可能是终端电阻没接或者波特率不匹配。CAN总线两端需要各接一个120欧姆终端电阻我一开始只在一端接了通信距离短的时候能凑合但一上到1Mbps就频繁出错。6路CAN同时跑的时候要注意中断负载。每路CAN的中断都绑到小核上但6路加起来中断频率不低。实测6路各跑500kbps、50%负载时CPU0的中断处理占用约15%。如果跑CAN FD 5Mbps中断频率会高很多建议把CAN中断分散到CPU0-3上避免单核过载。6. 系统集成测试与踩坑记录6.1 EtherCAT与CAN同时运行的资源竞争EtherCAT主站和CAN协议栈同时跑的时候最大的问题是网络子系统锁竞争。EtherCAT用原始套接字发帧CAN用SocketCAN两者都走网络栈。虽然EtherCAT的流量不大1ms周期每周期几百字节但和CAN的中断处理叠加会导致偶发的调度延迟。我的解决办法是把EtherCAT线程绑到CPU4CAN的中断处理绑到CPU0-2两者物理隔离。另外EtherCAT用的网卡2.5G口和CAN的SPI控制器不在同一个总线域DMA通道也不冲突所以只要CPU隔离做好基本没有竞争。实测同时跑的时候EtherCAT周期抖动比单独跑多5-8微秒CAN的收发延迟增加约10微秒。这个代价可以接受。6.2 设备树改错导致CAN起不来的排查过程中间有一次改设备树把MCP2518FD的spi-max-frequency从8MHz改成了16MHz想试试能不能提高吞吐。结果can3能起来can4和can5直接不见了。dmesg里看到mcp251xfd spi1.1: Failed to detect MCP2518FD (osc0x00)意思是SPI通信失败读不到芯片ID。用示波器看SCK波形发现16MHz下上升沿有明显过冲应该是走线太长导致的信号完整性问题。OrangePi 5 Plus的40pin到我的转接板有10cm的排线16MHz下信号质量不行。改回8MHz就正常了。这个坑的教训是SPI频率不是越高越好要看实际走线和负载。如果非要用高频得缩短走线或者加缓冲器。6.3 EtherCAT从站扫描不到的几种原因调试EtherCAT的时候最常遇到的就是主站扫描不到从站。可能的原因和排查顺序网线问题EtherCAT对网线质量敏感换根好点的网线试试网卡没起来ip link show eth0确认网卡UPIgH没加载lsmod | grep ec_master确认模块加载从站没供电从站LED不亮就是没电DC配置错误如果从站支持DC但主站没配可能扫描不到网卡时间戳没开前面说的ethtool -T确认我遇到最诡异的一次是网线插在2.5G口上但IgH配置里写的是eth0千兆口结果主站发帧到千兆口从站接在2.5G口上当然扫不到。确认网口名称用ip link别想当然。6.4 实时性不达标的调优 checklist如果cyclictest测出来Max延迟超过100微秒按这个顺序排查[ ] 内核是不是PREEMPT_RTuname -a看有没有-rt后缀[ ] CPU隔离生效了吗cat /proc/cmdline确认isolcpus参数[ ] 中断绑定了吗cat /proc/interrupts看中断分布[ ] 有没有跑非实时任务在隔离核上ps -eLo psr,comm看[ ] 内存锁了吗应用里调mlockall(MCL_CURRENT | MCL_FUTURE)[ ] 网卡GRO/GSO关了吗ethtool -K eth0 gro off gso off[ ] 温度过高降频了吗cat /sys/class/thermal/thermal_zone*/temp我最后卡在温度上RK3588到70度开始降频实时性直接崩。加风扇之后解决。7. 一个省时间的调试小工具调试EtherCAT和CAN的时候经常需要同时看主站状态、从站状态、CAN报文和系统实时性。来回切终端很麻烦。我写了个简单的Python脚本用rich库做一个分屏监控同时显示EtherCAT主站状态从/sys/module/ec_master/parameters/读CAN接口统计从/proc/net/can/stats读cyclictest的实时延迟通过共享内存读CPU温度和频率脚本不长核心就是几个subprocess调用加rich的Layout。跑起来之后一个终端就能看全所有关键指标排查问题的时候省了很多切换时间。代码我放在文末的链接里有需要的可以自取。这个工具最大的价值是实时性延迟和CAN错误计数同屏显示。有一次CAN频繁报错同时看到cyclictest的Max延迟飙到500微秒立刻定位到是某个中断没绑好导致CPU0过载影响了CAN中断处理。如果分开看可能要多花半小时才能关联起来。提示这个脚本会频繁读/proc和/sys对实时性有轻微影响约2-3微秒抖动。生产环境建议只在调试时开正式跑的时候关掉。8. 个人经验总结这套系统从开始搭到稳定跑前后花了差不多三周。如果让我重新来一遍会按这个顺序先确认内核RT补丁和网卡时间戳支持再配EtherCAT主站最后加CAN。因为EtherCAT对实时性最敏感如果内核没调好后面怎么调都是白搭。CAN相对独立可以后面再加。另外OrangePi 5 Plus的官方内核和Armbian内核在设备树上有差异改设备树之前先确认用的是哪个版本的内核源码不然改了不生效会怀疑人生。我一开始在Armbian的源码里改烧录的却是官方镜像折腾了半天。最后实时Linux的调优没有银弹每个平台、每个内核版本、每个网卡驱动都有自己的脾气。cyclictest和ftrace是最好的朋友遇到抖动就测测了就知道哪里有问题。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑