UART Controller in Verilog
UART Transmitter
module uart_tx (
input wire clk, // System clock
input wire reset, // Reset signal
input wire [7:0] data, // Data to transmit
input wire start_tx, // Start transmission signal
output reg tx, // UART transmit line
output reg busy, // Transmission busy flag
output reg done // Transmission done flag
);
parameter CLK_DIV = 16; // Clock division for baud rate
reg [3:0] state; // State machine state
reg [3:0] bit_cnt; // Bit counter
reg [7:0] shift_reg; // Shift register for data
reg [7:0] clk_div_cnt; // Clock division counter
parameter IDLE = 4'b0000,
START = 4'b0001,
SEND_DATA = 4'b0010,
STOP = 4'b0011;
always @(posedge clk or posedge reset) begin
if (reset) begin
state <= IDLE;
tx <= 1'b1; // Idle state is high
busy <= 1'b0;
done <= 1'b0;
bit_cnt <= 4'b0000;
clk_div_cnt <= 8'b0;
end else begin
clk_div_cnt <= clk_div_cnt + 1;
if (clk_div_cnt == CLK_DIV - 1) begin
clk_div_cnt <= 8'b0; // Reset clock division counter
case (state)
IDLE: begin
done <= 1'b0;
if (start_tx) begin
busy <= 1'b1;
state <= START;
shift_reg <= data; // Load data to shift register
bit_cnt <= 4'b0000; // Reset bit counter
tx <= 1'b0; // Start bit
end
end
START: begin
state <= SEND_DATA;
end
SEND_DATA: begin
if (bit_cnt < 8) begin
tx <= shift_reg[0]; // Send LSB first
shift_reg <= {1'b0, shift_reg[7:1]}; // Shift data
bit_cnt <= bit_cnt + 1;
end else begin
state <= STOP; // Move to stop bit
end
end
STOP: begin
tx <= 1'b1; // Stop bit
busy <= 1'b0;
done <= 1'b1; // Transmission done
state <= IDLE; // Go back to idle
end
default: state <= IDLE; // Default to idle
endcase
end
end
end
endmodule
UART Receiver
module uart_rx (
input wire clk, // System clock
input wire reset, // Reset signal
input wire rx, // UART receive line
output reg [7:0] data, // Received data
output reg data_ready, // Data ready signal
output reg busy // Receiver busy flag
);
parameter CLK_DIV = 16; // Clock division for baud rate
reg [3:0] state; // State machine state
reg [3:0] bit_cnt; // Bit counter
reg [7:0] shift_reg; // Shift register for data
reg [7:0] clk_div_cnt; // Clock division counter
parameter IDLE = 4'b0000,
START = 4'b0001,
RECEIVE_DATA = 4'b0010,
STOP = 4'b0011;
always @(posedge clk or posedge reset) begin
if (reset) begin
state <= IDLE;
data_ready <= 1'b0;
busy <= 1'b0;
bit_cnt <= 4'b0000;
clk_div_cnt <= 8'b0;
end else begin
clk_div_cnt <= clk_div_cnt + 1;
if (clk_div_cnt == CLK_DIV - 1) begin
clk_div_cnt <= 8'b0; // Reset clock division counter
case (state)
IDLE: begin
data_ready <= 1'b0;
if (rx == 1'b0) begin // Start bit detected
busy <= 1'b1;
state <= START;
end
end
START: begin
state <= RECEIVE_DATA;
bit_cnt <= 4'b0000; // Reset bit counter
end
RECEIVE_DATA: begin
if (bit_cnt < 8) begin
shift_reg[bit_cnt] <= rx; // Receive data
bit_cnt <= bit_cnt + 1;
end else begin
state <= STOP; // Move to stop bit
end
end
STOP: begin
data <= shift_reg; // Store received data
data_ready <= 1'b1; // Indicate data is ready
busy <= 1'b0;
state <= IDLE; // Go back to idle
end
default: state <= IDLE; // Default to idle
endcase
end
end
end
endmodule