1. 为什么需要 SM 和 FMMU:帧在飞,数据要有"门牌号"
EtherCAT 数据报是流水线式转发的:一个 LRW 帧从主站出发,依次穿过每个从站,每个从站只有极短的处理时间。两个现实问题必须由硬件解决:
- 帧里哪一段是我的?——一帧 LRW 携带的逻辑地址区段可能覆盖整条线上所有从站的数据。从站必须快速判断"这段逻辑地址是否命中我的区间",命中就截取/写入。这是 FMMU 的活:逻辑地址 → 本地内存映射 + 命中检查;
- 拿到的数据放哪、什么时候通知 MCU?——ESC 截下的数据要放进一个缓冲区,再通过 PDI 交给 MCU;MCU 写好的反馈也要从缓冲区被下一帧取走。缓冲区不能乱放、读写不能互相踩。这是 SM 的活:本地内存缓冲区的管理、握手与事件。
FMMU 管"帧 ⇄ ESC 内存"(网络侧),SM 管"ESC 内存 ⇄ 应用"(本地侧)。两者在 ESC 内部接力,共同完成"一帧数据从主站到 MCU 对象字典"的硬件级搬运——全程不占主站/从站 CPU。
2. FMMU:逻辑地址 → 本地内存的映射器
每个 FMMU 定义一段逻辑地址区间与一段本地内存的对应关系。帧里的逻辑地址落在区间内 → 数据被自动映射进(或读自)对应的本地地址。关键字段:
| 寄存器字段 | 作用 | 典型值 |
|---|---|---|
| 逻辑起始地址(4B) | FMMU 负责的逻辑地址区间的起点 | 由主站按全网规划分配,如 0x10000000 |
| 逻辑长度(2B) | 区间长度(字节) | = 该从站过程数据长度(如 10 字节) |
| 逻辑起始位 / 结束位 | 位级偏移(支持非字节对齐) | 一般 0 / 7(整字节) |
| 物理起始地址(2B) | 映射到 ESC 本地内存的哪一段 | = SM2/SM3 的缓冲区地址,如 0x1000 |
| 读 / 写使能 | 允许主站读(从站→主站)还是写(主站→从站) | 输出 PDO:写使能;输入 PDO:读使能 |
| 激活位 | FMMU 是否参与命中检查 | 1=激活(PreOp 后使能) |
一个从站通常配 2 个 FMMU:FMMU0 管输出 PDO(主站写:逻辑区间 → SM2 缓冲区)、FMMU1 管输入 PDO(主站读:SM3 缓冲区 → 逻辑区间)。
3. FMMU 命中检查:一帧 LRW 怎么喂全网
主站发一个 LRW 数据报,逻辑地址区间覆盖 N 个从站的数据段。帧经过每个从站时,ESC 并行检查:
logical_start ≤ 帧内目标逻辑地址 < logical_start + logical_length
命中 → 按映射把帧数据写入本地物理地址(写使能 FMMU),并把 WKC 加 1;未命中 → 原样转发下一从站。所有从站的 FMMU 区间在逻辑地址空间里不重叠,一帧就能精准喂到每一个
这就是 EtherCAT"一帧控全网"的物理基础:没有 FMMU,每个从站都得等主站逐个点名(节点寻址),数据就飞不快。逻辑寻址 + FMMU = 一次广播,各取所需。
4. SM:本地内存 ↔ 应用的交接管家
SM 管理一段本地内存缓冲区,并保证主站侧写、应用侧读(或反向)互不冲突。它维护写指针、读指针和状态位:
| 字段 | 作用 |
|---|---|
| 物理起始地址 / 长度 | 缓冲区在 ESC 本地内存的位置与大小 |
| 通道类型 | 邮箱输入(SM0)/ 邮箱输出(SM1)/ 过程数据输入(SM2)/ 过程数据输出(SM3) |
| 缓冲模式 | 单缓冲 / 三缓冲(过程数据常用三缓冲,见第 5 节) |
| 控制 / 状态 | 写指针、读指针、新数据标志、校验错误、中断使能 |
| 事件 | 新数据到达 → SM 事件/中断 → MCU 经 PDI 取走 |
SM 是"握手套件":主站写完 SM2 置新数据标志,MCU 读到后清标志;反过来 MCU 写完 SM3,主站下一帧读走并确认。握手没做对,就是"偶发丢数据"——最常见的一类从站 bug。
5. 邮箱与过程数据:SM0~SM3 四种通道
| SM | 通道 | 方向 | 内容 | 典型缓冲 |
|---|---|---|---|---|
| SM0 | 邮箱输入 | 主站 → 从站 | CoE/EoE 请求(SDO 下载、FoE) | 单缓冲或 3 缓冲 |
| SM1 | 邮箱输出 | 从站 → 主站 | CoE/EoE 应答(SDO 上传、紧急事件) | 单缓冲或 3 缓冲 |
| SM2 | 过程数据输入 | 主站 → 从站 | RxPDO(目标值、控制字) | 3 缓冲 |
| SM3 | 过程数据输出 | 从站 → 主站 | TxPDO(实际值、状态字) | 3 缓冲 |
主站和 MCU 各自独立读写,单缓冲会互相踩(主站覆盖 MCU 未取走的数据)。三缓冲 = 三个缓冲轮转:主站写一个、MCU 读一个、还有一个做交接缓冲区——读写永不冲突、数据永远是最新的完整帧。代价是多一倍内存和一次额外拷贝,但对 125μs 周期的伺服从站,值。
6. FMMU + SM 完整数据路径:一趟 PDO 的硬件旅程
把第 2~5 节串起来,一次输出 PDO(主站 → 从站)的硬件之旅:
| 步骤 | 谁干 | 动作 |
|---|---|---|
| 1 | 主站 | 把 0x607A 目标位置等写入过程数据缓冲,放进 LRW 帧 |
| 2 | ESC FMMU0 | 帧到达,命中检查:逻辑地址 ∈ FMMU0 区间 → 数据写入 SM2 缓冲区 |
| 3 | ESC SM2 | 置"新数据"标志,产生 SM 事件/中断(若使能) |
| 4 | MCU(PDI) | 中断或轮询发现新数据 → 经 SPI/并行读走缓冲 → 按 PDO 映射拆包进对象字典 |
| 5 | MCU | FOC 消费目标值,写反馈进 SM3 缓冲 |
| 6 | ESC FMMU1 + 帧返回 | 下一帧(或同一帧返回路径)经 FMMU1 把 SM3 数据映射进逻辑区间,主站读走,WKC +2 |
注意步骤 2/3 是纯硬件:ESC 在帧经过的几个时钟周期内完成命中、搬运、置标志——这就是 EtherCAT 从站能在一根线上串几十个、每个只引入几十 ns 延时的原因。
7. 配置时机:PreOp / SafeOp 阶段写入
SM 和 FMMU 不是出厂就有的,是主站在状态机迁移时写进 ESC 寄存器的:
| 状态 | 配置动作 |
|---|---|
| Init | 从站上电,ESC 读 EEPROM 配置字,等主站 |
| PreOp | 主站配置邮箱通道 SM0/SM1(地址、长度、模式)+ FMMU(如需);CoE 邮箱开始可用,传 SDO、下 PDO 映射 |
| SafeOp | 主站配置过程数据 SM2/SM3 与 FMMU(逻辑地址分配、激活)、DC 参数;过程数据开始流动,从站输出保持安全值 |
| OP | 全速运行:每周期 LRW 交换 PDO |
所以"改 PDO 映射"的完整动作链是:改 0x1600/0x1A00 → 改 0x1C10/0x1C11 → 重新走 Init→PreOp→SafeOp→OP,让主站重配 SM 长度和 FMMU 区间(详见《EtherCAT PDO 详解》)。
8. 交互演示:一帧 LRW 命中多个从站
拖动数据报,看 FMMU 命中检查如何"各取所需"——逻辑地址空间被 4 个从站各占一段,一帧覆盖全部:
观察要点:
- 4 个从站的 FMMU 区间在逻辑地址空间里连续不重叠,各自命中自己的数据段;
- 同一帧 LRW 的地址区间覆盖全部从站——每站命中一次,一次广播完成全网交换(这就是"一帧控全网");
- 区间边界处命中判断精确到字节:落在别人的区间里,数据就原样流过,谁也不碰。
9. 代码实现(C语言,可编译模块)
从站栈在 PreOp/SafeOp 时写 SM/FMMU 寄存器(按 ET1100 风格偏移,其他 ESC 改基址宏):
注:逻辑地址分配由主站统一规划(各从站区间不重叠),从站只需在 SafeOp 阶段把主站下发的值写进寄存器。邮箱 SM0/SM1 在 PreOp 先配,过程数据 SM2/SM3 与 FMMU 在 SafeOp 激活。
10. 工程避坑清单
| 坑 | 现象 | 对策 |
|---|---|---|
| SM 长度与映射不匹配 | 主站报过程数据长度错误 / WKC 异常 | SM2/SM3 长度 = ⌈Σbitlen/8⌉,改映射必同步改 SM |
| FMMU 区间重叠 | 两个从站收到同一份数据,互相污染 | 逻辑地址由主站统一分配,严禁手写重叠区间 |
| 读/写使能反了 | 输入输出数据全错或 WKC 不变 | 输出 PDO(主站写)用写使能 FMMU,输入 PDO(从站写)用读使能 |
| SM 握手没清标志 | 偶发丢数据/重复数据 | MCU 读走 SM2 后清"新数据"标志;写 SM3 后确认主站读走再覆盖 |
| 邮箱用单缓冲被踩 | SDO 偶发失败/校验错 | 邮箱改 3 缓冲;或保证主站与 MCU 访问窗口不重叠 |
| SafeOp 后改 FMMU 不重启 | 新配置不生效、数据错位 | SM/FMMU 修改后必须重新走 Init→…→SafeOp 状态机 |
| 非字节对齐 FMMU 位偏移 | 数据错位、偶发漂移 | 位级映射仅在特殊场景用,过程数据一律整字节对齐 |
一句话收尾:FMMU 让"一帧喂全网"成为可能,SM 让"数据安全交接"成为可能——前者解决"谁拿",后者解决"谁用",这两层管家配好,从站才真正跑在 EtherCAT 的硬件实时通道上。