IgH EtherCAT主站详解中,Master与Slave状态机如何工作?
摘要:一、Master FSM (ec_fsm_master) — 主站状态机 3.4.4.1 — 主站核心状态机,负责总线监控、从站扫描、DC 时间同步与 SII 写入 概览 什么是 Master FSM Master FSM 是 EtherC
一、Master FSM (ec_fsm_master) — 主站状态机
3.4.4.1 — 主站核心状态机,负责总线监控、从站扫描、DC 时间同步与 SII 写入
概览
什么是 Master FSM
Master FSM 是 EtherCAT 主站的核心状态机,运行在内核线程中。它负责:
总线监控:周期性广播读取从站数量和 AL 状态,检测拓扑变化
从站扫描:当检测到总线变化时,触发完整的从站扫描流程
DC 时间同步:测量传播延迟、计算并写入时间偏移量
SII 写入:处理用户空间发起的 EEPROM 写入请求
从站重启:执行单个或全部从站的重启操作
Master FSM 由 ec_master_idle_thread()(空闲线程)和 ec_master_operation_thread()(运行线程)在每次循环中调用 ec_fsm_master_exec() 驱动执行。
Master FSM 状态机全图
stateDiagram-v2
[*] --> start: FSM 初始化/重启
state "总线监控阶段" as Monitor {
start --> broadcast: BRD 读取从站数量(0x0130)
broadcast --> start: 检查下一个设备
broadcast --> dc_read_old_times: 需要重新扫描
broadcast --> read_al_status: 无需扫描,逐从站检查
read_al_status --> reboot_slave: 从站请求重启
read_al_status --> read_al_status: 下一个从站
reboot_slave --> start: 重启完成
}
state "扫描阶段" as Scan {
dc_read_old_times --> dc_read_old_times: 下一个从站
dc_read_old_times --> clear_addresses: 全部完成
clear_addresses --> dc_measure_delays: 地址清除完成
dc_measure_delays --> clear_addresses: 下一个设备
dc_measure_delays --> scan_slave: 全部设备完成
scan_slave --> scan_slave: 等待从站扫描完成
}
state "DC 同步阶段" as DCSync {
scan_slave --> dc_read_offset: 扫描完成,开始DC偏移
dc_read_offset --> dc_write_offset: 偏移量改变
dc_read_offset --> dc_read_offset: 下一个从站(无变化)
dc_write_offset --> dc_reset_filter: 写入成功
dc_reset_filter --> dc_read_offset: 下一个从站
}
state "辅助任务" as Misc {
broadcast --> write_sii: 有 SII 写入请求
write_sii --> write_sii: 继续写入下一个字
write_sii --> start: 全部写入完成
}
dc_read_offset --> start: 全部从站DC完成
read_al_status --> write_sii: 有 SII 写入请求
技术详情
状态详解
状态
函数名
职责
ESC 寄存器
start
ec_fsm_master_state_start
检查紧急请求、重启请求;发送 BRD 获取从站数
0x0130 (BRD)
broadcast
ec_fsm_master_state_broadcast
处理广播响应:检测拓扑变化、链路状态、从站状态变化
0x0130 (BRD)
read_al_status
ec_fsm_master_state_read_al_status
FPRD 读取单个从站 AL 状态
0x0130 (FPRD)
reboot_slave
ec_fsm_master_state_reboot_slave
通过 fsm_reboot 子状态机执行从站重启
—
dc_read_old_times
ec_fsm_master_state_dc_read_old_times
APRD 读取从站 DC 端口接收时间(扫描前快照)
0x0900 (APRD)
clear_addresses
ec_fsm_master_state_clear_addresses
BWR 广播清除所有从站站地址
0x0010 (BWR)
dc_measure_delays
ec_fsm_master_state_dc_measure_delays
BWR 触发从站锁存传播延迟
0x0900 (BWR)
scan_slave
ec_fsm_master_state_scan_slave
等待所有从站完成扫描(scan_required=0)
—
dc_read_offset
ec_fsm_master_state_dc_read_offset
读取 DC 系统时间(0x0910)、偏移(0x0920)、延迟(0x0928)
0x0910-0x092B (FPRD)
dc_write_offset
ec_fsm_master_state_dc_write_offset
写入新的 DC 时间偏移和传输延迟
0x0920-0x092B (FPWR)
dc_reset_filter
ec_fsm_master_state_dc_reset_filter
重置 DC 速度计数器滤波器(写入 0x1000)
0x0930 (FPWR)
write_sii
ec_fsm_master_state_write_sii
通过 fsm_sii 子状态机写入 EEPROM
0x0502
主循环调用时序
sequenceDiagram
participant IT as Idle Thread
participant OT as Operation Thread
participant FSM as Master FSM
participant SlaveFSM as Slave FSM (每个从站)
IT->>FSM: ec_fsm_master_exec()
FSM->>FSM: start → broadcast
Note over FSM: BRD 读取从站数和状态
alt 需要重新扫描
FSM->>FSM: dc_read_old_times
FSM->>FSM: clear_addresses
FSM->>FSM: dc_measure_delays
FSM->>SlaveFSM: set_ready() (触发扫描)
FSM->>FSM: scan_slave (等待)
FSM->>FSM: dc_read_offset → dc_write_offset
else 无需扫描
FSM->>FSM: read_al_status (逐从站)
end
OT->>FSM: ec_fsm_master_exec()
Note over FSM: 配置变化时重写DC偏移
DC 偏移计算
Master FSM 支持 32 位和 64 位两种偏移计算模式,取决于从站的 base_dc_range:
EC_DC_32:ec_fsm_master_dc_offset32() — 使用低 32 位计算
EC_DC_64:ec_fsm_master_dc_offset64() — 使用完整 64 位计算
容差阈值:EC_SYSTEM_TIME_TOLERANCE_NS = 1000 (1μs)。仅当时间差超过此值时才更新偏移。已在 SAFEOP 及以上状态的从站不会修改偏移,以避免干扰正在运行的 DC 同步。
关键寄存器访问表
寄存器地址
操作
用途
0x0010
BWR
广播清除站地址
0x0130
BRD / FPRD
读取 AL 状态
0x0900
APRD / BWR
DC 端口接收时间 / 延迟测量
0x0910
FPRD
DC 系统时间 (64-bit)
0x0920
FPRD / FPWR
DC 系统时间偏移 (64-bit)
0x0928
FPRD / FPWR
DC 传输延迟 (32-bit)
0x0930
FPWR
DC 速度计数器(滤波器重置)
0x0502
FPWR / FPRD
SII (EEPROM) 访问
深入源码
ec_fsm_master 结构体
字段
类型
说明
master
ec_master_t *
所属主站
datagram
ec_datagram_t *
使用的 datagram
retries
unsigned int
datagram 超时重试计数
state
void (*)(ec_fsm_master_t *)
当前状态函数指针
dev_idx
ec_device_index_t
当前设备索引(支持多设备/冗余)
idle
int
是否处于空闲阶段
scan_jiffies
unsigned long
扫描开始时间
link_state[]
uint8_t[EC_MAX_NUM_DEVICES]
上次链路状态
slaves_responding[]
unsigned int[EC_MAX_NUM_DEVICES]
每设备的响应从站数
rescan_required
unsigned int
是否需要重新扫描
slave_states[]
ec_slave_state_t[EC_MAX_NUM_DEVICES]
每设备的从站 AL 状态
slave
ec_slave_t *
当前操作的从站
sii_request
ec_sii_write_request_t *
当前 SII 写入请求
sii_index
off_t
SII 写入数据索引
fsm_reboot
ec_fsm_reboot_t
从站重启子状态机
fsm_sii
ec_fsm_sii_t
SII 读写子状态机
关键函数
ec_fsm_master_exec()
执行当前状态。如果 datagram 尚未发送/接收则延迟到下一周期。返回 1 表示已执行。
int ec_fsm_master_exec(ec_fsm_master_t *fsm)
{
if (fsm->datagram->state == EC_DATAGRAM_SENT
|| fsm->datagram->state == EC_DATAGRAM_QUEUED) {
return 0; // datagram 未完成
}
fsm->state(fsm); // 执行当前状态
return 1;
}
ec_fsm_master_state_start()
入口状态。依次检查紧急寄存器请求、重启请求,最终发送 BRD 读取从站数量。设置 fsm->idle = 1。
ec_fsm_master_state_broadcast()
核心决策状态。处理逻辑:
检查 WKC 变化 → 标记 rescan_required
检测链路断开 → 清除从站列表
读取 AL 状态变化 → 日志记录
遍历所有设备索引(主/备用)
如果需要扫描 → 分配从站内存、进入扫描流程
如果配置变化 → 进入 DC 写入流程
否则 → 逐从站读取 AL 状态
DC 偏移写入流程
enter_write_system_times() → dc_read_offset → dc_write_offset → dc_reset_filter 对每个支持 DC 的从站依次执行。
跳过不支持 DC 或不支持系统时间的从站
32 位模式:适用于 base_dc_range == EC_DC_32
64 位模式:适用于 base_dc_range == EC_DC_64
已运行从站(≥SAFEOP)不修改偏移,避免干扰
源文件索引
文件
说明
master/fsm_master.h
Master FSM 结构体和接口声明
master/fsm_master.c
Master FSM 状态实现 (~1430 行)
master/master.c
调用方:idle_thread / operation_thread
master/fsm_reboot.c
子状态机:从站重启
master/fsm_sii.c
子状态机:SII/EEPROM 访问
二、Slave FSM (ec_fsm_slave) — 从站状态机
3.4.4.2 — 每个从站独立运行的请求分发状态机,负责扫描、配置和各类协议请求处理
概览
什么是 Slave FSM
Slave FSM 是每个 EtherCAT 从站独立运行的状态机(各从站之间无耦合、互不等待)。它负责:
请求分发:在 ready 状态按优先级轮询各类请求
从站扫描:触发并等待 Slave Scan FSM 完成
从站配置:调用 Slave Config FSM 执行状态转换
SDO 请求:处理 CoE SDO 上传/下载
字典请求:读取从站 SDO 字典
寄存器请求:直接读写从站 ESC 寄存器
FoE 请求:固件升级文件传输
SoE 请求:伺服驱动 IDN 访问
EoE 请求:以太网隧道 IP 参数设置
MBG 请求:邮箱网关透传
每个从站拥有独立的 ec_fsm_slave_t 实例,由 Master FSM 通过 ec_fsm_slave_exec() 在每个周期驱动。
Slave FSM 状态机全图
stateDiagram-v2
[*] --> idle: 初始化
idle --> ready: set_ready()<br/>Master FSM 触发
ready --> idle: set_unready()
state "请求分发 (优先级顺序)" as Ready {
ready --> scan: scan_required=1
ready --> acknowledge: AL 错误标志
ready --> config: 需要配置/状态切换
ready --> sdo_request: 内部 SDO 请求
ready --> soe_request: 内部 SoE 请求
ready --> dict_request: 字典请求
ready --> sdo_request: 外部 SDO 请求
ready --> reg_request: 寄存器请求
ready --> foe_request: FoE 请求
ready --> soe_request: 外部 SoE 请求
ready --> eoe_request: EoE IP 参数请求
ready --> mbg_request: MBox Gateway 请求
}
scan --> idle: 扫描完成
acknowledge --> ready: 确认完成
config --> ready: 配置完成
dict_request --> ready: 字典获取完成
sdo_request --> ready: SDO 传输完成
soe_request --> ready: SoE 传输完成
reg_request --> ready: 寄存器访问完成
foe_request --> ready: FoE 传输完成
eoe_request --> ready: EoE 设置完成
mbg_request --> ready: MBG 传输完成
技术详情
状态详解
状态
函数名
职责
委托子 FSM
idle
ec_fsm_slave_state_idle
空闲状态,不处理任何请求
—
ready
ec_fsm_slave_state_ready
按优先级轮询所有待处理请求
—
scan
ec_fsm_slave_state_scan
执行从站扫描(EEPROM/PDO)
fsm_slave_scan
acknowledge
ec_fsm_slave_state_acknowledge
确认 AL 错误标志(ACK_ERR)
fsm_change
config
ec_fsm_slave_state_config
执行从站配置和状态切换
fsm_slave_config
dict_request
ec_fsm_slave_state_dict_request
读取 SDO 字典
fsm_coe
sdo_request
ec_fsm_slave_state_sdo_request
处理 SDO 上传/下载请求
fsm_coe
reg_request
ec_fsm_slave_state_reg_request
直接读写从站寄存器
直接 FPRD/FPWR
foe_request
ec_fsm_slave_state_foe_request
处理 FoE 文件传输请求
fsm_foe
soe_request
ec_fsm_slave_state_soe_request
处理 SoE IDN 请求
fsm_soe
eoe_request
ec_fsm_slave_state_eoe_request
处理 EoE IP 参数设置请求
fsm_eoe
mbg_request
ec_fsm_slave_state_mbg_request
处理邮箱网关透传请求
fsm_mbg
请求分发优先级
ready 状态按以下优先级顺序检查请求(前面的优先级更高):
优先级
请求类型
检查函数
说明
1 (最高)
Scan
ec_fsm_slave_action_scan
slave->scan_required 为真时触发
2
Config
ec_fsm_slave_action_config
含 AL 确认和配置下发
3
内部 SDO
ec_fsm_slave_action_process_config_sdo
配置中的 SDO 请求
4
内部 SoE
ec_fsm_slave_action_process_config_soe
配置中的 SoE 请求
5
字典读取
ec_fsm_slave_action_process_dict
SDO 字典获取
6
外部 SDO
ec_fsm_slave_action_process_sdo
用户空间 SDO 请求
7
寄存器
ec_fsm_slave_action_process_reg
直接寄存器读写
8
FoE
ec_fsm_slave_action_process_foe
固件传输
9
外部 SoE
ec_fsm_slave_action_process_soe
用户空间 SoE 请求
10
EoE
ec_fsm_slave_action_process_eoe
IP 参数设置
11 (最低)
MBG
ec_fsm_slave_action_process_mbg
邮箱网关
请求处理时序
sequenceDiagram
participant MF as Master FSM
participant SF as Slave FSM
participant SubFSM as 子状态机
MF->>SF: set_ready() → 进入 ready
Note over SF: 轮询检查各类请求
alt 有 Scan 请求
SF->>SubFSM: fsm_slave_scan_start()
SubFSM-->>SF: 扫描完成 → idle
else 有 Config 请求
SF->>SubFSM: fsm_slave_config_start()
SubFSM-->>SF: 配置完成 → ready
else 有 SDO 请求
SF->>SubFSM: fsm_coe_transfer()
SubFSM-->>SF: SDO 完成 → ready
else 有 FoE 请求
SF->>SubFSM: fsm_foe_transfer()
SubFSM-->>SF: FoE 完成 → ready
end
寄存器请求说明
寄存器请求不使用子 FSM,直接通过 datagram 操作 ESC 寄存器:
EC_DIR_INPUT:FPRD 读取
EC_DIR_OUTPUT:FPWR 写入
EC_DIR_BOTH:FPRW 读写
深入源码
ec_fsm_slave 结构体
字段
类型
说明
slave
ec_slave_t *
所属从站
list
struct list_head
链表节点(标记是否已在执行列表中)
state
void (*)(ec_fsm_slave_t *, ec_datagram_t *)
当前状态函数指针
datagram
ec_datagram_t *
使用的 datagram
sdo_request
ec_sdo_request_t *
当前处理的 SDO 请求
reg_request
ec_reg_request_t *
当前处理的寄存器请求
foe_request
ec_foe_request_t *
当前处理的 FoE 请求
soe_request
ec_soe_request_t *
当前处理的 SoE 请求
eoe_request
ec_eoe_request_t *
当前处理的 EoE 请求
mbg_request
ec_mbg_request_t *
当前处理的 MBG 请求
dict_request
ec_dict_request_t *
当前处理的字典请求
int_dict_request
ec_dict_request_t
内部字典请求(自动获取)
fsm_coe
ec_fsm_coe_t
CoE 子状态机
fsm_foe
ec_fsm_foe_t
FoE 子状态机
fsm_soe
ec_fsm_soe_t
SoE 子状态机
fsm_eoe
ec_fsm_eoe_t
EoE 子状态机
fsm_mbg
ec_fsm_mbg_t
MBG 子状态机
fsm_pdo
ec_fsm_pdo_t
PDO 子状态机
fsm_change
ec_fsm_change_t
状态转换子状态机
fsm_slave_config
ec_fsm_slave_config_t
从站配置子状态机
fsm_slave_scan
ec_fsm_slave_scan_t
从站扫描子状态机
关键函数
ec_fsm_slave_exec()
执行当前状态。返回 1 表示 datagram 被使用(状态机正在处理请求),返回 0 表示空闲。非 idle/ready 状态时 datagram 的 device_index 设为从站所属设备。
ec_fsm_slave_state_ready()
核心分发状态。按优先级依次调用 action_scan → action_config → action_process_config_sdo → action_process_config_soe → action_process_dict → action_process_sdo → action_process_reg → action_process_foe → action_process_soe → action_process_eoe → action_process_mbg。第一个返回非零的 action 将 FSM 切换到对应处理状态。
ec_fsm_slave_action_config()
配置分发逻辑:
检查 error_flag → 跳过
检查 AL ACK_ERR → 进入 acknowledge
检查 current_state != requested_state 或 force_config → 进入 config
支持 EC_QUICK_OP:SafeOP→OP 快速切换(跳过完整配置)
源文件索引
文件
说明
master/fsm_slave.h
Slave FSM 结构体和接口声明
master/fsm_slave.c
Slave FSM 状态实现 (~1400 行)
master/master.c
调用方:ecrt_master_send/receive_ext
