From 436edae734ab0c5b4cb8dbdfdcc9d087c74b42ee Mon Sep 17 00:00:00 2001 From: Gamenight77 Date: Mon, 19 May 2025 11:42:28 +0200 Subject: [PATCH] Add ultrasonic sensor model and driver, update testbench and scripts --- .../src/verilog/top_uart_ultrason_command.v | 9 +- Semaine_6/ULTRASON/.gitignore | 5 + Semaine_6/ULTRASON/README.md | 9 + Semaine_6/ULTRASON/project.bat | 6 + Semaine_6/ULTRASON/project.sh | 22 +++ Semaine_6/ULTRASON/scripts/linux/build.sh | 46 ++++++ Semaine_6/ULTRASON/scripts/linux/clean.sh | 4 + Semaine_6/ULTRASON/scripts/linux/gtkwave.sh | 5 + Semaine_6/ULTRASON/scripts/linux/simulate.sh | 17 ++ Semaine_6/ULTRASON/scripts/windows/build.bat | 45 +++++ Semaine_6/ULTRASON/scripts/windows/clean.bat | 4 + .../ULTRASON/scripts/windows/gtkwave.bat | 3 + .../ULTRASON/scripts/windows/simulate.bat | 29 ++++ .../ULTRASON/src/verilog/hc_sr04_model.v | 102 ++++++++++++ .../ULTRASON/src/verilog/ultrason_driver.v | 154 ++++++++++++++++++ .../ULTRASON/src/verilog/ultrasonic_fpga.v | 152 +++++++++++++++++ Semaine_6/ULTRASON/tests/verilog/hc_sr04_tb.v | 131 +++++++++++++++ 17 files changed, 740 insertions(+), 3 deletions(-) create mode 100644 Semaine_6/ULTRASON/.gitignore create mode 100644 Semaine_6/ULTRASON/README.md create mode 100644 Semaine_6/ULTRASON/project.bat create mode 100644 Semaine_6/ULTRASON/project.sh create mode 100644 Semaine_6/ULTRASON/scripts/linux/build.sh create mode 100644 Semaine_6/ULTRASON/scripts/linux/clean.sh create mode 100644 Semaine_6/ULTRASON/scripts/linux/gtkwave.sh create mode 100644 Semaine_6/ULTRASON/scripts/linux/simulate.sh create mode 100644 Semaine_6/ULTRASON/scripts/windows/build.bat create mode 100644 Semaine_6/ULTRASON/scripts/windows/clean.bat create mode 100644 Semaine_6/ULTRASON/scripts/windows/gtkwave.bat create mode 100644 Semaine_6/ULTRASON/scripts/windows/simulate.bat create mode 100644 Semaine_6/ULTRASON/src/verilog/hc_sr04_model.v create mode 100644 Semaine_6/ULTRASON/src/verilog/ultrason_driver.v create mode 100644 Semaine_6/ULTRASON/src/verilog/ultrasonic_fpga.v create mode 100644 Semaine_6/ULTRASON/tests/verilog/hc_sr04_tb.v diff --git a/Semaine_6/UART_ULTRASON_COMMANDS/src/verilog/top_uart_ultrason_command.v b/Semaine_6/UART_ULTRASON_COMMANDS/src/verilog/top_uart_ultrason_command.v index eb56ab0..1b5a4c0 100644 --- a/Semaine_6/UART_ULTRASON_COMMANDS/src/verilog/top_uart_ultrason_command.v +++ b/Semaine_6/UART_ULTRASON_COMMANDS/src/verilog/top_uart_ultrason_command.v @@ -56,7 +56,7 @@ module top_uart_ultrason_command ( reg [1:0] command = 0; - reg [31:0] delay_counter = 0; + reg [31:0] delay_counter = 13500000; // 0.5s localparam US_STATE_WIDTH = $clog2(NEXT_FIFO)+1; reg [US_STATE_WIDTH-1:0] mesure_state = IDLE; @@ -65,6 +65,8 @@ module top_uart_ultrason_command ( if (data_available) begin command <= rd_data[1:0]; leds <= rd_data[7:2]; + end else begin + command <= 0; end end @@ -97,7 +99,7 @@ module top_uart_ultrason_command ( CONTINUOUSSTART: begin if (command == 3) begin mesure_state <= NEXT_FIFO; - rd_en <= 1; + rd_en <= 0; end else begin mesure_state <= CONTINUOUSSTOP; start <= 1; @@ -111,8 +113,9 @@ module top_uart_ultrason_command ( end WAIT: begin // Compteur 0.5s - if (delay_counter > 1) begin + if (delay_counter > 32'd1) begin delay_counter <= delay_counter - 1; + mesure_state <= WAIT; end else begin mesure_state <= CONTINUOUSSTART; delay_counter <= 13500000; diff --git a/Semaine_6/ULTRASON/.gitignore b/Semaine_6/ULTRASON/.gitignore new file mode 100644 index 0000000..029ea4f --- /dev/null +++ b/Semaine_6/ULTRASON/.gitignore @@ -0,0 +1,5 @@ +runs +.vscode +workspace.code-workspace +*.pyc +.idea \ No newline at end of file diff --git a/Semaine_6/ULTRASON/README.md b/Semaine_6/ULTRASON/README.md new file mode 100644 index 0000000..34702e3 --- /dev/null +++ b/Semaine_6/ULTRASON/README.md @@ -0,0 +1,9 @@ +# ULTRASON VIA UART + +## Description +This project is designed to control an ultrasonic sensor using UART communication. The ultrasonic sensor is used to measure distance, and the data is transmitted via UART to a connected device. + +## Commands +0x01: Start one mesurement of the distance. +0x02: Start continuous mesurement of the distance. +0x03: Stop continuous mesurement of the distance. \ No newline at end of file diff --git a/Semaine_6/ULTRASON/project.bat b/Semaine_6/ULTRASON/project.bat new file mode 100644 index 0000000..c087898 --- /dev/null +++ b/Semaine_6/ULTRASON/project.bat @@ -0,0 +1,6 @@ +@call c:\oss-cad-suite\environment.bat +@echo off +if "%1"=="sim" call scripts\windows\simulate.bat +if "%1"=="wave" call scripts\windows\gtkwave.bat +if "%1"=="clean" call scripts\windows\clean.bat +if "%1"=="build" call scripts\windows\build.bat \ No newline at end of file diff --git a/Semaine_6/ULTRASON/project.sh b/Semaine_6/ULTRASON/project.sh new file mode 100644 index 0000000..7c0497b --- /dev/null +++ b/Semaine_6/ULTRASON/project.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# Charger l'environnement OSS CAD Suite +source /home/louis/oss-cad-suite/environment + +case "$1" in + sim) + bash scripts/linux/simulate.sh + ;; + wave) + bash scripts/linux/gtkwave.sh + ;; + clean) + bash scripts/linux/clean.sh + ;; + build) + bash scripts/linux/build.sh + ;; + *) + echo "Usage: $0 {sim|wave|clean|build}" + ;; +esac diff --git a/Semaine_6/ULTRASON/scripts/linux/build.sh b/Semaine_6/ULTRASON/scripts/linux/build.sh new file mode 100644 index 0000000..3c59fe2 --- /dev/null +++ b/Semaine_6/ULTRASON/scripts/linux/build.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +# Aller à la racine du projet +cd "$(dirname "$0")/../.." || exit 1 + +# Config de base +DEVICE="GW2AR-LV18QN88C8/I7" +BOARD="tangnano20k" +TOP="top_uart_ultrason_command" +CST_FILE="$TOP.cst" +JSON_FILE="runs/$TOP.json" +PNR_JSON="runs/pnr_$TOP.json" +BITSTREAM="runs/$TOP.fs" + +# Créer le dossier runs si nécessaire +mkdir -p runs + +echo "=== Étape 1 : Synthèse avec Yosys ===" +yosys -p "read_verilog -sv src/verilog/$TOP.v IP/verilog/ultrasonic_fpga.v IP/verilog/uart_tx_fifo.v IP/verilog/uart_rx_fifo.v IP/verilog/rxuartlite.v IP/verilog/fifo.v IP/verilog/uart_tx.v; synth_gowin -top $TOP -json $JSON_FILE" +if [ $? -ne 0 ]; then + echo "=== Erreur lors de la synthèse ===" + exit 1 +fi + +echo "=== Étape 2 : Placement & Routage avec nextpnr-himbaechel ===" +nextpnr-himbaechel --json "$JSON_FILE" --write "$PNR_JSON" --device "$DEVICE" --vopt cst=constraints/"$CST_FILE" --vopt family=GW2A-18C +if [ $? -ne 0 ]; then + echo "=== Erreur lors du placement/routage ===" + exit 1 +fi + +echo "=== Étape 3 : Packing avec gowin_pack ===" +gowin_pack -d "$DEVICE" -o "$BITSTREAM" "$PNR_JSON" +if [ $? -ne 0 ]; then + echo "=== Erreur lors du packing ===" + exit 1 +fi + +echo "=== Étape 4 : Flash avec openFPGALoader ===" +openFPGALoader -b "$BOARD" "$BITSTREAM" +if [ $? -ne 0 ]; then + echo "=== Erreur lors du flash ===" + exit 1 +fi + +echo "=== Compilation et flash réussis ===" diff --git a/Semaine_6/ULTRASON/scripts/linux/clean.sh b/Semaine_6/ULTRASON/scripts/linux/clean.sh new file mode 100644 index 0000000..a505cb7 --- /dev/null +++ b/Semaine_6/ULTRASON/scripts/linux/clean.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +echo "=== Nettoyage des fichiers générés ===" +rm -rf runs/* diff --git a/Semaine_6/ULTRASON/scripts/linux/gtkwave.sh b/Semaine_6/ULTRASON/scripts/linux/gtkwave.sh new file mode 100644 index 0000000..3c97f71 --- /dev/null +++ b/Semaine_6/ULTRASON/scripts/linux/gtkwave.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +echo "=== Lancement de GTKWave ===" +gtkwave runs/ultrason_commands.vcd +echo "=== GTKWave terminé ===" \ No newline at end of file diff --git a/Semaine_6/ULTRASON/scripts/linux/simulate.sh b/Semaine_6/ULTRASON/scripts/linux/simulate.sh new file mode 100644 index 0000000..72e0421 --- /dev/null +++ b/Semaine_6/ULTRASON/scripts/linux/simulate.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +echo "=== Simulation avec Icarus Verilog ===" + +OUT="runs/sim.vvp" +TOP="tb_ultrason_commands" +DIRS=("src/verilog" "tests/verilog" "IP/verilog") + +FILES=() +for dir in "${DIRS[@]}"; do + for file in "$dir"/*.v; do + FILES+=("$file") + done +done + +iverilog -g2012 -o "$OUT" -s "$TOP" "${FILES[@]}" +vvp "$OUT" diff --git a/Semaine_6/ULTRASON/scripts/windows/build.bat b/Semaine_6/ULTRASON/scripts/windows/build.bat new file mode 100644 index 0000000..8182a70 --- /dev/null +++ b/Semaine_6/ULTRASON/scripts/windows/build.bat @@ -0,0 +1,45 @@ +@echo off +setlocal + +rem === Aller à la racine du projet === +cd /d %~dp0\..\.. + +rem === Config de base === +set DEVICE=GW2AR-LV18QN88C8/I7 +set BOARD=tangnano20k +set TOP=top_uart_ultrason_command +set CST_FILE=%TOP%.cst +set JSON_FILE=runs/%TOP%.json +set PNR_JSON=runs/pnr_%TOP%.json +set BITSTREAM=runs/%TOP%.fs + +rem === Créer le dossier runs si nécessaire === +if not exist runs ( + mkdir runs +) + +echo === Étape 1 : Synthèse avec Yosys === +yosys -p "read_verilog -sv src/verilog/%TOP%.v IP/verilog/ultrasonic_fpga.v IP/verilog/uart_tx_fifo.v IP/verilog/uart_rx_fifo.v IP/verilog/rxuartlite.v IP/verilog/txuartlite.v IP/verilog/fifo.v; synth_gowin -top %TOP% -json %JSON_FILE%" +if errorlevel 1 goto error + +echo === Étape 2 : Placement & Routage avec nextpnr-himbaechel === +nextpnr-himbaechel --json %JSON_FILE% --write %PNR_JSON% --device %DEVICE% --vopt cst=constraints/%CST_FILE% --vopt family=GW2A-18C +if errorlevel 1 goto error + +echo === Étape 3 : Packing avec gowin_pack === +gowin_pack -d %DEVICE% -o %BITSTREAM% %PNR_JSON% +if errorlevel 1 goto error + +echo === Étape 4 : Flash avec openFPGALoader === +openFPGALoader -b %BOARD% %BITSTREAM% +if errorlevel 1 goto error + +echo === Compilation et flash réussis === +goto end + +:error +echo === Une erreur est survenue === + +:end +endlocal +pause diff --git a/Semaine_6/ULTRASON/scripts/windows/clean.bat b/Semaine_6/ULTRASON/scripts/windows/clean.bat new file mode 100644 index 0000000..6192ae1 --- /dev/null +++ b/Semaine_6/ULTRASON/scripts/windows/clean.bat @@ -0,0 +1,4 @@ +@echo off +echo === Nettoyage du dossier runs === +rd /s /q runs +mkdir runs diff --git a/Semaine_6/ULTRASON/scripts/windows/gtkwave.bat b/Semaine_6/ULTRASON/scripts/windows/gtkwave.bat new file mode 100644 index 0000000..0b86154 --- /dev/null +++ b/Semaine_6/ULTRASON/scripts/windows/gtkwave.bat @@ -0,0 +1,3 @@ +@echo off +echo === Lancement de GTKWave === +gtkwave runs/sim.vcd diff --git a/Semaine_6/ULTRASON/scripts/windows/simulate.bat b/Semaine_6/ULTRASON/scripts/windows/simulate.bat new file mode 100644 index 0000000..506fcaf --- /dev/null +++ b/Semaine_6/ULTRASON/scripts/windows/simulate.bat @@ -0,0 +1,29 @@ +@echo off +echo === Simulation avec Icarus Verilog === +setlocal enabledelayedexpansion + +:: Dossier de sortie +set OUT=runs/sim.vvp + +:: Top-level testbench module +set TOP=hc_sr04_tb + +:: Répertoires contenant des fichiers .v +set DIRS=src/verilog tests/verilog IP/verilog + +:: Variable pour stocker les fichiers +set FILES= + +:: Boucle sur chaque dossier +for %%D in (%DIRS%) do ( + for %%F in (%%D\*.v) do ( + set FILES=!FILES! %%F + ) +) + +:: Compilation avec Icarus Verilog +iverilog -g2012 -o %OUT% -s %TOP% %FILES% + +endlocal + +vvp runs/sim.vvp \ No newline at end of file diff --git a/Semaine_6/ULTRASON/src/verilog/hc_sr04_model.v b/Semaine_6/ULTRASON/src/verilog/hc_sr04_model.v new file mode 100644 index 0000000..97d157e --- /dev/null +++ b/Semaine_6/ULTRASON/src/verilog/hc_sr04_model.v @@ -0,0 +1,102 @@ +// Verilog model for single-pin ultrasonic sensor (e.g., HY-SRF05 in single-pin mode) +// Simulates bidirectional pin for trigger/echo with internal random distance for testbenches +// Author: Grok, xAI +// Date: May 14, 2025 + +module hc_sr04_model #( + parameter CLK_FREQ_MHZ = 27 // Clock frequency in MHz (default 27MHz) +) ( + input wire clk, // System clock + inout wire sensor_pin // Bidirectional pin for trigger and echo +); + + // Timing constants based on CLK_FREQ_MHZ + 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 CYCLE_TIME_CYCLES = (60_000_000 / CLK_PERIOD_NS); // 60ms cycle time + localparam ECHO_DELAY_CYCLES = (1000 / CLK_PERIOD_NS); // 1us delay before echo (sensor processing) + + // State machine states + localparam IDLE = 3'b000, + CHECK_TRIGGER = 3'b001, + ECHO_DELAY = 3'b010, + ECHO_PULSE = 3'b011, + WAIT_CYCLE = 3'b100; + + reg [2:0] state = IDLE; + reg [31:0] counter = 0; + reg sensor_pin_prev = 0; + reg [31:0] random_distance = 0; + reg [31:0] echo_cycles = 0; + reg drive_echo = 0; // Controls when model drives sensor_pin + + // Calculate echo pulse width dynamically + // Speed of sound: 343 m/s = 0.0343 cm/us + // 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 * 1000) / 343; // Echo time in us + 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 + assign sensor_pin = drive_echo ? 1'b1 : 1'bz; + + // Main state machine + always @(posedge clk) begin + // Store previous sensor_pin value for edge detection + sensor_pin_prev <= sensor_pin; + + case (state) + IDLE: begin + drive_echo <= 0; + counter <= 0; + if (sensor_pin ) begin // Rising edge of trigger + random_distance <= $urandom_range(2, 400); // Generate random distance + state <= CHECK_TRIGGER; + end + end + + CHECK_TRIGGER: begin + counter <= counter + 1; + if (!sensor_pin) begin // Trigger pulse ended + 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 + + ECHO_DELAY: begin + counter <= counter + 1; + if (counter >= ECHO_DELAY_CYCLES) begin + state <= ECHO_PULSE; + drive_echo <= 1; // Start driving sensor_pin + counter <= 0; + end + end + + ECHO_PULSE: begin + counter <= counter + 1; + if (counter >= echo_cycles) begin + drive_echo <= 0; // Stop driving sensor_pin + state <= WAIT_CYCLE; + counter <= 0; + end + end + + WAIT_CYCLE: begin + counter <= counter + 1; + if (counter >= CYCLE_TIME_CYCLES) begin + state <= IDLE; + counter <= 0; + end + end + + default: state <= IDLE; + endcase + end + +endmodule \ No newline at end of file diff --git a/Semaine_6/ULTRASON/src/verilog/ultrason_driver.v b/Semaine_6/ULTRASON/src/verilog/ultrason_driver.v new file mode 100644 index 0000000..0af2250 --- /dev/null +++ b/Semaine_6/ULTRASON/src/verilog/ultrason_driver.v @@ -0,0 +1,154 @@ +module ultrason_driver #( + parameter integer CLK_FREQ = 27_000_000 // Fréquence d'horloge en Hz +)( + input wire clk, + input wire start, + inout wire sig, // Broche bidirectionnelle vers le capteur + output reg [15:0] distance, // Distance mesurée en cm + output reg busy, + output reg done +); + reg [15:0] trig_counter = 0; + reg [31:0] echo_counter = 0; + reg [31:0] echo_div_counter = 0; + reg [15:0] distance_counter = 0; + + reg sig_out; + reg sig_dir; // 1: output, 0: input + + assign sig = sig_dir ? sig_out : 1'bz; // bz pour dire que le fpga laisse le fils libre et n'oblige pas de valeur + + reg sig_int, sig_ok; + + + localparam IDLE = 3'd0, + TRIG_HIGH = 3'd1, + TRIG_LOW = 3'd2, + WAIT_ECHO = 3'd3, + MEASURE_ECHO = 3'd4, + COMPUTE = 3'd5, + DONE = 3'd6, + WAIT_NEXT = 3'd7; + reg [2:0] state = IDLE; + + + localparam integer TRIG_PULSE_CYCLES = CLK_FREQ / 100_000; // 10us pulse + localparam integer DIST_DIVISOR = (58 * CLK_FREQ) / 1_000_000; // pour conversion us -> cm + localparam integer MAX_CM = 350; + localparam integer TIMEOUT_CYCLES = (MAX_CM * 58 * CLK_FREQ) / 1000000; + + localparam WAIT_NEXT_CYCLES = (CLK_FREQ / 1000) * 100; // 60 ms + + reg [31:0] wait_counter; + + always @(posedge clk) begin + sig_int <= sig; + sig_ok <= sig_int; + end + + always @(posedge clk) begin + busy <= (state != IDLE); + end + + always @(posedge clk) begin // FSM + + case (state) + IDLE: begin + done <= 0; + sig_out <= 0; + sig_dir <= 0; + distance <= 0; + + if (start) begin + state <= TRIG_HIGH; + trig_counter <= 0; + done <= 0; + end + end + + TRIG_HIGH: begin + sig_out <= 1; + sig_dir <= 1; + + if (trig_counter < TRIG_PULSE_CYCLES) begin + trig_counter <= trig_counter + 1; + end else begin + trig_counter <= 0; + state <= TRIG_LOW; + end + end + + TRIG_LOW: begin + sig_out <= 0; + sig_dir <= 0; // Mettre en entrée + + if (sig_ok) begin + state <= TRIG_LOW; + end else + state <= WAIT_ECHO; + end + + WAIT_ECHO: begin + if (sig_ok) begin + echo_counter <= 0; + state <= MEASURE_ECHO; + end else if (echo_counter >= TIMEOUT_CYCLES) begin + distance <= 0; + state <= DONE; + end else begin + echo_counter <= echo_counter + 1; + end + end + + MEASURE_ECHO: begin + if (sig_ok) begin + if (echo_counter < TIMEOUT_CYCLES) begin + echo_counter <= echo_counter + 1; + end else begin + state <= DONE; + end + + end else begin + state <= COMPUTE; + end + end + + COMPUTE: begin + if (echo_counter >= DIST_DIVISOR) begin + echo_counter <= echo_counter - DIST_DIVISOR; + distance_counter <= distance_counter + 1; + state <= COMPUTE; + end else begin + distance <= distance_counter; + state <= DONE; + end + end + + DONE: begin + if (start) begin + wait_counter <= 0; + state <= WAIT_NEXT; + end else begin + state <= IDLE; + end + done <= 1; + end + + WAIT_NEXT: begin + wait_counter <= wait_counter + 1; + if (wait_counter >= WAIT_NEXT_CYCLES) begin + state <= TRIG_HIGH; + trig_counter <= 0; + distance_counter <= 0; + echo_counter <= 0; + end + end + + default: begin + state <= IDLE; // Reset to IDLE state in case of an error + end + endcase + + end + +endmodule \ No newline at end of file diff --git a/Semaine_6/ULTRASON/src/verilog/ultrasonic_fpga.v b/Semaine_6/ULTRASON/src/verilog/ultrasonic_fpga.v new file mode 100644 index 0000000..c11d19e --- /dev/null +++ b/Semaine_6/ULTRASON/src/verilog/ultrasonic_fpga.v @@ -0,0 +1,152 @@ +module ultrasonic_fpga #( + parameter integer CLK_FREQ = 27_000_000 // Fréquence d'horloge en Hz +)( + input wire clk, + input wire start, + inout wire sig, // Broche bidirectionnelle vers le capteur + output reg [15:0] distance, // Distance mesurée en cm + output reg busy, + output reg done +); + reg [15:0] trig_counter = 0; + reg [31:0] echo_counter = 0; + reg [31:0] echo_div_counter = 0; + reg [15:0] distance_counter = 0; + + reg sig_out; + reg sig_dir; // 1: output, 0: input + + assign sig = sig_dir ? sig_out : 1'bz; // bz pour dire que le fpga laisse le fils libre et n'oblige pas de valeur + + reg sig_int, sig_ok; + + + localparam IDLE = 3'd0, + TRIG_HIGH = 3'd1, + TRIG_LOW = 3'd2, + WAIT_ECHO = 3'd3, + MEASURE_ECHO = 3'd4, + COMPUTE = 3'd5, + DONE = 3'd6, + WAIT_NEXT = 3'd7; + reg [2:0] state = IDLE; + + + localparam integer TRIG_PULSE_CYCLES = CLK_FREQ / 100_000; // 10us pulse + localparam integer DIST_DIVISOR = (58 * CLK_FREQ) / 1_000_000; // pour conversion us -> cm + localparam integer MAX_CM = 350; + localparam integer TIMEOUT_CYCLES = (MAX_CM * 58 * CLK_FREQ) / 1000000; + + localparam WAIT_NEXT_CYCLES = (CLK_FREQ / 1000) * 100; // 60 ms + + reg [31:0] wait_counter; + + always @(posedge clk) begin + sig_int <= sig; + sig_ok <= sig_int; + end + + always @(posedge clk) begin + busy <= (state != IDLE); + end + + always @(posedge clk) begin // FSM + + case (state) + IDLE: begin + done <= 0; + sig_out <= 0; + sig_dir <= 0; + distance <= 0; + if (start) begin + state <= TRIG_HIGH; + trig_counter <= 0; + done <= 0; + end + end + + TRIG_HIGH: begin + sig_out <= 1; + sig_dir <= 1; + if (trig_counter < TRIG_PULSE_CYCLES) begin + trig_counter <= trig_counter + 1; + end else begin + trig_counter <= 0; + state <= TRIG_LOW; + end + end + + TRIG_LOW: begin + sig_out <= 0; + sig_dir <= 0; // Mettre en entrée + + if (sig_ok) begin + state <= TRIG_LOW; + end else + state <= WAIT_ECHO; + end + + WAIT_ECHO: begin + if (sig_ok) begin + echo_counter <= 0; + state <= MEASURE_ECHO; + end else if (echo_counter >= TIMEOUT_CYCLES) begin + distance <= 0; + state <= DONE; + end else begin + echo_counter <= echo_counter + 1; + end + end + + MEASURE_ECHO: begin + if (sig_ok) begin + if (echo_counter < TIMEOUT_CYCLES) begin + echo_counter <= echo_counter + 1; + end else begin + state <= DONE; + end + + end else begin + state <= COMPUTE; + end + end + + COMPUTE: begin + if (echo_counter >= DIST_DIVISOR) begin + echo_counter <= echo_counter - DIST_DIVISOR; + distance_counter <= distance_counter + 1; + state <= COMPUTE; + end else begin + distance <= distance_counter; + state <= DONE; + end + end + + DONE: begin + if (start) begin + wait_counter <= 0; + state <= WAIT_NEXT; + end else begin + state <= IDLE; + end + done <= 1; + end + + WAIT_NEXT: begin + wait_counter <= wait_counter + 1; + if (wait_counter >= WAIT_NEXT_CYCLES) begin + state <= TRIG_HIGH; + trig_counter <= 0; + distance_counter <= 0; + echo_counter <= 0; + end + end + + default: begin + state <= IDLE; // Reset to IDLE state in case of an error + end + endcase + + end + +endmodule \ No newline at end of file diff --git a/Semaine_6/ULTRASON/tests/verilog/hc_sr04_tb.v b/Semaine_6/ULTRASON/tests/verilog/hc_sr04_tb.v new file mode 100644 index 0000000..6927fdb --- /dev/null +++ b/Semaine_6/ULTRASON/tests/verilog/hc_sr04_tb.v @@ -0,0 +1,131 @@ +`timescale 1ns/1ps + +module hc_sr04_tb; + + // === Signaux === + reg clk = 0; + reg start = 0; + wire sensor_pin; // Signal bidirectionnel entre driver et capteur + wire [15:0] distance; + wire busy; + wire done; + + // === Paramètres === + localparam CLK_FREQ = 27_000_000; // 27 MHz + localparam CLK_PERIOD = 37; // Période en ns (~37 ns pour 27 MHz) + + // Génération de l'horloge 27 MHz + always #(CLK_PERIOD/2) clk = ~clk; + + // === Instanciation des modules === + + // Capteur HC-SR04 simulé + hc_sr04_model #( + .CLK_FREQ_MHZ(27) + ) fake_sensor ( + .clk(clk), + .sensor_pin(sensor_pin) + ); + + // Driver pour contrôler le capteur + ultrason_driver #( + .CLK_FREQ(CLK_FREQ) + ) driver ( + .clk(clk), + .start(start), + .sig(sensor_pin), + .distance(distance), + .busy(busy), + .done(done) + ); + + // === Tâches pour simplifier les tests === + + // Tâche pour déclencher une mesure + task trigger_measurement; + begin + $display("[%0t ns] Déclenchement d'une mesure", $time); + start = 1; + #(CLK_PERIOD * 2); + start = 0; + // Attendre que la mesure soit terminée + wait(done); + $display("[%0t ns] Mesure terminée, distance=%0d, busy=%b", $time, distance, busy); + end + endtask + + // Tâche pour vérifier la distance + task check_distance(input [15:0] expected_distance); + begin + if (distance == expected_distance) begin + $display("[%0t ns] Distance correcte: %0d", $time, distance); + end else begin + $display("[%0t ns] ERREUR: Distance reçue=%0d, attendu=%0d", $time, distance, expected_distance); + end + end + endtask + + // === Stimulus de test === + initial begin + $dumpfile("runs/sim.vcd"); + $dumpvars(0, hc_sr04_tb); + + $display("==== Début Test HC-SR04 ===="); + + // Initialisation + #(CLK_PERIOD * 10); + + // Test 1: Mesure unique + $display("=== Test 1: Mesure unique ==="); + trigger_measurement(); + // Supposons que hc_sr04_model simule une distance fixe, par exemple 1000 (à ajuster) + check_distance(16'd1000); + + // Test 2: Mesures multiples + $display("=== Test 2: Mesures multiples ==="); + repeat (3) begin + #(CLK_PERIOD * 1000); // Attendre entre mesures + trigger_measurement(); + check_distance(16'd1000); + end + + // Test 3: Vérification de busy + $display("=== Test 3: Vérification de busy ==="); + start = 1; + #(CLK_PERIOD * 2); + start = 0; + #(CLK_PERIOD * 10); + if (busy) begin + $display("[%0t ns] Busy actif pendant la mesure, OK", $time); + end else begin + $display("[%0t ns] ERREUR: Busy devrait être actif", $time); + end + wait(done); + if (!busy) begin + $display("[%0t ns] Busy inactif après done, OK", $time); + end else begin + $display("[%0t ns] ERREUR: Busy devrait être inactif", $time); + end + + // Test 4: Pas de déclenchement + $display("=== Test 4: Pas de déclenchement ==="); + #(CLK_PERIOD * 10000); + if (!busy && !done) begin + $display("[%0t ns] Aucune activité sans déclenchement, OK", $time); + end else begin + $display("[%0t ns] ERREUR: Activité détectée sans déclenchement", $time); + end + + // Fin de la simulation + $display("==== Fin Test HC-SR04 ===="); + #(CLK_PERIOD * 1000); + $finish; + end + + // === Surveillance des signaux === + initial begin + $monitor("[%0t ns] sensor_pin=%b, start=%b, busy=%b, done=%b, distance=%0d", + $time, sensor_pin, start, busy, done, distance); + end + +endmodule \ No newline at end of file