//////////////////////////////////////////////////////////////////////////////// // // Create Date: 12/09/06 // Design Name: // Module Name: UART.v // Description: Quick and dirty UART // // // Revision: // Revision 0.01 - File Created // Additional Comments: // // File format: This file has been formated to use tabstop of 4 // // Development platform: Spartan-3E Starter kit // // Copyright (C) 2006, Rick Huang // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // // //////////////////////////////////////////////////////////////////////////////// module uart(bit_clk, reset, uart_tx, tx_data_reg, tx_busy, tx_load, tx_load_ack, uart_rx, rx_data_reg, rx_data_rdy, rx_frame_err, rx_sense ); // Common signals input bit_clk; input reset; // TX block signals output uart_tx; input [7:0] tx_data_reg; output tx_busy; input tx_load; // Is there data to load? output tx_load_ack; // Data is loaded into serilizer // RX block signals input uart_rx; output [7:0] rx_data_reg; // Data load register output [7:0] rx_frame_err; // Missing stop bit? output rx_data_rdy; // There is new data in data reg output rx_sense; // UART TX **************************************** reg [3:0] tx_clk_gen; // Use for div-16 reg [3:0] tx_state; // 10 bit transfer reg [9:0] tx_shift_reg; reg tx_busy; reg tx_load_ack; always @ (posedge bit_clk) begin if(reset) begin tx_clk_gen <= 4'b0; end else begin tx_clk_gen <= tx_clk_gen + 4'd1; end end always @ (posedge bit_clk) begin if(reset) begin tx_state <= 4'd0; tx_shift_reg[0] <= 1'b1; end else if(tx_clk_gen == 4'b0) begin case (tx_state) 4'd0: // Init state begin if(tx_load) begin tx_state <= 4'd1; tx_shift_reg[9] <= 1'b1; // Stop bit tx_shift_reg[8:1] <= tx_data_reg; tx_shift_reg[0] <= 1'b0; // Start bit tx_busy <= 1; tx_load_ack <= 1; end end 4'd10: begin if(tx_load) begin // Quick restart tx_state <= 4'd1; tx_shift_reg[9] <= 1'b1; // Stop bit tx_shift_reg[8:1] <= tx_data_reg; tx_shift_reg[0] <= 1'b0; // Start bit tx_busy <= 1; tx_load_ack <= 1; end else begin tx_state <= 4'd0; tx_busy <= 0; end end default: begin tx_shift_reg[8:0] <= tx_shift_reg[9:1]; tx_shift_reg[9] <= 1'b1; tx_state <= tx_state + 1; tx_load_ack <= 0; end endcase end end assign uart_tx = tx_shift_reg[0]; // UART RX ************************************ reg [3:0] rx_clk_gen; // Use for div-16 reg [3:0] rx_state; // 10 bit transfer reg [9:0] rx_shift_reg; reg [7:0] rx_data_reg; // Data load register reg [7:0] rx_frame_err; // Missing stop bit? reg [2:0] rx_sample; reg rx_buffed; reg rx_data_rdy; reg rx_sense; always @ (posedge bit_clk) rx_buffed <= uart_rx; // Sync to internal clock first always @ (posedge bit_clk) begin if(reset) begin rx_state <= 4'd0; rx_clk_gen <= 4'd0; rx_data_rdy <= 0; end else begin case (rx_state) 4'd0: // Init - rx_clk_gen at 10 for restart begin rx_data_rdy <= 0; if(rx_buffed == 0) // Start condition detected begin rx_clk_gen <= 4'd0; rx_state <= 4'd1; end end default: begin if(rx_clk_gen == 4'd4) begin rx_sample[0] <= rx_buffed; rx_sense <= 1; end if(rx_clk_gen == 4'd5) rx_sample[1] <= rx_buffed; if(rx_clk_gen == 4'd6) rx_sample[2] <= rx_buffed; if(rx_clk_gen == 4'd7) begin // Say it is a 1 if two or more bits is 1 rx_shift_reg[9] <= (rx_sample == 3'b011 || rx_sample == 3'b111 || rx_sample == 3'b110 || rx_sample == 3'b101) ? 1 : 0; rx_shift_reg[8:0] <= rx_shift_reg[9:1]; rx_sense <= 0; end if(rx_clk_gen == 4'd8) rx_state <= rx_state + 4'd1; rx_clk_gen <= rx_clk_gen + 4'd1; end 4'd11: begin // rx_clk_gen should be 9 at this time rx_data_reg <= rx_shift_reg[8:1]; rx_state <= 4'd0; if(rx_shift_reg[9] != 1'b1 || rx_shift_reg[0] != 1'b0) // Start/stop bit error rx_frame_err <= rx_frame_err + 1; rx_data_rdy <= 1; end endcase end end endmodule