diff --git a/Semaine_3/UARTV2/memo.png b/Semaine_3/UARTV2/memo.png new file mode 100644 index 0000000..87b7ec1 Binary files /dev/null and b/Semaine_3/UARTV2/memo.png differ diff --git a/Semaine_3/UARTV2/rx_fifo.v b/Semaine_3/UARTV2/rx_fifo.v new file mode 100644 index 0000000..e442fe9 --- /dev/null +++ b/Semaine_3/UARTV2/rx_fifo.v @@ -0,0 +1,49 @@ +module rx_fifo #( + parameter WIDTH = 8, // Taille des données (8 bits) + parameter DEPTH = 16 // Taille de la FIFO +)( + input clk, + input rst_p, + input [WIDTH-1:0] rx_data_in, + input rx_data_valid, // Indique que les données reçues sont valides + output reg [WIDTH-1:0] rx_data_out, + output reg rx_data_ready, // Indique que les données peuvent être lues + output reg fifo_empty, // FIFO vide + output reg fifo_full // FIFO pleine +); + + reg [WIDTH-1:0] fifo_mem [DEPTH-1:0]; // Mémoire FIFO + reg [4:0] wr_ptr = 0; // Pointeur d'écriture + reg [4:0] rd_ptr = 0; // Pointeur de lecture + reg [4:0] fifo_count = 0; // Compteur d'éléments dans la FIFO + + always @(posedge clk or posedge rst_p) begin + if (rst_p) begin + wr_ptr <= 0; + rd_ptr <= 0; + fifo_count <= 0; + rx_data_ready <= 0; + fifo_empty <= 1; + fifo_full <= 0; + end else begin + // Écriture dans la FIFO + if (rx_data_valid && !fifo_full) begin + fifo_mem[wr_ptr] <= rx_data_in; + wr_ptr <= wr_ptr + 1; + fifo_count <= fifo_count + 1; + end + + // Lecture de la FIFO + if (!fifo_empty) begin + rx_data_out <= fifo_mem[rd_ptr]; + rd_ptr <= rd_ptr + 1; + fifo_count <= fifo_count - 1; + end + + // Mise à jour des indicateurs de vide et de plein + fifo_empty <= (fifo_count == 0); + fifo_full <= (fifo_count == DEPTH); + rx_data_ready <= !fifo_empty; + end + end +endmodule diff --git a/Semaine_3/UARTV2/tb_top_uart_rx_tx.v b/Semaine_3/UARTV2/tb_top_uart_rx_tx.v new file mode 100644 index 0000000..6c9dc52 --- /dev/null +++ b/Semaine_3/UARTV2/tb_top_uart_rx_tx.v @@ -0,0 +1,69 @@ +`timescale 1ns / 1ps + +module tb_top_uart_rx_tx; + + parameter CLK_FREQ = 27_000_000; + parameter BAUD_RATE = 115200; + + // Signaux + reg clk = 0; + reg start = 0; + reg [7:0] data_in = 0; + wire [7:0] data_out; + wire valid; + wire tx; + wire rx; // On connecte tx directement à rx pour le test + + // Instance du module à tester + top_uart_rx_tx #( + .CLK_FREQ(CLK_FREQ), + .BAUD_RATE(BAUD_RATE) + ) uut ( + .clk(clk), + .start(start), + .data_in(data_in), + .rx(rx), + .data_out(data_out), + .valid(valid), + .tx(tx) + ); + + // Boucle le tx sur rx + assign rx = tx; + + // Clock à 50 MHz (20 ns période) + always #10 clk = ~clk; + + // Simulation principale + initial begin + $display("Début de la simulation"); + $dumpfile("uart_loopback.vcd"); // Pour GTKWave + $dumpvars(0, tb_top_uart_rx_tx); + + // Attendre un peu + #(20 * 10); + + // Envoi d'une valeur + data_in = 8'hA5; // Exemple de data + start = 1; + #20; + start = 0; + + // Attendre la réception (valeur valid = 1) + wait(valid == 1); + + // Affichage des résultats + $display("Data envoyee : 0x%h", data_in); + $display("Data recue : 0x%h", data_out); + + if (data_out == data_in) + $display("Test reussi !"); + else + $display("Test echoue..."); + + // Fin de simulation + #(20 * 10); + $finish; + end + +endmodule \ No newline at end of file diff --git a/Semaine_3/UARTV2/tb_uart_rx.v b/Semaine_3/UARTV2/tb_uart_rx.v new file mode 100644 index 0000000..874dfd7 --- /dev/null +++ b/Semaine_3/UARTV2/tb_uart_rx.v @@ -0,0 +1,64 @@ +`timescale 1ns / 1ps + +module tb_uart_rx; + + reg clk = 0; + reg rx = 1; + wire [7:0] data; + wire valid; + wire ready; + + localparam CLK_FREQ = 27_000_000; + localparam BAUD_RATE = 115_200; + localparam BIT_PERIOD = CLK_FREQ / BAUD_RATE; + localparam CLK_PERIOD_NS = 1000000000 / CLK_FREQ; + + uart_rx #( + .CLK_FREQ(CLK_FREQ), + .BAUD_RATE(BAUD_RATE) + ) rx_instance ( + .clk(clk), + .rx(rx), + .data(data), + .valid(valid), + .ready(ready) + ); + + always #(CLK_PERIOD_NS/2) clk = ~clk; + + task send_bit(input reg b); + begin + rx <= b; + #(BIT_PERIOD * CLK_PERIOD_NS); + end + endtask + + integer i; + + task send_byte(input [7:0] byte); + begin + send_bit(0); + for (i = 0; i < 8; i = i + 1) + send_bit(byte[i]); + send_bit(1); + + #(BIT_PERIOD * CLK_PERIOD_NS); + end + endtask + + initial begin + $display("Start UART RX test"); + #100; + + send_byte(8'b01010101); + + #(10 * BIT_PERIOD * CLK_PERIOD_NS); + + if (valid && data == 8'b01010101) + $display("Test ok : data = %b", data); + else + $display("Test pas ok : data = %b, valid = %b", data, valid); + + $finish; + end +endmodule diff --git a/Semaine_3/UARTV2/tb_uart_tx.v b/Semaine_3/UARTV2/tb_uart_tx.v new file mode 100644 index 0000000..4c1fe2d --- /dev/null +++ b/Semaine_3/UARTV2/tb_uart_tx.v @@ -0,0 +1,49 @@ +`timescale 1ns/1ps + +module tb_uart_tx; + + reg clk = 0; + reg start = 0; + reg [7:0] data = 8'h00; + wire tx; + wire busy; + + always #18.5 clk = ~clk; + + uart_tx #( + .CLK_FREQ(27_000_000), + .BAUD_RATE(115_200) + )tx_instance ( + .clk(clk), + .start(start), + .data(data), + .tx(tx), + .busy(busy) + ); + + initial begin + $dumpfile("uart_tx.vcd"); + $dumpvars(0, tb_uart_tx); + + #100; + + data <= 8'hA5; // 10100101 0xA5 + start <= 1; + #37 start <= 0; + + // Attendre + wait (busy == 0); + + #1000; + + data <= 8'h3C; // 00111100 0x3C + start <= 1; + #37 start <= 0; + + wait (busy == 0); + + #1000; + $stop; + end + +endmodule \ No newline at end of file diff --git a/Semaine_3/UARTV2/top_led_uart.v b/Semaine_3/UARTV2/top_led_uart.v new file mode 100644 index 0000000..6db1633 --- /dev/null +++ b/Semaine_3/UARTV2/top_led_uart.v @@ -0,0 +1,61 @@ +module top_led_uart( + input wire clk, + input wire rx, + output wire tx, + output reg [5:0] leds +); + wire [7:0] data_out; + wire valid; + reg start_tx = 0; + reg [7:0] data_in = 0; + + uart_top uart ( + .clk(clk), + .start(start_tx), + .data_in(data_in), + .rx(rx), + .data_out(data_out), + .valid(valid), + .tx(tx) + ); + + reg [1:0] state = 0; + localparam IDLE = 2'd0; + localparam TOGGLE = 2'd1; + localparam SEND_BACK = 2'd2; + + always @(posedge clk) begin + case (state) + INIT: begin + leds <= 6'b000000; + start_tx <= 0; + if (valid) begin + + leds <= data_out[5:0]; + state <= SEND_BACK; + + end + end + IDLE: begin + start_tx <= 0; + if (valid) begin + + leds <= data_out[5:0]; + state <= SEND_BACK; + + end + end + + SEND_BACK: begin + data_in <= data_out; + start_tx <= 1; + state <= TOGGLE; + end + + TOGGLE: begin + start_tx <= 0; + state <= IDLE; + end + endcase + end +endmodule diff --git a/Semaine_3/UARTV2/top_uart_ultrasonic.v b/Semaine_3/UARTV2/top_uart_ultrasonic.v new file mode 100644 index 0000000..5ef3d60 --- /dev/null +++ b/Semaine_3/UARTV2/top_uart_ultrasonic.v @@ -0,0 +1,133 @@ +module top_uart_ultrasonic ( + input wire clk, + input wire rst_p, + input wire start, // Démarrage de la mesure + inout wire sig, // Signal vers le capteur ultrason + output wire uart_tx // TX vers le PC +); + wire [15:0] distance; + wire [2:0] state; + + reg [7:0] tx_data_in; + reg tx_data_valid; + wire tx_data_ready; + wire fifo_empty; + wire fifo_full; + + wire uart_ready; + reg uart_start; + reg [7:0] uart_data; + + reg [1:0] send_state; + localparam IDLE = 2'd0, + SEND_HIGH = 2'd1, + SEND_LOW = 2'd2, + WAIT_UART = 2'd3; + + // Instanciation du module ultrason + ultrasonic_fpga #( + .CLK_FREQ(27_000_000) + ) ultrasonic_inst ( + .clk(clk), + .start(start), + .sig(sig), + .distance(distance), + .state(state) + ); + + // Instanciation de la FIFO + tx_fifo #( + .WIDTH(8), + .DEPTH(16) + ) fifo_inst ( + .clk(clk), + .rst_p(rst_p), + .tx_data_in(tx_data_in), + .tx_data_valid(tx_data_valid), + .tx_data_ready(tx_data_ready), + .fifo_empty(fifo_empty), + .fifo_full(fifo_full) + ); + + // Instanciation de l'UART + uart_tx uart_inst ( + .clk(clk), + .rst(rst_p), + .tx_start(uart_start), + .tx_data(uart_data), + .tx(uart_tx), + .tx_ready(uart_ready) + ); + + reg [15:0] distance_reg; + reg new_distance; + + // Détecte un nouveau résultat de distance + always @(posedge clk or posedge rst_p) begin + if (rst_p) begin + distance_reg <= 16'd0; + new_distance <= 1'b0; + end else begin + if (state == 3'd6 && distance != distance_reg) begin // Quand l'ultrason est à DONE + distance_reg <= distance; + new_distance <= 1'b1; + end else begin + new_distance <= 1'b0; + end + end + end + + // Envoi dans la FIFO (distance sur 2 octets : high byte + low byte) + always @(posedge clk or posedge rst_p) begin + if (rst_p) begin + tx_data_in <= 8'd0; + tx_data_valid <= 1'b0; + send_state <= IDLE; + end else begin + case (send_state) + IDLE: begin + tx_data_valid <= 1'b0; + if (new_distance && !fifo_full) begin + tx_data_in <= distance_reg[15:8]; // MSB en premier + tx_data_valid <= 1'b1; + send_state <= SEND_LOW; + end + end + + SEND_LOW: begin + tx_data_valid <= 1'b0; + if (tx_data_ready && !fifo_full) begin + tx_data_in <= distance_reg[7:0]; // LSB ensuite + tx_data_valid <= 1'b1; + send_state <= WAIT_UART; + end + end + + WAIT_UART: begin + tx_data_valid <= 1'b0; + send_state <= IDLE; + end + + default: send_state <= IDLE; + endcase + end + end + + // Gestion FIFO -> UART + always @(posedge clk or posedge rst_p) begin + if (rst_p) begin + uart_start <= 1'b0; + uart_data <= 8'd0; + end else begin + uart_start <= 1'b0; // Par défaut + + if (uart_ready && !fifo_empty) begin + uart_data <= fifo_inst.fifo_mem[fifo_inst.rd_ptr]; // Lecture de la FIFO + uart_start <= 1'b1; + fifo_inst.rd_ptr <= fifo_inst.rd_ptr + 1; + fifo_inst.fifo_count <= fifo_inst.fifo_count - 1; + end + end + end + +endmodule diff --git a/Semaine_3/UARTV2/tx_fifo.v b/Semaine_3/UARTV2/tx_fifo.v new file mode 100644 index 0000000..80ff502 --- /dev/null +++ b/Semaine_3/UARTV2/tx_fifo.v @@ -0,0 +1,57 @@ +module tx_fifo #( + parameter WIDTH = 8, // Taille des données (8 bits) + parameter DEPTH = 16 // Taille de la FIFO +)( + input wire clk, + input wire rst_p, + + // Entrée utilisateur + input wire [WIDTH-1:0] tx_data_in, + input wire tx_data_valid, // Donnée disponible à écrire + output wire tx_data_ready, // FIFO prête à recevoir + + // Sortie vers UART + output reg [WIDTH-1:0] tx_data_out, + input wire uart_tx_ready, // UART demande une donnée + output reg fifo_empty, + output reg fifo_full +); + + reg [WIDTH-1:0] fifo_mem [DEPTH-1:0]; + reg [4:0] wr_ptr = 0; + reg [4:0] rd_ptr = 0; + reg [4:0] fifo_count = 0; + + always @(posedge clk or posedge rst_p) begin + if (rst_p) begin + wr_ptr <= 0; + rd_ptr <= 0; + fifo_count <= 0; + fifo_empty <= 1; + fifo_full <= 0; + tx_data_out <= 0; + end else begin + // Écriture dans FIFO + if (tx_data_valid && !fifo_full) begin + fifo_mem[wr_ptr] <= tx_data_in; + wr_ptr <= wr_ptr + 1; + fifo_count <= fifo_count + 1; + end + + // Lecture depuis FIFO + if (uart_tx_ready && !fifo_empty) begin + tx_data_out <= fifo_mem[rd_ptr]; + rd_ptr <= rd_ptr + 1; + fifo_count <= fifo_count - 1; + end + + // Mise à jour des flags + fifo_empty <= (fifo_count == 0); + fifo_full <= (fifo_count == DEPTH); + end + end + + // FIFO est prête à recevoir des données si pas pleine + assign tx_data_ready = !fifo_full; + +endmodule diff --git a/Semaine_3/UARTV2/uart_rx.v b/Semaine_3/UARTV2/uart_rx.v new file mode 100644 index 0000000..278ee7c --- /dev/null +++ b/Semaine_3/UARTV2/uart_rx.v @@ -0,0 +1,145 @@ +module uart_rx #( + parameter CLK_FREQ = 27_000_000, + parameter BAUD_RATE = 115200 +)( + input clk, //clock input + input rst_p, //asynchronous reset input, high active + input rx_data_ready, //data receiver module ready + input rx_pin, //serial data input + + output reg[7:0] rx_data, //received serial data + output reg rx_data_valid //received serial data is valid +); + +localparam CYCLE = CLK_FREQ * / BAUD_RATE; + +//state machine code +localparam S_IDLE = 1; +localparam S_START = 2; //start bit +localparam S_REC_BYTE = 3; //data bits +localparam S_STOP = 4; //stop bit +localparam S_DATA = 5; + +reg[2:0] state; +reg[2:0] next_state; + +reg rx_d0; //delay 1 clock for rx_pin +reg rx_d1; //delay 1 clock for rx_d0 +wire rx_negedge; //negedge of rx_pin +reg[7:0] rx_bits; //temporary storage of received data +reg[15:0] cycle_cnt; //baud counter +reg[2:0] bit_cnt; //bit counter + +assign rx_negedge = rx_d1 && ~rx_d0; // Front déscendant + +always@(posedge clk or negedge rst_p) // Filtrage du signial +begin + if(rst_p == 1'b1)begin + rx_d0 <= 1'b0; + rx_d1 <= 1'b0; + + end else begin + rx_d0 <= rx_pin; + rx_d1 <= rx_d0; + end +end + + +always@(posedge clk or negedge rst_p)begin // Compteur d'etat + if(rst_p == 1'b1) + state <= S_IDLE; + else + state <= next_state; +end + +always@(*)begin + case(state) + S_IDLE: + if(rx_negedge) // Detection du start bit + next_state = S_START; + else + next_state = S_IDLE; + + S_START: + if(cycle_cnt == CYCLE - 1) //one data cycle + next_state = S_REC_BYTE; + else + next_state = S_START; + + S_REC_BYTE: + if(cycle_cnt == CYCLE - 1 && bit_cnt == 3'd7) //receive 8bit data + next_state = S_STOP; + else + next_state = S_REC_BYTE; + + S_STOP: + if(cycle_cnt == CYCLE/2 - 1) //half bit cycle,to avoid missing the next byte receiver + next_state = S_DATA; + else + next_state = S_STOP; + + S_DATA: + if(rx_data_ready) //data receive complete + next_state = S_IDLE; + else + next_state = S_DATA; + + default: + next_state = S_IDLE; + endcase +end + +always@(posedge clk or negedge rst_p) +begin + if(rst_p == 1'b1) + rx_data_valid <= 1'b0; + else if(state == S_STOP && next_state != state) + rx_data_valid <= 1'b1; + else if(state == S_DATA && rx_data_ready) + rx_data_valid <= 1'b0; +end + +always@(posedge clk or negedge rst_p) +begin + if(rst_p == 1'b1) + rx_data <= 8'd0; + else if(state == S_STOP && next_state != state) + rx_data <= rx_bits;//latch received data +end + +always@(posedge clk or negedge rst_p) +begin + if(rst_p == 1'b1) + begin + bit_cnt <= 3'd0; + end + else if(state == S_REC_BYTE) + if(cycle_cnt == CYCLE - 1) + bit_cnt <= bit_cnt + 3'd1; + else + bit_cnt <= bit_cnt; + else + bit_cnt <= 3'd0; +end + + +always@(posedge clk or negedge rst_p) +begin + if(rst_p == 1'b1) + cycle_cnt <= 16'd0; + else if((state == S_REC_BYTE && cycle_cnt == CYCLE - 1) || next_state != state) + cycle_cnt <= 16'd0; + else + cycle_cnt <= cycle_cnt + 16'd1; +end +//receive serial data bit data +always@(posedge clk or negedge rst_p) +begin + if(rst_p == 1'b1) + rx_bits <= 8'd0; + else if(state == S_REC_BYTE && cycle_cnt == CYCLE/2 - 1) + rx_bits[bit_cnt] <= rx_pin; + else + rx_bits <= rx_bits; +end +endmodule \ No newline at end of file diff --git a/Semaine_3/UARTV2/uart_top.v b/Semaine_3/UARTV2/uart_top.v new file mode 100644 index 0000000..ac9739e --- /dev/null +++ b/Semaine_3/UARTV2/uart_top.v @@ -0,0 +1,86 @@ +module uart_top( + input wire clk, + input wire rst, + + input wire uart_rx, + output wire uart_tx, + + // Interfaces RX vers utilisateur + output wire [7:0] rx_data, + output wire rx_data_valid, + input wire rx_data_ready, + + // Interfaces TX depuis utilisateur + input wire [7:0] tx_data, + input wire tx_data_valid, + output wire tx_data_ready +); + + parameter CLK_FRE = 27_000_000; // Hz + parameter UART_FRE = 115200; // Baudrate + + // === Signaux internes === + wire [7:0] uart_rx_data; + wire uart_rx_data_valid; + wire uart_rx_data_ready; + + wire [7:0] uart_tx_data; + wire uart_tx_data_valid; + wire uart_tx_data_ready; + + // === FIFO RX === + rx_fifo #( + .WIDTH(8), + .DEPTH(16) + ) rx_fifo_inst ( + .clk (clk), + .rst_p (rst), + .rx_data_in (uart_rx_data), + .rx_data_valid (uart_rx_data_valid), + .rx_data_out (rx_data), + .rx_data_ready (rx_data_ready), + .fifo_empty (), // pas utilisé ici + .fifo_full () + ); + + // === FIFO TX === + tx_fifo #( + .WIDTH(8), + .DEPTH(16) + ) tx_fifo_inst ( + .clk (clk), + .rst_p (rst), + .tx_data_in (tx_data), + .tx_data_valid (tx_data_valid), + .tx_data_ready (tx_data_ready), + .tx_data_out (uart_tx_data), + .uart_tx_ready (uart_tx_data_ready) + ); + + // === Instanciation RX UART === + uart_rx #( + .CLK_FRE(CLK_FRE), + .BAUD_RATE(UART_FRE) + ) uart_rx_inst ( + .clk (clk), + .rst_p (rst), + .rx_data (uart_rx_data), + .rx_data_valid (uart_rx_data_valid), + .rx_data_ready (uart_rx_data_ready), + .rx_pin (uart_rx) + ); + + // === Instanciation TX UART === + uart_tx #( + .CLK_FRE(CLK_FRE), + .BAUD_RATE(UART_FRE) + ) uart_tx_inst ( + .clk (clk), + .rst_p (rst), + .tx_data (uart_tx_data), + .tx_data_valid (uart_tx_data_valid), + .tx_data_ready (uart_tx_data_ready), + .tx_pin (uart_tx) + ); + +endmodule diff --git a/Semaine_3/UARTV2/uart_tx.v b/Semaine_3/UARTV2/uart_tx.v new file mode 100644 index 0000000..748631e --- /dev/null +++ b/Semaine_3/UARTV2/uart_tx.v @@ -0,0 +1,133 @@ +module uart_tx #( + parameter CLK_FREQ = 27_000_000, + parameter BAUD_RATE = 115200 +)( + input wire clk, + input wire rst_p, + input wire[7:0] data, + input wire tx_data_valid, + + output wire tx, + output reg tx_data_ready +); + + localparam CYCLE = CLK_FREQ / BAUD_RATE; + + localparam IDLE = 2'd0; + localparam START = 2'd1; + localparam DATA = 2'd2; + localparam STOP = 2'd3; + + reg [1:0] state = IDLE; + reg [1:0] next_state; + reg [15:0] cycle_cnt; //baud counter + reg [3:0] bit_index = 0; + reg [15:0] clk_count = 0; + reg [7:0] tx_data = 0; + reg tx_reg; + + assign tx = tx_reg; + + always@(posedge clk or posedge rst_p)begin // Avance d'etat + if(rst_p == 1'b1) + state <= IDLE; + else + state <= next_state; + end + + always@(*) begin + case(state) + IDLE: + if(tx_data_valid == 1'b1) + next_state = START; + else + next_state = IDLE; + + START: + if(cycle_cnt == CYCLE - 1) + next_state = DATA; + else + next_state = START; + + DATA: + if(cycle_cnt == CYCLE - 1 && bit_cnt == 3'd7) + next_state = STOP; + else + next_state = DATA; + + STOP: + if(cycle_cnt == CYCLE - 1) + next_state = IDLE; + else + next_state = STOP; + default: + next_state = IDLE; + endcase + end + + always@(posedge clk or posedge rst_p)begin // tx_data_ready block + if(rst_p == 1'b1) + begin + tx_data_ready <= 1'b0; + end + + else if(state == IDLE) + if(tx_data_valid == 1'b1) + tx_data_ready <= 1'b0; + else + tx_data_ready <= 1'b1; + + else if(state == STOP && cycle_cnt == CYCLE - 1) + tx_data_ready <= 1'b1; + end + + + always@(posedge clk or posedge rst_p) begin // tx_data_latch block + if(rst_p == 1'b1)begin + tx_data_latch <= 8'd0; + + end else if(state == IDLE && tx_data_valid == 1'b1) + tx_data_latch <= tx_data; + + end + + always@(posedge clk or posedge rst_p)begin // DATA bit_cnt block + if(rst_p == 1'b1)begin + bit_cnt <= 3'd0; + + end else if(state == DATA) + if(cycle_cnt == CYCLE - 1) + bit_cnt <= bit_cnt + 3'd1; + else + bit_cnt <= bit_cnt; + else + bit_cnt <= 3'd0; + end + + + always@(posedge clk or posedge rst_p)begin // Cycle counter + if(rst_p == 1'b1) + cycle_cnt <= 16'd0; + + else if((state == DATA && cycle_cnt == CYCLE - 1) || next_state != state) + cycle_cnt <= 16'd0; + else + cycle_cnt <= cycle_cnt + 16'd1; + end + + always@(posedge clk or posedge rst_p)begin // tx state managment + if(rst_p == 1'b1) + tx_reg <= 1'b1; + else + case(state) + IDLE,STOP: + tx_reg <= 1'b1; + START: + tx_reg <= 1'b0; + DATA: + tx_reg <= tx_data_latch[bit_cnt]; // SENDING BYTE HERE + default: + tx_reg <= 1'b1; + endcase + end +endmodule