Skip to content

Commit 19fb915

Browse files
authored
Added uart_sum example (Add two 8-bit numbers on FPGA and return result via UART) (#23)
* Added uart_sum example
1 parent 31a60d5 commit 19fb915

File tree

7 files changed

+1484
-0
lines changed

7 files changed

+1484
-0
lines changed

examples/uart_sum/README.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Add Two 8-bit Numbers on FPGA and Return Result via UART
2+
This project demonstrates UART-based communication between an RP2040 and an FPGA. Two 8-bit numbers are sent from the RP2040 to the FPGA over UART. The FPGA stores the received values, performs an addition operation, and then transmits the result back to the RP2040 using UART.
3+
4+
## Overview on FPGA side
5+
- This project consists of three modules :
6+
1) `top :` This module implements the FSM.
7+
- Continuously look for input data
8+
- Add the two 8 bit numbers.
9+
- Generate appropriate transmission signal onces summation is done.
10+
2) `uart_rx : ` This module implements a UART Receiver.
11+
- When the data is received, it makes "data valid" signal high.
12+
3) `uart_rx : ` This module implements a UART Transmitter.
13+
- When the start signal is given, it transmit the data present in its output buffer.
14+
15+
---
16+
17+
## Features
18+
- Configurable `BAUD_RATE`
19+
20+
---
21+
22+
## Top Module Interface
23+
24+
| Signal | Direction | Description |
25+
|---------------|-----|--------------------------------------|
26+
| `clk` | In | System clock (50 MHz typical) |
27+
| `rst` | In | Reset Pin |
28+
| `rx` | In | Receiver Line |
29+
| `tx` | Out | Transmission Line |
30+
| `tx_en` | Out | Output enable for transmitter (always 1) |
31+
| `clk_en` | Out | Clock enable (always 1) |
32+
33+
---
34+
35+
## Parameters Used
36+
#### `CLK :`
37+
- Parameter to represent the System clock frequency in Hz.
38+
- `parameter CLK = 50_000_000`
39+
#### `BAUD_RATE :`
40+
- Parameter to configure Baud Rate of UART communication.
41+
- `parameter BAUD_RATE = 115200`
42+
43+
---
44+
45+
## Pin Usage for Testing
46+
This design was tested using configuration given below:
47+
48+
### FPGA
49+
| FPGA GPIO Pin | Signal Name | Direction | Description |
50+
|----------|-------------|-----------|-----------------------------------|
51+
| 3 | Reset | Input | For Reseting the FPGA |
52+
| 4 | UART TX | Input | UART ouput to RP2040 |
53+
| 6 | UART RX | Output | UART input from RP2040 |
54+
55+
### RP2040
56+
| RP2040 Pin | Signal Name | Direction | Description |
57+
|----------|-------------|-----------|-----------------------------------|
58+
| 1 | UART RX | Input | UART input from FPGA |
59+
| 0 | UART TX | Output | UART ouput to FPGA |
60+
| 2 | Reset | Output | MCU output for reseting the FPGA |
61+
62+
When testing using RP2040 MCU, first load the bitstream to FPGA then run the `uart_sum.py`. The pin number in your FPGA constraints must match what is used in the micropython code.
63+
64+
---
65+
66+
## Expected Output in Thonny
67+
![Expected Output in Thonny](ffpga/images/output.JPG "Expected Output")
11.4 KB
Loading

examples/uart_sum/ffpga/src/top.v

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
(* top *) module top #(
2+
parameter CLK = 50_000_000,
3+
parameter BAUD_RATE = 115200
4+
)(
5+
(* iopad_external_pin, clkbuf_inhibit *)input clk,
6+
(* iopad_external_pin *) output clk_en,
7+
(* iopad_external_pin *) input rst,
8+
(* iopad_external_pin *) input rx,
9+
(* iopad_external_pin *) output tx,
10+
(* iopad_external_pin *) output tx_en
11+
);
12+
13+
assign clk_en = 1'b1;
14+
assign tx_en = 1'b1;
15+
16+
reg [7:0] num1, num2, sum;
17+
reg flag = 1'b0;
18+
19+
/* uart_rx module instantiation */
20+
wire [7:0] data;
21+
wire data_valid;
22+
uart_rx # ( .CLK(CLK),
23+
.BAUD_RATE(BAUD_RATE) )
24+
U_uart_rx
25+
26+
(
27+
.i_Clock(clk),
28+
.i_RX_Serial(rx),
29+
.o_RX_DV(data_valid),
30+
.o_RX_Byte (data)
31+
);
32+
33+
/* uart_tx module instantiation */
34+
uart_tx # ( .IN_CLK_HZ(CLK),
35+
.DATA_FRAME(8),
36+
.BAUD_RATE(BAUD_RATE),
37+
.OVERSAMPLING_MODE(16),
38+
.STOP_BIT(1),
39+
.LSB(1'b0) )
40+
U_uart_tx
41+
(
42+
.i_clk(clk),
43+
.i_rst(rst),
44+
.o_tx(tx),
45+
.i_tx_data(sum), // sum = num1 + num2
46+
.i_tx_start(flag), // transmit sum when flag is HIGH
47+
.o_tx_done()
48+
);
49+
50+
localparam S1 = 2'b00;
51+
localparam S2 = 2'b01;
52+
localparam S3 = 2'b10;
53+
localparam S4 = 2'b11;
54+
55+
reg [1:0] state = S1;
56+
always @(posedge clk) begin
57+
if (rst) begin
58+
state <= S1;
59+
end else begin
60+
if (state == S1 && data_valid) begin
61+
num1 <= data;
62+
state <= S2;
63+
end else if (state == S2 && data_valid) begin
64+
num2 <= data;
65+
state <= S3;
66+
end else if (state == S3) begin
67+
sum <= num1 + num2;
68+
flag <= 1'b1;
69+
state <= S4;
70+
end else if (state == S4) begin
71+
flag <= 1'b0;
72+
state <= S1;
73+
end
74+
end
75+
end
76+
77+
endmodule
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
module uart_rx #(
2+
parameter CLK = 50_000_000,
3+
parameter BAUD_RATE = 115200
4+
) (
5+
input i_Clock,
6+
input i_RX_Serial,
7+
output o_RX_DV,
8+
output [7:0] o_RX_Byte
9+
);
10+
11+
parameter CLOCKS_PER_BIT = CLK/BAUD_RATE;
12+
parameter IDLE = 3'b000;
13+
parameter RX_START_BIT = 3'b001;
14+
parameter RX_DATA_BITS = 3'b010;
15+
parameter RX_STOP_BIT = 3'b011;
16+
parameter CLEANUP = 3'b100;
17+
18+
reg [17:0] r_Clock_Count;
19+
reg [2:0] r_Bit_Index;
20+
reg [7:0] r_RX_Byte;
21+
reg r_RX_DV;
22+
reg [2:0] r_SM_Main;
23+
24+
always @(posedge i_Clock) begin
25+
case (r_SM_Main)
26+
IDLE: begin
27+
r_RX_DV <= 1'b0;
28+
r_Clock_Count <= 0;
29+
r_Bit_Index <= 0;
30+
31+
if (i_RX_Serial == 1'b0)
32+
r_SM_Main <= RX_START_BIT;
33+
else
34+
r_SM_Main <= IDLE;
35+
end
36+
37+
RX_START_BIT: begin
38+
if (r_Clock_Count == CLOCKS_PER_BIT / 2) begin
39+
if (i_RX_Serial == 1'b0) begin
40+
r_Clock_Count <= 0;
41+
r_SM_Main <= RX_DATA_BITS;
42+
end else
43+
r_SM_Main <= IDLE;
44+
end else begin
45+
r_Clock_Count <= r_Clock_Count + 1'b1;
46+
r_SM_Main <= RX_START_BIT;
47+
end
48+
end
49+
50+
RX_DATA_BITS: begin
51+
if(r_Clock_Count < CLOCKS_PER_BIT - 1) begin
52+
r_Clock_Count <= r_Clock_Count + 1'b1;
53+
r_SM_Main <= RX_DATA_BITS;
54+
end else begin
55+
r_Clock_Count <= 0;
56+
r_RX_Byte[r_Bit_Index] <= i_RX_Serial;
57+
58+
if (r_Bit_Index < 7) begin
59+
r_Bit_Index <= r_Bit_Index + 1'b1;
60+
r_SM_Main <= RX_DATA_BITS;
61+
end else begin
62+
r_Bit_Index <= 0;
63+
r_SM_Main <= RX_STOP_BIT;
64+
end
65+
end
66+
end
67+
68+
RX_STOP_BIT: begin
69+
if(r_Clock_Count < CLOCKS_PER_BIT - 1) begin
70+
r_Clock_Count <= r_Clock_Count + 1'b1;
71+
r_SM_Main <= RX_STOP_BIT;
72+
end else begin
73+
r_RX_DV <= 1'b1;
74+
r_Clock_Count <= 0;
75+
r_SM_Main <= CLEANUP;
76+
end
77+
end
78+
79+
CLEANUP: begin
80+
r_SM_Main <= IDLE;
81+
r_RX_DV <= 1'b0;
82+
end
83+
84+
default: r_SM_Main <= IDLE;
85+
endcase
86+
end
87+
88+
assign o_RX_Byte = r_RX_Byte;
89+
assign o_RX_DV = r_RX_DV;
90+
91+
endmodule

0 commit comments

Comments
 (0)