Akasam Sai Pavan
Title: Full-Duplex UART for a single transmitter to single receiver
Subtitle: FSM and Verilog Implementation
Akasam Sai Pavan
Introduction
Universal Asynchronous Receiver Transmitter (UART) is a widely used protocol for serial
communication, especially in embedded systems and real-time applications. In a full-
duplex UART, data can be transmitted and received simultaneously, providing a
continuous communication stream. In this design, a single transmitter will send data to
many receivers simultaneously, optimizing for industrial usage, high accuracy, and real-
time performance.
or
UART (Universal Asynchronous Receiver/Transmitter) is a hardware communication
protocol used for serial communication between devices. It operates by transmitting and
receiving data in an asynchronous fashion, where the transmitter and receiver clocks are
not synchronized. A full-duplex UART enables simultaneous transmission and reception
of data. In real-time applications, particularly in industrial settings, reliability, low latency,
and scalability are critical. A full-duplex UART connecting a single transmitter to multiple
receivers is useful in industrial control systems, sensor networks, and automation, where
a central controller may need to broadcast data to multiple devices while receiving status
updates in parallel.
UARTs have been used for more than 60 years, and they were the primary means of
moving serial data between digital systems for most of those years, (in fact the terms
UART and serial port assumed a common meaning for many years). The term UART
actually refers only to the digital send and receive circuit blocks, and not the
transmission system itself. The UART circuit blocks are independent from (and are
probably not aware of) the physical signaling method used to transport data.
UARTs use one signal to transmit data, and a second independent signal to receive
data. A given UART may use just one signal for unidirectional “simplex" communication,
or two signals for bidirectional communications. Bidirectional communications can be
“full-duplex", with information flowing in both directions simultaneously, or “half-duplex",
where information only flows in one direction at a time. Akasam Sai Pavan
Akasam Sai Pavan
Synchronous Design:
A synchronous design refers to a system where all operations are coordinated by a global clock signal. In
this design, the entire system moves forward in lockstep based on clock pulses. The operations and state
transitions of flip-flops and registers occur at specific intervals, controlled by the rising or falling edge of
the clock signal.
Key Characteristics:
• Clock Signal: All components operate in sync with the clock.
• Deterministic behaviour: Outputs and operations happen at predictable times (synchronous to the
clock).
• Ease of Design: Design tools and methodologies are well-established for synchronous circuits,
simplifying design, verification, and testing.
• Timing constraints: Timing must be managed carefully to avoid violations like setup time or hold time
violations (e.g., signals must settle before the next clock edge).
• Scalability: Limited by clock distribution, especially in larger systems where distributing the clock
uniformly can become a challenge.
Advantages of Synchronous Design: Akasam Sai Pavan
• Predictable and reliable timing.
• Easier to design and debug.
• Wide tool support for synthesis and verification.
Disadvantages of Synchronous Design:
• Clock distribution complexity.
• Power consumption due to continuous toggling of the clock.
• The need for synchronization between different clock domains in complex systems.
Asynchronous Design:
An asynchronous design does not rely on a global clock. Instead, components are driven by signals or
"events" that trigger specific operations. Communication between modules happens via handshake
protocols, where data transfers are based on requests and acknowledgments.
Key Characteristics:
• No Clock: Operations are triggered by events or changes in input signals rather than a clock signal.
• Handshaking Protocols: Data is transferred between modules using request and acknowledgment
signals (common in communication protocols).
• Speed Independence: Components run at their own pace, often faster than in synchronous
designs, limited only by their own delays.
• Timing Tolerance: Asynchronous designs are inherently more tolerant to delays, variations, and
metastability, as the system is not tied to a fixed clock speed.
Akasam Sai Pavan
Advantages of Asynchronous Design:
• Lower Power Consumption: Components only switch when needed (event-driven) instead of
continuous clock-driven toggling.
• Robust to Variations: Asynchronous circuits can adapt better to voltage, temperature, and process
variations, as there is no strict timing requirement.
• Speed Flexibility: Can operate at different speeds in different parts of the system, making them
suitable for mixed-timing systems.
• Reduced Electromagnetic Interference (EMI): The absence of a global clock reduces EMI, which is
important in communication systems.
Disadvantages of Asynchronous Design:
• Design Complexity: The absence of a clock makes verification, debugging, and synthesis more
challenging due to the need for careful management of timing and handshaking signals.
• Tool Support: Fewer automated tools and methodologies are available, making design flow more
complicated.
Why Asynchronous Designs Are Used in Communication Protocols: Akasam Sai Pavan
Asynchronous designs are frequently used in communication protocols for several reasons:
1. Data-Driven Nature: Communication protocols are often event-driven, where data arrives at irregular
intervals. Asynchronous systems naturally align with this behaviour since they don’t depend on a fixed
clock rate.
2. No Global Synchronization Required: In distributed systems (like communication networks), it is
impractical to synchronize all components to a single clock. Asynchronous designs allow parts of the
system to operate at different speeds or in different time zones without synchronization overhead.
3. Reduced Latency: In asynchronous designs, operations happen as soon as they are ready, without
waiting for the next clock cycle. This can lead to reduced latency, which is essential in high-speed
communication.
4. Lower Power Consumption: Communication systems often need to save power, particularly in
mobile or battery-operated devices. Asynchronous circuits only switch when necessary, leading to lower
dynamic power consumption compared to clock-driven synchronous designs.
5. Metastability Tolerance: In communication protocols, signals from different domains may arrive at
unpredictable times. Asynchronous designs can handle this uncertainty better, as they are more tolerant
to metastability (conditions where inputs don’t meet setup/hold times).
Akasam Sai Pavan
Akasam Sai Pavan
Asynchronous Communication:
1. No clock signal is needed; devices must agree on baud rate (data transfer
speed).
2. Full-Duplex Communication: Separate transmit (TX) and receive (RX) lines
allow simultaneous two-way communication.
3. Data Framing: Data is transmitted in frames, each consisting of a start bit, data
bits (typically 8), an optional parity bit, and one or more stop bits.
4. Error Checking: Optional parity bit allows simple error detection.
Akasam Sai Pavan
The UART communication typically involves two pins:
TX (Transmit): The pin where the microcontroller sends data.
RX (Receive): The pin where the microcontroller receives data.
• The main purpose of a transmitter and receiver line for each device is to transmit and
receive serial data intended for serial communication.
• The transmitting UART is connected to a controlling data bus that sends data in a
parallel form. From this, the data will now be transmitted on the transmission line
(wire) serially, bit by bit, to the receiving UART.
• This, in turn, will convert the serial data into parallel for the receiving device. The
UART lines serve as the communication medium to transmit and receive one data to
another.
• Take note that a UART device has a transmit and receive pin dedicated for either
transmitting or receiving.
• For UART and most serial communications, the baud rate needs to be set the same
on both the transmitting and receiving device. The baud rate is the rate at which
information is transferred to a communication channel. In the serial port context, the
set baud rate will serve as the maximum number of bits per second to be transferred.
Akasam Sai Pavan
Baud Rate:
The baud rate defines the speed of data transmission in bits per second (bps). Both
communicating devices must agree on a common baud rate to ensure proper data
exchange. Common baud rates include 9600, 115200, etc.
But what exactly would the 9600 baud rate mean? It means a device can send up to
9600 bits, or ones and zeros, per second.
Design Requirements:
• Full-duplex communication: Simultaneous transmission and receiving of data.
• Single transmitter, single / multiple receivers: A transmitter sends data to 1 or more
receivers simultaneously.
• Real-time operation: The UART must operate in real-time, with minimal delays, to
meet the requirements of industrial applications.
Akasam Sai Pavan
• Industrial-grade accuracy: High noise immunity and reliable data transmission under
adverse environmental conditions.
• Error detection: Parity checking and framing error detection mechanisms for data
integrity.
Akasam Sai Pavan
Design Overview:
o Transmitter: The transmitter will be responsible for serializing parallel data and
broadcasting it to all three receivers simultaneously. The data will be transmitted bit-
by-bit along with start and stop bits and optional parity bits for error detection.
o Receivers: Each receiver will decode the serialized data, deserializing it into its
original parallel form, and verifying the integrity of the received data using error-
checking mechanisms.
o Baud Rate Generator: Both transmitter and receiver need a baud rate generator for
synchronous timing to ensure proper data transmission and reception. The baud rate
must match across the transmitter and receivers.
o Control Logic: The control logic will handle framing, error checking, and
synchronization between the transmitter and the receivers. Control signals such as
tx_en (transmit enable) and rx_en (receive enable) will be used to start or stop
communication.
o Testbench: The testbench will verify the correctness of the design by simulating real-
time data transfer between the transmitter and the three receivers.
Akasam Sai Pavan
Finite State Machine (FSM) for the full-duplex UART design governs both the
transmitter and receivers. Below is the FSM diagram explanation for each module:
States of the Transmitter:
IDLE:
• Initial state where the transmitter is idle and waits for the tx_start signal.
• Transitions to START state when tx_start signal is asserted and the tx_busy flag
is low (ensures it's not already transmitting).
START:
• In this state, the start bit (which is always 0) is transmitted.
• After one baud tick, the FSM transitions to the DATA state.
DATA:
• Here, the data bits (LSB first) are transmitted one bit at a time.
• For each baud tick, the FSM shifts out the next data bit through tx_shift_reg.
• The FSM counts the number of bits sent using tx_bit_count. When all 8 bits have
been transmitted, the FSM transitions to the STOP state.
Akasam Sai Pavan
STOP:
• After all the data bits have been transmitted, a stop bit (which is always 1) is
transmitted.
• After one baud tick, the FSM transitions to the DONE state.
DONE:
• This state signals the end of the transmission by setting tx_done to 1.
• The FSM returns to the IDLE state, ready for the next transmission.
IDLE → START: When tx_start signal is high.
START → DATA: Transmit start bit.
DATA → STOP: When all 8 data bits are sent.
STOP → DONE: Transmit stop bit.
DONE → IDLE: Transmission is complete, ready for new data.
Akasam Sai Pavan
States of the Receiver:
IDLE:
• The receiver is waiting for a start bit (a low signal on the receive line).
• Transitions to START when a start bit (low signal) is detected.
START:
• The start bit is checked and then the FSM transitions to the DATA state.
DATA:
• The data bits are received one by one. Each bit is shifted into rx_shift_reg (LSB first).
• The FSM counts the bits received using rx_bit_count.
• Once all 8 bits are received, the FSM transitions to STOP.
Akasam Sai Pavan
STOP:
• The stop bit is verified (should be 1).
• The FSM transitions to the DONE state.
DONE:
• The FSM sets the rx_done signal to indicate that valid data has been received.
• After data is processed, it transitions back to the IDLE state.
IDLE → START: When start bit is detected (rx_line goes low).
START → DATA: Start bit confirmed, begin receiving data bits.
DATA → STOP: When all 8 bits are received.
STOP → DONE: Stop bit checked.
DONE → IDLE: Reception is complete, ready for new data.
Akasam Sai Pavan
Verilog Design Explanation:
• The uart_full_duplex module manages both transmission and reception. The
transmitter sends serial data through tx_line, and the receivers capture data from
separate rx_line1.
• Receiver processes the incoming serial data and stores it in a buffer, while the
transmitter indicates the completion of transmission using tx_done.
• The testbench stimulates the design by applying a clock and reset signal. Data is
transmitted, and the design captures the responses from all three receivers, ensuring
proper functioning.
• Baud Rate Generator: This generates a baud_tick signal at the correct frequency for
the specified baud rate. It uses a counter to divide the system clock.
• Transmitter (TX): It follows a state machine that handles start, data transmission, and
stop bits. The tx_shift_reg shifts out each bit, starting with the least significant bit
(LSB).
Akasam Sai Pavan
• Receiver (RX1): Receiver has its own state machine, similar to the transmitter, but
it reads incoming bits from the rx_line1. The shift registers (rx_shift_reg1) store the
received data.
• Bit Counting: Each state machine tracks the number of bits transmitted or
received with a counter (tx_bit_count for the transmitter and rx_bit_count1 for the
receiver).
Akasam Sai Pavan
UART Transmitter Design Module (Verilog):
module uart_full_duplex (
input wire clk, // System clock
input wire rst_n, // Active low reset
input wire tx_start, // Transmit start signal
input wire [7:0] tx_data, // Data to transmit
output reg tx_done, // Transmit complete signal
output wire tx_line, // Transmitter output
input wire rx_line1, // Receiver line 1
output reg [7:0] rx_data1, // Data received at receiver 1
output reg rx_done1, // Receive complete for receiver 1
);
Akasam Sai Pavan
// UART parameters
parameter CLK_FREQ = 50000000; // 50 MHz clock
parameter BAUD_RATE = 9600; // Baud rate
parameter BAUD_DIV = CLK_FREQ / (BAUD_RATE * 16); // Baud rate divider
// Transmitter and receiver control signals
reg [3:0] tx_bit_count;
reg [3:0] rx_bit_count1;
reg [7:0] tx_shift_reg;
reg [7:0] rx_shift_reg1;
reg [15:0] baud_counter;
reg tx_busy;
reg tx_shift_enable;
reg rx_shift_enable1;
reg [2:0] tx_state, rx_state1;
Akasam Sai Pavan
assign tx_line = tx_shift_reg[0]; // Transmit data bit
// State machine encoding
localparam IDLE = 3'b000;
localparam START = 3'b001;
localparam DATA = 3'b010;
localparam STOP = 3'b011;
localparam DONE = 3'b100;
// Baud rate generator
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
baud_counter <= 16'b0;
else if (baud_counter == BAUD_DIV - 1)
baud_counter <= 16'b0;
else
baud_counter <= baud_counter + 1;
end
Akasam Sai Pavan
wire baud_tick = (baud_counter == BAUD_DIV - 1);
// Transmitter state machine
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
tx_state <= IDLE;
tx_shift_reg <= 8'b11111111; // Idle state for UART
tx_done <= 0;
tx_bit_count <= 4'b0;
tx_busy <= 0;
end else if (baud_tick) begin
case (tx_state)
IDLE: begin
tx_done <= 0;
Akasam Sai Pavan
if (tx_start && !tx_busy) begin
tx_state <= START;
tx_shift_reg <= {1'b1, tx_data, 1'b0}; // Start bit, data, stop bit
tx_busy <= 1;
end
end
START: begin
tx_state <= DATA;
end
DATA: begin
if (tx_bit_count == 8) begin
tx_state <= STOP;
tx_bit_count <= 0;
end
Akasam Sai Pavan
else begin
tx_shift_reg <= {1'b1, tx_shift_reg[7:1]}; // Shift out LSB first
tx_bit_count <= tx_bit_count + 1;
end
end
STOP: begin
tx_state <= DONE;
end
DONE: begin
tx_state <= IDLE;
tx_done <= 1;
tx_busy <= 0;
end
endcase
end
end
Akasam Sai Pavan
// Receiver 1 state machine
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
rx_state1 <= IDLE;
rx_shift_reg1 <= 8'b0;
rx_done1 <= 0;
rx_bit_count1 <= 0;
end else if (baud_tick) begin
case (rx_state1)
IDLE: begin
rx_done1 <= 0;
if (!rx_line1) begin // Start bit detected (low)
rx_state1 <= START;
end
end
Akasam Sai Pavan
START: begin
rx_state1 <= DATA;
end
DATA: begin
if (rx_bit_count1 == 8) begin
rx_state1 <= STOP;
rx_bit_count1 <= 0;
end else begin
rx_shift_reg1 <= {rx_line1, rx_shift_reg1[7:1]}; // Shift in LSB first
rx_bit_count1 <= rx_bit_count1 + 1;
end
end
STOP: begin
rx_state1 <= DONE;
end
Akasam Sai Pavan
DONE: begin
rx_done1 <= 1;
rx_data1 <= rx_shift_reg1;
rx_state1 <= IDLE;
end
endcase
end
end
endmodule
✓ This design handles full-duplex communication with a independent
receiver, and it is configurable for different baud rates by adjusting the
clock divider parameter.
Akasam Sai Pavan
UART Testbench Module (Verilog):
module uart_tb;
reg clk;
reg rst_n;
reg tx_en;
reg [7:0] tx_data;
wire tx_out;
reg rx_in1;
wire [7:0] rx_data1;
wire rx_data_valid1;
// Instantiate the UART system
uart_system uart (
.clk(clk),
.rst_n(rst_n),
.tx_en(tx_en),
.tx_data(tx_data),
.tx_out(tx_out),
.rx_in1(tx_out),
.rx_data1(rx_data1),
.rx_data_valid1(rx_data_valid1));
Akasam Sai Pavan
// Clock generation
always #5 clk = ~clk; // 100MHz clock
initial begin
// Initialize signals // Monitor statement
clk = 0; initial
rst_n = 0; begin
tx_en = 0; $monitor("Time: %0t | tx_data: %h | tx_out:
tx_data = 8'h00; %b | rx_data1: %h | rx_data_valid1: %b",
rx_in1 = 1; $time, tx_data, tx_out, rx_data1,
rx_data_valid1);
// Reset end
#10 rst_n = 1;
// Wait for reception
// Transmit data #100;
#20 tx_data = 8'hA5; $stop;
tx_en = 1; end
#10 tx_en = 0; endmodule
Akasam Sai Pavan
NOTE: // Random Testcase Generation
initial begin
// Initialize signals
clk = 0;
rst_n = 0;
tx_en = 0;
tx_data = 8'h00;
rx_in1 = 1;
rx_in2 = 1;
rx_in3 = 1;
// Reset
#10 rst_n = 1;
// Random test case generation
repeat (10) begin
#20 tx_data = $random; // Generate random 8-bit data
tx_en = 1; // Enable transmission
#10 tx_en = 0; // Disable transmission after sending one frame
end
Akasam Sai Pavan
Simulation & Verification
• Waveform: Run the simulation using any HDL simulator (e.g., ModelSim or Xilinx Vivado) to
verify that the data is transmitted and received correctly by all three receivers.
• Error-checking: Check that the data received by all three receivers matches the transmitted
data and that no framing errors are detected.
Key Points in Random Testcase Implementation:
Repeat Block: The repeat (10) block sends 10 random data transmissions to the receiver.
• The data (tx_data) is randomly generated using the $random function.
• The tx_en signal is used to trigger the transmission.
Monitor Output: Each time data is transmitted, the monitor statement prints out the transmitted data
and the received data, allowing you to compare the values and check for correctness.
Delays: Delays like #20 and #100 ensure that the transmission completes before sending the next
random value and that the simulation has enough time for the receiver to receive and process the data.
Akasam Sai Pavan
Thank You