| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389 |
- 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
|