Lab #4: Simple UART
In lab 4, you will create Simple UART transmitter. The block diagram for the complete system is shown below.
UART Basics
Characteristics
An RS-232 interface has the following characteristics:
· Uses a 9 pin connector "DB-9"
· Allows for bidirectional full-duplex communication (you can send and receive data at the same time).
· Can communicate at a maximum speed of roughly 10KBytes/s.
DB-9 connector
The DB-9 connector has 9 pins, but the 3 used for serial communication are:
· pin 2: RxD (receive data).
· pin 3: TxD (transmit data).
· pin 5: GND (ground)
Asynchronous Communication
The RS232 interface uses an "asynchronous" protocol. That means that no clock signal is transmitted along the data. The receiver has to have a way to synchronize to the incoming data bits.
In the case of RS-232:
- Both sides of the cable agree in advance on the communication parameters (speed, format...). That's done manually before communication starts.
- The transmitter sends logic ‘1’ when and as long as the line is idle.
- The transmitter sends a "start" or logic ‘0’ before each byte transmitted, this is a flag to the receiver to indicate that data is coming.
- After the "start", data comes in the agreed speed and format, so the receiver can interpret it.
- The transmitter sends a "stop" or logic ‘1’ after each data byte.
Data is sent one bit at a time. The LSB (data bit 0) is sent first, the MSB (bit 7) last.
This is how transmitting the byte 0x55 looks:
Byte 0x55 or 01010101 in binary.
But since it is transmitted LSB (bit-0) first, the line toggles: 1-0-1-0-1-0-1-0.
Here's another example:
Here the data is 0xC4 or 11000100 in binary
UART_TX Module
The UART_TX module will receive 1 byte of data from the Stored Data module and transmit the individual bits serially over the TxD pin to the UART receiver. The ASM chart for the UART_TX module is shown below.
The inputs to the UART_Tx Module are:
clk / 50 MHz clock. FPGA Pin T9reset / Reset from button (BTN3) FPGA Pin: L14
TxD_data [7:0] / 1-Byte ASCII character to be serially transmitted to the UART Reciever
TxD_start / Signal from Stored_Data module to begin transmission of current TxD_data
The outputs of the UART_Tx Module are:
TxD_busy / Signal to Stored_Data to indicate that the current serial transmission is not completeTxD / Serial ASCII data sent to UART Receiver
BAUD Rate Generator
For lab 4 we will be using a baud rate of 19200 Hz. Since we cannot divide 50 MHz clock by a power of 2 to obtain the 19200 Hz the clock we will have to add a offset every time we increment our clock divider counter. To obtain a 19200 Hz clock from our 50 MHz clock we need to divide by 0. Instead we will use, which is close to our ideal ratio, and makes an efficient FPGA implementation.
parameter baud_offset=25;
reg [16:0] baud_counter; //16 bits for the accumulator and one carry-out bit
wire BaudTick = baud_counter[16]; // carry-out bit
always @(posedge clk)
begin
if (reset)
baud_counter <=0;
else if(TxD_busy==1)
baud_counter <= baud_counter[15:0] + baud_offset; // use only 16 bits from the //previous result, but save the full 17 bits
end
Using our 50 MHz clock, "BaudTick" is asserted 19073 times a second, a 0.6% error from the ideal 19200.
The UART_Tx module Datapath consists of:
parameter: BAUD_OFFSET=25
17-bit register: baud_counter
1-bit wire: Baud_Tick
8-bit register: TxD_data_reg
1-bit wire: TxD
1-bit wire: TxD_ready
1-bit wire: TxD_busy = ~TxD_ready
Current State DataPath Operation
S_wait_start / 8-bit input data from Stored_Data module stored to TxD_data_Reg.TxD_ready logic ‘1’
All other states / TxD_ready logic ‘0’
baud_counter <= baud_counter[15:0] + baud_offset;
The output TxD should be assigned based on the current state as shown below:
assign TxD = (state==S_wait_start) ? 1'b1
:(state==S_start_bit) ? 1'b0
:(state==S_bit0) ? TxD_dataReg[0]
:(state==S_bit1) ? TxD_dataReg[1]
:(state==S_bit2) ? TxD_dataReg[2]
:(state==S_bit3) ? TxD_dataReg[3]
:(state==S_bit4) ? TxD_dataReg[4]
:(state==S_bit5) ? TxD_dataReg[5]
:(state==S_bit6) ? TxD_dataReg[6]
:(state==S_bit7) ? TxD_dataReg[7]
:(state==S_stop_bit) ? 1'b1
: 1'b1;
Stored Data Module
The Stored Data module will send 1 byte ASCII data to the UART_Tx module and initiate the serial transmission of the data to the UART Reciever.
The inputs to the Stored Data Module are:
Clk / 50 MHz clock. FPGA Pin T9Reset / Reset from button (BTN3) FPGA Pin: L14
TxD_busy / Signal from UART_Tx Module to indicate that the current serial transmission is not complete
Button_1 / (BNT2) FPGA Pin: L13
Button_2 / (BNT1) FPGA Pin: M14
Button_3 / (BNT0) FPGA Pin: M13
The outputs of the Stored Data Module are:
TxD_data [7:0] / 1-Byte ASCII character to be serially transmitted to the UART RecieverTxD_start / Signal from UART_Tx module to begin transmission of current TxD_data
The Stored Data module Datapath consists of:
25-bit register: delay_counter
1-bit register: TxD_start
Current State DataPath Operation
S_data_1, S_data_2, ….. / TxD_start logic ‘1’All other States / TxD_start logic ‘0’
S_delay / delay_counter <= delay_counter + 1
Display Data
Button 1 / Display: HELLO WORLDButton 2 / Display: (your first and last name)
Button 3 / Display: FPGA UART LAB
The ASCII display data can be parameterized as shown below:
//button 1 data
parameter data1=8'h48;//H
parameter data2=8'h65;//e
parameter data3=8'h6C;//l
parameter data4=8'h6C;//l
parameter data5=8'h6F;//o
parameter data6=8'h20;//sp
parameter data7=8'h57;//W
parameter data8=8'h6F;//o
parameter data9=8'h72;//r
parameter data10=8'h6C;//l
parameter data11=8'h64;//d
parameter data12=8'h0D;//cr
parameter data13=8'h0A;//nl
On the following page is an example ASM chart for the transmission of 2 bytes to the UART_TX module. Your state machine should be an expansion of this chart and should allow for the transmission of more bytes to the UART_TX module and multiple button inputs.
UART Receiver Settings
Your UART receiver should have the following settings:
BAUD Rate: 19200
Data: 8-bits
Stop Bits: 1
No Parity
No Flow Control
module UART_top(
output TxD,
input clk,
input reset,
input button_1,
input button_2,
input button_3
);
wire TxD_start;
wire TxD_busy;
wire [7:0] data_out;
stored_data SD(
.clk(clk),
.reset(reset),
.button_1(button_1),
.button_2(button_2),
.button_3(button_3),
.data_out(data_out),
.TxD_busy(TxD_busy),
.TxD_start(TxD_start)
);
UART RS(
.clk(clk),
.reset(reset),
.TxD_start(TxD_start),
.TxD_data(data_out),
.TxD(TxD),
.TxD_busy(TxD_busy)
);
endmodule
UCF File
NET "button_1" LOC = "L13" ;
NET "button_2" LOC = "M14" ;
NET "button_3" LOC = "M13" ;
NET "clk" LOC = "T9" ;
NET "reset" LOC = "L14" ;
NET "TxD" LOC = "R13" ;