1
0
forked from tanchou/Verilog

Code FPGA fonctionnel

This commit is contained in:
Gamenight77
2025-05-27 15:36:40 +02:00
parent 4e16bb3cbe
commit 168431849b
24 changed files with 2038 additions and 4 deletions

View File

@@ -120,10 +120,8 @@ module dht11_interface #(
timer <= timer + 1; timer <= timer + 1;
if (sig_in == 1 ) begin if (sig_in == 1 ) begin
timer <= 0; timer <= 0;
state <= RESPONSE_HIGH; state <= RESPONSE_HIGH;
end end
end end
@@ -132,8 +130,8 @@ module dht11_interface #(
o_state <= state; o_state <= state;
if (sig_in == 0) begin if (sig_in == 0) begin
timer <= 0; timer <= 0;
state <= READ_BITS_LOW; state <= READ_BITS_LOW;
end end
end end

View File

@@ -14,3 +14,4 @@ expliquer que c'est long a cause des simulations (creation de model pour simuler
parfois en vrais les marges sont plus souple et ne respecte pas la doc parfois en vrais les marges sont plus souple et ne respecte pas la doc
debuguage dure expliquer pourquoi debuguage dure expliquer pourquoi

View File

@@ -0,0 +1,5 @@
runs
.vscode
workspace.code-workspace
*.pyc
.idea

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -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
// <http://www.gnu.org/licenses/> 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

View File

@@ -0,0 +1,56 @@
module uart_rx_fifo #(
parameter CLK_FREQ = 27_000_000,
parameter BAUD_RATE = 115200,
parameter FIFO_SIZE = 8
)(
input clk,
input rd_en,
output wire [7:0] rd_data,
input rx_pin,
output data_available
);
// UART RX wires
wire [7:0] rx_data;
wire rx_received;
// FIFO control
reg wr_en;
wire fifo_empty;
wire fifo_full;
// UART Receiver instance
rxuartlite uart_rx_inst (
.i_clk(clk),
.i_reset(1'b0),
.i_uart_rx(rx_pin),
.o_wr(rx_received),
.o_data(rx_data)
);
// FIFO instance
fifo #(
.WIDTH(8),
.SIZE(FIFO_SIZE)
) fifo_inst (
.clk(clk),
.wr_en(wr_en),
.wr_data(rx_data),
.rd_en(rd_en),
.rd_data(rd_data),
.empty(fifo_empty),
.full(fifo_full)
);
assign data_available = ~fifo_empty;
// Écriture dans la FIFO uniquement si donnée reçue ET FIFO pas pleine
always @(posedge clk) begin
if (rx_received && !fifo_full) begin
wr_en <= 1'b1;
end else begin
wr_en <= 1'b0;
end
end
endmodule

View File

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

View File

@@ -0,0 +1,21 @@
IO_LOC "o_tx" 69;
IO_PORT "o_tx" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3;
IO_LOC "i_rx" 70;
IO_PORT "i_rx" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3;
IO_LOC "i_clk" 4;
IO_PORT "i_clk" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3;
IO_LOC "o_leds[0]" 15;
IO_PORT "o_leds[0]" PULL_MODE=UP DRIVE=8 BANK_VCCIO=1.8;
IO_LOC "o_leds[1]" 16;
IO_PORT "o_leds[1]" PULL_MODE=UP DRIVE=8 BANK_VCCIO=1.8;
IO_LOC "o_leds[2]" 17;
IO_PORT "o_leds[2]" PULL_MODE=UP DRIVE=8 BANK_VCCIO=1.8;
IO_LOC "o_leds[3]" 18;
IO_PORT "o_leds[3]" PULL_MODE=UP DRIVE=8 BANK_VCCIO=1.8;
IO_LOC "o_leds[4]" 19;
IO_PORT "o_leds[4]" PULL_MODE=UP DRIVE=8 BANK_VCCIO=1.8;
IO_LOC "o_leds[5]" 20;
IO_PORT "o_leds[5]" PULL_MODE=UP DRIVE=8 BANK_VCCIO=1.8;

View File

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

View File

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

View File

@@ -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 ==="
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 ==="

View File

@@ -0,0 +1,4 @@
#!/bin/bash
echo "=== Nettoyage des fichiers générés ==="
rm -rf runs/*

View File

@@ -0,0 +1,5 @@
#!/bin/bash
echo "=== Lancement de GTKWave ==="
gtkwave runs/sim.vcd
echo "=== GTKWave terminé ==="

View File

@@ -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"

View File

@@ -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 ==="

View File

@@ -0,0 +1,47 @@
@echo off
setlocal
rem === Aller à la racine du projet ===
cd /d %~dp0\..\..
echo Script lancé depuis : %cd%
rem === Config de base ===
set DEVICE=GW2AR-LV18QN88C8/I7
set BOARD=tangnano20k
set TOP=fpga_wifi_led
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/uart_tx_fifo.v IP/verilog/uart_rx_fifo.v IP/verilog/fifo.v IP/verilog/txuartlite.v IP/verilog/rxuartlite.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

View File

@@ -0,0 +1,4 @@
@echo off
echo === Nettoyage du dossier runs ===
rd /s /q runs
mkdir runs

View File

@@ -0,0 +1,3 @@
@echo off
echo === Lancement de GTKWave ===
gtkwave runs/sim.vcd

View File

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

View File

@@ -0,0 +1,106 @@
#include <WiFi.h>
#include <WiFiManager.h> // Include WiFiManager library
// TCP server port
const uint16_t port = 1234;
// TCP server object
WiFiServer server(port);
// TCP client object
WiFiClient client;
// Touch sensor settings
const int touchPin = T0; // Use touch pin T0 (GPIO 4)
const int touchThreshold = 30; // Adjust based on testing (lower value = touch detected)
const unsigned long resetHoldTime = 5000; // 5 seconds to trigger reset
unsigned long touchStartTime = 0;
bool touchDetected = false;
void setup() {
// Initialize Serial for UART communication (115200 baud)
Serial.begin(115200);
// Initialize WiFiManager
WiFiManager wifiManager;
// Check for touch sensor reset
if (checkTouchReset()) {
wifiManager.resetSettings();
Serial.println("WiFi settings reset due to touch sensor");
ESP.restart(); // Restart to apply reset
}
// Connect to WiFi using WiFiManager (creates AP if no saved credentials)
if (!wifiManager.autoConnect("ESP32_AP")) {
Serial.println("Failed to connect to WiFi and hit timeout");
ESP.restart();
}
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Start TCP server
server.begin();
Serial.println("TCP server started on port " + String(port));
}
void loop() {
// Check for touch sensor reset
handleTouchReset();
// Check for incoming client connections
if (!client.connected()) {
client = server.available();
if (client) {
Serial.println("New client connected");
}
}
// Relay data from TCP client to UART
while (client.connected() && client.available()) {
char c = client.read();
Serial.write(c); // Send to UART
}
// Relay data from UART to TCP client
while (Serial.available() && client.connected()) {
char c = Serial.read();
client.write(c); // Send to TCP client
}
// Handle client disconnection
if (client && !client.connected()) {
Serial.println("Client disconnected");
client.stop();
}
}
// Function to check touch sensor at boot for reset
bool checkTouchReset() {
int touchValue = touchRead(touchPin);
if (touchValue < touchThreshold) {
unsigned long startTime = millis();
while (touchRead(touchPin) < touchThreshold) {
if (millis() - startTime >= resetHoldTime) {
return true; // Touch held long enough, trigger reset
}
}
}
return false;
}
// Function to handle touch sensor reset during loop
void handleTouchReset() {
int touchValue = touchRead(touchPin);
if (touchValue < touchThreshold && !touchDetected) {
touchDetected = true;
touchStartTime = millis();
} else if (touchValue >= touchThreshold && touchDetected) {
touchDetected = false; // Reset when touch is released
}
if (touchDetected && (millis() - touchStartTime >= resetHoldTime)) {
WiFiManager wifiManager;
wifiManager.resetSettings();
Serial.println("WiFi settings reset due to touch sensor");
ESP.restart(); // Restart to apply reset
}
}

View File

@@ -0,0 +1,134 @@
`default_nettype none
module fpga_wifi_led (
input i_clk,
input i_rx,
output o_tx,
output [5:0] o_leds
);
// === PARAMÈTRES ===
localparam CLK_FREQ = 27_000_000;
localparam BAUD_RATE = 115200;
localparam FIFO_SIZE = 8;
// === SIGNAUX UART RX ===
wire [7:0] rx_data;
wire rx_data_available;
reg rx_rd_en;
// === SIGNAUX UART TX ===
reg [7:0] tx_data;
reg tx_wr_en;
wire tx_fifo_full;
// === SIGNAUX INTERNES ===
reg [5:0] leds_reg;
reg [1:0] state;
reg [7:0] received_byte;
// === ÉTATS DE LA FSM ===
localparam IDLE = 2'd0,
WAIT_BYTE = 2'd1,
PROCESS_CMD = 2'd2,
SEND_RESPONSE = 2'd3;
// === INSTANCIATION UART RX FIFO ===
uart_rx_fifo #(
.CLK_FREQ(CLK_FREQ),
.BAUD_RATE(BAUD_RATE),
.FIFO_SIZE(FIFO_SIZE)
) uart_rx_inst (
.clk(i_clk),
.rd_en(rx_rd_en),
.rd_data(rx_data),
.rx_pin(i_rx),
.data_available(rx_data_available)
);
// === INSTANCIATION UART TX FIFO ===
uart_tx_fifo #(
.CLK_FREQ(CLK_FREQ),
.BAUD_RATE(BAUD_RATE),
.FIFO_SIZE(FIFO_SIZE)
) uart_tx_inst (
.clk(i_clk),
.wr_en(tx_wr_en),
.wr_data(tx_data),
.tx_pin(o_tx),
.fifo_full(tx_fifo_full)
);
// === ASSIGNATION DES LEDS ===
assign o_leds = ~leds_reg;
// === INITIALISATION ===
initial begin
leds_reg = 6'b000000;
state = IDLE;
rx_rd_en = 0;
tx_wr_en = 0;
tx_data = 8'h00;
received_byte = 8'h00;
end
// === MACHINE D'ÉTAT PRINCIPALE ===
always @(posedge i_clk) begin
// Désactiver les signaux de contrôle par défaut
rx_rd_en <= 0;
tx_wr_en <= 0;
case (state)
IDLE: begin
received_byte <= 8'h00;
if (rx_data_available) begin
state <= WAIT_BYTE;
end
end
WAIT_BYTE: begin
if (rx_data_available) begin
rx_rd_en <= 1;
received_byte <= rx_data;
state <= PROCESS_CMD;
end
end
PROCESS_CMD: begin
// Vérifier la commande reçue
if (received_byte == 8'h01) begin
// Allumer la LED 0
leds_reg[0] <= 1;
// Préparer la réponse
state <= SEND_RESPONSE;
end else if (received_byte == 8'h02) begin
// Éteindre la LED 0
leds_reg[0] <= 0;
// Préparer la réponse
state <= SEND_RESPONSE;
end else begin
// Commande non reconnue, éteindre toutes les LEDs
leds_reg <= 6'b000000;
state <= IDLE;
end
end
SEND_RESPONSE: begin
if (!tx_fifo_full) begin
// Renvoyer le même byte reçu (0x01 ou 0x02)
tx_data <= received_byte;
tx_wr_en <= 1;
state <= IDLE;
end
end
default: begin
state <= IDLE;
end
endcase
end
endmodule

View File

@@ -0,0 +1,30 @@
import serial
import time
# Configuration du port série
ser = serial.Serial(
port='/dev/ttyUSB0', # Remplace par ton port (ex : COM3 sous Windows)
baudrate=115200,
timeout=1 # En secondes
)
print("Lecture du port série... (Ctrl+C pour quitter)")
try:
while True:
# Lire 2 octets
data = ser.read(2)
if len(data) == 2:
temperature = data[0]
humidite = data[1]
print(f"Température: {temperature}°C, Humidité: {humidite}%")
else:
print("Pas assez de données reçues.")
time.sleep(1)
except KeyboardInterrupt:
print("\nArrêt du script.")
finally:
ser.close()

View File

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