ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

深入 EtherCAT 主站核心:高精度 PDO 发帧节拍发生器的设计与实现

深入 EtherCAT 主站核心:高精度 PDO 发帧节拍发生器的设计与实现 本模块是 EtherCAT 主站 PDO 周期通信的发帧节拍发生器负责按固定周期产生 frame_req 脉冲触发下游仲裁模块发送一帧过程数据。一.核心设计采用两阶段状态机二.实现方法详解主状态机结构主状态机采用异步复位复位信号 确保 DC 同步完成前模块保持复位。状态机优先级 复位 frame_req_reg 自清零 状态分支逻辑关键设计frame_req_reg 默认赋值为 0且上一拍为 1 时强制清零保证 frame_req 始终是单拍脉冲。ST_WARMUP 预热阶段预热阶段使用本地 40MHz 晶振作为时基通过 warmup_timer_ns 计数实现固定周期发帧。ST_WARMUP:if(~period_cfg_valid)warmup_timer_ns0;// 周期未配置不计数elseif(warmup_timer_nsloop_period_ns)warmup_timer_ns0;// 周期到清零if(~frame_busy_reg)frame_req_reg1;// 空闲则发帧if(warmup_frame_cnt254)sync_target_time_nsdc_sys_time_nsP;// 第255帧计算首帧锁相目标sm_stateST_SYNC;// 切换锁相elsewarmup_frame_cntwarmup_frame_cnt1;elsewarmup_timer_nswarmup_timer_ns25;// 每拍25ns核心要点计时单位warmup_timer_ns 以 ns 为单位每拍 2540MHz 25ns22位防溢出loop_period_ns 最大 21 位 ≈ 2.1ms22 位计时器可容纳无溢出风险忙时跳过若 frame_busy_reg1上一帧未应答本周期不发帧也不计数等待下周期,第255帧切换warmup_frame_cnt 从 0 计到 254 时发第 255 帧并切换 ST_SYNC**ST_SYNC 锁相阶段**锁相阶段切换到 DC 系统时基通过比较 dc_sys_time_ns 与 sync_target_time_ns 实现精确周期触发。ST_SYNC:if(period_cfg_valid~frame_busy_regdc_sys_time_nssync_target_time_ns)frame_req_reg1;if(dc_sys_time_ns-sync_target_time_nsloop_period_ns)sync_target_time_nsdc_sys_time_nsloop_period_ns;// 落后1周期重同步丢帧elsesync_target_time_nssync_target_time_nsloop_period_ns;// 正常递增1周期触发公式触发条件dc_sys_time_ns ≥ sync_target_time_ns正常更新sync_target_time_ns ← sync_target_time_ns loop_period_ns重同步 sync_target_time_ns ← dc_sys_time_ns loop_period_ns每帧触发时刻 sync_target_time_ns而 sync_target_time_ns 每帧递增 loop_period_ns因此帧周期精确等于 loop_period_ns且与 DC 时钟严格对齐。**重同步机制**当因总线忙碌导致落后超过 1 个周期时直接将 sync_target_time_ns 跳到 dc_sys_time_ns loop_period_ns丢弃落后的帧避免突发流量冲击总线。**追赶策略平衡**本设计选择丢帧重同步而非突发补发。若应用要求帧不可丢需引入限速补发机制若应用要求帧不可丢可引入补发间隔计时器 catchup_timer_ns限制补发帧之间的最小时间间隔。核心思路落后时 sync_target_time_ns 只 1P不跳变补发帧之间强制间隔 ≥ loop_period_ns / 2实现补发速率 2帧/P净追上 1帧/P平稳无突发平衡原则补发速率必须大于正常帧率1帧/P才能追上同时需限制上限防止总线拥塞。loop_period_ns/2 是兼顾追赶速度与总线平稳的折中值。本模块源码/* 本模块是 EtherCAT 主站 PDO 周期通信的发帧节拍发生器负责按固定周期产生 frame_req 脉冲 触发下游仲裁模块发送一帧过程数据。 没有实现落后帧数估算 自适应补发间隔 */moduleecat_process_beat_gen(input clk,//40MHZinput rst_n,input[20:0]loop_period_ns,// 帧周期(ns), 典型值2000000(2ms)output frame_req,// 发帧请求脉冲(单拍)input[63:0]dc_sys_time_ns,// DC同步系统时间(ns)input frame_tx_done_ack,// 帧发送完成应答output frame_busy,// 忙标志(帧在途时拉高)output[7:0]frame_seq_id);//-------------------状态定义---------------------------------------------localparam ST_WARMUP1b0;// 预热阶段: 本地晶振自由计数localparam ST_SYNC1b1;// 锁相阶段: DC系统时间对齐// 寄存器声明 reg sm_state;// 状态机当前状态reg[7:0]warmup_frame_cnt;// 预热帧计数 0~254, 共255帧reg[21:0]warmup_timer_ns;// 预热计时器(ns), 每拍25, 22位防溢出reg[63:0]sync_target_time_ns;// 锁相目标绝对时间(ns)reg frame_req_reg;// 发帧请求寄存器reg frame_busy_reg;// 忙标志寄存器reg[7:0]frame_seq_reg;// 帧序号寄存器// 周期配置有效: loop_period_ns 非零wire period_cfg_valid|loop_period_ns;always (posedge clk or negedge rst_n)if(!rst_n)begin sm_stateST_WARMUP;warmup_frame_cnt8d0;warmup_timer_ns22d0;sync_target_time_ns64d0;frame_req_reg1b0;endelseif(frame_req_reg)// 上一拍触发的, 本拍强制清零(单拍脉冲)frame_req_reg1b0;elsebegin frame_req_reg1b0;// 默认无脉冲case(sm_state)// ---------- 预热阶段: 本地晶振计数 ----------ST_WARMUP:beginif(!period_cfg_valid)warmup_timer_ns22d0;elseif(warmup_timer_ns{1b0,loop_period_ns})//周期到begin warmup_timer_ns22d0;if(~frame_busy_reg)// 空闲则发帧begin frame_req_reg1b1;if(warmup_frame_cnt8d254)// 第255帧: 计算首帧锁相目标 当前DC时间 一个周期begin sm_stateST_SYNC;sync_target_time_nsdc_sys_time_ns{1b0,loop_period_ns};//下一次发送时刻endelsewarmup_frame_cntwarmup_frame_cnt1b1;end endelsewarmup_timer_nswarmup_timer_ns10d25;end// ---------- 锁相阶段: DC时钟对齐 ----------ST_SYNC:beginif(period_cfg_valid~frame_busy_regdc_sys_time_nssync_target_time_ns)begin frame_req_reg1b1;// 落后判断: 若落后超过1个周期, 重同步到当前时间周期(丢帧防突发)if(dc_sys_time_ns-sync_target_time_ns{43d0,loop_period_ns})sync_target_time_nsdc_sys_time_ns{43d0,loop_period_ns};elsesync_target_time_nssync_target_time_ns{43d0,loop_period_ns};end enddefault:sm_stateST_WARMUP;endcase end// 握手响应 // frame_req优先置位, 避免与frame_tx_done_ack同拍时握手失效always (posedge clk or negedge rst_n)if(!rst_n)frame_busy_reg1b0;elseif(frame_req_reg)frame_busy_reg1b1;// 新帧请求 - 置忙elseif(frame_tx_done_ack)frame_busy_reg1b0;// 发送完成 - 清忙always (posedge clk or negedge rst_n)if(!rst_n)frame_seq_reg8hc8;elseif(frame_req_reg)beginif(frame_seq_reg8hff)frame_seq_reg8hc8;elseframe_seq_regframe_seq_reg1b1;end// 输出连线 assign frame_reqframe_req_reg;assign frame_busyframe_busy_reg;assign frame_seq_idframe_seq_reg;endmodule
返回列表