From d178e7bee0e1327e3ec1e58cfef82e1cbc7387cb Mon Sep 17 00:00:00 2001 From: Aadi Desai <21363892+supleed2@users.noreply.github.com> Date: Thu, 27 May 2021 17:09:15 +0100 Subject: [PATCH] Add UART interface IP Tp be tested --- .../ip/de10lite-hdl/uart.v | 273 ++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 Vision/DE10_LITE_D8M_VIP_16/ip/de10lite-hdl/uart.v diff --git a/Vision/DE10_LITE_D8M_VIP_16/ip/de10lite-hdl/uart.v b/Vision/DE10_LITE_D8M_VIP_16/ip/de10lite-hdl/uart.v new file mode 100644 index 0000000..df3820e --- /dev/null +++ b/Vision/DE10_LITE_D8M_VIP_16/ip/de10lite-hdl/uart.v @@ -0,0 +1,273 @@ +/* +Source: https://github.com/hildebrandmw/de10lite-hdl/blob/master/components/uart/hdl/uart.v +Description: Very simple UART tx/rx module. Requires a streaming interface, +provides no buffering for input or output data. +*/ + +module uart +#( parameter CLK_FREQ = 50_000_000, + parameter BAUD = 115_200 +) +( input clk, + input reset, + + // Receiving + input rx, // Received serial stream + output reg [7:0] rx_data, // Deserialized byte. + output rx_valid, // Asserted when rx_data is valid + + // Transmitting + output reg tx, // Transmitted serial stream + input [7:0] tx_data, // Deserialized byte to transmit. + input tx_transmit, // Start Signal. No effect if tx_ready = 0 + output reg tx_ready // Asserted when ready to accept data + ); + + /////////////////////////////// + // Functionality Description // + /////////////////////////////// + + /* + RECEIVING: Module receives a serial stream through the port rx. + When a byte has been successfully received, the received data will be + available on the output port rx_data and the output port rx_valid will be + asserted for 1 clock cycle. + + Validity of output data is not guaranteed if rx_valid is not 1. If this + is important for you, you may modify this design to register the output. + + TRANSMITTING: When input port tx_transmit is 1 (asserted), module will + store the data on the input port tx_data and serialize through the output + port tx. + + Module will only save and transmit the data at tx_data if the signal + tx_ready is asserted when tx_transmit is asserted. This module will not + buffer input data. While transmitting, tx_ready is deasserted and the + input port tx_transmit will have no effect. + + Once tx_ready is deasserted, data at port tx_data is not used and need + not be stable. + */ + + ///////////////////////// + // Signal Declarations // + ///////////////////////// + + // ---------------------- // + // -- Local Parameters -- // + // ---------------------- // + + // Number of synchronization stages to avoid metastability + localparam SYNC_STAGES = 2; + + // Over Sampling Factor + localparam OSF = 16; + + // Compute count to generate local clock enable + localparam CLK_DIV_COUNT = CLK_FREQ / (OSF * BAUD); + + // ---------------------------- // + // -- Clock Dividing Counter -- // + // ---------------------------- // + + reg [15:0] count; + reg enable; // Local Clock Enable + + // -- RX Synchronizer -- + reg [SYNC_STAGES-1:0] rx_sync; + reg rx_internal; + + // ---------------- // + // -- RX Signals -- // + // ---------------- // + + // State Machine Assignments + localparam RX_WAIT = 0; + localparam RX_CHECK_START = 1; + localparam RX_RECEIVING = 2; + localparam RX_WAIT_FOR_STOP = 3; + + localparam RX_INITIAL_STATE = RX_WAIT; + reg [1:0] rx_state = RX_INITIAL_STATE; + + reg [4:0] rx_count; // Counts Over-sampling clock enables + reg [2:0] rx_sampleCount; // Counts number of bits received + + // These last two signals are used to make sure the "rx_valid" signal + // is only asserted for one clock cycle. + + reg rx_validInternal, rx_validLast; + + // -----------------// + // -- TX Signals -- // + // -----------------// + + // State Machine Assignments + localparam TX_WAIT = 0; + localparam TX_TRANSMITTING = 1; + + localparam TX_INITIAL_STATE = TX_WAIT; + reg tx_state = TX_INITIAL_STATE; + + reg [9:0] tx_dataBuffer; // Capture Register for transmitted data + reg [4:0] tx_count; // Counts over-sampling clock + reg [3:0] tx_sampleCount; // Number of Bits Sent + + ///////////////////// + // Implementations // + ///////////////////// + + // ---------------------------- // + // -- Misc Synchronous Logic -- // + // ---------------------------- // + + always @(posedge clk) begin + + // Clock Divider + if (reset) begin + count <= 0; + enable <= 0; + end else if (count == CLK_DIV_COUNT - 1) begin + count <= 0; + enable <= 1; + end else begin + count <= count + 1; + enable <= 0; + end + + // RX Synchronizer + if (enable) begin + {rx_sync,rx_internal} <= {rx, rx_sync}; + end + + // Pulse Shortener for rx_valid signal + rx_validLast <= rx_validInternal; + end + + // Pulse Shortner for rx_valid signal + assign rx_valid = rx_validInternal & ~rx_validLast; + + + // ---------------------- // + // -- RX State Machine -- // + // ---------------------- // + + always @(posedge clk) begin + if (reset) begin + rx_state <= RX_INITIAL_STATE; + rx_validInternal <= 0; + end else if (enable) begin + case (rx_state) + + // Wait for the start bit. (RX = 0) + + RX_WAIT: begin + rx_validInternal <= 0; + if (rx_internal == 0) begin + rx_state <= RX_CHECK_START; + rx_count <= 1; + end + end + + // Aligh with center of transmitted bit + + RX_CHECK_START: begin + + // Check if RX is still 0 + if (rx_count == (OSF >> 1) - 1 && rx_internal == 0) begin + rx_state <= RX_RECEIVING; + rx_count <= 0; + rx_sampleCount <= 0; + + // Faulty Start Bit + end else if (rx_count == (OSF >> 1) - 1 && rx_internal == 1) begin + rx_state <= RX_WAIT; + + // Default Option: Count local clocks + end else begin + rx_count <= rx_count + 1; + end + end + + // Sample in middle of received bit. Shift data into rx_data + RX_RECEIVING: begin + if (rx_count == OSF - 1) begin + rx_count <= 0; + rx_data <= {rx_internal, rx_data[7:1]}; + rx_sampleCount <= rx_sampleCount + 1; + + // Check if this is the last bit of data + if (rx_sampleCount == 7) begin + rx_state <= RX_WAIT_FOR_STOP; + end + end else begin + rx_count <= rx_count + 1; + end + end + + // Wait until stop bit is received + // Not the best logic in the world, but it works. + RX_WAIT_FOR_STOP: begin + if (rx_internal == 1'b1) begin + rx_state <= RX_WAIT; + rx_validInternal <= 1; + end + end + + // In case something goes horribly wrong. + default: begin + rx_state <= RX_INITIAL_STATE; + end + endcase + end + end + + // ---------------------- // + // -- TX State Machine -- // + // ---------------------- // + + always @(posedge clk) begin + if (reset) begin + tx_state <= TX_INITIAL_STATE; + tx <= 1; + end else begin + case (tx_state) + // Wait for start signal. + // Register transmitted data and deassert ready. + TX_WAIT: begin + tx <= 1; + if (tx_transmit) begin + tx_dataBuffer <= {1'b1, tx_data, 1'b0}; + tx_count <= 0; + tx_sampleCount <= 0; + tx_ready <= 0; + tx_state <= TX_TRANSMITTING; + end else begin + tx_ready <= 1; + end + end + + // Shift Out Data + TX_TRANSMITTING: begin + if (enable) begin + if (tx_count == OSF - 1) begin + tx_count <= 0; + tx_sampleCount <= tx_sampleCount + 1; + tx <= tx_dataBuffer[0]; + tx_dataBuffer <= {1'b1, tx_dataBuffer[9:1]}; + if (tx_sampleCount == 9) begin + tx_state <= TX_WAIT; + end + end else begin + tx_count <= tx_count + 1; + end + end + end + + default: begin + tx_state <= TX_WAIT; + end + endcase + end + end +endmodule \ No newline at end of file