Back to Templates
UART 收发器UART Transceiver (TX + RX)
基于 VLSI-Shubh/UART 的 UART 收发器,含 16x 过采样 TX/RX 和波特率发生器。
UARTmasterverilog
Open Source Notice
Source Repository: https://github.com/VLSI-Shubh/UART
License: MIT
Author: Shubham Kapil Upadhyay
Copyright (c) 2025 Shubham Kapil Upadhyay
Key Points
- - TX: start bit + 8 data bits (LSB first) + stop bit
- - RX: 16x oversampling with mid-bit sampling
- - Baud generator: configurable rate via parameters
- - Full-duplex operation (independent TX and RX)
RTL Source
// Copyright (c) 2025 Shubham Kapil Upadhyay
// SPDX-License-Identifier: MIT
// Source: https://github.com/VLSI-Shubh/UART
// Annotated UART TX/RX with baud generator
// Based on uart_tx, uart_rx, baudgen modules from VLSI-Shubh/UART
// 中文:UART 收发器模板,基于 VLSI-Shubh/UART 项目
`timescale 1ns / 1ps
// UART Transmitter with 16x oversampling
// 中文:UART 发送器,16 倍过采样,帧格式:起始位+8数据位+停止位
// Frame: 1 start bit + 8 data bits (LSB first) + 1 stop bit
module uart_tx (
input wire [7:0] data_in, // Parallel data input
input wire clk, // System clock
input wire rst, // Synchronous reset
input wire start_tx, // Start transmission
input wire baud_tick, // Baud rate tick (16x oversampling)
output reg tx_done, // Transmission complete flag
output reg tx_line // UART TX serial output
);
// FSM state encoding (one-hot)
parameter [3:0] S_IDLE = 4'b0001, // Idle: TX line high
S_START = 4'b0010, // Send start bit (low)
S_DATA = 4'b0100, // Send 8 data bits
S_STOP = 4'b1000; // Send stop bit (high)
reg [3:0] ps, ns; // Present state, next state
reg [3:0] tick_counter; // 16x oversampling counter
reg [2:0] bit_index; // Current data bit index
reg [7:0] tx_data; // Latched TX data
// Sequential: state register
always @(posedge clk) begin
if (rst) begin
ps <= S_IDLE;
tick_counter <= 0;
bit_index <= 0;
end else begin
ps <= ns;
end
end
// Combinational: next-state logic
always @(*) begin
case (ps)
S_IDLE: begin
if (start_tx)
ns = S_START;
else
ns = S_IDLE;
end
S_START: begin
if (baud_tick)
ns = S_DATA;
else
ns = S_START;
end
S_DATA: begin
if (baud_tick && bit_index == 7)
ns = S_STOP;
else
ns = S_DATA;
end
S_STOP: begin
if (baud_tick && tx_done)
ns = S_IDLE;
else
ns = S_STOP;
end
default: ns = ps;
endcase
end
// Output logic
always @(posedge clk) begin
case (ps)
S_IDLE: begin
tx_line <= 1; // Idle high
if (start_tx) begin
tx_done <= 0;
tx_data <= data_in; // Latch input data
end else begin
tx_done <= 0;
end
end
S_START: begin
tx_done <= 0;
tx_line <= 0; // Start bit = 0
bit_index <= 0;
end
S_DATA: begin
if (baud_tick) begin
if (tick_counter == 0) begin
tx_line <= tx_data[bit_index]; // Output data bit
end
if (tick_counter == 15) begin
bit_index <= bit_index + 1;
end
end
end
S_STOP: begin
if (baud_tick) begin
tx_line <= 1; // Stop bit = 1
if (tick_counter == 15) begin
tx_done <= 1; // Signal completion
end
end
end
default: begin
tx_done <= 1;
tx_line <= 1;
end
endcase
end
// 16x oversampling tick counter
always @(posedge clk) begin
if (rst) begin
tick_counter <= 0;
end else if (ps == S_IDLE) begin
tick_counter <= 0;
end else if (baud_tick) begin
if (tick_counter == 15)
tick_counter <= 0;
else
tick_counter <= tick_counter + 1;
end
end
endmodule
// UART Receiver with 16x oversampling
// Detects start bit, samples data at mid-bit, outputs parallel data
module uart_rx (
input wire rx, // UART RX serial input
input wire clk, // System clock
input wire rst, // Synchronous reset
input wire baud_tick, // Baud rate tick (16x oversampling)
output reg rx_done, // Data received flag
output reg [7:0] data_out // Received parallel data
);
// FSM state encoding (one-hot)
parameter [3:0] S_IDLE = 4'b0001,
S_START = 4'b0010,
S_DATA = 4'b0100,
S_STOP = 4'b1000;
reg [3:0] ps, ns;
reg [3:0] tick_counter;
reg [3:0] bit_index;
reg [7:0] rx_data;
// Sequential: state register
always @(posedge clk) begin
if (rst) begin
ps <= S_IDLE;
tick_counter <= 0;
bit_index <= 0;
end else begin
ps <= ns;
end
end
// Combinational: next-state logic
always @(*) begin
case (ps)
S_IDLE: begin
if (~rx) // Detect start bit (falling edge)
ns = S_START;
else
ns = S_IDLE;
end
S_START: begin
if (baud_tick && tick_counter == 7) // Sample at mid-bit
ns = S_DATA;
else
ns = S_START;
end
S_DATA: begin
if (baud_tick && bit_index > 7)
ns = S_STOP;
else
ns = S_DATA;
end
S_STOP: begin
if (baud_tick && tick_counter == 7)
ns = S_IDLE;
else
ns = S_STOP;
end
default: ns = S_IDLE;
endcase
end
// Output logic and data sampling
always @(posedge clk) begin
if (rst) begin
tick_counter <= 0;
bit_index <= 0;
rx_done <= 0;
rx_data <= 0;
data_out <= 0;
end else begin
case (ps)
S_IDLE: begin
if (baud_tick) begin
rx_done <= 0;
tick_counter <= 0;
bit_index <= 0;
end
end
S_START: begin
rx_done <= 0;
if (baud_tick) begin
if (tick_counter == 7)
tick_counter <= 0;
else
tick_counter <= tick_counter + 1;
end
end
S_DATA: begin
if (baud_tick) begin
if (bit_index < 8) begin
if (tick_counter == 7) begin
rx_data[bit_index] <= rx; // Sample at mid-bit
end
if (tick_counter == 15) begin
bit_index <= bit_index + 1;
tick_counter <= 0;
end else begin
tick_counter <= tick_counter + 1;
end
end
end
end
S_STOP: begin
rx_done <= 0;
if (baud_tick) begin
if (tick_counter == 7) begin
data_out <= rx_data;
rx_done <= 1;
tick_counter <= 0;
end else begin
tick_counter <= tick_counter + 1;
end
end
end
default: begin
rx_done <= 0;
bit_index <= 0;
tick_counter <= 0;
end
endcase
end
end
endmodule
// Baud Rate Generator with 16x oversampling
// Generates baud_tick pulses at 16x the desired baud rate
module baudgen #(
parameter BAUD_RATE = 9600, // Target baud rate
parameter CLOCK_FREQ = 50_000_000 // System clock frequency
)(
input wire clk,
input wire rst,
output reg baud_tick
);
// Calculate divider value for 16x oversampling
localparam TICKS = CLOCK_FREQ / (BAUD_RATE * 16);
reg [$clog2(TICKS)-1:0] baud_counter;
always @(posedge clk) begin
if (rst) begin
baud_counter <= 0;
baud_tick <= 0;
end else begin
if (baud_counter == TICKS - 1) begin
baud_counter <= 0;
baud_tick <= 1;
end else begin
baud_counter <= baud_counter + 1;
baud_tick <= 0;
end
end
end
endmodule