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