如果你也试过用普通PLC去带台达伺服,大概率会被总线版本的差价噎一下。想上EtherCAT,主站这一头要么买专用运动控制卡,要么换带EtherCAT的高端PLC,起步价都不便宜。换个思路:用STM32F407或STM32H7跑开源SOEM,自己焊一块带网口的板子,就能把台达伺服拉进EtherCAT环。这个低成本主站方案听起来“折腾”,但确实有不少人在做,也真能跑起来。今天这篇就把从硬件选型、RMII接线、SOEM移植到台达伺服走位置模式的完整链路讲清楚,最后把实测中踩过的坑一并交代。
1. 低成本主站不是伪命题:先把边界说清楚
1.1 为什么是MCU而不是PC或专用控制卡
很多人一听EtherCAT主站,第一反应是PC + 专用主站软件,或者干脆买现成的运动控制卡。这两种方案确实成熟,问题是贵,而且对设备形态有要求。做非标设备、小型实验台或者院校课题,往往只需要带一两台伺服、十几个IO,用一台完整工控机做主站太浪费,软件授权和硬件成本加起来能占到整个控制柜的大头。
MCU方案的价值在于把主站成本压到两三百块钱的物料级别。STM32F407这种芯片带以太网MAC,外接一颗PHY芯片就能组成完整的百兆以太网节点。跑开源SOEM协议栈,不依赖任何商业授权,整个系统从芯片到协议栈都是可控、可裁剪的。对于“固定几台伺服、固定拓扑、固定周期”的场景,MCU主站完全够用。
当然便宜不等于万能。MCU主站在计算能力、浮点运算、多轴插补、非周期通信并发处理上都比不过PC主站。但对台达伺服这种从站设备,主站真正的任务只有一个:在固定周期内把过程数据发出去、收回来,并且在需要的时候通过SDO读写对象字典。这个任务对STM32F407来说压力并不大。
1.2 F407和H7谁更适合做主站
这两颗芯片我都跑过EtherCAT,结论是:F407可以稳定跑1ms周期,带3到4台伺服加几个IO从站;STM32H7因为主频高、RAM大,可以把周期压到500us甚至250us,前提是你的应用逻辑足够精简。
F407优势是资料多、功耗低、没有D-Cache,移植SOEM时少一个巨大的坑。H7优势是性能强,但D-Cache一致性处理不当,会出现各种“偶发性问题”,后面我会专门讲。如果只是学习或者带一两台台达伺服,F407是更稳妥的选择;如果追求更小的周期同步抖动、轴数更多,直接上H7。
这里还要说一个容易被忽略的点:SOEM在MCU上跑,瓶颈往往不是CPU频率,而是以太网帧的收发延迟和协议栈本身的处理时间。1ms周期下,F407在发送完一帧到接收返回帧的时间窗口内,还要做运动规划、状态机刷新、SDO排队,真正留给应用逻辑的时间并不宽裕。
1.3 SOEM不是“能用就行”的库,底层完全可以自己控
SOEM是开源EtherCAT主站库,结构上分成协议核心和网卡驱动两层。协议层负责状态机扫描、SDO读写、PDO映射、DC同步,这部分基本不用改。真正要动手的是网卡驱动层,它要直接操作STM32的以太网DMA,完成原始EtherCAT帧的收发。
EtherCAT用的不是普通IP帧,而是以太网帧类型为0x88A4的原始帧,不能走传统的TCP/IP协议栈。所以SOEM移植不是简单调几个LWIP接口,而是要把底层收发的路完全腾出来给它。这个特点决定了SOEM移植的工作量比很多人预想的要大,但一旦跑通,你对这个主站的每一个字节都有绝对控制权,这对调试伺服非常有帮助。
2. 硬件底子怎么打:RMII接线、PHY选型和引脚恩怨
2.1 RMII接口为什么更适合这种小板子
STM32的以太网MAC支持RMII和MII两种物理接口。MII需要16根数据线,在狭小的开发板上布线非常痛苦,引脚占用也多,一般只有需要特殊PHY芯片或者追求极低延迟才会用。RMII只需要9根线,数据收发各2位,时钟统一用50MHz参考时钟,大大降低布线和GPIO压力。
RMII的固定连接关系是这样的:一组50MHz参考时钟、TXD0/TXD1两根发送数据线、RXD0/RXD1两根接收数据线、TX_EN发送使能、CRS_DV载波侦听数据有效、MDC/MDIO管理接口,外加可选的RX_ER。这些引脚在STM32上大多是固定复用,基本没有重映射空间,所以选型第一步就是核对引脚冲突。
我见过不少人在这里踩坑:原理图上标了RMII相关引脚,结果有几个脚被串口或者ADC占用,只能飞线。建议layout之前先打开芯片数据手册,把RMII引脚全部拉出来,和项目里其他外设逐一比对,冲突的引脚能避则避。
2.2 PHY选型和时钟网络,最容易烧脑的一步
PHY芯片常见的有LAN8720A、DP83848、KSZ8081这几款,淘宝上都能单独买到小模块。我用的比较顺手的是LAN8720A,体积小、外围简单、价格便宜,和STM32 RMII对接的案例也最多。
时钟是整个PHY设计里最容易乱的地方。RMII模式要求PHY和MAC共用50MHz参考时钟。常见的做法有两种:
一种是把25MHz晶振接在PHY旁边,由PHY内部倍频到50MHz,然后通过REF_CLK输出给STM32。这种接法比较整洁,主芯片只负责接收时钟输入,省去MCO脚。
另一种是STM32的MCO1引脚输出50MHz给PHY的REF_CLK,适合手头没有合适晶振的情况。但我实际用下来更推荐第一种,因为MCO时钟需要在初始化代码里正确配置,一旦配置错PHY就完全不通。
还有一点要提醒:RMII的50MHz时钟不是随便一个IO能输出的,要严格按PHY数据手册要求的输入电平和时间来。我调试时遇到过用示波器量时钟正常、PHY却始终link不上,最后发现是PHY地址和复位时序不对。建议初始化代码里单独控制PHY的复位引脚,拉低等待10ms以上再拉高,再延时几个毫秒后开始配置PHY寄存器。
2.3 引脚冲突与调试口预留
以太网接口占用的引脚一般是PA0、PA1、PA2、PA3、PA8、PB11、PB12、PB13、PC1、PC4这些位置。和JTAG有很大的重叠风险,尤其是PB3、PB4这两个复用脚,如果你要同时用标准JTAG下载器,基本会冲突。
我的习惯是只保留SWD两线(PA13、PA14),把JTAG整个关掉,以太网的PB3、PB4就能腾出来。调试口宁可少一个,也不要在项目中期和以太网抢引脚。另外串口2、串口3、定时器PWM输出这类常用外设,尽量选不靠近以太网引脚的位置,防止飞线。
如果你做的是双网口或者要通过网络调试的主站,还要额外考虑第二个MAC口或USB网口的资源分配。在我那个模拟项目里,就因为这个没预留,后面加网络调试功能只能重新改板子,教训比较深。
2.4 给伺服环境留个后手:隔离与电源
工业现场带台达伺服,主控板和伺服之间是通过EtherCAT网线连接,现场电机启停、变频器干扰比较多。虽然EtherCAT本身有较强的抗干扰能力,但MCU板子的电源和PHY变压器仍建议做隔离保护。
最简单有效的做法是:PHY芯片和RJ45之间放网络变压器,没有网络变压器的模块也可以买带变压器的RJ45座。电源部分,主控板和伺服驱动器最好使用隔离DC-DC供电,至少保证开关电源的地和现场设备地之间不要直接形成大环路。实测下来,网口变压器对通信稳定性帮助很大,尤其是现场有大功率伺服同时动作的时候。
3. SOEM移植:四个底层接口决定实时底线
3.1 SOEM到底在干三件事
移植SOEM之前,先理解它整个初始化流程其实就三件事:扫描总线上有哪些从站、配置从站的过程数据映射、让所有从站进入OP(操作模式),然后周期性地收发过程数据。
扫描阶段,SOEM通过广播帧读取每个从站地址、厂商ID、产品码、SII信息。配置阶段,主站告诉从站PDO应该在哪一帧的哪个偏移位置。跑起来之后,主站把PDO打包进一帧,从站依次处理,帧头出去帧尾回来,一个周期的数据交换就完成了。
这个模型听起来很简单,真正移植的重点在底层帧收发函数。SOEM的设计高度抽象,它在nicdrv这个文件里通过一组函数指针访问底层网卡。不同版本函数名略有不同,但核心就是初始化、缓冲管理、发送帧、接收帧。
3.2 我实际适配过的四个底层函数
我当时在F407上移植,需要实现的最小集合大概是这四类:
- 端口初始化:打开以太网外设、配置PHY寄存器、建立DMA描述符和收发缓冲。
- buffer相关:SOEM需要两块环形缓冲来组织待发送和已接收的数据。
- 发送函数:把给定长度的数据作为以太网帧发送出去。
- 接收函数:从DMA描述符链上取回一帧完整数据,交给SOEM解析。
发送和接收都要注意,SOEM传给底层的是一个内存地址和长度,底层要把它完整地放到DMA描述符对应的缓冲区里。如果直接传指针给DMA,DMA描述符会自行搬运数据,速度会快很多,但对内存对齐的要求也更严格。F407要求缓冲区地址至少4字节对齐,H7因为带cache,还要求buffer地址和长度必须对齐到cache line的宽度。这些细节在移植手册里通常不会写,踩过就知道。
3.3 H7的D-Cache和DMA描述符,移植中最阴的一刀
F407没有D-Cache,移植SOEM非常简单,DMA搬完数据CPU直接读就行。换成H7以后问题就来了:以太网DMA写内存的过程是绕过CPU的,而CPU读数据时可能从D-Cache里拿到旧值。
症状很典型:第一次上电扫描从站,偶尔能扫到,偶尔扫不全;多次上下电之后,从站个数变化无常;或者写SDO时第一次成功,后面就超时。这种问题用示波器看不到任何电平异常,就是数据和内存不一致。
解决办法很死板也很有效:CPU写发送缓冲之前,调用SCB_CleanDCache把脏数据刷下去,让DMA能读到正确内容;DMA接收完成后,调用SCB_InvalidateDCache把缓冲对应的cache失效,让CPU重新从RAM里读。注意H7的cache line一般是32字节,缓冲区和描述符定义时要考虑对齐,否则invalidate会把相邻数据也搞失效。
3.4 周期性调用的骨架
SOEM跑起来以后,周期任务大概长这样:
// 伪代码:1ms周期任务 void vEthercatCycleTask(void) { // 第一步:发送上一周期准备好的帧 ecx_send(&gEc, 0); // 第二步:等待并接收返回帧 ecx_receive(&gEc, 0, gTimeout); // 第三步:解析两个方向的过程数据 // 读从站状态字、实际位置 // 写控制字、目标位置 // 第四步:非周期任务,比如SDO请求、状态机维护 }这个函数要放在一个稳定的周期源里,通常用定时器中断置标志,主循环或高优先级任务里执行。不能在中断里直接跑完整SOEM流程,因为SDO和状态机逻辑可能让周期任务的耗时变得不确定。我用的是定时器中断置标志位,主循环里等标志,这样周期抖动完全由主循环调度决定。
周期任务的时间预算要留余量。1ms周期里,一次收发加解析大约占几百微秒,剩下的时间才是你的应用逻辑。如果应用逻辑复杂到超过余量,就要考虑提高主频或缩短处理路径。
4. 台达伺服进环:扫描、PDO映射到位置模式
4.1 先把从站“认”出来:扫描与识别
硬件焊接完成、SOEM底层收发跑通后,第一次上电扫描从站是很有成就感的时刻。扫描调用SOEM的初始化接口,让主站发送一轮广播命令,总线上所有从站会回复自己的基本信息。
台达A3伺服驱动器作为EtherCAT从站,扫描后能看到它的厂商ID和产品码。SOEM会为每个从站分配一个从站索引,后续所有SDO读写和PDO映射都基于这个索引。
扫描通过不代表可以用。还需要确认从站的SII信息完整,包括设备名、厂商字符串、PDO默认映射。有些时候从站返回的设备名是乱码,多半是邮箱通信还没建好或者从站处于异常状态,重新上下电基本能解决。
4.2 PDO映射:摸清台达最常用的几个对象
EtherCAT把周期数据通信叫做过程数据,发送从站接收数据的方向叫RXPDO,从站返回数据的叫TXPDO。伺服驱动器的对象字典遵循CiA402规范,常用的对象其实就那几个。
我先列一张实际用到的映射表:
| 方向 | 对象索引 | 名称 | 长度 |
|---|---|---|---|
| RXPDO | 0x6040 | 控制字 | 16位 |
| RXPDO | 0x607A | 目标位置 | 32位 |
| RXPDO | 0x6060 | 模式选择 | 8位 |
| TXPDO | 0x6041 | 状态字 | 16位 |
| TXPDO | 0x6064 | 实际位置 | 32位 |
| TXPDO | 0x606C | 实际速度 | 32位 |
台达伺服的默认PDO映射可能和这个不完全一致,但我们可以通过SDO修改映射,或直接在从站配置文件里指定。SOEM里的映射配置,本质上是告诉主站把这些对象按顺序排进过程数据帧,然后为每个方向分配一块连续内存,周期任务里直接读写这块内存就行。
4.3 CiA402状态机与使能时序
伺服使能不是写一位就动的,驱动器内部有个严格的状态机,叫CiA402状态机。主站必须按顺序驱动它:初始化后从站处于不可使能状态,需要通过控制字0x6040逐级切换,先到待使能,再到已使能,最后到运行使能。
实际操作顺序是这样:把0x6060设为1,进入轮廓位置模式;然后把控制字设成0x06,电机开始准备;再设成0x07,切换到开关接通状态;最后设成0x0F,进入运行使能。每一步都要延时几毫秒,然后读回状态字,确认服务端状态已经到位,再走下一步。
很多初用伺服的人直接给0x0F想让它立刻动,结果电机纹丝不动。原因是设备从未使能状态要经过中间状态,状态机有严格的位判断。我调试遇到最多的问题不是状态机记不住,而是上位机程序把状态检查写得太草率,读回状态字没做掩码判断,导致误判。
4.4 位置模式实测:给伺服下第一段运动指令
使能成功之后,就可以下发第一段位置指令了。我建议把模式固定为轮廓位置模式,也就是写0x6060为1,这样做的好处是位置指令和运动控制逻辑都集中在主站侧,逻辑最透明。
下指令的流程是:先写目标位置0x607A,然后改变控制字触发启动。CiA402规定,控制字第4位表示“新目标”,第6位表示“立即启动”。一般做法是,第一次写0x0F,第二次写0x3F,这样伺服会按照映射好的目标位置开始运动。运行过程中可以随时修改目标位置,只要再次把第4位置1。
第一次看到电机转起来,很多人会以为大功告成。但千万别急着接负载,先在空载下测一圈正反转、急停、回零逻辑。我那个测试用的台达A3,空载跑起来完全正常,接上负载之后出现轻微振动,最后发现是增益参数没调,和主站周期无关。
5. 实测复盘:抖动、掉线、D-Cache这几道坎
5.1 周期抖动,用示波器看才直观
主站的周期准确性直接决定伺服的跟随效果。裸跑SOEM、不用DC同步时,我用示波器抓伺服驱动器的报警灯或者特殊IO,测到周期抖动在几十微秒到两百微秒之间波动。这个数值对定位精度要求不高的场景能接受,但做一个高精度位置同步就吃力了。
EtherCAT的分布式时钟(DC)可以把所有从站时钟同步到主站参考时钟上,让各从站同步执行采样指令。SOEM支持DC配置,但需要正确设置SYNC0和SYNC1周期以及触发时间。配置好DC后,抖动可以压到几微秒级别,伺服的高速插补明显更平稳。
DC配置不是免费的,它要求主站周期非常稳定,否则参考时钟本身就会抖。我建议先不开DC跑通功能,再把DC加上看效果,两者对比后你会更容易理解DC的价值。
5.2 掉线重连:从OP掉回INIT怎么办
EtherCAT从站有个特点,一旦通信异常,它会让看门狗触发,从站自动回到安全状态。表现就是主站还在周期发帧,但从站状态已经变成INIT,伺服立刻停止运动。
排查这种问题,我先看网络物理层:RJ45指示灯是否常亮、网线是否过长、是否弯折严重。然后再看主站超时设置。SOEM里有一个超时时间,周期任务中接收不到返回帧会触发超时计数,如果连续多次超时,状态机就可能认为从站离线。
掉线重连的逻辑要自己写完整,不能只发扫描命令,还需要先重置从站AL状态,重新做邮箱通信,再重新配置PDO,最后重新进入OP。我总结了一套固定顺序:发现状态异常后,先把控制字清掉,等待从站回到INIT,然后重新初始化,再按之前的顺序重新配置。整个重连时间大约在200ms以内,对于非急停场景可以接受,如果要求更快得像热插拔一样恢复,就需要在硬件和SOEM底层加不少处理。
5.3 H7的D-Cache现场:一个典型的“偶发怪毛病”
H7的cache一致性问题在F407上完全不存在,所以很容易被忽略。有一次我在H7上跑,周期任务运行几分钟后,突然某个从站的状态字永远读上一条的值,或者位置反馈偶尔跳变。刚开始怀疑从站问题,换台达伺服也一样,后来才意识到是D-Cache没有正确清理。
具体原因是,DMA把接收数据写进RAM后,CPU读取时命中了D-Cache里旧的行,于是拿到的还是上一次的数据。只要在每次接收后加一行invalidate,每次发送前加一行clean,问题立刻消失。听起来简单,但如果你对H7的内存体系不熟,这个坑能折腾一个星期。提醒一句,不要只在初始化时做一次cache清理,周期任务里每个收发循环都要做。
5.4 其他常见问题与对策速查
排错到最后,拿一张速查表总结各种怪现象很有用:
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 扫描不到从站 | PHY复位时序不对 | 检查复位引脚延时 |
| 偶尔掉线 | 时钟不稳定 | 换PHY时钟配置 |
| SDO写超时 | 从站邮箱没准备好 | 放慢SDO重试间隔 |
| 电机转一下就停 | 未按顺序走状态机 | 核对控制字转换流程 |
| 位置反馈跳变 | DC或cache问题 | 先关DC,再查cache |
| 周期不稳定 | 主循环时间过长 | 精简中断和任务 |
每次改完都要重新测稳定周期,不要只看能不能转,要看长时间运行的状态保持。
最后再分享一点个人经验:低成本主站方案最适合学习和中小型设备原型验证。真要上批量产品,安全、认证、长期稳定性这些都要单独评估。但作为一条松绑厂商锁定、吃透EtherCAT底层原理的路子,用STM32F407跑SOEM再带一台台达伺服,是我实操下来性价比最高的一条。准备一根质量好的网线、一个逻辑分析仪,从单轴开始,先把周期跑稳,再把状态机和PDO吃透,后面不管接什么从站,你的底气都会足很多。