Context : I have been tasked with testing a HC-04 Ultrasonic sensor with Verilog, and below is the Verilog code, the testbench and the waveform that I am getting,
/* Module HC_SR04 Ultrasonic Sensor This module will detect objects present in front of the range, and give the distance in mm. Input: clk_50M - 50 MHz clock reset - reset input signal (Use negative reset) echo_rx - receive echo from the sensor Output: trig - trigger sensor for the sensor op - output signal to indicate object is present. distance_out - distance in mm, if object is present. */ // module Declaration module t1b_ultrasonic( input clk_50M, reset, echo_rx, output reg trig, output reg op, output reg [15:0] distance_out ); initial begin trig = 0; end //////////////////DO NOT MAKE ANY CHANGES ABOVE THIS LINE ////////////////// // FSM states localparam IDLE = 3'd0, WAIT_1US = 3'd1, TRIG_HIGH = 3'd2, WAIT_ECHO = 3'd3, MEASURE = 3'd4, DONE = 3'd5, WAIT_LONG = 3'd6, FINAL = 3'd7; reg [2:0] state, next_state; reg [2:0] measurement_count; reg [31:0] counter; // General-purpose counter for delays reg [31:0] echo_counter; // Counter for echo pulse duration // Timing parameters for 50MHz clock localparam ONE_US = 32'd49; // Adjusted for exact timing match localparam TRIG_PULSE = 32'd500; // 10 us = 500 cycles @ 50MHz localparam W1 = 32'd550002; localparam W2 = 32'd520002; localparam W3 = 32'd500002; localparam W4 = 32'd570002; // Divisor for distance based on 340 m/s localparam integer DIST_DIV = 32'd295; localparam integer ROUND_OFFSET = 32'd58; // Initialize registers for simulation safety initial begin state = IDLE; next_state = IDLE; measurement_count = 3'd0; counter = 32'd0; echo_counter = 32'd0; op = 1'b0; distance_out = 16'd0; end // Sequential logic: state updates, counters, and outputs always @(posedge clk_50M or negedge reset) begin if (!reset) begin // Active-low asynchronous reset state <= IDLE; measurement_count <= 3'd0; counter <= 32'd0; echo_counter <= 32'd0; trig <= 1'b0; op <= 1'b0; distance_out <= 16'd0; end else begin // Update outputs on transitions before state change if (state == MEASURE && !echo_rx) begin distance_out <= (echo_counter + ROUND_OFFSET) / DIST_DIV; op <= (((echo_counter + ROUND_OFFSET) / DIST_DIV) < 16'd70) ? 1'b1 : 1'b0; end else if (state == WAIT_ECHO && !echo_rx) begin distance_out <= 16'd0; op <= 1'b0; end state <= next_state; case (state) IDLE: begin trig <= 1'b0; counter <= 32'd0; echo_counter <= 32'd0; end WAIT_1US: begin trig <= 1'b0; counter <= (next_state == TRIG_HIGH) ? 32'd0 : counter + 1; end TRIG_HIGH: begin trig <= (counter < TRIG_PULSE) ? 1'b1 : 1'b0; counter <= counter + 1; end WAIT_ECHO: begin trig <= 1'b0; counter <= 32'd0; if (echo_rx) begin echo_counter <= 32'd1; end else begin echo_counter <= 32'd0; end end MEASURE: begin trig <= 1'b0; if (echo_rx) begin echo_counter <= echo_counter + 1; end else begin echo_counter <= 32'd0; end end DONE: begin trig <= 1'b0; measurement_count <= measurement_count + 1; counter <= 32'd0; end WAIT_LONG: begin trig <= 1'b0; counter <= (next_state == IDLE) ? 32'd0 : counter + 1; end FINAL: begin trig <= 1'b0; end default: begin trig <= 1'b0; end endcase // Override counter reset for transition to WAIT_ECHO if (next_state == WAIT_ECHO && state != WAIT_ECHO) begin counter <= 32'd0; end end end // Combinational: next-state logic always @(*) begin next_state = state; case (state) IDLE: begin next_state = WAIT_1US; end WAIT_1US: begin if (counter >= ONE_US) begin next_state = TRIG_HIGH; end end TRIG_HIGH: begin if (counter >= TRIG_PULSE) begin next_state = WAIT_ECHO; end end WAIT_ECHO: begin if (echo_rx) begin next_state = MEASURE; end else begin next_state = DONE; end end MEASURE: begin if (!echo_rx) begin next_state = DONE; end end DONE: begin if (measurement_count == 3'd4) begin next_state = FINAL; end else begin next_state = WAIT_LONG; end end WAIT_LONG: begin case (measurement_count) 3'd1: begin if (counter >= W1) next_state = IDLE; end 3'd2: begin if (counter >= W2) next_state = IDLE; end 3'd3: begin if (counter >= W3) next_state = IDLE; end 3'd4: begin if (counter >= W4) next_state = IDLE; end default: begin next_state = IDLE; end endcase end FINAL: begin next_state = FINAL; end default: begin next_state = IDLE; end endcase end //////////////////DO NOT MAKE ANY CHANGES BELOW THIS LINE ////////////////// endmodule The testbench is;
// This module will test the ultrasonic sensor. `timescale 1ns/1ns module tb(); reg clk_50M; reg reset; reg echo; wire trig; wire obstacle; wire [15:0] distance_out; reg exp_trig; reg [15:0] exp_distance_out; integer i, fw; integer counter, error_count; t1b_ultrasonic uut( .clk_50M(clk_50M), .reset(reset), .echo_rx(echo), .trig(trig), .op(obstacle), .distance_out(distance_out) ); initial begin clk_50M = 0; reset = 1; echo = 0; i = 0; fw = 0; counter = 0; error_count = 0; exp_trig = 0; exp_distance_out = 0; end always begin #10 clk_50M = ~clk_50M; end always @(posedge clk_50M) begin #100; reset = 1; #920; exp_trig = 1; i = i + 1; #10000; exp_trig = 0; echo = 1; repeat(50000)@(posedge clk_50M); echo = 0; @(posedge clk_50M); exp_distance_out = 169; repeat(49999)@(posedge clk_50M); #10001100; exp_trig = 1; i = i + 1; #10000; exp_trig = 0; echo = 1; repeat(80000)@(posedge clk_50M); echo = 0; @(posedge clk_50M); exp_distance_out = 271; repeat(19999)@(posedge clk_50M); #10001100; exp_trig = 1; i = i + 1; #10000; exp_trig = 0; echo = 1; repeat(100000)@(posedge clk_50M); echo = 0; @(posedge clk_50M); exp_distance_out = 339; #10001080; exp_trig = 1; i = i + 1; #10000; exp_trig = 0; echo = 1; repeat(30000)@(posedge clk_50M); echo = 0; @(posedge clk_50M); exp_distance_out = 101; repeat(69999)@(posedge clk_50M); echo = 0; #10001100; exp_trig = 1; i = i + 1; #10000; exp_trig = 0; @(posedge clk_50M); exp_distance_out = 0; exp_trig = 0; repeat(500)@(posedge clk_50M); //$stop(); end always@(posedge clk_50M) begin #1; if(trig !== exp_trig) error_count = error_count + 1; if(distance_out !== exp_distance_out) error_count = error_count + 1; if(i >= 4 ) begin if(error_count !== 0) begin fw = $fopen("result.txt", "w"); $fdisplay(fw, "%02h","Errors"); $display("Error(s) encountered, please check your design!"); $fclose(fw); end else begin fw = $fopen("result.txt", "w"); $fdisplay(fw, "%02h","No Errors"); $display("No errors encountered, congratulations!"); $fclose(fw); end i = 0; end end endmodule The waveforms are;
The waveform when first error is flagged;
How do I fix this issue between the trig and exp_trig signal which is 2 clocks delayed and this propagates to give error_count = 19. What change in the Verilog code can I make to fix this?

