Skip to content

Commit a045839

Browse files
committed
Added extreme minimal UART implementations. Testing in progress
1 parent 1de6441 commit a045839

File tree

5 files changed

+175
-45
lines changed

5 files changed

+175
-45
lines changed

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
####(licensed under CC BY-SA 4_0)
44

55

6-
**/Advanced Synthesis Cookbook/** - useful code from Altera`s cookbook
7-
**/KCPSM6_Release9_30Sept14/** - Xilinx`s Picoblaze soft processor
6+
**/Advanced Synthesis Cookbook/** - useful code from Altera's cookbook
7+
**/KCPSM6_Release9_30Sept14/** - Xilinx's Picoblaze soft processor
88
**/pacoblaze-2.2/** - version of Picoblaze adapted for Altera devices
99

1010
**Main_tb.v** - basic testbench template
@@ -21,8 +21,11 @@
2121
**SimplePulseGen.v** - generates one-cycle pulse with given delay
2222
**StaticDelay.v** - static delay made on Xilinx`s SRL16E primitives
2323
**Synch.v** - input synchronizer (and also "static delay module"), standard way to get rid of metastability issues
24+
2425
**UartRx.v** - straightforward yet simple UART receiver implementation for FPGA written in Verilog
2526
**UartTx.v** - straightforward yet simple UART transmitter implementation for FPGA written in Verilog
27+
**UartRxExtreme.v** - extreme minimal UART receiver implementation for FPGA written in Verilog
28+
**UartTxExtreme.v** - extreme minimal UART transmitter implementation for FPGA written in Verilog
2629

2730
Also added some simple testbenches for selected modules
2831

UartRx.v

Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66
// INFO --------------------------------------------------------------------------------
77
// Straightforward yet simple UART receiver implementation for FPGA written in Verilog
88
// Expects at least one stop bit
9+
// Features continuous data aquisition at BAUD levels up to CLK_HZ / 2
10+
// Features early asynchronous 'busy' reset
911

1012

1113
/* --- INSTANTIATION TEMPLATE BEGIN ---
1214
1315
UartRx UR1 (
1416
.clk(),
1517
.nrst(),
16-
1718
.rx_data(),
1819
.rx_busy(),
1920
.rx_done(),
@@ -36,74 +37,68 @@ input wire clk;
3637
input wire nrst;
3738

3839
output reg [7:0] rx_data = 0;
40+
reg rx_data_9th_bit = 0; // {rx_data[7:0],rx_data_9th_bit} is actually a shift register
41+
3942
output reg rx_busy = 0;
40-
output reg rx_done = 0; // read strobe
41-
output reg rx_err = 0; // read strobe
43+
output wire rx_done; // read strobe
44+
output wire rx_err;
4245
input wire rxd;
4346

4447

48+
Synch S (
49+
.clk(clk),
50+
.nrst(nrst),
51+
.in(rxd),
52+
.out(s_rxd) // Synchronized rxd
53+
);
54+
defparam S.LENGTH = 2;
55+
defparam S.WIDTH = 1;
56+
57+
4558
reg rxd_prev = 0;
4659
always @ (posedge clk) begin
4760
if (~nrst) begin
4861
rxd_prev <= 0;
4962
end else begin
50-
rxd_prev <= rxd;
63+
rxd_prev <= s_rxd;
5164
end
5265
end
53-
54-
wire start_bit_strobe = ~rxd & rxd_prev;
66+
wire start_bit_strobe = ~s_rxd & rxd_prev;
5567

5668
reg [15:0] rx_sample_cntr = (BAUD_DIVISOR_2 - 1);
5769
wire rx_do_sample = (rx_sample_cntr[15:0] == 0);
58-
reg [3:0] rx_data_cntr = 4'b1000;
59-
6070
always @ (posedge clk) begin
6171
if (~nrst) begin
62-
rx_data[7:0] <= 0;
6372
rx_busy <= 0;
64-
rx_done <= 0;
65-
rx_err <= 0;
66-
rx_sample_cntr[15:0] <= (BAUD_DIVISOR_2 - 1);
67-
rx_data_cntr[3:0] <= 4'b1000;
6873
end else begin
6974
if (~rx_busy) begin
7075
if (start_bit_strobe) begin
7176
rx_sample_cntr[15:0] <= (BAUD_DIVISOR_2 * 3 - 1); // wait for 1,5-bit period till next sample
72-
rx_data[7:0] <= 0;
77+
{rx_data[7:0],rx_data_9th_bit} <= 9'b100000000;
7378
rx_busy <= 1;
74-
rx_done <= 0;
75-
rx_err <= 0;
76-
rx_data_cntr[3:0] <= 4'b1000;
7779
end // start_bit_strobe
7880
end else begin
7981

8082
if (rx_sample_cntr[15:0] == 0) begin
81-
rx_sample_cntr[15:0] <= (BAUD_DIVISOR_2 * 2 - 1); // wait for 1-bit-period till next sample
83+
rx_sample_cntr[15:0] <= (BAUD_DIVISOR_2 * 2 - 1); // wait for 1-bit-period till next sample
8284
end else begin
8385
rx_sample_cntr[15:0] <= rx_sample_cntr[15:0] - 1; // counting and sampling only when 'busy'
8486
end
8587

8688
if (rx_do_sample) begin
87-
if (rx_data_cntr[3:0] == 0) begin // do stop bit check
88-
if (rxd) begin
89-
rx_done <= 1;
90-
end else begin
91-
rx_err <= 1;
92-
end // rxd
93-
end else begin // do sample and shift data
94-
rx_data[7:0] <= {rxd, rx_data[7:1]};
95-
rx_data_cntr[3:0] <= rx_data_cntr[3:0] - 1;
96-
end // rx_data_cntr[3:0]
89+
if (rx_data_9th_bit == 1) begin
90+
rx_busy <= 0; // early asynchronous 'busy' reset
91+
end else begin
92+
{rx_data[7:0],rx_data_9th_bit} <= {s_rxd, rx_data[7:0]};
93+
end //
9794
end // rx_do_sample
9895

99-
if (rx_done || rx_err) begin
100-
rx_busy <= 0;
101-
rx_done <= 0;
102-
rx_err <= 0;
103-
end // rx_done
104-
10596
end // ~rx_busy
10697
end // ~nrst
10798
end
10899

100+
assign
101+
rx_done = rx_data_9th_bit && rx_do_sample && s_rxd, // rx_done and rx_busy fall simultaneously
102+
rx_err = rx_data_9th_bit && rx_do_sample && ~s_rxd;
103+
109104
endmodule

UartRxExtreme.v

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//--------------------------------------------------------------------------------
2+
// UartRxExtreme.v
3+
// Konstantin Pavlov, pavlovconst@gmail.com
4+
//--------------------------------------------------------------------------------
5+
6+
// INFO --------------------------------------------------------------------------------
7+
// Extreme minimal UART receiver optimized for 20MHz/115200 data rate
8+
9+
10+
/* --- INSTANTIATION TEMPLATE BEGIN ---
11+
12+
UartRxExtreme UR1 (
13+
.clk(),
14+
.rx_data(),
15+
.rx_busy(),
16+
.rx_done(),
17+
.rxd()
18+
);
19+
20+
--- INSTANTIATION TEMPLATE END ---*/
21+
22+
23+
module UartRxExtreme(clk, rx_data, rx_busy, rx_done, rxd);
24+
25+
26+
input wire clk;
27+
28+
output reg [7:0] rx_data = 0;
29+
reg rx_data_9th_bit = 0; // {rx_data[7:0],rx_data_9th_bit} is actually a shift register
30+
31+
output wire rx_busy;
32+
output wire rx_done;
33+
input wire rxd;
34+
35+
36+
reg rxd_prev = 0;
37+
always @ (posedge clk) begin
38+
rxd_prev <= rxd;
39+
end
40+
wire start_bit_strobe = ~rx_busy && (~rxd & rxd_prev);
41+
42+
43+
reg [7:0] rx_sample_cntr = 0;
44+
always @ (posedge clk) begin
45+
if (start_bit_strobe) begin
46+
rx_sample_cntr[7:0] <= (86 * 3 - 1) - 2;
47+
end else begin
48+
if (rx_sample_cntr[7:0] == 0) begin
49+
rx_sample_cntr[7:0] <= (86 * 2 - 1);
50+
end else begin
51+
rx_sample_cntr[7:0] <= rx_sample_cntr[7:0] - 1;
52+
end // rx_sample_cntr
53+
end // ~rx_busy && start_bit_strobe
54+
end
55+
wire rx_do_sample = (rx_sample_cntr[7:0] == 0);
56+
57+
58+
always @ (posedge clk) begin
59+
if (start_bit_strobe) begin
60+
{rx_data[7:0],rx_data_9th_bit} <= 9'b100000000;
61+
end // start_bit_strobe
62+
63+
if (rx_do_sample) begin
64+
if (~rx_done) begin
65+
{rx_data[7:0],rx_data_9th_bit} <= {rxd,rx_data[7:0]};
66+
end else begin
67+
rx_data[7:0] <= 0;
68+
rx_data_9th_bit <= 0;
69+
end // ~rx_done
70+
end // rx_do_sample
71+
end
72+
73+
assign
74+
rx_busy = |{rx_data[7:0],rx_data_9th_bit},
75+
rx_done = rx_data_9th_bit && rx_do_sample && rxd;
76+
77+
78+
endmodule

UartTx.v

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,17 @@
66
// INFO --------------------------------------------------------------------------------
77
// Straightforward yet simple UART transmitter implementation for FPGA written in Verilog
88
// One stop bit setting is hardcoded
9+
// Features continuous data output at BAUD levels up to CLK_HZ / 2
10+
// Features early asynchronous 'busy' set and reset to gain time to prepare new data
11+
// If multiple UartTX instances should be inferred - make tx_sample_cntr logic common for all TX instances for effective chip area usage
912

1013

1114
/* --- INSTANTIATION TEMPLATE BEGIN ---
1215
1316
UartTx UT1 (
1417
.clk(),
1518
.nrst(),
16-
19+
//.tx_do_sample(),
1720
.tx_data(),
1821
.tx_start(),
1922
.tx_busy(),
@@ -26,33 +29,34 @@ defparam UT1.BAUD = 9600; // max. BAUD is CLK_HZ / 2
2629

2730

2831
module UartTx(clk, nrst, tx_data, tx_start, tx_busy, txd);
32+
//module UartTx(clk, nrst, tx_do_sample, tx_data, tx_start, tx_busy, txd);
2933

3034
parameter CLK_HZ = 200_000_000;
3135
parameter BAUD = 9600;
3236
parameter BAUD_DIVISOR = CLK_HZ / BAUD;
3337

3438
input wire clk;
3539
input wire nrst;
40+
//input wire tx_do_sample;
3641

3742
input wire [7:0] tx_data;
3843
input wire tx_start; // write strobe
3944
output reg tx_busy = 0;
4045
output reg txd = 1;
4146

4247

43-
reg [15:0] tx_sample_cntr = (BAUD_DIVISOR-1);
4448
reg [9:0] tx_shifter = 0;
45-
49+
reg [15:0] tx_sample_cntr = 0;
4650
always @ (posedge clk) begin
4751
if ((~nrst) || (tx_sample_cntr[15:0] == 0)) begin
4852
tx_sample_cntr[15:0] <= (BAUD_DIVISOR-1);
4953
end else begin
50-
tx_sample_cntr[15:0] <= tx_sample_cntr[15:0] - 1'b1;
54+
tx_sample_cntr[15:0] <= tx_sample_cntr[15:0] - 1;
5155
end
5256
end
53-
5457
wire tx_do_sample = (tx_sample_cntr[15:0] == 0);
5558

59+
5660
always @ (posedge clk) begin
5761
if (~nrst) begin
5862
tx_busy <= 0;
@@ -68,12 +72,11 @@ always @ (posedge clk) begin
6872

6973
if (tx_do_sample) begin // next bit
7074
{tx_shifter[9:0],txd} <= {tx_shifter[9:0],txd} >> 1; // txd MUST change only on tx_do_sample although data may be loaded earlier
75+
if (~|tx_shifter[9:1]) begin // early asynchronous 'busy' reset
76+
tx_busy <= 0; // txd still holds data, but shifter is ready to get new info
77+
end
7178
end // tx_do_sample
7279

73-
if (~|tx_shifter[9:0]) begin // asynchronous 'busy' reset
74-
tx_busy <= 0; // txd still holds data, but shifter is ready
75-
end
76-
7780
end // ~tx_busy
7881
end // ~nrst
7982
end

UartTxExtreme.v

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//--------------------------------------------------------------------------------
2+
// UartTxExtreme.v
3+
// Konstantin Pavlov, pavlovconst@gmail.com
4+
//--------------------------------------------------------------------------------
5+
6+
// INFO --------------------------------------------------------------------------------
7+
// Extreme minimal UART transmitter
8+
9+
10+
/* --- INSTANTIATION TEMPLATE BEGIN ---
11+
12+
UartTxExtreme UT1 (
13+
.clk(),
14+
//.tx_do_sample(),
15+
.tx_data(),
16+
.tx_start(),
17+
.tx_busy(),
18+
.txd()
19+
);
20+
21+
--- INSTANTIATION TEMPLATE END ---*/
22+
23+
24+
module UartTxExtreme(clk, tx_do_sample, tx_data, tx_start, tx_busy, txd);
25+
26+
27+
input wire clk;
28+
input wire tx_do_sample;
29+
30+
input wire [7:0] tx_data;
31+
input wire tx_start;
32+
output wire tx_busy;
33+
output reg txd = 1;
34+
35+
36+
reg [9:0] tx_shifter = 0;
37+
38+
always @ (posedge clk) begin
39+
if (tx_start) begin
40+
tx_shifter[9:0] <= {1'b1,tx_data[7:0],1'b0};
41+
end // tx_start
42+
43+
if (tx_do_sample) begin
44+
{tx_shifter[9:0],txd} <= {tx_shifter[9:0],txd} >> 1;
45+
end // tx_do_sample
46+
end
47+
48+
assign
49+
tx_busy = |tx_shifter[9:1];
50+
51+
endmodule

0 commit comments

Comments
 (0)