From a02d6e7d2274ecfa9840b57f42e325bb0cc9958a Mon Sep 17 00:00:00 2001 From: Gamenight77 Date: Sun, 25 May 2025 19:04:56 +0200 Subject: [PATCH] init semaine 7 --- Semaine_7/DHT11/.gitignore | 5 + Semaine_7/DHT11/README.md | 9 + .../DHT11/constraints/dht11_interface.cst | 24 + Semaine_7/DHT11/project.bat | 9 + Semaine_7/DHT11/project.sh | 24 + Semaine_7/DHT11/scripts/linux/build.sh | 46 ++ Semaine_7/DHT11/scripts/linux/clean.sh | 4 + Semaine_7/DHT11/scripts/linux/gtkwave.sh | 5 + Semaine_7/DHT11/scripts/linux/simulate.sh | 17 + Semaine_7/DHT11/scripts/windows/build.bat | 45 ++ Semaine_7/DHT11/scripts/windows/clean.bat | 4 + Semaine_7/DHT11/scripts/windows/gtkwave.bat | 3 + Semaine_7/DHT11/scripts/windows/simulate.bat | 29 ++ Semaine_7/DHT11/src/verilog/dht11_interface.v | 213 ++++++++ Semaine_7/DHT11/src/verilog/dht11_model.v | 174 +++++++ Semaine_7/DHT11/tests/verilog/tb_dht11.v | 65 +++ Semaine_7/DHT11_UART/.gitignore | 5 + .../DHT11_UART/IP/verilog/dht11_interface.v | 213 ++++++++ Semaine_7/DHT11_UART/IP/verilog/fifo.v | 48 ++ Semaine_7/DHT11_UART/IP/verilog/txuartlite.v | 472 ++++++++++++++++++ .../DHT11_UART/IP/verilog/uart_tx_fifo.v | 89 ++++ Semaine_7/DHT11_UART/README.md | 9 + .../DHT11_UART/constraints/dht11_uart_top.cst | 8 + Semaine_7/DHT11_UART/project.bat | 9 + Semaine_7/DHT11_UART/project.sh | 24 + Semaine_7/DHT11_UART/scripts/linux/build.sh | 46 ++ Semaine_7/DHT11_UART/scripts/linux/clean.sh | 4 + Semaine_7/DHT11_UART/scripts/linux/gtkwave.sh | 5 + .../DHT11_UART/scripts/linux/simulate.sh | 17 + Semaine_7/DHT11_UART/scripts/linux/upload.sh | 25 + .../DHT11_UART/scripts/windows/build.bat | 45 ++ .../DHT11_UART/scripts/windows/clean.bat | 4 + .../DHT11_UART/scripts/windows/gtkwave.bat | 3 + .../DHT11_UART/scripts/windows/simulate.bat | 29 ++ .../DHT11_UART/src/verilog/dht11_uart_top.v | 104 ++++ Semaine_7/DHT11_UART/tests/verilog/tb_dht11.v | 65 +++ 36 files changed, 1900 insertions(+) create mode 100644 Semaine_7/DHT11/.gitignore create mode 100644 Semaine_7/DHT11/README.md create mode 100644 Semaine_7/DHT11/constraints/dht11_interface.cst create mode 100644 Semaine_7/DHT11/project.bat create mode 100644 Semaine_7/DHT11/project.sh create mode 100644 Semaine_7/DHT11/scripts/linux/build.sh create mode 100644 Semaine_7/DHT11/scripts/linux/clean.sh create mode 100644 Semaine_7/DHT11/scripts/linux/gtkwave.sh create mode 100644 Semaine_7/DHT11/scripts/linux/simulate.sh create mode 100644 Semaine_7/DHT11/scripts/windows/build.bat create mode 100644 Semaine_7/DHT11/scripts/windows/clean.bat create mode 100644 Semaine_7/DHT11/scripts/windows/gtkwave.bat create mode 100644 Semaine_7/DHT11/scripts/windows/simulate.bat create mode 100644 Semaine_7/DHT11/src/verilog/dht11_interface.v create mode 100644 Semaine_7/DHT11/src/verilog/dht11_model.v create mode 100644 Semaine_7/DHT11/tests/verilog/tb_dht11.v create mode 100644 Semaine_7/DHT11_UART/.gitignore create mode 100644 Semaine_7/DHT11_UART/IP/verilog/dht11_interface.v create mode 100644 Semaine_7/DHT11_UART/IP/verilog/fifo.v create mode 100644 Semaine_7/DHT11_UART/IP/verilog/txuartlite.v create mode 100644 Semaine_7/DHT11_UART/IP/verilog/uart_tx_fifo.v create mode 100644 Semaine_7/DHT11_UART/README.md create mode 100644 Semaine_7/DHT11_UART/constraints/dht11_uart_top.cst create mode 100644 Semaine_7/DHT11_UART/project.bat create mode 100644 Semaine_7/DHT11_UART/project.sh create mode 100644 Semaine_7/DHT11_UART/scripts/linux/build.sh create mode 100644 Semaine_7/DHT11_UART/scripts/linux/clean.sh create mode 100644 Semaine_7/DHT11_UART/scripts/linux/gtkwave.sh create mode 100644 Semaine_7/DHT11_UART/scripts/linux/simulate.sh create mode 100644 Semaine_7/DHT11_UART/scripts/linux/upload.sh create mode 100644 Semaine_7/DHT11_UART/scripts/windows/build.bat create mode 100644 Semaine_7/DHT11_UART/scripts/windows/clean.bat create mode 100644 Semaine_7/DHT11_UART/scripts/windows/gtkwave.bat create mode 100644 Semaine_7/DHT11_UART/scripts/windows/simulate.bat create mode 100644 Semaine_7/DHT11_UART/src/verilog/dht11_uart_top.v create mode 100644 Semaine_7/DHT11_UART/tests/verilog/tb_dht11.v diff --git a/Semaine_7/DHT11/.gitignore b/Semaine_7/DHT11/.gitignore new file mode 100644 index 0000000..029ea4f --- /dev/null +++ b/Semaine_7/DHT11/.gitignore @@ -0,0 +1,5 @@ +runs +.vscode +workspace.code-workspace +*.pyc +.idea \ No newline at end of file diff --git a/Semaine_7/DHT11/README.md b/Semaine_7/DHT11/README.md new file mode 100644 index 0000000..34702e3 --- /dev/null +++ b/Semaine_7/DHT11/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_7/DHT11/constraints/dht11_interface.cst b/Semaine_7/DHT11/constraints/dht11_interface.cst new file mode 100644 index 0000000..110a02b --- /dev/null +++ b/Semaine_7/DHT11/constraints/dht11_interface.cst @@ -0,0 +1,24 @@ +IO_LOC "tx" 69; +IO_PORT "tx" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3; + +IO_LOC "rx" 70; +IO_PORT "rx" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3; + +IO_LOC "clk" 4; +IO_PORT "clk" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3; + +IO_LOC "ultrason_sig" 73; +IO_PORT "ultrason_sig" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3; + +IO_LOC "leds[0]" 15; +IO_PORT "leds[0]" PULL_MODE=UP DRIVE=8 BANK_VCCIO=1.8; +IO_LOC "leds[1]" 16; +IO_PORT "leds[1]" PULL_MODE=UP DRIVE=8 BANK_VCCIO=1.8; +IO_LOC "leds[2]" 17; +IO_PORT "leds[2]" PULL_MODE=UP DRIVE=8 BANK_VCCIO=1.8; +IO_LOC "leds[3]" 18; +IO_PORT "leds[3]" PULL_MODE=UP DRIVE=8 BANK_VCCIO=1.8; +IO_LOC "leds[4]" 19; +IO_PORT "leds[4]" PULL_MODE=UP DRIVE=8 BANK_VCCIO=1.8; +IO_LOC "leds[5]" 20; +IO_PORT "leds[5]" PULL_MODE=UP DRIVE=8 BANK_VCCIO=1.8; \ No newline at end of file diff --git a/Semaine_7/DHT11/project.bat b/Semaine_7/DHT11/project.bat new file mode 100644 index 0000000..987449a --- /dev/null +++ b/Semaine_7/DHT11/project.bat @@ -0,0 +1,9 @@ +@call c:\oss-cad-suite\environment.bat +@echo off + +mkdir runs + +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_7/DHT11/project.sh b/Semaine_7/DHT11/project.sh new file mode 100644 index 0000000..c759d7c --- /dev/null +++ b/Semaine_7/DHT11/project.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Charger l'environnement OSS CAD Suite +source /home/louis/oss-cad-suite/environment + +mkdir -p runs + +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_7/DHT11/scripts/linux/build.sh b/Semaine_7/DHT11/scripts/linux/build.sh new file mode 100644 index 0000000..3c59fe2 --- /dev/null +++ b/Semaine_7/DHT11/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_7/DHT11/scripts/linux/clean.sh b/Semaine_7/DHT11/scripts/linux/clean.sh new file mode 100644 index 0000000..a505cb7 --- /dev/null +++ b/Semaine_7/DHT11/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_7/DHT11/scripts/linux/gtkwave.sh b/Semaine_7/DHT11/scripts/linux/gtkwave.sh new file mode 100644 index 0000000..f623377 --- /dev/null +++ b/Semaine_7/DHT11/scripts/linux/gtkwave.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +echo "=== Lancement de GTKWave ===" +gtkwave runs/sim.vcd +echo "=== GTKWave terminé ===" \ No newline at end of file diff --git a/Semaine_7/DHT11/scripts/linux/simulate.sh b/Semaine_7/DHT11/scripts/linux/simulate.sh new file mode 100644 index 0000000..24d3f6e --- /dev/null +++ b/Semaine_7/DHT11/scripts/linux/simulate.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +echo "=== Simulation avec Icarus Verilog ===" + +OUT="runs/sim.vvp" +TOP="tb_dht11" +DIRS=("src/verilog" "tests/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_7/DHT11/scripts/windows/build.bat b/Semaine_7/DHT11/scripts/windows/build.bat new file mode 100644 index 0000000..89520d5 --- /dev/null +++ b/Semaine_7/DHT11/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/fifo.v IP/verilog/uart_tx.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_7/DHT11/scripts/windows/clean.bat b/Semaine_7/DHT11/scripts/windows/clean.bat new file mode 100644 index 0000000..6192ae1 --- /dev/null +++ b/Semaine_7/DHT11/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_7/DHT11/scripts/windows/gtkwave.bat b/Semaine_7/DHT11/scripts/windows/gtkwave.bat new file mode 100644 index 0000000..0b86154 --- /dev/null +++ b/Semaine_7/DHT11/scripts/windows/gtkwave.bat @@ -0,0 +1,3 @@ +@echo off +echo === Lancement de GTKWave === +gtkwave runs/sim.vcd diff --git a/Semaine_7/DHT11/scripts/windows/simulate.bat b/Semaine_7/DHT11/scripts/windows/simulate.bat new file mode 100644 index 0000000..fbe0ee2 --- /dev/null +++ b/Semaine_7/DHT11/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=tb_dht11 + +:: 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_7/DHT11/src/verilog/dht11_interface.v b/Semaine_7/DHT11/src/verilog/dht11_interface.v new file mode 100644 index 0000000..a395468 --- /dev/null +++ b/Semaine_7/DHT11/src/verilog/dht11_interface.v @@ -0,0 +1,213 @@ +module dht11_interface #( + parameter CLK_FREQ = 27_000_000 +)( + input wire i_clk, + inout wire io_dht11_sig, + input wire i_start, + output reg o_dht11_data_ready, + output reg o_busy, + output reg [7:0] o_temp_data, + output reg [7:0] o_hum_data, + output reg o_dht11_error +); + + // === DHT11 INTERFACE === + + // === PARAMÈTRES === + localparam T_18MS = CLK_FREQ * 18 / 1_000; // cycles pour 18ms a partir + localparam T_80US = CLK_FREQ * 81 / 1_000_000; + localparam T_79US = CLK_FREQ * 79 / 1_000_000; + localparam T_71US = CLK_FREQ * 71 / 1_000_000; + localparam T_51US = CLK_FREQ * 51 / 1_000_000; + localparam T_50US = CLK_FREQ * 50 / 1_000_000; + localparam T_49US = CLK_FREQ * 49 / 1_000_000; + localparam T_41US = CLK_FREQ * 41 / 1_000_000; + localparam T_28US = CLK_FREQ * 28 / 1_000_000; + localparam T_26US = CLK_FREQ * 26 / 1_000_000; + localparam T_20US = CLK_FREQ * 20 / 1_000_000; + + + // === Signal bidirectionnel === + reg sig_dir; + reg sig_out; + wire sig_in; + + assign io_dht11_sig = sig_dir ? sig_out : 1'bz; // Si sig_dir = 1, on force la valeur de sig_out sur la ligne, sinon on laisse la ligne libre (1'bz) + assign sig_in = io_dht11_sig; + + // === REGISTRES === + reg [3:0] state; + reg [31:0] timer; + + reg [7:0] temp_data, hum_data; + reg [7:0] temp_dec, hum_dec, checksum; + reg [2:0] bit_count; + reg [5:0] bit_index; + reg [39:0] raw_data; + + // === FSM === + localparam IDLE = 4'd0, // Pull up la ligne + START = 4'd1, // Pull low 18ms + WAIT_RESPONSE = 4'd2, // Release la ligne (entre 20 et 40us) + RESPONSE_LOW = 4'd3, // DHT11 pull low 80us + RESPONSE_HIGH = 4'd4, // DHT11 pull high 80us + READ_BITS_LOW = 4'd5, + READ_BITS_HIGH = 4'd6, + DONE = 4'd7, + ERROR = 4'd8; + + // === INITIALISATION === + initial begin + sig_dir = 0; + sig_out = 1; + timer = 0; + state = IDLE; + bit_index = 0; + raw_data = 0; + o_dht11_data_ready = 0; + o_dht11_error = 0; + end + + // === FSM principale === + always @(posedge i_clk) begin + case (state) + + IDLE: begin + sig_dir <= 0; + //sig_out <= 1; + timer <= 0; + bit_index <= 0; + raw_data <= 0; + + o_busy <= 0; + + if (i_start) begin + sig_dir <= 1; + sig_out <= 0; + timer <= 0; + o_busy <= 1; + state <= START; + o_dht11_data_ready <= 0; + o_dht11_error <= 0; + end + end + + START: begin + timer <= timer + 1; + if (timer >= T_18MS) begin + sig_dir <= 0; // libérer la ligne + timer <= 0; + state <= WAIT_RESPONSE; + end + end + + WAIT_RESPONSE: begin + timer <= timer + 1; + + if (sig_in == 0) begin + if (timer > T_20US && timer < T_41US) begin + + state <= RESPONSE_LOW; + timer <= 0; + end else begin + state <= ERROR; + end + end else if (timer > T_41US) begin + state <= ERROR; + end + end + + RESPONSE_LOW: begin + timer <= timer + 1; + + if (sig_in == 1) begin + if (timer > T_79US && timer < T_80US) begin + timer <= 0; + state <= RESPONSE_HIGH; + end else begin + state <= ERROR; + end + end else if (timer > T_80US) begin + state <= ERROR; + end + end + + RESPONSE_HIGH: begin + timer <= timer + 1; + + if (sig_in == 0) begin + if (timer > T_79US && timer < T_80US) begin + timer <= 0; + state <= READ_BITS_LOW; + end else begin + state <= ERROR; + end + end else if (timer > T_80US) begin + state <= ERROR; + end + end + + READ_BITS_LOW: begin + timer <= timer + 1; + if (sig_in == 1) begin + if (timer > T_49US && timer < T_51US) begin + timer <= 0; + state <= READ_BITS_HIGH; + end else begin + state <= ERROR; + end + end else if (timer > T_51US) begin + state <= ERROR; + end + end + + READ_BITS_HIGH: begin // entre 26 et 28us = 0 et ~70us = 1 + timer <= timer + 1; + if (sig_in == 0) begin + if (timer <= T_26US) begin + state <= ERROR; + end + + raw_data <= {raw_data[38:0], (timer > T_28US)}; // 1 si high > ~28us + timer <= 0; + bit_index <= bit_index + 1; + + if (bit_index == 39) begin // Code a testé ici pour etre sur de capter le dernier bit + state <= DONE; + end else begin + state <= READ_BITS_LOW; + end + + end else if (timer > T_71US) begin + state <= ERROR; + end + end + + DONE: begin + hum_data <= raw_data[39:32]; + hum_dec <= raw_data[31:24]; + temp_data <= raw_data[23:16]; + temp_dec <= raw_data[15:8]; + checksum <= raw_data[7:0]; + + if (raw_data[7:0] == (raw_data[39:32] + raw_data[31:24] + raw_data[23:16] + raw_data[15:8])) begin + o_hum_data <= raw_data[39:32]; + o_temp_data <= raw_data[23:16]; + o_dht11_data_ready <= 1; + end else begin + o_dht11_error <= 1; + end + + o_busy <= 0; + state <= IDLE; + end + + ERROR: begin + o_dht11_error <= 1; + state <= IDLE; + end + + endcase + end + +endmodule diff --git a/Semaine_7/DHT11/src/verilog/dht11_model.v b/Semaine_7/DHT11/src/verilog/dht11_model.v new file mode 100644 index 0000000..e233250 --- /dev/null +++ b/Semaine_7/DHT11/src/verilog/dht11_model.v @@ -0,0 +1,174 @@ +module dht11_model #( + parameter CLK_FREQ = 27_000_000 +) +( + inout wire data, // Ligne de données bidirectionnelle + input wire clk, // Horloge système (27 MHz) + input wire rst_n // Reset actif bas +); + + // Paramètres pour les timings (basés sur une horloge de 27 MHz, période ~37 ns) + localparam integer CLK_PERIOD_NS = (1_000_000_000 / CLK_FREQ); // 37 ns + localparam T_START_LOW = (17_000_000 / CLK_PERIOD_NS); // 17 ms (ajusté selon votre code) + localparam T_START_HIGH = (40_000 / CLK_PERIOD_NS); // 40 µs + localparam T_RESP_LOW = (80_000 / CLK_PERIOD_NS); // 80 µs + localparam T_RESP_HIGH = (80_000 / CLK_PERIOD_NS); // 80 µs + localparam T_BIT_LOW = (50_000 / CLK_PERIOD_NS); // 50 µs pour le signal LOW de chaque bit + localparam T_BIT0_HIGH = (27_000 / CLK_PERIOD_NS); // 26 µs pour le signal HIGH d'un bit '0' + localparam T_BIT1_HIGH = (70_000 / CLK_PERIOD_NS); // 70 µs pour le signal HIGH d'un bit '1' + localparam T_BIT_GAP = (50_000 / CLK_PERIOD_NS); // 50 µs entre bits + localparam DATA_BITS = 40; // 40 bits de données + + // États de la machine à états de Moore + localparam IDLE = 4'd0, + WAIT_START_LOW = 4'd1, + WAIT_START_HIGH= 4'd2, + RESPONSE_LOW = 4'd3, + RESPONSE_HIGH = 4'd4, + SEND_BIT_LOW = 4'd5, + SEND_BIT_HIGH = 4'd6, + END_TRANS = 4'd7, + LAST_BIT_LOW = 4'd8; + + // Signaux internes + reg [3:0] state; // État actuel + reg [31:0] counter; // Compteur pour les timings (supporte jusqu'à 20 ms) + reg [5:0] bit_index; // Index du bit à envoyer + reg data_out; // Valeur de sortie sur la ligne data + reg data_oe; // Output enable (1 = sortie, 0 = haute impédance) + wire data_in; // Valeur lue sur la ligne data + + // Données simulées (exemple : humidité = 45.0%, température = 23.0°C) + reg [7:0] humidity_int = 8'h2D; // 45 en décimal + reg [7:0] humidity_dec = 8'h00; // 0 + reg [7:0] temp_int = 8'h17; // 23 en décimal + reg [7:0] temp_dec = 8'h00; // 0 + reg [7:0] checksum; // Checksum + reg [39:0] data_shift; // Registre pour les 40 bits de données + + // Gestion de la ligne bidirectionnelle + assign data = data_oe ? data_out : 1'bz; + assign data_in = data; + + // Calcul du checksum et préparation des données + always @(posedge clk or negedge rst_n) begin + if (!rst_n) begin + checksum <= 8'h00; + data_shift <= 40'b0; + end else begin + checksum <= humidity_int + humidity_dec + temp_int + temp_dec; + data_shift <= {humidity_int, humidity_dec, temp_int, temp_dec, checksum}; + end + end + + // Logique séquentielle (machine à états de Moore) + always @(posedge clk or negedge rst_n) begin + if (!rst_n) begin + state <= IDLE; + counter <= 32'b0; + bit_index <= 6'b0; + data_out <= 1'b1; + data_oe <= 1'b0; + end else begin + counter <= counter + 1; // Incrément du compteur par défaut + // assert (bit_index < DATA_BITS) else $error("Index out of bounds: %d", bit_index); + + case (state) + IDLE: begin + counter <= 32'b0; + bit_index <= 6'b0; + data_out <= 1'b1; + data_oe <= 1'b0; + if (data_in === 1'b0) begin + state <= WAIT_START_LOW; + end + end + WAIT_START_LOW: begin + data_out <= 1'b1; + data_oe <= 1'b0; + if (data_in === 1'b1 && counter >= T_START_LOW) begin + state <= WAIT_START_HIGH; + counter <= 32'b0; + $display("17ms"); + end else if (data_in === 1'b1) begin + state <= IDLE; // Signal de démarrage trop court + end + end + WAIT_START_HIGH: begin + data_out <= 1'b1; + data_oe <= 1'b0; + if (counter >= T_START_HIGH) begin + state <= RESPONSE_LOW; + counter <= 32'b0; + end + end + RESPONSE_LOW: begin + data_out <= 1'b0; + data_oe <= 1'b1; + if (counter >= T_RESP_LOW) begin + state <= RESPONSE_HIGH; + counter <= 32'b0; + end + end + RESPONSE_HIGH: begin + data_out <= 1'b1; + data_oe <= 1'b1; + if (counter >= T_RESP_HIGH) begin + counter <= 32'b0; + state <= SEND_BIT_LOW; + end + end + SEND_BIT_LOW: begin + + data_out <= 1'b0; + data_oe <= 1'b1; + if (counter >= T_BIT_LOW) begin + state <= SEND_BIT_HIGH; + counter <= 32'b0; + end + end + SEND_BIT_HIGH: begin + data_out <= 1'b1; + data_oe <= 1'b1; + + if (counter >= (data_shift[39-bit_index] ? T_BIT1_HIGH : T_BIT0_HIGH)) begin + counter <= 32'b0; + bit_index <= bit_index + 1; + if (bit_index + 1 < DATA_BITS) begin + state <= SEND_BIT_LOW; + + end else begin + state <= LAST_BIT_LOW; + bit_index <= 6'b0; + counter <= 32'b0; + end + end + end + + LAST_BIT_LOW: begin + data_out <= 1'b0; + data_oe <= 1'b1; + if (counter >= T_BIT_LOW) begin + state <= END_TRANS; + counter <= 32'b0; + end + end + + + END_TRANS: begin + data_out <= 1'b1; + data_oe <= 1'b0; + counter <= 32'b0; + state <= IDLE; + end + default: begin + state <= IDLE; + counter <= 32'b0; + data_out <= 1'b1; + data_oe <= 1'b0; + end + endcase + end + end + +endmodule \ No newline at end of file diff --git a/Semaine_7/DHT11/tests/verilog/tb_dht11.v b/Semaine_7/DHT11/tests/verilog/tb_dht11.v new file mode 100644 index 0000000..82a8f5f --- /dev/null +++ b/Semaine_7/DHT11/tests/verilog/tb_dht11.v @@ -0,0 +1,65 @@ +`timescale 1ns/1ps + +module tb_dht11; + + reg clk = 0; + always #18.5 clk = ~clk; // Génère une clock 27 MHz + + // === Registres === + wire io_dht11_sig; + reg dht11_start; + wire dht11_data_ready; + wire dht11_busy; + wire [7:0] dht11_temp_data; + wire [7:0] dht11_hum_data; + wire dht11_error; + + // === Simulation du module DHT11 === + dht11_model dht11_model ( + .data(io_dht11_sig), + .clk(clk), + .rst_n(1'b1) // Reset non utilisé dans ce test + ); + + // === Module DHT11 INTERFACE === + dht11_interface dht11_interface ( + .i_clk(clk), + .io_dht11_sig(io_dht11_sig), + .i_start(dht11_start), + .o_dht11_data_ready(dht11_data_ready), + .o_busy(dht11_busy), + .o_temp_data(dht11_temp_data), + .o_hum_data(dht11_hum_data), + .o_dht11_error(dht11_error) + ); + + pullup(io_dht11_sig); + + // === TEST SEQUENCE === + initial begin + $dumpfile("runs/sim.vcd"); + $dumpvars(0, tb_dht11); + dht11_start = 0; + + $display("==== Start DHT11 Test ===="); + + #100; + dht11_start = 1; // Démarre la lecture des données + $display("DHT11 start..."); + + wait(dht11_busy); // Attend que le module soit occupé + $display("DHT11 busy..."); + + dht11_start = 0; + + wait(dht11_data_ready); // Attend que les données soient prêtes + $display("DHT11 data ready..."); + + $display("Température : %d.%d °C", dht11_temp_data); + $display("Humidité : %d.%d %%", dht11_hum_data); + + $display("==== End DHT11 Test ===="); + $finish; + end + +endmodule \ No newline at end of file diff --git a/Semaine_7/DHT11_UART/.gitignore b/Semaine_7/DHT11_UART/.gitignore new file mode 100644 index 0000000..029ea4f --- /dev/null +++ b/Semaine_7/DHT11_UART/.gitignore @@ -0,0 +1,5 @@ +runs +.vscode +workspace.code-workspace +*.pyc +.idea \ No newline at end of file diff --git a/Semaine_7/DHT11_UART/IP/verilog/dht11_interface.v b/Semaine_7/DHT11_UART/IP/verilog/dht11_interface.v new file mode 100644 index 0000000..a395468 --- /dev/null +++ b/Semaine_7/DHT11_UART/IP/verilog/dht11_interface.v @@ -0,0 +1,213 @@ +module dht11_interface #( + parameter CLK_FREQ = 27_000_000 +)( + input wire i_clk, + inout wire io_dht11_sig, + input wire i_start, + output reg o_dht11_data_ready, + output reg o_busy, + output reg [7:0] o_temp_data, + output reg [7:0] o_hum_data, + output reg o_dht11_error +); + + // === DHT11 INTERFACE === + + // === PARAMÈTRES === + localparam T_18MS = CLK_FREQ * 18 / 1_000; // cycles pour 18ms a partir + localparam T_80US = CLK_FREQ * 81 / 1_000_000; + localparam T_79US = CLK_FREQ * 79 / 1_000_000; + localparam T_71US = CLK_FREQ * 71 / 1_000_000; + localparam T_51US = CLK_FREQ * 51 / 1_000_000; + localparam T_50US = CLK_FREQ * 50 / 1_000_000; + localparam T_49US = CLK_FREQ * 49 / 1_000_000; + localparam T_41US = CLK_FREQ * 41 / 1_000_000; + localparam T_28US = CLK_FREQ * 28 / 1_000_000; + localparam T_26US = CLK_FREQ * 26 / 1_000_000; + localparam T_20US = CLK_FREQ * 20 / 1_000_000; + + + // === Signal bidirectionnel === + reg sig_dir; + reg sig_out; + wire sig_in; + + assign io_dht11_sig = sig_dir ? sig_out : 1'bz; // Si sig_dir = 1, on force la valeur de sig_out sur la ligne, sinon on laisse la ligne libre (1'bz) + assign sig_in = io_dht11_sig; + + // === REGISTRES === + reg [3:0] state; + reg [31:0] timer; + + reg [7:0] temp_data, hum_data; + reg [7:0] temp_dec, hum_dec, checksum; + reg [2:0] bit_count; + reg [5:0] bit_index; + reg [39:0] raw_data; + + // === FSM === + localparam IDLE = 4'd0, // Pull up la ligne + START = 4'd1, // Pull low 18ms + WAIT_RESPONSE = 4'd2, // Release la ligne (entre 20 et 40us) + RESPONSE_LOW = 4'd3, // DHT11 pull low 80us + RESPONSE_HIGH = 4'd4, // DHT11 pull high 80us + READ_BITS_LOW = 4'd5, + READ_BITS_HIGH = 4'd6, + DONE = 4'd7, + ERROR = 4'd8; + + // === INITIALISATION === + initial begin + sig_dir = 0; + sig_out = 1; + timer = 0; + state = IDLE; + bit_index = 0; + raw_data = 0; + o_dht11_data_ready = 0; + o_dht11_error = 0; + end + + // === FSM principale === + always @(posedge i_clk) begin + case (state) + + IDLE: begin + sig_dir <= 0; + //sig_out <= 1; + timer <= 0; + bit_index <= 0; + raw_data <= 0; + + o_busy <= 0; + + if (i_start) begin + sig_dir <= 1; + sig_out <= 0; + timer <= 0; + o_busy <= 1; + state <= START; + o_dht11_data_ready <= 0; + o_dht11_error <= 0; + end + end + + START: begin + timer <= timer + 1; + if (timer >= T_18MS) begin + sig_dir <= 0; // libérer la ligne + timer <= 0; + state <= WAIT_RESPONSE; + end + end + + WAIT_RESPONSE: begin + timer <= timer + 1; + + if (sig_in == 0) begin + if (timer > T_20US && timer < T_41US) begin + + state <= RESPONSE_LOW; + timer <= 0; + end else begin + state <= ERROR; + end + end else if (timer > T_41US) begin + state <= ERROR; + end + end + + RESPONSE_LOW: begin + timer <= timer + 1; + + if (sig_in == 1) begin + if (timer > T_79US && timer < T_80US) begin + timer <= 0; + state <= RESPONSE_HIGH; + end else begin + state <= ERROR; + end + end else if (timer > T_80US) begin + state <= ERROR; + end + end + + RESPONSE_HIGH: begin + timer <= timer + 1; + + if (sig_in == 0) begin + if (timer > T_79US && timer < T_80US) begin + timer <= 0; + state <= READ_BITS_LOW; + end else begin + state <= ERROR; + end + end else if (timer > T_80US) begin + state <= ERROR; + end + end + + READ_BITS_LOW: begin + timer <= timer + 1; + if (sig_in == 1) begin + if (timer > T_49US && timer < T_51US) begin + timer <= 0; + state <= READ_BITS_HIGH; + end else begin + state <= ERROR; + end + end else if (timer > T_51US) begin + state <= ERROR; + end + end + + READ_BITS_HIGH: begin // entre 26 et 28us = 0 et ~70us = 1 + timer <= timer + 1; + if (sig_in == 0) begin + if (timer <= T_26US) begin + state <= ERROR; + end + + raw_data <= {raw_data[38:0], (timer > T_28US)}; // 1 si high > ~28us + timer <= 0; + bit_index <= bit_index + 1; + + if (bit_index == 39) begin // Code a testé ici pour etre sur de capter le dernier bit + state <= DONE; + end else begin + state <= READ_BITS_LOW; + end + + end else if (timer > T_71US) begin + state <= ERROR; + end + end + + DONE: begin + hum_data <= raw_data[39:32]; + hum_dec <= raw_data[31:24]; + temp_data <= raw_data[23:16]; + temp_dec <= raw_data[15:8]; + checksum <= raw_data[7:0]; + + if (raw_data[7:0] == (raw_data[39:32] + raw_data[31:24] + raw_data[23:16] + raw_data[15:8])) begin + o_hum_data <= raw_data[39:32]; + o_temp_data <= raw_data[23:16]; + o_dht11_data_ready <= 1; + end else begin + o_dht11_error <= 1; + end + + o_busy <= 0; + state <= IDLE; + end + + ERROR: begin + o_dht11_error <= 1; + state <= IDLE; + end + + endcase + end + +endmodule diff --git a/Semaine_7/DHT11_UART/IP/verilog/fifo.v b/Semaine_7/DHT11_UART/IP/verilog/fifo.v new file mode 100644 index 0000000..82915e2 --- /dev/null +++ b/Semaine_7/DHT11_UART/IP/verilog/fifo.v @@ -0,0 +1,48 @@ + module fifo #( + parameter SIZE = 16, + parameter WIDTH = 8 +)( + input wire clk, + input wire wr_en, + input wire[WIDTH-1:0] wr_data, + input wire rd_en, + output reg[WIDTH-1:0] rd_data, + + output wire full, + output wire empty +); + + localparam LOGSIZE = $clog2(SIZE); + + reg [WIDTH-1:0] fifo[0:SIZE-1]; + reg [LOGSIZE-1:0] wr_ptr; + reg [LOGSIZE-1:0] rd_ptr; + reg [LOGSIZE:0] count; + + assign full = (count == SIZE); + assign empty = (count == 0); + + initial begin + wr_ptr = 0; + rd_ptr = 0; + count = 0; + end + + always @(posedge clk) begin // IN + rd_data <= fifo[rd_ptr]; + if (wr_en && !full && rd_en && !empty) begin + fifo[wr_ptr] <= wr_data; + wr_ptr <= (wr_ptr == SIZE - 1) ? 0 : (wr_ptr + 1) ; + rd_ptr <= (rd_ptr == SIZE - 1) ? 0 : (rd_ptr + 1) ; + end else if (wr_en && !full) begin + fifo[wr_ptr] <= wr_data; + wr_ptr <= (wr_ptr == SIZE - 1) ? 0 : (wr_ptr + 1) ; + count <= count + 1; + end else if (rd_en && !empty) begin // OUT + rd_ptr <= (rd_ptr == SIZE - 1) ? 0 : (rd_ptr + 1) ; + count <= count - 1; + end + + end + +endmodule diff --git a/Semaine_7/DHT11_UART/IP/verilog/txuartlite.v b/Semaine_7/DHT11_UART/IP/verilog/txuartlite.v new file mode 100644 index 0000000..c43edfe --- /dev/null +++ b/Semaine_7/DHT11_UART/IP/verilog/txuartlite.v @@ -0,0 +1,472 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Filename: txuartlite.v +// {{{ +// Project: wbuart32, a full featured UART with simulator +// +// Purpose: Transmit outputs over a single UART line. This particular UART +// implementation has been extremely simplified: it does not handle +// generating break conditions, nor does it handle anything other than the +// 8N1 (8 data bits, no parity, 1 stop bit) UART sub-protocol. +// +// To interface with this module, connect it to your system clock, and +// pass it the byte of data you wish to transmit. Strobe the i_wr line +// high for one cycle, and your data will be off. Wait until the 'o_busy' +// line is low before strobing the i_wr line again--this implementation +// has NO BUFFER, so strobing i_wr while the core is busy will just +// get ignored. The output will be placed on the o_txuart output line. +// +// (I often set both data and strobe on the same clock, and then just leave +// them set until the busy line is low. Then I move on to the next piece +// of data.) +// +// Creator: Dan Gisselquist, Ph.D. +// Gisselquist Technology, LLC +// +//////////////////////////////////////////////////////////////////////////////// +// }}} +// Copyright (C) 2015-2024, Gisselquist Technology, LLC +// {{{ +// This program is free software (firmware): you can redistribute it and/or +// modify it under the terms of the GNU General Public License as published +// by the Free Software Foundation, either version 3 of the License, or (at +// your option) any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program. (It's in the $(ROOT)/doc directory. Run make with no +// target there if the PDF file isn't present.) If not, see +// for a copy. +// }}} +// License: GPL, v3, as defined and found on www.gnu.org, +// {{{ +// http://www.gnu.org/licenses/gpl.html +// +//////////////////////////////////////////////////////////////////////////////// +// +`default_nettype none +// }}} +module txuartlite #( + // {{{ + // TIMING_BITS -- the number of bits required to represent + // the number of clocks per baud. 24 should be sufficient for + // most baud rates, but you can trim it down to save logic if + // you would like. TB is just an abbreviation for TIMING_BITS. + parameter [4:0] TIMING_BITS = 5'd8, + localparam TB = TIMING_BITS, + // CLOCKS_PER_BAUD -- the number of system clocks per baud + // interval. + parameter [(TB-1):0] CLOCKS_PER_BAUD = 234 // 24'd868 + // }}} + ) ( + // {{{ + input wire i_clk, i_reset, + input wire i_wr, + input wire [7:0] i_data, + // And the UART input line itself + output reg o_uart_tx, + // A line to tell others when we are ready to accept data. If + // (i_wr)&&(!o_busy) is ever true, then the core has accepted + // a byte for transmission. + output wire o_busy + // }}} + ); + + // Register/net declarations + // {{{ + localparam [3:0] TXUL_BIT_ZERO = 4'h0, + // TXUL_BIT_ONE = 4'h1, + // TXUL_BIT_TWO = 4'h2, + // TXUL_BIT_THREE = 4'h3, + // TXUL_BIT_FOUR = 4'h4, + // TXUL_BIT_FIVE = 4'h5, + // TXUL_BIT_SIX = 4'h6, + // TXUL_BIT_SEVEN = 4'h7, + TXUL_STOP = 4'h8, + TXUL_IDLE = 4'hf; + + reg [(TB-1):0] baud_counter; + reg [3:0] state; + reg [7:0] lcl_data; + reg r_busy, zero_baud_counter; + // }}} + + // Big state machine controlling: r_busy, state + // {{{ + // + initial r_busy = 1'b1; + initial state = TXUL_IDLE; + always @(posedge i_clk) + if (i_reset) + begin + r_busy <= 1'b1; + state <= TXUL_IDLE; + end else if (!zero_baud_counter) + // r_busy needs to be set coming into here + r_busy <= 1'b1; + else if (state > TXUL_STOP) // STATE_IDLE + begin + state <= TXUL_IDLE; + r_busy <= 1'b0; + if ((i_wr)&&(!r_busy)) + begin // Immediately start us off with a start bit + r_busy <= 1'b1; + state <= TXUL_BIT_ZERO; + end + end else begin + // One clock tick in each of these states ... + r_busy <= 1'b1; + if (state <=TXUL_STOP) // start bit, 8-d bits, stop-b + state <= state + 1'b1; + else + state <= TXUL_IDLE; + end + // }}} + + // o_busy + // {{{ + // + // This is a wire, designed to be true is we are ever busy above. + // originally, this was going to be true if we were ever not in the + // idle state. The logic has since become more complex, hence we have + // a register dedicated to this and just copy out that registers value. + assign o_busy = (r_busy); + // }}} + + // lcl_data + // {{{ + // + // This is our working copy of the i_data register which we use + // when transmitting. It is only of interest during transmit, and is + // allowed to be whatever at any other time. Hence, if r_busy isn't + // true, we can always set it. On the one clock where r_busy isn't + // true and i_wr is, we set it and r_busy is true thereafter. + // Then, on any zero_baud_counter (i.e. change between baud intervals) + // we simple logically shift the register right to grab the next bit. + initial lcl_data = 8'hff; + always @(posedge i_clk) + if (i_reset) + lcl_data <= 8'hff; + else if (i_wr && !r_busy) + lcl_data <= i_data; + else if (zero_baud_counter) + lcl_data <= { 1'b1, lcl_data[7:1] }; + // }}} + + // o_uart_tx + // {{{ + // + // This is the final result/output desired of this core. It's all + // centered about o_uart_tx. This is what finally needs to follow + // the UART protocol. + // + initial o_uart_tx = 1'b1; + always @(posedge i_clk) + if (i_reset) + o_uart_tx <= 1'b1; + else if (i_wr && !r_busy) + o_uart_tx <= 1'b0; // Set the start bit on writes + else if (zero_baud_counter) // Set the data bit. + o_uart_tx <= lcl_data[0]; + // }}} + + // Baud counter + // {{{ + // All of the above logic is driven by the baud counter. Bits must last + // CLOCKS_PER_BAUD in length, and this baud counter is what we use to + // make certain of that. + // + // The basic logic is this: at the beginning of a bit interval, start + // the baud counter and set it to count CLOCKS_PER_BAUD. When it gets + // to zero, restart it. + // + // However, comparing a 28'bit number to zero can be rather complex-- + // especially if we wish to do anything else on that same clock. For + // that reason, we create "zero_baud_counter". zero_baud_counter is + // nothing more than a flag that is true anytime baud_counter is zero. + // It's true when the logic (above) needs to step to the next bit. + // Simple enough? + // + // I wish we could stop there, but there are some other (ugly) + // conditions to deal with that offer exceptions to this basic logic. + // + // 1. When the user has commanded a BREAK across the line, we need to + // wait several baud intervals following the break before we start + // transmitting, to give any receiver a chance to recognize that we are + // out of the break condition, and to know that the next bit will be + // a stop bit. + // + // 2. A reset is similar to a break condition--on both we wait several + // baud intervals before allowing a start bit. + // + // 3. In the idle state, we stop our counter--so that upon a request + // to transmit when idle we can start transmitting immediately, rather + // than waiting for the end of the next (fictitious and arbitrary) baud + // interval. + // + // When (i_wr)&&(!r_busy)&&(state == TXUL_IDLE) then we're not only in + // the idle state, but we also just accepted a command to start writing + // the next word. At this point, the baud counter needs to be reset + // to the number of CLOCKS_PER_BAUD, and zero_baud_counter set to zero. + // + // The logic is a bit twisted here, in that it will only check for the + // above condition when zero_baud_counter is false--so as to make + // certain the STOP bit is complete. + initial zero_baud_counter = 1'b1; + initial baud_counter = 0; + always @(posedge i_clk) + if (i_reset) + begin + zero_baud_counter <= 1'b1; + baud_counter <= 0; + end else begin + zero_baud_counter <= (baud_counter == 1); + + if (state == TXUL_IDLE) + begin + baud_counter <= 0; + zero_baud_counter <= 1'b1; + if ((i_wr)&&(!r_busy)) + begin + baud_counter <= CLOCKS_PER_BAUD - 1'b1; + zero_baud_counter <= 1'b0; + end + end else if (!zero_baud_counter) + baud_counter <= baud_counter - 1'b1; + else if (state > TXUL_STOP) + begin + baud_counter <= 0; + zero_baud_counter <= 1'b1; + end else if (state == TXUL_STOP) + // Need to complete this state one clock early, so + // we can release busy one clock before the stop bit + // is complete, so we can start on the next byte + // exactly 10*CLOCKS_PER_BAUD clocks after we started + // the last one + baud_counter <= CLOCKS_PER_BAUD - 2; + else // All other states + baud_counter <= CLOCKS_PER_BAUD - 1'b1; + end + // }}} +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// +// FORMAL METHODS +// {{{ +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +`ifdef FORMAL + // Declarations +`ifdef TXUARTLITE +`define ASSUME assume +`else +`define ASSUME assert +`endif + reg f_past_valid, f_last_clk; + reg [(TB-1):0] f_baud_count; + reg [9:0] f_txbits; + reg [3:0] f_bitcount; + reg [7:0] f_request_tx_data; + wire [3:0] subcount; + + // Setup + // {{{ + initial f_past_valid = 1'b0; + always @(posedge i_clk) + f_past_valid <= 1'b1; + + initial `ASSUME(!i_wr); + always @(posedge i_clk) + if ((f_past_valid)&&($past(i_wr))&&($past(o_busy))) + begin + `ASSUME(i_wr == $past(i_wr)); + `ASSUME(i_data == $past(i_data)); + end + // }}} + + // Check the baud counter + // {{{ + always @(posedge i_clk) + assert(zero_baud_counter == (baud_counter == 0)); + + always @(posedge i_clk) + if (f_past_valid && !$past(i_reset) && $past(baud_counter != 0) + && $past(state != TXUL_IDLE)) + assert(baud_counter == $past(baud_counter - 1'b1)); + + always @(posedge i_clk) + if (f_past_valid && !$past(i_reset) && !$past(zero_baud_counter) + && $past(state != TXUL_IDLE)) + assert($stable(o_uart_tx)); + + initial f_baud_count = 1'b0; + always @(posedge i_clk) + if (zero_baud_counter) + f_baud_count <= 0; + else + f_baud_count <= f_baud_count + 1'b1; + + always @(posedge i_clk) + assert(f_baud_count < CLOCKS_PER_BAUD); + + always @(posedge i_clk) + if (baud_counter != 0) + assert(o_busy); + // }}} + + // {{{ + initial f_txbits = 0; + always @(posedge i_clk) + if (zero_baud_counter) + f_txbits <= { o_uart_tx, f_txbits[9:1] }; + + always @(posedge i_clk) + if (f_past_valid && !$past(i_reset)&& !$past(zero_baud_counter) + && !$past(state==TXUL_IDLE)) + assert(state == $past(state)); + + initial f_bitcount = 0; + always @(posedge i_clk) + if ((!f_past_valid)||(!$past(f_past_valid))) + f_bitcount <= 0; + else if ((state == TXUL_IDLE)&&(zero_baud_counter)) + f_bitcount <= 0; + else if (zero_baud_counter) + f_bitcount <= f_bitcount + 1'b1; + + always @(posedge i_clk) + assert(f_bitcount <= 4'ha); + + always @(*) + if (!o_busy) + assert(zero_baud_counter); + + always @(posedge i_clk) + if ((i_wr)&&(!o_busy)) + f_request_tx_data <= i_data; + + assign subcount = 10-f_bitcount; + always @(posedge i_clk) + if (f_bitcount > 0) + assert(!f_txbits[subcount]); + + always @(posedge i_clk) + if (f_bitcount == 4'ha) + begin + assert(f_txbits[8:1] == f_request_tx_data); + assert( f_txbits[9]); + end + + always @(posedge i_clk) + assert((state <= TXUL_STOP + 1'b1)||(state == TXUL_IDLE)); + + always @(posedge i_clk) + if ((f_past_valid)&&($past(f_past_valid))&&($past(o_busy))) + cover(!o_busy); + // }}} + +`endif // FORMAL +`ifdef VERIFIC_SVA + reg [7:0] fsv_data; + + // + // Grab a copy of the data any time we are sent a new byte to transmit + // We'll use this in a moment to compare the item transmitted against + // what is supposed to be transmitted + // + always @(posedge i_clk) + if ((i_wr)&&(!o_busy)) + fsv_data <= i_data; + + // + // One baud interval + // {{{ + // + // 1. The UART output is constant at DAT + // 2. The internal state remains constant at ST + // 3. CKS = the number of clocks per bit. + // + // Everything stays constant during the CKS clocks with the exception + // of (zero_baud_counter), which is *only* raised on the last clock + // interval + sequence BAUD_INTERVAL(CKS, DAT, SR, ST); + ((o_uart_tx == DAT)&&(state == ST) + &&(lcl_data == SR) + &&(!zero_baud_counter))[*(CKS-1)] + ##1 (o_uart_tx == DAT)&&(state == ST) + &&(lcl_data == SR) + &&(zero_baud_counter); + endsequence + // }}} + + // + // One byte transmitted + // {{{ + // + // DATA = the byte that is sent + // CKS = the number of clocks per bit + // + sequence SEND(CKS, DATA); + BAUD_INTERVAL(CKS, 1'b0, DATA, 4'h0) + ##1 BAUD_INTERVAL(CKS, DATA[0], {{(1){1'b1}},DATA[7:1]}, 4'h1) + ##1 BAUD_INTERVAL(CKS, DATA[1], {{(2){1'b1}},DATA[7:2]}, 4'h2) + ##1 BAUD_INTERVAL(CKS, DATA[2], {{(3){1'b1}},DATA[7:3]}, 4'h3) + ##1 BAUD_INTERVAL(CKS, DATA[3], {{(4){1'b1}},DATA[7:4]}, 4'h4) + ##1 BAUD_INTERVAL(CKS, DATA[4], {{(5){1'b1}},DATA[7:5]}, 4'h5) + ##1 BAUD_INTERVAL(CKS, DATA[5], {{(6){1'b1}},DATA[7:6]}, 4'h6) + ##1 BAUD_INTERVAL(CKS, DATA[6], {{(7){1'b1}},DATA[7:7]}, 4'h7) + ##1 BAUD_INTERVAL(CKS, DATA[7], 8'hff, 4'h8) + ##1 BAUD_INTERVAL(CKS-1, 1'b1, 8'hff, 4'h9); + endsequence + // }}} + + // + // Transmit one byte + // {{{ + // Once the byte is transmitted, make certain we return to + // idle + // + assert property ( + @(posedge i_clk) + (i_wr)&&(!o_busy) + |=> ((o_busy) throughout SEND(CLOCKS_PER_BAUD,fsv_data)) + ##1 (!o_busy)&&(o_uart_tx)&&(zero_baud_counter)); + // }}} + + // {{{ + assume property ( + @(posedge i_clk) + (i_wr)&&(o_busy) |=> + (i_wr)&&($stable(i_data))); + + // + // Make certain that o_busy is true any time zero_baud_counter is + // non-zero + // + always @(*) + assert((o_busy)||(zero_baud_counter) ); + + // If and only if zero_baud_counter is true, baud_counter must be zero + // Insist on that relationship here. + always @(*) + assert(zero_baud_counter == (baud_counter == 0)); + + // To make certain baud_counter stays below CLOCKS_PER_BAUD + always @(*) + assert(baud_counter < CLOCKS_PER_BAUD); + + // + // Insist that we are only ever in a valid state + always @(*) + assert((state <= TXUL_STOP+1'b1)||(state == TXUL_IDLE)); + // }}} + +`endif // Verific SVA +// }}} +endmodule diff --git a/Semaine_7/DHT11_UART/IP/verilog/uart_tx_fifo.v b/Semaine_7/DHT11_UART/IP/verilog/uart_tx_fifo.v new file mode 100644 index 0000000..5d5387b --- /dev/null +++ b/Semaine_7/DHT11_UART/IP/verilog/uart_tx_fifo.v @@ -0,0 +1,89 @@ +module uart_tx_fifo #( + parameter CLK_FREQ = 27_000_000, + parameter BAUD_RATE = 115200, + parameter FIFO_SIZE = 8 +)( + input clk, + input wr_en, + input [7:0] wr_data, + output tx_pin, + output fifo_full +); + + // FIFO wires + wire [7:0] fifo_rd_data; + wire fifo_empty; + reg fifo_rd_en; + + // UART wires + wire tx_busy; + reg uart_tx_enable; + reg [7:0] uart_tx_data; + + // FSM + typedef enum logic [1:0] { + IDLE, + WAIT_READY, + READ_FIFO, + SEND + } state_t; + + state_t state = IDLE; + + // FIFO instantiation + fifo #( + .WIDTH(8), + .SIZE(FIFO_SIZE) + ) fifo_inst ( + .clk(clk), + .wr_en(wr_en), + .wr_data(wr_data), + .rd_en(fifo_rd_en), + .rd_data(fifo_rd_data), + .empty(fifo_empty), + .full(fifo_full) + ); + + // UART TX instantiation + txuartlite uart_tx_inst ( + .i_clk(clk), + .i_reset(1'b0), + .i_wr(uart_tx_enable), + .i_data(uart_tx_data), + .o_uart_tx(tx_pin), + .o_busy(tx_busy) + ); + + always_ff @(posedge clk) begin + fifo_rd_en <= 0; + uart_tx_enable <= 0; + + case (state) + IDLE: begin + if (!fifo_empty) + state <= WAIT_READY; + end + + WAIT_READY: begin + if (!tx_busy) begin + fifo_rd_en <= 1; + uart_tx_data <= fifo_rd_data; + state <= READ_FIFO; + end + end + + READ_FIFO: begin + // fifo_rd_data sera valide ici + fifo_rd_en <= 0; + uart_tx_enable <= 1; + state <= SEND; + end + + SEND: begin + state <= IDLE; + uart_tx_enable <= 0; + end + endcase + end + +endmodule \ No newline at end of file diff --git a/Semaine_7/DHT11_UART/README.md b/Semaine_7/DHT11_UART/README.md new file mode 100644 index 0000000..34702e3 --- /dev/null +++ b/Semaine_7/DHT11_UART/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_7/DHT11_UART/constraints/dht11_uart_top.cst b/Semaine_7/DHT11_UART/constraints/dht11_uart_top.cst new file mode 100644 index 0000000..14bc549 --- /dev/null +++ b/Semaine_7/DHT11_UART/constraints/dht11_uart_top.cst @@ -0,0 +1,8 @@ +IO_LOC "tx" 69; +IO_PORT "tx" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3; + +IO_LOC "clk" 4; +IO_PORT "clk" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3; + +IO_LOC "io_dht11_sig" 73; +IO_PORT "io_dht11_sig" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3; diff --git a/Semaine_7/DHT11_UART/project.bat b/Semaine_7/DHT11_UART/project.bat new file mode 100644 index 0000000..987449a --- /dev/null +++ b/Semaine_7/DHT11_UART/project.bat @@ -0,0 +1,9 @@ +@call c:\oss-cad-suite\environment.bat +@echo off + +mkdir runs + +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_7/DHT11_UART/project.sh b/Semaine_7/DHT11_UART/project.sh new file mode 100644 index 0000000..c759d7c --- /dev/null +++ b/Semaine_7/DHT11_UART/project.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Charger l'environnement OSS CAD Suite +source /home/louis/oss-cad-suite/environment + +mkdir -p runs + +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_7/DHT11_UART/scripts/linux/build.sh b/Semaine_7/DHT11_UART/scripts/linux/build.sh new file mode 100644 index 0000000..3d697c0 --- /dev/null +++ b/Semaine_7/DHT11_UART/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="dht11_uart_top" +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/dht11_interface.v IP/verilog/uart_tx_fifo.v IP/verilog/fifo.v IP/verilog/txuartlite.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_7/DHT11_UART/scripts/linux/clean.sh b/Semaine_7/DHT11_UART/scripts/linux/clean.sh new file mode 100644 index 0000000..a505cb7 --- /dev/null +++ b/Semaine_7/DHT11_UART/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_7/DHT11_UART/scripts/linux/gtkwave.sh b/Semaine_7/DHT11_UART/scripts/linux/gtkwave.sh new file mode 100644 index 0000000..f623377 --- /dev/null +++ b/Semaine_7/DHT11_UART/scripts/linux/gtkwave.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +echo "=== Lancement de GTKWave ===" +gtkwave runs/sim.vcd +echo "=== GTKWave terminé ===" \ No newline at end of file diff --git a/Semaine_7/DHT11_UART/scripts/linux/simulate.sh b/Semaine_7/DHT11_UART/scripts/linux/simulate.sh new file mode 100644 index 0000000..24d3f6e --- /dev/null +++ b/Semaine_7/DHT11_UART/scripts/linux/simulate.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +echo "=== Simulation avec Icarus Verilog ===" + +OUT="runs/sim.vvp" +TOP="tb_dht11" +DIRS=("src/verilog" "tests/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_7/DHT11_UART/scripts/linux/upload.sh b/Semaine_7/DHT11_UART/scripts/linux/upload.sh new file mode 100644 index 0000000..343e3b8 --- /dev/null +++ b/Semaine_7/DHT11_UART/scripts/linux/upload.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Aller à la racine du projet +cd "$(dirname "$0")/../.." || exit 1 + +# Config de base +DEVICE="GW2AR-LV18QN88C8/I7" +BOARD="tangnano20k" +TOP="dht11_uart_top" +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 4 : Flash avec openFPGALoader ===" +sudo /etc/oss-cad-suite/bin/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_7/DHT11_UART/scripts/windows/build.bat b/Semaine_7/DHT11_UART/scripts/windows/build.bat new file mode 100644 index 0000000..89520d5 --- /dev/null +++ b/Semaine_7/DHT11_UART/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/fifo.v IP/verilog/uart_tx.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_7/DHT11_UART/scripts/windows/clean.bat b/Semaine_7/DHT11_UART/scripts/windows/clean.bat new file mode 100644 index 0000000..6192ae1 --- /dev/null +++ b/Semaine_7/DHT11_UART/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_7/DHT11_UART/scripts/windows/gtkwave.bat b/Semaine_7/DHT11_UART/scripts/windows/gtkwave.bat new file mode 100644 index 0000000..0b86154 --- /dev/null +++ b/Semaine_7/DHT11_UART/scripts/windows/gtkwave.bat @@ -0,0 +1,3 @@ +@echo off +echo === Lancement de GTKWave === +gtkwave runs/sim.vcd diff --git a/Semaine_7/DHT11_UART/scripts/windows/simulate.bat b/Semaine_7/DHT11_UART/scripts/windows/simulate.bat new file mode 100644 index 0000000..fbe0ee2 --- /dev/null +++ b/Semaine_7/DHT11_UART/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=tb_dht11 + +:: 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_7/DHT11_UART/src/verilog/dht11_uart_top.v b/Semaine_7/DHT11_UART/src/verilog/dht11_uart_top.v new file mode 100644 index 0000000..fa066b5 --- /dev/null +++ b/Semaine_7/DHT11_UART/src/verilog/dht11_uart_top.v @@ -0,0 +1,104 @@ +`default_nettype none +module dht11_uart_top ( + input clk, + inout io_dht11_sig, + output tx +); + +localparam CLK_FREQ = 27_000_000; // 27 MHz + +reg [7:0] wr_data; +reg wr_en; +wire tx_fifo_full; + + +reg i_start; +wire o_dht11_data_ready; +wire o_busy; +wire [7:0] o_temp_data; +wire [7:0] o_hum_data; +wire o_dht11_error; + +uart_tx_fifo #( + .CLK_FREQ(CLK_FREQ), + .BAUD_RATE(115200), + .FIFO_SIZE(8) +) uart_tx_inst ( + .clk(clk), + .wr_en(wr_en), + .wr_data(wr_data), + .fifo_full(tx_fifo_full), + .tx_pin(tx) +); + +dht11_interface dht11_inst ( + .i_clk(clk), + .io_dht11_sig(io_dht11_sig), + .i_start(i_start), + .o_dht11_data_ready(o_dht11_data_ready), + .o_busy(o_busy), + .o_temp_data(o_temp_data), + .o_hum_data(o_hum_data), + .o_dht11_error(o_dht11_error) +); + +// === FSM === +localparam X=4, WAIT = 0, MESURE = 1, SEND_FIFO1 = 2, SEND_FIFO2 = 3; +reg [2:0] state = X; +reg [31:0] delay_counter = 0; +reg strobe2s = 0; +reg [7:0] data_fifo = 30; + +// 2s counter +always_ff @(posedge clk) begin + if (delay_counter == CLK_FREQ * 2 - 1) begin + delay_counter <= 0; + strobe2s <= 1; + end else begin + delay_counter <= delay_counter + 1; + strobe2s <= 0; + end +end + +always_ff @(posedge clk) begin + case (state) + X: begin + i_start <= 0; + wr_en <= 1; + wr_data <= data_fifo; + state <= WAIT; + end + WAIT: begin + i_start <= 0; + wr_en <= 0; + if (strobe2s) begin + state <= MESURE; + i_start <= 1; + end + end + + MESURE: begin + i_start <= 0; + if (o_dht11_data_ready) begin + state <= SEND_FIFO1; + wr_data <= o_temp_data; + wr_en <= 1; + end + end + + SEND_FIFO1: begin + wr_data <= o_hum_data; + wr_en <= 1; + state <= SEND_FIFO2; + end + + SEND_FIFO2: begin + wr_en <= 0; + state <= WAIT; + end + + default: state <= WAIT; + endcase +end + +endmodule \ No newline at end of file diff --git a/Semaine_7/DHT11_UART/tests/verilog/tb_dht11.v b/Semaine_7/DHT11_UART/tests/verilog/tb_dht11.v new file mode 100644 index 0000000..82a8f5f --- /dev/null +++ b/Semaine_7/DHT11_UART/tests/verilog/tb_dht11.v @@ -0,0 +1,65 @@ +`timescale 1ns/1ps + +module tb_dht11; + + reg clk = 0; + always #18.5 clk = ~clk; // Génère une clock 27 MHz + + // === Registres === + wire io_dht11_sig; + reg dht11_start; + wire dht11_data_ready; + wire dht11_busy; + wire [7:0] dht11_temp_data; + wire [7:0] dht11_hum_data; + wire dht11_error; + + // === Simulation du module DHT11 === + dht11_model dht11_model ( + .data(io_dht11_sig), + .clk(clk), + .rst_n(1'b1) // Reset non utilisé dans ce test + ); + + // === Module DHT11 INTERFACE === + dht11_interface dht11_interface ( + .i_clk(clk), + .io_dht11_sig(io_dht11_sig), + .i_start(dht11_start), + .o_dht11_data_ready(dht11_data_ready), + .o_busy(dht11_busy), + .o_temp_data(dht11_temp_data), + .o_hum_data(dht11_hum_data), + .o_dht11_error(dht11_error) + ); + + pullup(io_dht11_sig); + + // === TEST SEQUENCE === + initial begin + $dumpfile("runs/sim.vcd"); + $dumpvars(0, tb_dht11); + dht11_start = 0; + + $display("==== Start DHT11 Test ===="); + + #100; + dht11_start = 1; // Démarre la lecture des données + $display("DHT11 start..."); + + wait(dht11_busy); // Attend que le module soit occupé + $display("DHT11 busy..."); + + dht11_start = 0; + + wait(dht11_data_ready); // Attend que les données soient prêtes + $display("DHT11 data ready..."); + + $display("Température : %d.%d °C", dht11_temp_data); + $display("Humidité : %d.%d %%", dht11_hum_data); + + $display("==== End DHT11 Test ===="); + $finish; + end + +endmodule \ No newline at end of file