RS232 UART Verilog Core

Make it to the Right and Larger Audience

RS232 UART Verilog Core

Here is a study note about a simple uart core design. In the design, I need uart to be able to handle several baud rates such as 115200, 57600, 38400, 19200, 9600, etc. and several system clocks such as 60Mhz, 50Mhz, 30Mhz, 25Mhz, 20Mhz, etc. Lots of cores online are not flexible enough to handle these baud rates and clocks. Find a good reference design at  http://opencores.org/project,uart2bus.

Here is how clock is handled. First uart rx and tx works at 16x oversampling – in one baud/bit, data is oversampled by 16x. It is fixed in this design but can be modified to handle the case of high baud rate and low system clock rate so 16x is not possible. Second assuming clk as system clock and clk_ovrsamp as 16x uart baud rate, we use two formula to calculate baud_freq and baud_limit as:

$baud\_freq = \frac{clk\_ovrsamp}{GCD(clk, clk\_ovrsamp)}$

$baud\_limit = \frac{clk}{GCD(clk, clk\_ovrsamp)}- baud\_freq$

Then use the following baud_gen module to generate clk_ovrsamp from clk:

How it works? Let’s say system clk is clk=10 and clk_ovrsamp is 4. 10/4 is not an integer so how can you get 4 from clk=10? With above formula, GCD(10,4)=2, baud_freq=4/2=2, and baud_limit=10/2-2=3. Then with baud_gen module, count shows a sequence as 0, 2, 4, 1, 3, 0, 2, … When count is 4 or 3, clk_ovrsamp=1 otherwise 0. Therefore clk_ovrsamp is 3 clk cycles long in one cycle and then 2 clk cycles long in the next cycle so on average it is 2.5 clk cycles just as 10/4. As you may already sense, we don’t have to use GCD but using GCD minimizes RTL calculation otherwise for above example baud_freq=4 and baud_limit=6 then the sequence will be 0, 4, 8, 2, 6, 0, 4… Obviously +4 is more calculation intensive than +2.

Here is a short C code to calculate baud_freq and baud_limit assuming clk is 20Mhz and uart baud rate is 115200 so clk_ovrsamp is 16*115200. Compile and run it will print baud_freq is 0x120 and baud_limit is 0xb15.

UART Rx. As can be seen, it is a very simple implementation. Data is assumed to be 8bit always while uart protocol supports 5-9 bits. There is no parity bit. No check on stop bit either. If stop bit is not a mart (1’b1), there is no error reported.

UART Tx:

A simple uart top module is as below. It instantiates baud_gen, uart_tx, and uart_rx . It has a control input, loopback, to specify if the loopback mode is enabled. If loopback=1, uart rx data is wired to uart tx and sent back.

Here is a simple test bench. It instantiates two uart modules, uart_local and uart_remote. Uart local tx sends one byte 0x5a to uart_remote. Uart_remote is in loopback mode. It receives 0x5a and immediately sends back to uart_local rx.

Waveform is as expected. On uart_local side, uart tx sends 0x5a to uart remote and then receives 0x5a from uart remote.

On uart remote side, it receives 0x5a from uart local and immediately loop back.

Here is zip file for all the codes:

Electrical Engineer
Author brief is empty
Groups:

Tags: