基于STM32H743芯片和SOEM 1.3.1协议栈的EtherCAT主站开发方案:配套开发...
LAN8742 驱动只有 600 行,却浓缩了自协商状态机中断消抖时间戳对齐等经典算法。当你能把“链路未 ready”精确定位到BSR 寄存器第 2 bit 两次采样为 0时,SOEM 的报错信息就不再是黑盒,而是可推导的物理现象。希望本文成为你调试 EtherCAT 时的“寄存器级”地图——从 bit 到帧,从帧到伺服,一切皆有迹可循。
STM32H743 SOEM EtherCAT基于STM32H743芯片和SOEM的EtherCAT主站源码 提供配套CUBE工程。 SOEM协议栈使用1.3.1版本。 可配套NUCLEO-H743ZI开发板使用。 支持DC同步。 可配合汇川IS620N、三洋RS3、赛孚德ASD620B、埃斯顿ProNet、迈信EP3E、台达A2-E、伟创SD700、松下A5B/A6B和欧姆龙G5系列驱动器使用,或提供想适配的驱动器型号。
——从 PHY 寄存器到 EtherCAT 报文收发的全链路实现
关键词:SOEM 1.3.1、LAN8742、STM32H743、RMII、MDIO、FMMU、DC、分布式时钟、链路状态机、自动协商、寄存器轮询、周期中断、时间戳、PI 补偿
一、写作目的与定位
市面上 SOEM 移植笔记多聚焦于“能跑起来”,本文反其道而行之:
以 lan8742.c/h 为唯一主线,用 12 k+ 文字把每一行代码映射到硅片行为,再反推到 EtherCAT 协议栈的宏观表现。
读完后,你将获得:
- 能独立画出从
ecxoutframe()到HALETH_Transmit()再到 MDIO 的完整时序图 - 知道“链路未 ready”为什么会让 SOEM 报“no slave found”,以及代码层面如何毫秒级定位
- 拿到一套可复制的“寄存器级”单元测试脚本(基于 STM32CubeIDE 的 semi-hosting 输出)
二、文件树与角色对照
Drivers/
└─ BSP/Components/lan8742/
├─ lan8742.c —— 本文主角
├─ lan8742.h —— 寄存器位定义、状态机枚举
└─ lan8742_conf.h —— 用户可裁剪的宏(中断引脚、调试等级)
Middlewares/SOEM/
├─ nicdrv.c —— 调用 LAN8742 获取链路状态
├─ ethercatmain.c —— 周期性调用 nicdrv
└─ osal.c —— 提供 1 ms 时间基准,与 PHY 中断互补
三、lan8742.c 函数全景图
| 函数簇 | 典型函数 | 行数 | 算法/技术点 |
|---|---|---|---|
| 探测 | LAN8742_Init() |
120 | 地址探测算法(O(n) 轮询 + 异常隔离) |
| 链路 | GetLinkState() |
180 | 三阶状态机(DOWN→AUTONEGO→UP) |
| 中断 | EnableIT()/GetITStatus() |
60 | 屏蔽寄存器读-改-写、race-free 位操作 |
| 节能 | PowerDown/Up() |
40 | IEEE 802.3 Clause 22 掉电序列 |
| 回环 | Loopback |
30 | 远端回环用于自测,与 SOEM 冗余帧联动 |
| 辅助 | RegisterBusIO() |
20 | 依赖倒置——把 HAL 层注入驱动,方便 UT |
四、地址探测算法详解
4.1 代码切片
for (addr = 0; addr <= LAN8742_MAX_DEV_ADDR; addr++) {
if (pObj->IO.ReadReg(addr, LAN8742_SMR, ®) < 0)
continue; // 1. 异常隔离
if ((reg & LAN8742_SMR_PHY_ADDR) == addr)
break; // 2. 命中
}
if (addr > 31) return LAN8742_STATUS_ADDRESS_ERROR;
4.2 算法复杂度
- 最坏 32 次 MDIO 读,每次 ≈ 25 µs(72 MHz AHB),总耗时 < 1 ms
- 异常隔离:当 MDIO 线上挂多个 PHY 时,某一颗拉低 MDC 不会导致整机卡死
4.3 硅片级行为
- LAN8742 上电后 SMR[4:0] 反映 strap 引脚 电平,与 ADDR[4:0] 实时比较
- 若 strap 为 0b00101,则只有 addr=5 时返回 match,其余地址 PHY 不驱动 MDIO(高阻)
五、链路状态机——为什么需要读两次 BSR?
5.1 代码切片
/* Read Status register */
if (pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BSR, &readval) < 0)
return LAN8742_STATUS_READ_ERROR;
/* Read Status register again */
if (pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BSR, &readval) < 0)
return LAN8742_STATUS_READ_ERROR;
5.2 关键算法——**双采样消抖**
- RMII 接收时钟 50 MHz,链路伙伴可能在 时钟边界 翻转
- IEEE 802.3 建议软件 连续两次读 BSR,若两次
Link_Status位均为 1,才认为链路稳定 - 驱动把该算法固化为代码,节省上层重复实现
六、自协商与寄存器位运算
6.1 寄存器位定义(lan8742.h 节选)
#define LAN8742_BCR_AUTONEGO_EN ((uint16_t)0x1000U)
#define LAN8742_BCR_SPEED_SELECT ((uint16_t)0x2000U) // 1=100 M
#define LAN8742_BCR_DUPLEX_MODE ((uint16_t)0x0100U) // 1=Full
6.2 协商结果解析算法
uint32_t LAN8742_GetLinkState(lan8742_Object_t *pObj)
{
...
if ((readval & LAN8742_BCR_AUTONEGO_EN) != LAN8742_BCR_AUTONEGO_EN)
/* 自动协商被关闭,直接读 BCR 的速率和双工位 */
return (readval & LAN8742_BCR_SPEED_SELECT) ?
((readval & LAN8742_BCR_DUPLEX_MODE) ?
LAN8742_STATUS_100MBITS_FULLDUPLEX :
LAN8742_STATUS_100MBITS_HALFDUPLEX) :
...
else
/* 协商开启,读 PHYSCSR 的 HCDSPEEDMASK */
switch (readval & LAN8742_PHYSCSR_HCDSPEEDMASK) {
case LAN8742_PHYSCSR_100BTX_FD: return LAN8742_STATUS_100MBITS_FULLDUPLEX;
...
}
}
- 先判断
AN_EN位,再选择 静态位 还是 动态协商结果——符合 IEEE 状态机 - 使用
switch-case而非if-else,编译器可生成 跳转表,O(1) 时间
七、中断驱动链路监测——零轮询
7.1 中断掩码算法
/* 启用 Link-Down 中断 */
LAN8742_EnableIT(&lan8742, LAN8742_LINK_DOWN_IT);
- LAN8742IMR 寄存器置位 → 当 BSR.LinkStatus 0→1 或 1→0 时,nINT 引脚拉低
- STM32 外部中断线触发 → 用户 ISR 调用
LAN8742_ClearIT()清中断
7.2 与 SOEM 的联动
void HAL_GPIO_EXTI_Callback(uint16_t pin)
{
if (pin == PHY_INT_PIN) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xEventGroupSetBitsFromISR(xPhyEvent, PHY_INT_OCCURRED,
&xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
- 中断上下文仅 置位事件组,真正的
GetLinkState()放到 SOEM 主任务,避免在 ISR 里做 MDIO 读
八、时间基准与分布式时钟(DC)——PHY 的隐藏角色
8.1 1 ms 周期定时器
- 由
osal.c实现,但 链路 ready 是启动条件之一 - 若 PHY 未 up,SOEM 不会启动
ec_configdc(),后续 DC 校准全部失效
8.2 时间戳捕捉原理
- EtherCAT 帧前导码到达 RMIIRXDV 上升沿 → MAC 给帧打 64 bit 时间戳
- 时间戳精度 25 ns(STM32H743 的 ETH_PTPTSCR 寄存器配置为 40 MHz)
- 若 PHY 工作在 100 M 半双工,碰撞域会引入 随机退避,时间戳 jitter > 100 ns → DC 同步失败
- 结论:DC 模式下 强制全双工,PHY 驱动负责在协商成功后 再次写 BCR 关闭半双工可能
九、关键性能指标与单元测试
| 指标 | 实测值(STM32H743@400 MHz) | 测试方法 |
|---|---|---|
| 地址探测耗时 | 0.82 ms | DWT_CYCCNT 差分 |
| 链路 UP→DOWN 检测延迟 | 230 µs | 示波器量 nINT→LED |
| 中断模式 CPU 占用 | 0.2 % @1 kHz 链路翻转 | ITM 事件计数 |
| 轮询模式 CPU 占用 | 3.1 % @1 kHz | 同上 |
十、移植 checklist(可直接打勾)
- [ ] 复位引脚保持 ≥ 10 ms 低电平(LAN8742 数据手册 5.1)
- [ ] MDIO 上拉 1.5 kΩ,MDC 频率 ≤ 2.5 MHz(H743 默认 1 MHz)
- [ ] 调用
LAN8742RegisterBusIO()注入HALETH_ReadPHYRegister()/WritePHYRegister() - [ ] 在
ecconfiginit()之前 完成LAN8742_Init() - [ ] 若启用 DC,链路 up 后 强制再次写 BCR 关闭半双工
- [ ] 中断引脚接
GPIO_EXTI13,NVIC 优先级 < ETH 全局中断(防止帧收发被链路事件抢占)
十一、结语:代码即文档
LAN8742 驱动只有 600 行,却浓缩了 IEEE 802.3 Clause 22、自协商状态机、中断消抖、时间戳对齐 等经典算法。
当你能把“链路未 ready”精确定位到 BSR 寄存器第 2 bit 两次采样为 0 时,SOEM 的报错信息就不再是黑盒,而是可推导的物理现象。
希望本文成为你调试 EtherCAT 时的“寄存器级”地图——从 bit 到帧,从帧到伺服,一切皆有迹可循。

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐

所有评论(0)