1
0
forked from tanchou/Verilog

Refactor ultrasonic modules and testbench for improved functionality and clarity

This commit is contained in:
2025-05-20 14:24:41 +02:00
parent 436edae734
commit b3e646d854
8 changed files with 115 additions and 83 deletions

View File

@@ -32,7 +32,8 @@ module ultrasonic_fpga #(
reg [2:0] state = IDLE; reg [2:0] state = IDLE;
localparam integer TRIG_PULSE_CYCLES = CLK_FREQ / 100_000; // 10us pulse localparam integer TRIG_PULSE_CYCLES = CLK_FREQ / 100_000 + 5; // 10us pulse
// localparam integer DIST_DIVISOR = ((CLK_FREQ / 100) / 343) * 2; // pour conversion us -> cm
localparam integer DIST_DIVISOR = (58 * CLK_FREQ) / 1_000_000; // pour conversion us -> cm localparam integer DIST_DIVISOR = (58 * CLK_FREQ) / 1_000_000; // pour conversion us -> cm
localparam integer MAX_CM = 350; localparam integer MAX_CM = 350;
localparam integer TIMEOUT_CYCLES = (MAX_CM * 58 * CLK_FREQ) / 1000000; localparam integer TIMEOUT_CYCLES = (MAX_CM * 58 * CLK_FREQ) / 1000000;
@@ -58,6 +59,10 @@ module ultrasonic_fpga #(
sig_out <= 0; sig_out <= 0;
sig_dir <= 0; sig_dir <= 0;
distance <= 0; distance <= 0;
echo_counter <= 0;
distance_counter <= 0;
trig_counter <= 0;
if (start) begin if (start) begin
state <= TRIG_HIGH; state <= TRIG_HIGH;
trig_counter <= 0; trig_counter <= 0;
@@ -68,6 +73,7 @@ module ultrasonic_fpga #(
TRIG_HIGH: begin TRIG_HIGH: begin
sig_out <= 1; sig_out <= 1;
sig_dir <= 1; sig_dir <= 1;
if (trig_counter < TRIG_PULSE_CYCLES) begin if (trig_counter < TRIG_PULSE_CYCLES) begin
trig_counter <= trig_counter + 1; trig_counter <= trig_counter + 1;
end else begin end else begin

View File

@@ -1,95 +1,100 @@
module ultrasonic_sensor( // Simulation of an ultrasonic sensor module ultrasonic_sensor(
input wire clk, parameter CLK_FREQ_MHZ = 27 // Clock frequency in MHz (default 27MHz)
inout wire signal // Signal from the ultrasonic sensor ) (
input wire clk, // System clock
inout wire signal // Bidirectional pin for trigger and echo
); );
parameter integer CLK_FREQ = 27_000_000;
reg [2:0] state = 3'd0; // State of the FSM // Timing constants based on CLK_FREQ_MHZ
reg [2:0] next_state; localparam CLK_PERIOD_NS = 1000 / CLK_FREQ_MHZ; // Clock period in ns
reg sig_dir; // 1: output, 0: input localparam TRIGGER_MIN_CYCLES = (10_000 / CLK_PERIOD_NS); // 10us minimum trigger pulse
reg [15:0] trig_counter = 0; // Counter for the trigger pulse // localparam CYCLE_TIME_CYCLES = (60_000_000 / CLK_PERIOD_NS); // 60ms cycle time
reg [31:0] echo_counter = 0; // Echo signal localparam CYCLE_TIME_CYCLES = (60 / CLK_PERIOD_NS); // 60ms cycle time
reg valid_trig = 0; // Valid trigger signal localparam ECHO_DELAY_CYCLES = (1000 / CLK_PERIOD_NS); // 1us delay before echo (sensor processing)
reg echo_sended = 0; // Flag to indicate if echo has been sent // State machine states
localparam IDLE = 3'b000,
CHECK_TRIGGER = 3'b001,
ECHO_DELAY = 3'b010,
ECHO_PULSE = 3'b011,
WAIT_CYCLE = 3'b100;
reg signal_out = 0; reg [2:0] state = IDLE;
assign signal = sig_dir ? signal_out : 1'bz; // Assign the signal to the output if sig_dir is high, otherwise set it to high impedance reg [31:0] counter = 0;
reg signal_prev = 0;
reg [31:0] random_distance = 0;
reg [31:0] echo_cycles = 0;
reg drive_echo = 0; // Controls when model drives signal
localparam S_WAIT_TRIG = 3'd0, // Calculate echo pulse width dynamically
S_MEASURE_TRIG = 3'd1, // Speed of sound: 343 m/s = 0.0343 cm/us
S_SEND_ECHO = 3'd2; // Echo duration (us) = 2 * distance (cm) / 0.0343 (cm/us)
// Convert to clock cycles: duration (us) * 1000 / CLK_PERIOD_NS
wire [31:0] echo_duration_us = (2 * random_distance * 10_000) / 343; // Echo time in us
wire [31:0] calculated_echo_cycles = (echo_duration_us * 1000) / CLK_PERIOD_NS; // Echo time in cycles
localparam integer TRIG_PULSE_CYCLES = CLK_FREQ / 100_000; // 10us pulse // Bidirectional pin control: drive signal only during echo pulse
assign signal = drive_echo ? 1'b1 : 1'bz;
// Main state machine
always @(posedge clk) begin
// Store previous signal value for edge detection
signal_prev <= signal;
always @(*) begin
case (state) case (state)
S_WAIT_TRIG: begin IDLE: begin
sig_dir = 0; drive_echo <= 0;
if (signal == 1) begin counter <= 0;
next_state = S_MEASURE_TRIG; if (signal ) begin // Rising edge of trigger
end else begin random_distance <= $urandom_range(2, 400); // Generate random distance
next_state = S_WAIT_TRIG; state <= CHECK_TRIGGER;
end end
end end
S_MEASURE_TRIG: begin CHECK_TRIGGER: begin
sig_dir = 0; counter <= counter + 1;
if (valid_trig)begin if (signal) begin // Trigger pulse ended
next_state = S_SEND_ECHO; end
else begin
if (counter >= TRIGGER_MIN_CYCLES) begin
$display("HC-SR04: Random distance = %0d cm at time %0t", random_distance, $time);
echo_cycles <= calculated_echo_cycles; // Sample echo duration
state <= ECHO_DELAY;
counter <= 0;
end else begin
state <= IDLE; // Trigger too short
end
end end
end end
S_SEND_ECHO: begin ECHO_DELAY: begin
sig_dir = 1; // Mettre en sortie counter <= counter + 1;
if (counter >= ECHO_DELAY_CYCLES) begin
if (echo_sended) begin state <= ECHO_PULSE;
echo_sended = 0; // Reset flag drive_echo <= 1; // Start driving signal
next_state = S_WAIT_TRIG; counter <= 0;
end else begin
next_state = S_SEND_ECHO;
end end
end end
default: begin ECHO_PULSE: begin
sig_dir = 0; counter <= counter + 1;
next_state = S_WAIT_TRIG; if (counter >= echo_cycles) begin
drive_echo <= 0; // Stop driving signal
state <= WAIT_CYCLE;
counter <= 0;
end
end end
WAIT_CYCLE: begin
counter <= counter + 1;
if (counter >= CYCLE_TIME_CYCLES) begin
state <= IDLE;
counter <= 0;
end
end
default: state <= IDLE;
endcase endcase
end end
always @(posedge clk) begin
state <= next_state;
end
always @(posedge clk) begin
if (state == S_MEASURE_TRIG) begin
if (signal == 1) begin
trig_counter <= trig_counter + 1;
end else begin
if (trig_counter >= TRIG_PULSE_CYCLES-20) begin
valid_trig <= 1;
end else begin
valid_trig <= 0;
end
end
end
end
reg [15:0] echo_delay_counter;
always @(posedge clk) begin
if (state == S_SEND_ECHO) begin
if (echo_delay_counter == 5800) begin //
signal_out <= 0;
echo_sended <= 1;
end else begin
signal_out <= 1;
echo_delay_counter <= echo_delay_counter + 1;
end
end else begin
echo_delay_counter <= 0;
end
end
endmodule endmodule

View File

@@ -64,21 +64,25 @@ module top_uart_ultrason_command (
always @(posedge clk) begin always @(posedge clk) begin
if (data_available) begin if (data_available) begin
command <= rd_data[1:0]; command <= rd_data[1:0];
leds <= rd_data[7:2];
end else begin end else begin
command <= 0; command <= 0;
end end
leds <= {~command, ~mesure_state};
end end
always @(posedge clk) begin // Mesure state machine always @(posedge clk) begin // Mesure state machine
case (mesure_state) case (mesure_state)
IDLE: begin IDLE: begin
if (command == 2'd1 && data_available) begin if (command == 2'd1 && data_available) begin
mesure_state <= ONESTART; mesure_state <= ONESTART;
rd_en <= 1; rd_en <= 1;
end else if (command == 2'd2 && data_available) begin end else if (command == 2'd2 && data_available) begin
mesure_state <= CONTINUOUSSTART; mesure_state <= CONTINUOUSSTART;
rd_en <= 1; rd_en <= 1;
end else if (command == 2'd3 && data_available) begin
mesure_state <= IDLE;
rd_en <= 1;
end else begin end else begin
mesure_state <= IDLE; mesure_state <= IDLE;
rd_en <= 0; rd_en <= 0;

View File

@@ -3,7 +3,7 @@ import time
import struct import struct
# === Paramètres de communication === # === Paramètres de communication ===
SERIAL_PORT = "COM6" # Modifie selon ton système, ex. "/dev/ttyUSB0" sur Linux SERIAL_PORT = "COM10" # Modifie selon ton système, ex. "/dev/ttyUSB0" sur Linux
BAUDRATE = 115200 # Change si différent BAUDRATE = 115200 # Change si différent
TIMEOUT = 2 # secondes TIMEOUT = 2 # secondes

View File

@@ -13,7 +13,8 @@ module hc_sr04_model #(
// Timing constants based on CLK_FREQ_MHZ // Timing constants based on CLK_FREQ_MHZ
localparam CLK_PERIOD_NS = 1000 / CLK_FREQ_MHZ; // Clock period in ns localparam CLK_PERIOD_NS = 1000 / CLK_FREQ_MHZ; // Clock period in ns
localparam TRIGGER_MIN_CYCLES = (10_000 / CLK_PERIOD_NS); // 10us minimum trigger pulse localparam TRIGGER_MIN_CYCLES = (10_000 / CLK_PERIOD_NS); // 10us minimum trigger pulse
localparam CYCLE_TIME_CYCLES = (60_000_000 / CLK_PERIOD_NS); // 60ms cycle time // localparam CYCLE_TIME_CYCLES = (60_000_000 / CLK_PERIOD_NS); // 60ms cycle time
localparam CYCLE_TIME_CYCLES = (60 / CLK_PERIOD_NS); // 60ms cycle time
localparam ECHO_DELAY_CYCLES = (1000 / CLK_PERIOD_NS); // 1us delay before echo (sensor processing) localparam ECHO_DELAY_CYCLES = (1000 / CLK_PERIOD_NS); // 1us delay before echo (sensor processing)
// State machine states // State machine states
@@ -34,7 +35,7 @@ module hc_sr04_model #(
// Speed of sound: 343 m/s = 0.0343 cm/us // Speed of sound: 343 m/s = 0.0343 cm/us
// Echo duration (us) = 2 * distance (cm) / 0.0343 (cm/us) // Echo duration (us) = 2 * distance (cm) / 0.0343 (cm/us)
// Convert to clock cycles: duration (us) * 1000 / CLK_PERIOD_NS // Convert to clock cycles: duration (us) * 1000 / CLK_PERIOD_NS
wire [31:0] echo_duration_us = (2 * random_distance * 1000) / 343; // Echo time in us wire [31:0] echo_duration_us = (2 * random_distance * 10_000) / 343; // Echo time in us
wire [31:0] calculated_echo_cycles = (echo_duration_us * 1000) / CLK_PERIOD_NS; // Echo time in cycles wire [31:0] calculated_echo_cycles = (echo_duration_us * 1000) / CLK_PERIOD_NS; // Echo time in cycles
// Bidirectional pin control: drive sensor_pin only during echo pulse // Bidirectional pin control: drive sensor_pin only during echo pulse
@@ -57,7 +58,9 @@ module hc_sr04_model #(
CHECK_TRIGGER: begin CHECK_TRIGGER: begin
counter <= counter + 1; counter <= counter + 1;
if (!sensor_pin) begin // Trigger pulse ended if (sensor_pin) begin // Trigger pulse ended
end
else begin
if (counter >= TRIGGER_MIN_CYCLES) begin if (counter >= TRIGGER_MIN_CYCLES) begin
$display("HC-SR04: Random distance = %0d cm at time %0t", random_distance, $time); $display("HC-SR04: Random distance = %0d cm at time %0t", random_distance, $time);
echo_cycles <= calculated_echo_cycles; // Sample echo duration echo_cycles <= calculated_echo_cycles; // Sample echo duration

View File

@@ -32,7 +32,8 @@ module ultrason_driver #(
reg [2:0] state = IDLE; reg [2:0] state = IDLE;
localparam integer TRIG_PULSE_CYCLES = CLK_FREQ / 100_000; // 10us pulse localparam integer TRIG_PULSE_CYCLES = CLK_FREQ / 100_000 + 5; // 10us pulse
// localparam integer DIST_DIVISOR = ((CLK_FREQ / 100) / 343) * 2; // pour conversion us -> cm
localparam integer DIST_DIVISOR = (58 * CLK_FREQ) / 1_000_000; // pour conversion us -> cm localparam integer DIST_DIVISOR = (58 * CLK_FREQ) / 1_000_000; // pour conversion us -> cm
localparam integer MAX_CM = 350; localparam integer MAX_CM = 350;
localparam integer TIMEOUT_CYCLES = (MAX_CM * 58 * CLK_FREQ) / 1000000; localparam integer TIMEOUT_CYCLES = (MAX_CM * 58 * CLK_FREQ) / 1000000;
@@ -58,6 +59,9 @@ module ultrason_driver #(
sig_out <= 0; sig_out <= 0;
sig_dir <= 0; sig_dir <= 0;
distance <= 0; distance <= 0;
echo_counter <= 0;
distance_counter <= 0;
trig_counter <= 0;
if (start) begin if (start) begin
state <= TRIG_HIGH; state <= TRIG_HIGH;

View File

@@ -32,7 +32,8 @@ module ultrasonic_fpga #(
reg [2:0] state = IDLE; reg [2:0] state = IDLE;
localparam integer TRIG_PULSE_CYCLES = CLK_FREQ / 100_000; // 10us pulse localparam integer TRIG_PULSE_CYCLES = CLK_FREQ / 100_000 + 5; // 10us pulse
// localparam integer DIST_DIVISOR = ((CLK_FREQ / 100) / 343) * 2; // pour conversion us -> cm
localparam integer DIST_DIVISOR = (58 * CLK_FREQ) / 1_000_000; // pour conversion us -> cm localparam integer DIST_DIVISOR = (58 * CLK_FREQ) / 1_000_000; // pour conversion us -> cm
localparam integer MAX_CM = 350; localparam integer MAX_CM = 350;
localparam integer TIMEOUT_CYCLES = (MAX_CM * 58 * CLK_FREQ) / 1000000; localparam integer TIMEOUT_CYCLES = (MAX_CM * 58 * CLK_FREQ) / 1000000;
@@ -58,6 +59,10 @@ module ultrasonic_fpga #(
sig_out <= 0; sig_out <= 0;
sig_dir <= 0; sig_dir <= 0;
distance <= 0; distance <= 0;
echo_counter <= 0;
distance_counter <= 0;
trig_counter <= 0;
if (start) begin if (start) begin
state <= TRIG_HIGH; state <= TRIG_HIGH;
trig_counter <= 0; trig_counter <= 0;
@@ -68,6 +73,7 @@ module ultrasonic_fpga #(
TRIG_HIGH: begin TRIG_HIGH: begin
sig_out <= 1; sig_out <= 1;
sig_dir <= 1; sig_dir <= 1;
if (trig_counter < TRIG_PULSE_CYCLES) begin if (trig_counter < TRIG_PULSE_CYCLES) begin
trig_counter <= trig_counter + 1; trig_counter <= trig_counter + 1;
end else begin end else begin

View File

@@ -13,6 +13,7 @@ module hc_sr04_tb;
// === Paramètres === // === Paramètres ===
localparam CLK_FREQ = 27_000_000; // 27 MHz localparam CLK_FREQ = 27_000_000; // 27 MHz
localparam CLK_PERIOD = 37; // Période en ns (~37 ns pour 27 MHz) localparam CLK_PERIOD = 37; // Période en ns (~37 ns pour 27 MHz)
localparam CLK_MS = CLK_PERIOD * 100;
// Génération de l'horloge 27 MHz // Génération de l'horloge 27 MHz
always #(CLK_PERIOD/2) clk = ~clk; always #(CLK_PERIOD/2) clk = ~clk;
@@ -46,7 +47,7 @@ module hc_sr04_tb;
begin begin
$display("[%0t ns] Déclenchement d'une mesure", $time); $display("[%0t ns] Déclenchement d'une mesure", $time);
start = 1; start = 1;
#(CLK_PERIOD * 2); #CLK_PERIOD;
start = 0; start = 0;
// Attendre que la mesure soit terminée // Attendre que la mesure soit terminée
wait(done); wait(done);
@@ -77,6 +78,7 @@ module hc_sr04_tb;
// Test 1: Mesure unique // Test 1: Mesure unique
$display("=== Test 1: Mesure unique ==="); $display("=== Test 1: Mesure unique ===");
@(posedge clk); // Synchroniser avec l'horloge
trigger_measurement(); trigger_measurement();
// Supposons que hc_sr04_model simule une distance fixe, par exemple 1000 (à ajuster) // Supposons que hc_sr04_model simule une distance fixe, par exemple 1000 (à ajuster)
check_distance(16'd1000); check_distance(16'd1000);
@@ -84,7 +86,9 @@ module hc_sr04_tb;
// Test 2: Mesures multiples // Test 2: Mesures multiples
$display("=== Test 2: Mesures multiples ==="); $display("=== Test 2: Mesures multiples ===");
repeat (3) begin repeat (3) begin
#(CLK_PERIOD * 1000); // Attendre entre mesures #(CLK_MS * 100); // Attendre entre mesures
@(posedge clk); // Synchroniser avec l'horloge
$display("[%0t ns] Déclenchement d'une nouvelle mesure", $time);
trigger_measurement(); trigger_measurement();
check_distance(16'd1000); check_distance(16'd1000);
end end