0% found this document useful (0 votes)
18 views26 pages

Understanding UART Communication Basics

Uploaded by

SHIVARAJ
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views26 pages

Understanding UART Communication Basics

Uploaded by

SHIVARAJ
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

UART is a universal asynchronous receiver and transmitter.

It is an asynchronous communication
interface i.e it do not have any common clock going between sender and receiver based on data we
receive sender and receiver will align the clock.

Typical data format:

Whenever we have new data we pull the line low so that the other device knows that we have some
data we wish to communicate and that aligns its clock to a transmitter. Than we serially transmit data
bit by bit. The parity bit is optional, which could be use to detect single bit [Link] have a stop bit
which could be 1 bit,1.5 bit or 2 bit duration.

UART can be full/half duplex.

- In asynchronous communication, baud rate measures the speed of data transmission. Baud
rate accounts for all bits sent, including start, stop, and parity bits.
- The actual data transfer speed, represented as bit rate (bps), indicates the amount of data
transmitted from the sender to the receiver.
- UART speeds are expressed in bits per second (bit/s or bps).
- Standard baud rates are as follows: 110, 300, 1200, 2400, 4800, 9600, 14400,19200, 28800,
38400, 57600, 76800, 115200, 230400, 460800, 921600,1382400, 1843200, and 2764800
bit/s.

UART is commonly used to transmit data at lower data rates and when distance of transmission is
small.

A simple UART can have only 2 pins to communicate data between devices
Simple UART Design
Tx

UART Rx

Our signal will be low for entire duration. Once the receiver recognizes the start bit it will be ready to
receive the data. Than we will be serially transmitting the data from transmitter to [Link] the
data that we are going to send is the LSB of our data.

We have made TX line


high this will notify the
receiver that we have
completed
transmission.

We can generate single pulse at the end of a bit duration. That is also one strategy or we can
generate the pulse at the middle of a bit duration and than transmit the data. The common practice
is to generate 16 pulses within single bit duration and this is what we refer as oversampling.

We send all 8 bits than we need to convey the end of transaction by sending the stop bit. The stop bit
is basically making line high again.
Designing the Transmitter Module
Input clock frequency on which
our module will work

Clk and rst are global signals

- A parameter clkcount is calculated as the ratio of clk_freq


(system clock frequency) and baud_rate.
- An always block monitors the posedge clk (rising edge of the
system clock).
- A counter increments until it reaches clkcount/2. When this
happens:
• The counter resets to 0.
• The UART clock (uclk) toggles, marking the half-period.
Operation Flow:
• Count < clkcount/2: The counter increments.
• Count >= clkcount/2: The UART clock toggles, and the
counter resets to zero. This creates a clock for the UART bit
transmission, synced to the desired baud rate.

Temp Variable to store data

Given Parameters:
• System Clock (Sys_Clk): 1 MHz (frequency of the system clock).
• Baud Rate: 9600 (rate at which bits are transmitted).
Ratio (clkcount): This determines the number of system clock cycles
needed to produce one bit.

Half Clock Period: Since the clock signal is toggled at the middle
of the bit duration, the half-period is:

Uclk ➔ slower clock


If rst is high than we are
in idle state

We wait in idle state until


new data gets high

We sample data to din,din


temporary variable We will move to transfer
state
We send start of transmission

Now we will send all 8 bits of data


We begin the transfer of data

We send the data to tx from temporary variable din

At this state we completed the transmission of data


so we made donetx high
Receiver Design
Similar to Transmitter Design
When rx becomes low this marks start of transaction

Once RX becomes low, this marks the start of a


transaction. Hence,from the next logic onward, that
is, from the next cycle of bit duration, we should start
receiving the data from the RX pin. So we jump to the
start state. Else, we stay in an idle state.

-As long as RX is high, we will stay in an idle state. In


the start state,we will collect all bits of data received
serially on the RX pin

We have implemented a right shift register over here,


where the MSB bit will be the data we have on the RX
line,and the seven MSB values of RX data will be shifted
in and right. So at the end of the cycle,we will have RX
on an LSB bit.

Once we receive all eight bits, we make the


count zero again so that it could be utilized in
the next cycle. Done will again be high, and
the state will return to idle, where we will
wait for the next data reception. The default
value for the receiver will be idle.
UART TOP

We have declared a UART top module that will consist of both transmitter and receiver. The series of
ports present in the top module includes clock and reset, which will be global signals going to both
the transmitter and receiver. To receive data from the other device, we have an RX pin. To transmit
data to another device, we have a TX pin. To mark the completion of transmission and reception
operations, we have done RX and done TX, respectively. To send new data, we have a new data and
D_TX bus where we will be adding the data, whereas D_OUT_RX is the bus where we will send the
data received from another device. So these are the series of ports that we need to add to the top
module. Finally, we need to make the necessary connections. So, we have a module UART top, then
the series of ports that we require. Finally, we add the UART TX module and UARTRX module and
perform the necessary connections
UART TB

Testbench Verification for Top Module

We are adding a testbench to verify the functionality of our top module. In this testbench:

1. Variable Setup:

o We define a register variable for the input in the design.

o Wire variables are assigned to each output port.

o These variables are connected to the Device Under Test (DUT).

o Two temporary variables are introduced to hold data for comparison during the
verification process.

2. Transmitter (TX) Logic:

o When new_data is set high, data is transmitted serially on the N_TX line.

o We collect this serial data and compare it with the data on the input bus (D_in).

o If the collected serial data matches the input data bus, it verifies the transmitter is
functioning correctly.

3. Receiver (RX) Logic:

o Data is received serially on the RX line.

o Once the done_RX signal is high, the received data is transferred to the output bus
(D_out_RX).

o We compare the received serial data with the data on the D_out_RX bus to verify the
receiver.

4. Stimulus Generation:

o A high reset signal is maintained for five clock cycles and then released.

o We send 10 random transactions on D_in using a new_random function and transmit


them serially.

o The new_data signal goes high when new data is available for transmission, and the
TX line becomes active.

5. Data Transmission:

o A right-shift register is used to transmit data serially.

o Data is added to the MSB, and after each transmission, the TX data is shifted right,
ensuring the data moves from MSB to LSB.

o The same process is mirrored for the receiver, where data is serially received and
stored in an RX data register.

6. Transaction Execution:
o 10 random transactions are performed for both the transmitter and receiver.

o We observe the done_TX signal for each transaction, confirming successful


transmission by comparing TX_data with the expected values on D_in.

o Similarly, the done_RX signal is checked to ensure that received data matches the
data on the output bus.

7. Final Observation:

o The transmitted and received data values are compared for both the transmitter and
receiver.

o Upon matching values, we conclude that the system is functioning as expected.


module uart_top

#(

parameter clk_freq = 1000000,


parameter baud_rate = 9600

input clk,rst,

input rx,

input [7:0] dintx,

input newd,

output tx,

output [7:0] doutrx,

output donetx,

output donerx

);

uarttx

#(clk_freq, baud_rate)

utx

(clk, rst, newd, dintx, tx, donetx);

uartrx

#(clk_freq, baud_rate)

rtx

(clk, rst, rx, donerx, doutrx);

endmodule

//////////////////////////////////////////////////////////////////

module uarttx

#(
parameter clk_freq = 1000000,

parameter baud_rate = 9600

input clk,rst,

input newd,

input [7:0] tx_data,

output reg tx,

output reg donetx

);

localparam clkcount = (clk_freq/baud_rate); ///x

integer count = 0;

integer counts = 0;

reg uclk = 0;

enum bit[1:0] {idle = 2'b00, start = 2'b01, transfer = 2'b10, done = 2'b11} state;

///////////uart_clock_gen

always@(posedge clk)

begin

if(count < clkcount/2)

count <= count + 1;

else begin

count <= 0;

uclk <= ~uclk;

end

end
reg [7:0] din;

////////////////////Reset decoder

always@(posedge uclk)

begin

if(rst)

begin

state <= idle;

end

else

begin

case(state)

idle:

begin

counts <= 0;

tx <= 1'b1;

donetx <= 1'b0;

if(newd)

begin

state <= transfer;

din <= tx_data;

tx <= 1'b0;

end

else

state <= idle;

end
transfer: begin

if(counts <= 7) begin

counts <= counts + 1;

tx <= din[counts];

state <= transfer;

end

else

begin

counts <= 0;

tx <= 1'b1;

state <= idle;

donetx <= 1'b1;

end

end

default : state <= idle;

endcase

end

end

endmodule

////////////////////////////////////////////////////////////////////
module uartrx

#(

parameter clk_freq = 1000000, //MHz

parameter baud_rate = 9600

input clk,

input rst,

input rx,

output reg done,

output reg [7:0] rxdata

);

localparam clkcount = (clk_freq/baud_rate);

integer count = 0;

integer counts = 0;

reg uclk = 0;

enum bit[1:0] {idle = 2'b00, start = 2'b01} state;

///////////uart_clock_gen

always@(posedge clk)

begin

if(count < clkcount/2)

count <= count + 1;

else begin
count <= 0;

uclk <= ~uclk;

end

end

always@(posedge uclk)

begin

if(rst)

begin

rxdata <= 8'h00;

counts <= 0;

done <= 1'b0;

end

else

begin

case(state)

idle :

begin

rxdata <= 8'h00;

counts <= 0;

done <= 1'b0;

if(rx == 1'b0)

state <= start;

else

state <= idle;

end
start:

begin

if(counts <= 7)

begin

counts <= counts + 1;

rxdata <= {rx, rxdata[7:1]};

end

else

begin

counts <= 0;

done <= 1'b1;

state <= idle;

end

end

default : state <= idle;

endcase

end

end

endmodule

TESTBENCH
module uart_tb;

reg clk = 0,rst = 0;


reg rx = 1;

reg [7:0] dintx;

reg newd;

wire tx;

wire [7:0] doutrx;

wire donetx;

wire donerx;

uart_top #(1000000, 9600) dut (clk, rst, rx, dintx, newd, tx, doutrx, donetx, donerx);

always #5 clk = ~clk;

reg [7:0] rx_data = 0;

reg [7:0] tx_data = 0;

initial begin

rst = 1;

repeat(5) @(posedge clk);

rst = 0;

for(int i = 0 ; i < 10; i++)

begin

rst = 0;

newd = 1;

dintx = $urandom();

wait(tx == 0);

@(posedge [Link]);

for(int j = 0; j < 8; j++)

begin
@(posedge [Link]);

tx_data = {tx,tx_data[7:1]};

end

@(posedge donetx);

end

for(int i = 0 ; i < 10; i++)

begin

rst = 0;

newd = 0;

rx = 1'b0;

@(posedge [Link]);

for(int j = 0; j < 8; j++)

begin

@(posedge [Link]);

rx = $urandom;

rx_data = {rx, rx_data[7:1]};

end

@(posedge donerx);

end

end
endmodule

You might also like