FPGA Implementation of UART (Including Source Code)

1. What is UART?

As one of the three commonly used low-speed buses (UART, SPI, IIC), UART plays an important role in designing various communication interfaces and debugging.

UART stands for Universal Asynchronous Receiver/Transmitter, which is mainly used for serial data transmission, and operates in a full-duplex mode.

When sending data, it converts parallel data into serial data for transmission, and when receiving data, it converts the received serial data back into parallel data.

The term “asynchronous” indicates that a synchronized clock is not used between the two modules involved in data transmission.

In fact, during asynchronous UART transmission, a clock is not needed; instead, specific timing is used to mark the beginning (start bit — from high to low) and the end (stop bit, pulled high) of the transmission.

2. Components of UART

2.1 Physical Layer of UART

UART communication consists of only two signal lines: one is the transmission data line called tx (Transmitter), and the other is the reception data line called rx (Receiver).

As shown in the figure, for a PC, its tx must connect to the rx of the FPGA, and similarly, the rx of the PC must connect to the tx of the FPGA. If two tx or two rx are connected, the data cannot be sent and received properly.

FPGA Implementation of UART (Including Source Code)

The signal transmission is implemented by external driving circuits. The process of transmitting electrical signals has different voltage standards and interface specifications. The interface standards for asynchronous serial communication include RS232, RS422, RS485, etc.

These standards define different electrical characteristics for the interfaces, such as RS-232 being single-ended input/output, while RS-422/485 are differential input/output.

For short transmission distances (not exceeding 15m), RS232 is the most commonly used interface standard for serial communication. The most common interface type for RS-232 serial ports is DB9, as shown in the figure. Industrial control computers generally come equipped with multiple serial ports, and many older desktop computers also have serial ports.

However, laptops and newer desktop computers typically do not have serial ports; they usually communicate with external devices via USB-to-serial converters.

FPGA Implementation of UART (Including Source Code)

The DB9 interface definition and the function description of each pin are shown in the figure. We generally only use pins 2 (RXD), 3 (TXD), and 5 (GND); other pins are usually not used in normal serial port mode:

FPGA Implementation of UART (Including Source Code)

2.2 UART Protocol

A frame of data in UART during the sending or receiving process consists of four parts: start bit, data bits, parity bit, and stop bit, as shown in the figure.

The start bit marks the beginning of a frame of data, while the stop bit marks the end of a frame of data. The data bits are the valid data within a frame of data.

The parity bit can be either odd or even, and is used to check if there is an error in the data during transmission.

In odd parity, the sender must ensure that the total number of 1s in the data bits plus the parity bit is odd; the receiver checks the number of 1s upon receiving the data.

If it is not odd, it indicates that an error occurred during transmission. Similarly, even parity checks if the number of 1s is even. For more details on odd and even parity, refer to the FPGA implementation of parity using Verilog.

FPGA Implementation of UART (Including Source Code)

The data format and transmission rate during UART communication are configurable. For correct communication, both parties must agree on and adhere to the same settings.

Data bits can be selected to be 5, 6, 7, or 8 bits, with 8 bits being the most commonly used in practical applications; parity bits can be odd, even, or no parity; stop bits can be 1 bit (default), 1.5, or 2 bits.

The baud rate of serial communication is represented in bps (bits per second), indicating the number of binary data bits transmitted per second. Common baud rates include 9600, 19200, 38400, 57600, and 115200, etc.

For instance, a baud rate of 9600 means that 9600 bits of data are transmitted per second. If we consider sending 1 byte as 10 bits (1 start bit + 8 data bits + 1 stop bit + NO parity bit), the time required to transmit 1 byte is 1*10/9600 seconds.

3. UART Sending Module

3.1 Interface Definition and Overall Design

The overall block diagram of the sending module and the input/output signals are shown below:

FPGA Implementation of UART (Including Source Code)

The signal ports are as follows:

FPGA Implementation of UART (Including Source Code)

It should be noted that uart_tx_data is the one byte of data to be sent, and uart_tx_en is the transmission enable bit. When it is pulled high, it indicates that the data uart_tx_data is being sent through the serial port transmission line.

3.2 Design Concept

This module supports sending at any baud rate (theoretically), but requires parameters to instantiate the module during use. The data bits are set to 8 bits, with 1 start bit and 1 stop bit, and no parity.

When the enable signal is valid, the transmission flag signal is pulled high, indicating that the module has entered the sending process. After sending 10 bits, the transmission flag signal is pulled low, indicating the end of the sending process. The data to be sent is stored when the enable signal is valid.

Assuming a baud rate of 9600, the time for sending one bit is 1s/9600, and a data transmission consists of 10 bits (8 data bits, 1 start bit, and 1 stop bit), thus it takes 1s/9600.

Assuming the system clock is 50MHz (parameterized to adapt to different system frequencies), its period is 20ns, then the number of system cycles required to send one bit is (1s/9600)/20ns ≈ 5208 (cycles).

During the sending process, a counter is used to count, with a range of (0~5208-1); this range consists of 10 counts (one byte requires sending 10 bits).

Additionally, another counter is needed to count the number of bits sent (every time the previous counter reaches 5207, it indicates that one bit has been sent). The counting range is (0~9).

During the sending process, based on the value of the counter (bit counter), the sending data line is operated.

If the sending bit counter = 0, it indicates that the start bit needs to be sent at this moment;

If the sending bit counter = 1, it indicates that the least significant bit (LSB) of the data is to be sent (data is always sent with the low bit first, high bit last);

······

If the sending bit counter = 8, it indicates that the most significant bit (MSB) of the data is to be sent;

If the sending bit counter = 9, it indicates that the stop bit is to be sent;

The sending data line must be pulled high when not in the sending state to satisfy the idle state of UART timing.

3.3 Verilog Code

Based on the design concept above, part of the sending module code is as follows:

 // *******************************************************************************************************// ** Author : Lonely Single Blade                                                         // ** Email : [email protected]// ** Blog : https://blog.csdn.net/wuzhikaidetb // ** Date : 2022/07/31  // ** Function : 1. UART sending driver module based on FPGA; //        2. Configurable baud rate BPS, main clock CLK_FRE; //        3. 1 start bit, 8 data bits, 1 stop bit, no parity; //        4. After sending 1 byte, pull uart_tx_done high for one cycle, can be used for subsequent multi-byte modules. // *******************************************************************************************************   module uart_tx#(  parameter  integer  BPS    = 9_600    ,  // Baud rate  parameter   integer  CLK_FRE  = 50_000_000  // Main clock frequency)(// System interface  input       sys_clk      ,      // System clock  input       sys_rst_n    ,      // System reset, active low // User interface    input  [7:0]   uart_tx_data  ,      // Data to be sent via UART, valid when uart_tx_en is high  input      uart_tx_en    ,      // Transmission valid, when high, indicates that the data to be sent is valid // UART transmission    output  reg    uart_tx_done  ,      // Pull high for one cycle after successfully sending 1 BYTE of data  output   reg    uart_txd          // UART transmission data line tx);  // When the transmission enable signal arrives, store the data to be sent to avoid subsequent changes or loss always @(posedge sys_clk or negedge sys_rst_n)begin  if(!sys_rst_n)    uart_tx_data_reg <=8'd0;  else if(uart_tx_en)              // Valid data to be sent    uart_tx_data_reg <= uart_tx_data;    // Store the data to be sent        else     uart_tx_data_reg <= uart_tx_data_reg;end    // When the transmission enable signal arrives, enter the sending process always @(posedge sys_clk or negedge sys_rst_n)begin  if(!sys_rst_n)    tx_state <=1'b0;    else if(uart_tx_en)                            tx_state <= 1'b1;            // Valid transmission signal, enter the sending process  // If the last data has been sent, exit the sending process      else if((bit_cnt == BITS_NUM - 1'b1) && (clk_cnt == BPS_CNT - 1'b1))        tx_state <= 1'b0;                                                else     tx_state <= tx_state;  end // After the data is sent, pull the transmission complete signal high for one cycle, indicating one byte has been sent always @(posedge sys_clk or negedge sys_rst_n)begin  if(!sys_rst_n)    uart_tx_done <=1'b0;  // After sending data, pull the completion signal high for one cycle       else if((bit_cnt == BITS_NUM - 1'b1) && (clk_cnt == BPS_CNT - 1'b1))                                                 uart_tx_done <=1'b1;                      else     uart_tx_done <=1'b0;end// After entering the sending process, start the clock counter and bit count counter always @(posedge sys_clk or negedge sys_rst_n)begin  if(!sys_rst_n)begin    clk_cnt <= 32'd0;    bit_cnt <= 4'd0;  end  else if(tx_state) begin                    // In sending state    if(clk_cnt < BPS_CNT - 1'd1)begin            // One bit data has not been sent yet      clk_cnt <= clk_cnt + 1'b1;              // Clock counter +1      bit_cnt <= bit_cnt;                  // Bit counter remains unchanged    end              else begin                        // One bit data has been sent        clk_cnt <= 32'd0;                  // Clear clock counter and restart timing      bit_cnt <= bit_cnt+1'b1;              // Bit counter +1, indicating one bit of data has been sent    end            end            else begin                          // Not in sending state    clk_cnt <= 32'd0;                             // Clear    bit_cnt <= 4'd0;                              // Clear  endendendmodule

3.4 Testbench

The design of the Testbench for the sending module is as follows:

Set the baud rate to 230400 (this is to facilitate observing the transmission enable signal uart_tx_en, saving time).

After 3000ns, pull the transmission enable signal uart_tx_en high for one cycle, while generating 1 random 8-bit data for uart_tx_data as the data to be sent.

Observe whether the timing on the TX line of UART meets the requirements.

// *******************************************************************************************************// ** Author : Lonely Single Blade                                                         // ** Email : [email protected]// ** Blog : https://blog.csdn.net/wuzhikaidetb // ** Date : 2022/07/29  // ** Function : 1. Testbench for the UART sending driver module based on FPGA //        2. Sends one 8-bit random data, observes the waveform to check if it meets UART timing // *******************************************************************************************************     `timescale 1ns/1ns  // Define time scale module tb_uart_tx(); reg       sys_clk      ;      reg       sys_rst_n    ;      reg [7:0]    uart_tx_data  ;reg       uart_tx_en    ;      wire        uart_txd    ; parameter  integer  BPS   = 'd230400    ;      // Baud rate parameter  integer  CLK_FRE = 'd50_000_000  ;      // System frequency 50M  localparam  integer  BIT_TIME = 'd1000_000_000 / BPS ;  // Calculate the time required for each bit of transmission initial begin    sys_clk <=1'b0;    sys_rst_n <=1'b0;      uart_tx_en <=1'b0;  uart_tx_data <=8'd0;          #80                     // System starts working    sys_rst_n <=1'b1;      #200    @(posedge sys_clk);    uart_tx_en <=1'b1;      uart_tx_data <= ({$random} % 256);    // Send 8-bit random data  #20      uart_tx_en <=1'b0;    #(BIT_TIME * 10)              // Sending 1 BYTE requires 10 bits  #200 $finish;                // End simulation end always #10 sys_clk=~sys_clk;          // Define main clock, period 20ns, frequency 50M // Instantiate the sending driver module uart_tx #(  .BPS      (BPS      ),      .CLK_FRE    (CLK_FRE    )    )  uart_tx_inst(    .sys_clk    (sys_clk    ),        .sys_rst_n    (sys_rst_n    ),    .uart_tx_data  (uart_tx_data  ),        .uart_tx_en    (uart_tx_en    ),      .uart_tx_done  (uart_tx_done  ),      .uart_txd    (uart_txd    )  ); endmodule

3.5 Simulation Result Analysis

The simulation results are shown in the figure below (with detailed comments):

In the figure, it can be seen that the sending module sent one data 8’h24, and after a while, the sending finished, but the timing on the TX line could not be directly observed.

FPGA Implementation of UART (Including Source Code)

Overall Simulation Timing

In the figure below, it can be seen that the sending module sent one data 8’h24, and after a while, the sending finished, and the TX line can be seen sending data 00100100 (low bit first, high bit last), which is 8’h24.

FPGA Implementation of UART (Including Source Code)

Single Transmission Timing

It can be seen that the simulation results meet the expected design requirements.

3.6 On-Board Testing

Having successfully completed the simulation verification of the sending module, the next step is to conduct on-board testing using an Altera Cyclone IV E development board.

A testing module for the sending module is written, which calls the serial sending module and raises the transmission enable signal and generates sending data at certain intervals (default 1s), with the sending data starting from 0x01 and incrementing by 1 until 0xFF (overflowing to 0x00).

Meanwhile, a serial debugging software on the computer is used to receive the data sent. The success of the serial sending module is determined based on the data received by the serial debugging software.

The verification module code for the sending module is as follows:

 // *******************************************************************************************************// ** Author : Lonely Single Blade                                                         // ** Email : [email protected]// ** Blog : https://blog.csdn.net/wuzhikaidetb // ** Date : 2022/07/29  // ** Function : 1. Testing module for UART sending driver module based on FPGA; //        2. Sends 1 incrementing data every second to the host machine. // *******************************************************************************************************   module uart_tx_test(// System interface  input       sys_clk      ,  input       sys_rst_n    ,  // UART sending line    output      uart_txd            // UART sending line);    parameter  integer  BPS   = 'd230400    ;    // Baud rate parameter  integer  CLK_FRE = 'd50_000_000  ;    // System frequency 50M   reg    [31:0]  cnt_time; reg        uart_tx_en;              // Transmission enable, when high, indicates that data needs to be sent    reg    [7:0]   uart_tx_data;            // Data to be sent via UART, valid when uart_tx_en is high // 1s counting module, sends data and raises the transmission enable signal once every second; data increments from 0 always @(posedge sys_clk or negedge sys_rst_n)begin  if(!sys_rst_n)begin    cnt_time <= 'd0;    uart_tx_en <= 1'd0;    uart_tx_data <= 8'd0;  end  else if(cnt_time == (50_000_000 - 1'b1))begin    cnt_time <= 'd0;    uart_tx_en <= 1'd1;              // Raise transmission enable    uart_tx_data <= uart_tx_data + 1'd1;    // Increment data to be sent  end  else begin    cnt_time <= cnt_time + 1'd1;    uart_tx_en <= 1'd0;    uart_tx_data <= uart_tx_data;   endend  // Instantiate the sending module uart_tx#(  .BPS      (BPS      ),  .CLK_FRE    (CLK_FRE    ))  uart_tx_inst(    .sys_clk    (sys_clk    ),  .sys_rst_n    (sys_rst_n    ),  .uart_tx_en    (uart_tx_en    ),  .uart_tx_data  (uart_tx_data    ),  .uart_tx_done  (        ),    .uart_txd    (uart_txd    ));   endmodule

The results from the serial debugging software are as follows:

Sequentially received the data 01, 02, 03······. This indicates that our sending module is functioning normally.

FPGA Implementation of UART (Including Source Code)

4. UART Receiving Module

4.1 Interface Definition and Overall Design

The overall block diagram of the receiving module and the input/output signals are shown below:

FPGA Implementation of UART (Including Source Code)

The signal descriptions are as follows:

FPGA Implementation of UART (Including Source Code)

It should be noted that uart_rx_data is the one byte of data received, and uart_rx_done is the reception completion flag. When it is pulled high, it indicates that the received serial data uart_rx_data is valid.

4.2 Design Concept

This module supports receiving at any baud rate (theoretically), but requires parameters to instantiate the module during use. The data bits are set to 8 bits, with 1 start bit and 1 stop bit, and no parity.

The transmission of UART starts with the start bit, which pulls the data line low, so we need to capture the falling edge of the data line and sample the reception data line 3 times to capture its falling edge.

When the falling edge of the reception data line is captured, the reception flag signal is raised, marking the module’s entry into the reception process; after receiving 10 bits, the reception flag signal is pulled low, indicating the end of the reception process.

Assuming a baud rate of 9600, the time for sending one bit is 1s/9600, and a data transmission consists of 10 bits (8 data bits, 1 start bit, and 1 stop bit), thus it takes 1s/960.

Assuming the system clock is 50MHz (parameterized to adapt to different system frequencies), its period is 20ns, then the number of system cycles required to send one bit is (1s/960)/20ns ≈ 5208 (cycles).

During the receiving process, a counter is used to count, with a range of (0~5208-1); this range consists of 10 counts (one byte requires receiving 10 bits).

Additionally, another counter is needed to count the number of bits received (every time the previous counter reaches 5207, it indicates that one bit has been received). The counting range is (0~9).

During the receiving process, based on the value of the counter (bit counter), the received data is sampled and stored (data is most stable in the middle of the level).

If the receiving bit counter = 0, it indicates that the start bit does not need to be received;

If the receiving bit counter = 1, it indicates that the least significant bit (LSB) of the data is to be received and is assigned to the least significant bit of the stored data;

······

If the receiving bit counter = 8, it indicates that the most significant bit (MSB) of the data is to be received and is assigned to the most significant bit of the stored data;

If the receiving bit counter = 9, it indicates that the stop bit does not need to be received.

4.3 Verilog Code

Based on the design concept above, part of the code is as follows:

 // *******************************************************************************************************// ** Author : Lonely Single Blade                                                         // ** Email : [email protected]// ** Blog : https://blog.csdn.net/wuzhikaidetb // ** Date : 2022/08/05  // ** Function : 1. UART receiving driver module based on FPGA; //        2. Configurable baud rate BPS, main clock CLK_FRE; //        3. 1 start bit, 8 data bits, 1 stop bit, no parity. // *******************************************************************************************************       module uart_rx#(  parameter  integer  BPS    = 9_600    ,    // Baud rate  parameter   integer  CLK_FRE  = 50_000_000    // Input clock frequency)  (  // System interface  input         sys_clk      ,      // 50M system clock  input         sys_rst_n    ,      // System reset // UART receiving line    input         uart_rxd    ,      // Receiving data line // User interface    output reg       uart_rx_done  ,      // Data reception completion flag, when high, indicates that received data is valid  output reg [7:0]  uart_rx_data        // Received data, valid when uart_rx_done is high); assign  neg_uart_rxd = uart_rx_d3 & (~uart_rx_d2);  // Capture the falling edge of the data line to mark the beginning of data transmission // Sample the data line 3 times, to synchronize signals from different clock domains and prevent metastability; always@(posedge sys_clk or negedge sys_rst_n)begin  if(!sys_rst_n)begin    uart_rx_d1 <= 1'b0;    uart_rx_d2 <= 1'b0;    uart_rx_d3 <= 1'b0;  end  else begin    uart_rx_d1 <= uart_rxd;    uart_rx_d2 <= uart_rx_d1;    uart_rx_d3 <= uart_rx_d2;  end    end// After capturing the falling edge of data (start bit 0), raise the transmission start flag, and during the transmission of the 9th data (stop bit), pull the transmission start flag low to mark the end of transmission always@(posedge sys_clk or negedge sys_rst_n)begin  if(!sys_rst_n)    rx_en <= 1'b0;  else begin     if(neg_uart_rxd )                      rx_en <= 1'b1;    // After receiving the 9th data (stop bit), pull the transmission start flag low to mark the end of transmission, checking for high level    else if((bit_cnt == 4'd9) && (clk_cnt == BPS_CNT >> 1'b1) && (uart_rx_d3 == 1'b1) )      rx_en <= 1'b0;    else       rx_en <= rx_en;        endend// When the data transmission reaches the stop bit, pull the transmission completion flag high and output the data always@(posedge sys_clk or negedge sys_rst_n)begin  if(!sys_rst_n)begin    uart_rx_done <= 1'b0;    uart_rx_data <= 8'd0;  end    // After finishing reception, output the received data  else if((bit_cnt == 4'd9) && (clk_cnt == BPS_CNT >> 1'd1) && (uart_rx_d3 == 1'b1))begin        uart_rx_done <= 1'b1;                  // Pull high for one clock cycle    uart_rx_data <= uart_rx_data_reg;    end                else begin              uart_rx_done <= 1'b0;                  // Pull high for one clock cycle    uart_rx_data <= uart_rx_data;  endend // Every time the clock counts a BPS_CNT (the number of clocks needed to transmit one bit), increment the data counter and clear the clock counter always@(posedge sys_clk or negedge sys_rst_n)begin  if(!sys_rst_n)begin    bit_cnt <= 4'd0;    clk_cnt <= 32'd0;  end  else if(rx_en)begin                            // In receiving state    if(clk_cnt < BPS_CNT - 1'd1)begin                 // One bit data has not been received yet      clk_cnt <= clk_cnt + 1'b1;                    // Clock counter +1      bit_cnt <= bit_cnt;                           // Bit counter remains unchanged    end                                                   else begin                                        // One bit data has been received        clk_cnt <= 32'd0;                             // Clear clock counter, restart timing      bit_cnt <= bit_cnt + 1'b1;                    // Bit counter +1, indicating one bit of data has been received    end                                                 end                                                       else begin                                        // Not in receiving state      bit_cnt <= 4'd0;                              // Clear      clk_cnt <= 32'd0;                             // Clear    end    end endmodule

4.4 Testbench

The design of the Testbench for the receiving module is as follows:

Set the baud rate to 230400 (this is to facilitate observing the transmission enable signal uart_tx_en).

Define a task that outputs one bit at a time using a baud rate of 230400, simulating the host sending data to the FPGA.

After 3000ns, send the first random data.

After sending the first random data, send the second random data, for a total of 4 random data.

 // *******************************************************************************************************// ** Author : Lonely Single Blade                                                         // ** Email : [email protected]// ** Blog : https://blog.csdn.net/wuzhikaidetb // ** Date : 2022/07/29  // ** Function : 1. Testbench for the UART receiving driver module based on FPGA //        2. Simulates the timing of sending data to the serial receiving driver by constructing a task to observe whether the module can successfully receive data. //        3. Sends 4 random 8-bit data sequentially // *******************************************************************************************************       `timescale 1ns/1ns  // Define time scale // Module and interface definition module tb_uart_rx(); reg       sys_clk      ;      reg       sys_rst_n    ;      reg       uart_rxd    ; wire       uart_rx_done  ;    wire  [7:0]  uart_rx_data  ; localparam  integer  BPS   = 'd230400        ;  // Baud rate localparam  integer  CLK_FRE = 'd50_000_000      ;  // System frequency 50M localparam  integer  CNT     = 1000_000_000 / BPS  ;  // Calculate the time required for each bit of transmission, units: ns  // Initial time definition initial begin    $timeformat(-9, 0, " ns", 10);  // Define time display format    sys_clk  =1'b0;    sys_rst_n <=1'b0;      uart_rxd <=1'b1;    #20 // System starts working  sys_rst_n <=1'b1;    #3000  rx_byte({$random} % 256);    // Generate 8-bit random number  rx_byte({$random} % 256);    // Generate 8-bit random number  rx_byte({$random} % 256);       // Generate 8-bit random number  rx_byte({$random} % 256);       // Generate 8-bit random number    #60  $finish();end // Print out every time a BYTE of data is successfully received always @(posedge sys_clk)begin  if(uart_rx_done)begin    $display("@time%t", $time);      $display("rx : 0x%h",uart_rx_data);  endend // Define a task, each sent data is 10 bits (1 start bit + 8 data bits + 1 stop bit) task rx_byte(  input [7:0] data);  integer i; // Define a constant  // Use for loop to generate a frame of data, the last content in the for brackets can only be written i=i+1  for(i=0; i<10; i=i+1) begin    case(i)    0: uart_rxd <= 1'b0;    // Start bit    1: uart_rxd <= data[0];    // LSB    2: uart_rxd <= data[1];    3: uart_rxd <= data[2];    4: uart_rxd <= data[3];    5: uart_rxd <= data[4];    6: uart_rxd <= data[5];    7: uart_rxd <= data[6];    8: uart_rxd <= data[7];    // MSB    9: uart_rxd <= 1'b1;    // Stop bit    endcase    #CNT;             // Delay for each bit of data sent  end    endtask               // End of task // Set the main clock always #10 sys_clk <= ~sys_clk;    // Clock 20ns, 50M // Instantiate the tested UART receiving driver uart_rx#(  .BPS      (BPS      ),      .CLK_FRE    (CLK_FRE    ))uart_rx_inst(  .sys_clk    (sys_clk    ),        .sys_rst_n    (sys_rst_n    ),        .uart_rxd    (uart_rxd    ),        .uart_rx_done  (uart_rx_done  ),      .uart_rx_data  (uart_rx_data  )  ); endmodule

4.5 Simulation Result Analysis

The simulation results are shown in the figure below (with detailed comments):

In the figure, 4 data 8’h24–8’h81–8’h09–8’h63 were sent respectively; the receiving module received the 4 data 8’h24–8’h81–8’h09–8’h63. The sent and received data match.

FPGA Implementation of UART (Including Source Code)

Overall Receiving Timing

The figure below shows the timing of receiving the first data (8’h24, that is 00100100).

FPGA Implementation of UART (Including Source Code)

Single Byte Receiving Timing

4.6 On-Board Testing

Having successfully completed the simulation verification of the receiving module, the next step is to conduct on-board testing using an Altera Cyclone IV E development board.

First, generate an IP core — ISSP (In-System Sources and Probes), which can provide an output for online output, equivalent to a simple signal generator — Source. Additionally, it can provide probes to monitor the signal output online.

In this design, we use Probes to observe the data received via the serial port. The ISSP is called as follows:

FPGA Implementation of UART (Including Source Code)

After downloading the program, open the In-System Sources and Probes Editor in Quartus II, and then use the serial debugging software to send data 0x55–0xaa–0x88 (randomly selected 3), and observe the values of the registers in the In-System Sources and Probes Editor, which are as follows:

FPGA Implementation of UART (Including Source Code)
FPGA Implementation of UART (Including Source Code)
FPGA Implementation of UART (Including Source Code)

5. Conclusion

UART, as a commonly used communication protocol and debugging method, must be mastered proficiently!

The implementation of UART based on FPGA is not difficult; as long as you pay attention to designing the counter reasonably according to the baud rate, data transmission and reception can be achieved.

If you need the complete project file, please click here: Project File Download

Copyright statement: This article is an original article by CSDN blogger “Lonely Single Blade”, following the CC 4.0 BY-SA copyright agreement. Please include the original source link and this statement when reprinting.

Original link:

https://blog.csdn.net/wuzhikaidetb/article/details/114596930

FPGA Implementation of UART (Including Source Code)

FPGA Implementation of UART (Including Source Code)

↑ Hot courses, limited time coupon! 🎉 Grab it now ↑

FPGA Implementation of UART (Including Source Code)

FPGA Implementation of UART (Including Source Code)

FPGA Implementation of UART (Including Source Code)Click “Read the original text” to view the course

Leave a Comment