module trig_ctrl ( input pclk, presetn, input [11:0] paddr, input pwrite, input [31:0] pwdata, output reg [31:0] prdata, input psel, penable, input [11:0] trig_threshold, input [15:0] trig_pulse_width, input [1:0] trig_edge, input [1:0] trig_mode, input [4:0] trig_time_slot, input [15:0] trig_auto_timeout, input adc_en, adc_run, adc_restart, input adc_eoc, input [11:0] adc_data, output reg ram_wren_b, output reg [9:0] ram_wr_addr, output reg [15:0] ram_wr_data_b, output reg trig_done, output reg [9:0] trigger_ptr ); localparam POST_TRIG_CNT = 512; localparam RAM_DEPTH = 1024; localparam INTERVAL_MIN = 1023; localparam IDLE = 3'b000; localparam PRE_FILL = 3'b001; localparam SAMPLING = 3'b010; localparam POST_TRIG = 3'b011; localparam DONE = 3'b100; localparam ADDR_TRIG_DONE = 'h00; localparam ADDR_TRIG_PTR = 'h04; // ========== 时基抽取相关信号 =================================== reg [15:0] decim_factor; // 抽取因子 reg [15:0] eoc_cnt; // EOC 计数器 reg write_strobe; // 间隔写脉冲 always @(posedge pclk or negedge presetn) begin if(!presetn) decim_factor <= 15'd1; else begin case (trig_time_slot) 5'd1: decim_factor <= 15'd1; // 50µs/div 5'd2: decim_factor <= 15'd2; // 100µs/div 5'd3: decim_factor <= 15'd4; // 200µs/div 5'd4: decim_factor <= 15'd10; // 500µs/div 5'd5: decim_factor <= 15'd20; // 1ms/div 5'd6: decim_factor <= 15'd40; // 2ms/div 5'd7: decim_factor <= 15'd100; // 5ms/div 5'd8: decim_factor <= 15'd200; // 10ms/div 5'd9: decim_factor <= 15'd400; // 20ms/div 5'd10: decim_factor <= 15'd1000; // 50ms/div 5'd11: decim_factor <= 15'd2000; // 100ms/div 5'd12: decim_factor <= 15'd4000; // 200ms/div 5'd13: decim_factor <= 15'd10000; // 500ms/div 5'd14: decim_factor <= 15'd20000; // 1s/div default: decim_factor <= 15'd1; endcase end end // ========== 写脉冲生成 ================ always @(posedge pclk or negedge presetn) begin if (!presetn) begin eoc_cnt <= 15'd0; write_strobe <= 1'b0; end else if (adc_restart_ris) begin eoc_cnt <= 15'd0; write_strobe <= 1'b0; end else begin write_strobe <= 1'b0; if (adc_eoc_ris && adc_en && adc_run && !single_shot_lock && (curr_state == PRE_FILL || curr_state == SAMPLING || curr_state == POST_TRIG)) begin if (eoc_cnt >= decim_factor - 1) begin eoc_cnt <= 15'd0; write_strobe <= 1'b1; end else begin eoc_cnt <= eoc_cnt + 1'b1; end end end end // ===================================================================== // 状态机 reg [2:0] curr_state, next_state; // 同步与边沿 reg adc_eoc_sync1, adc_eoc_sync2; wire adc_eoc_ris; reg adc_rst_sync1, adc_rst_sync2, adc_rst_sync3; wire adc_restart_ris; reg [11:0] adc_data_prev; reg [8:0] post_trig_cnt; reg single_shot_lock; // ========== 用于边沿触发的间隔保护(地址差值法) ========== reg [9:0] last_trig_end_addr_edge; // 边沿触发专用的上次触发结束地址 wire [9:0] addr_diff_edge; wire trig_interval_ok_edge; // ========== 用于自动超时触发的间隔保护(计数器法) ========== reg [10:0] gap_cnt_auto; // 自动模式专用的间隔计数器 wire trig_interval_ok_auto; reg [9:0] auto_wait_cnt; // 自动触发等待计数器 // 触发条件 wire sample_valid; wire edge_trigger; wire auto_force_trigger; wire trig_hit_comb; reg trig_hit_reg; // ========== 新增:脉宽触发相关信号 =================================== reg pulse_trigger; // 脉宽触发条件满足标志 reg [15:0] pulse_cnt; // 脉宽计数器(最大65535,足够) reg pulse_active; // 脉宽检测激活标志 reg pulse_level; // 当前检测的电平(1:高于阈值,0:低于阈值) // ===================================================================== // --------------------------- 同步与边沿检测 --------------------------- always @(posedge pclk or negedge presetn) begin if (!presetn) begin adc_eoc_sync1 <= 1'b0; adc_eoc_sync2 <= 1'b0; end else begin adc_eoc_sync1 <= adc_eoc; adc_eoc_sync2 <= adc_eoc_sync1; end end assign adc_eoc_ris = adc_eoc_sync1 & ~adc_eoc_sync2; always @(posedge pclk or negedge presetn) begin if (!presetn) begin adc_rst_sync1 <= 1'b0; adc_rst_sync2 <= 1'b0; adc_rst_sync3 <= 1'b0; end else begin adc_rst_sync1 <= adc_restart; adc_rst_sync2 <= adc_rst_sync1; adc_rst_sync3 <= adc_rst_sync2; end end assign adc_restart_ris = adc_rst_sync2 & ~adc_rst_sync3; // --------------------------- 有效采样时刻 --------------------------- assign sample_valid = write_strobe && adc_en && adc_run && !single_shot_lock && (curr_state == PRE_FILL || curr_state == SAMPLING); // ============================================================== // 边沿触发的间隔保护(地址差值法) // ============================================================== assign addr_diff_edge = (ram_wr_addr - last_trig_end_addr_edge + RAM_DEPTH) % RAM_DEPTH; assign trig_interval_ok_edge = (curr_state == SAMPLING) && (addr_diff_edge >= INTERVAL_MIN); // 边沿触发条件 assign edge_trigger = sample_valid && (curr_state == SAMPLING) && trig_interval_ok_edge && (trig_edge != 2'b11) && ( (trig_edge == 2'b00 && (adc_data_prev < trig_threshold) && (adc_data >= trig_threshold)) || (trig_edge == 2'b01 && (adc_data_prev > trig_threshold) && (adc_data <= trig_threshold)) || (trig_edge == 2'b10 && ( ((adc_data_prev < trig_threshold) && (adc_data >= trig_threshold)) || ((adc_data_prev > trig_threshold) && (adc_data <= trig_threshold)) )) ); // ========== 脉宽触发逻辑 ======================================= // 在 sample_valid 且 trig_edge == 2'b11 时进行脉宽检测 always @(posedge pclk or negedge presetn) begin if (!presetn) begin pulse_active <= 1'b0; pulse_cnt <= 16'd0; pulse_level <= 1'b0; pulse_trigger <= 1'b0; end else if (adc_restart_ris) begin pulse_active <= 1'b0; pulse_cnt <= 16'd0; pulse_level <= 1'b0; pulse_trigger <= 1'b0; end else if (curr_state == SAMPLING && trig_edge == 2'b11 && adc_en && adc_run && !single_shot_lock) begin pulse_trigger <= 1'b0; if(write_strobe) begin if (!pulse_active) begin if (trig_interval_ok_edge) begin // 检测边沿启动脉宽测量 if ((adc_data_prev < trig_threshold) && (adc_data >= trig_threshold)) begin pulse_active <= 1'b1; pulse_level <= 1'b1; // 高电平脉宽 pulse_cnt <= 16'd0; // 从0开始计数(边沿点不计入) pulse_trigger <= 1'b0; end else if ((adc_data_prev > trig_threshold) && (adc_data <= trig_threshold)) begin pulse_active <= 1'b1; pulse_level <= 1'b0; // 低电平脉宽 pulse_cnt <= 16'd0; pulse_trigger <= 1'b0; end else begin pulse_trigger <= 1'b0; end end end else begin // 已激活,检查电平是否保持 if (((adc_data >= trig_threshold) && pulse_level) || ((adc_data <= trig_threshold) && !pulse_level)) begin if (pulse_cnt < trig_pulse_width - 1) begin pulse_cnt <= pulse_cnt + 1'b1; pulse_trigger <= 1'b0; end else begin // 达到设定宽度(采样点数达到 trig_pulse_width) pulse_trigger <= 1'b1; pulse_active <= 1'b0; pulse_cnt <= 16'd0; end end else begin // 电平改变,脉宽不足,停止测量 pulse_active <= 1'b0; pulse_cnt <= 16'd0; pulse_trigger <= 1'b0; end end end end else begin // 非脉宽模式或条件不满足时,清零 pulse_active <= 1'b0; pulse_cnt <= 16'd0; pulse_trigger <= 1'b0; end end // =================================================================== // ============================================================== // 自动超时触发的间隔保护(计数法) // ============================================================== always @(posedge pclk or negedge presetn) begin if (!presetn) begin gap_cnt_auto <= 11'd0; end else if (adc_restart_ris) begin gap_cnt_auto <= 11'd0; end else if (curr_state == PRE_FILL && next_state == SAMPLING) begin gap_cnt_auto <= 11'd0; // 进入SAMPLING时清零 end else if (sample_valid) begin if (auto_force_trigger || edge_trigger || pulse_trigger) // 任何触发都清零 gap_cnt_auto <= 11'd0; else if (curr_state == SAMPLING) gap_cnt_auto <= gap_cnt_auto + 1'b1; end end assign trig_interval_ok_auto = (curr_state == SAMPLING) && (gap_cnt_auto >= 11'd1023); // 自动触发等待计数器 always @(posedge pclk or negedge presetn) begin if (!presetn) begin auto_wait_cnt <= 10'd0; end else if (adc_restart_ris) begin auto_wait_cnt <= 10'd0; end else if (curr_state == SAMPLING && sample_valid) begin if (edge_trigger) begin auto_wait_cnt <= 10'd0; end else if (trig_interval_ok_auto && trig_mode == 2'b00) begin auto_wait_cnt <= auto_wait_cnt + 1'b1; end else begin auto_wait_cnt <= auto_wait_cnt; // 保持,防绕回清零 end end else if (curr_state != SAMPLING) begin auto_wait_cnt <= 10'd0; end end // 自动强制触发条件 assign auto_force_trigger = (curr_state == SAMPLING) && sample_valid && (auto_wait_cnt >= 10'd511) && trig_interval_ok_auto && !edge_trigger && !pulse_trigger; // ============================================================== // 综合触发信号 // ============================================================== assign trig_hit_comb = edge_trigger || auto_force_trigger || pulse_trigger; always @(posedge pclk or negedge presetn) begin if (!presetn) trig_hit_reg <= 1'b0; else trig_hit_reg <= trig_hit_comb; end // --------------------------- 状态机 --------------------------- always @(posedge pclk or negedge presetn) begin if (!presetn) curr_state <= IDLE; else curr_state <= next_state; end always @(*) begin next_state = curr_state; case (curr_state) IDLE: if (adc_en && adc_run && !single_shot_lock) next_state = PRE_FILL; PRE_FILL: if (!adc_en || !adc_run || single_shot_lock) next_state = IDLE; else if (sample_valid && ram_wr_addr == RAM_DEPTH - 1) next_state = SAMPLING; SAMPLING: if (!adc_en || !adc_run || single_shot_lock) next_state = IDLE; else if (trig_hit_reg) next_state = POST_TRIG; POST_TRIG: if (!adc_en) next_state = IDLE; else if (post_trig_cnt == POST_TRIG_CNT - 1) next_state = DONE; DONE: if (adc_restart_ris || !adc_en) next_state = IDLE; default: next_state = IDLE; endcase end // --------------------------- 写控制与寄存器 --------------------------- always @(posedge pclk or negedge presetn) begin if (!presetn) begin ram_wr_addr <= 10'd0; ram_wren_b <= 1'b0; ram_wr_data_b <= 16'd0; post_trig_cnt <= 9'd0; trig_done <= 1'b0; trigger_ptr <= 10'd0; single_shot_lock <= 1'b0; adc_data_prev <= 12'd0; last_trig_end_addr_edge<= 10'd0; end else if (adc_restart_ris) begin ram_wr_addr <= 10'd0; ram_wren_b <= 1'b0; post_trig_cnt <= 9'd0; trig_done <= 1'b0; trigger_ptr <= 10'd0; single_shot_lock <= 1'b0; adc_data_prev <= 12'd0; last_trig_end_addr_edge<= 10'd0; end else begin ram_wren_b <= 1'b0; // if (adc_eoc_ris && adc_en && adc_run && !single_shot_lock && // (curr_state == PRE_FILL || curr_state == SAMPLING || curr_state == POST_TRIG)) begin // adc_data_prev <= adc_data; // 保持1µs一次的更新 // end case (curr_state) PRE_FILL, SAMPLING, POST_TRIG: begin if (write_strobe) begin ram_wr_addr <= ram_wr_addr + 1'b1; ram_wren_b <= 1'b1; ram_wr_data_b <= {4'd0, adc_data}; adc_data_prev <= adc_data; if (curr_state == POST_TRIG) post_trig_cnt <= post_trig_cnt + 1'b1; // 触发记录:边沿触发更新边沿专用结束地址,自动触发也更新 if (curr_state == SAMPLING && (edge_trigger || auto_force_trigger || pulse_trigger)) begin trigger_ptr <= ram_wr_addr; last_trig_end_addr_edge <= (ram_wr_addr + POST_TRIG_CNT) % RAM_DEPTH; end end end DONE: begin trig_done <= 1'b1; if (trig_mode == 2'b10) begin single_shot_lock <= 1'b1; end end default: ; endcase end end // --------------------------- APB 读 --------------------------- always @(posedge pclk or negedge presetn) begin if (!presetn) prdata <= 32'd0; else if (psel && !penable && !pwrite) begin case (paddr) ADDR_TRIG_DONE: prdata <= {31'd0, trig_done}; ADDR_TRIG_PTR: prdata <= {22'd0, trigger_ptr}; default: prdata <= 32'd0; endcase end end endmodule