Skip to content

Commit 6ec4bba

Browse files
committed
Add UART rx subsystem
1 parent 7fc7151 commit 6ec4bba

File tree

4 files changed

+96
-25
lines changed

4 files changed

+96
-25
lines changed

docs/src/uart.md

+17-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
# UART
22

33
To communicate with the outside world, a memory-mapped UART module was added to
4-
the system. It contains a receiver and a transmitter.
4+
the system. It contains a receiver and a transmitter, both tested at baud rates
5+
of 115200, 19200 and 9600.
56

6-
## Hardware block
7+
## Receiver hardware
8+
9+
Specification:
10+
11+
- 8 data bit
12+
- 1 stop bit
13+
- parity bit supported
14+
- AHB data interface
715

816
The receiver uses an oversampling technique to estimate transmitted bits on the
917
data line. In the absence of a clock line, detection of a start bit (0 value)
@@ -18,13 +26,14 @@ accurate retrieval. A standard oversampling factor of 16 minimizes the error to
1826
Transmission of a byte
1927
```
2028

21-
Specification:
29+
A stop bit (1 value) indicates the end of a transfer and historically provided a
30+
crude method of data pacing for slower processors.
2231

23-
- 8 data bit
24-
- 1 stop bit
25-
- parity bit supported
26-
- AHB data interface
32+
### Parity
33+
34+
The parity bit is 0 when the popcount is odd. A simple scheme to generate this
35+
is to negate a reduction XOR operation.
2736

28-
The hardware has been tested at baud rates of 115200, 19200 and 9600.
37+
## Transmitter hardware
2938

3039
## Software interface

hdl/uart/baud_gen.v

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
`include "platform.vh"
22
`default_nettype none
33

4-
module baud_gen
5-
#(parameter OVERSAMPLING = 16,
6-
parameter BAUD_RATE = 115200) (
4+
module baud_gen #(
5+
parameter OVERSAMPLING = 16,
6+
parameter BAUD_RATE = 115200
7+
) (
78
input wire clk,
89
input wire rst_n,
910

hdl/uart/uart_rx.v

+61-3
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,75 @@
11
`default_nettype none
22

3-
module uart_rx (
3+
module uart_rx #(
4+
parameter WORD_WIDTH = 8,
5+
parameter OVERSAMPLING = 16
6+
)(
47
input wire clk,
58
input wire rst_n,
6-
input wire sd
9+
input wire din,
10+
11+
// read interface
12+
output reg rd_valid,
13+
output wire [WORD_WIDTH-1:0] rd_data,
14+
input wire rd_ready
715
);
816

17+
localparam DATA_WIDTH = WORD_WIDTH + 1;
18+
wire parity = 1'b1;
19+
920
wire tick;
21+
wire des_done;
22+
wire [DATA_WIDTH-1:0] data;
23+
24+
// errors
25+
wire frame_err;
26+
reg parity_err;
27+
reg overflow_err;
1028

11-
baud_gen baud_gen0 (
29+
baud_gen #( .OVERSAMPLING(OVERSAMPLING) ) baud_gen0 (
1230
.clk(clk),
1331
.rst_n(rst_n),
1432
.tick(tick)
1533
);
1634

35+
uart_rx_des #( .OVERSAMPLING(OVERSAMPLING), .WORD_WIDTH(WORD_WIDTH) )
36+
uart_rx_des0 (
37+
.clk(clk),
38+
.rst_n(rst_n),
39+
.tick(tick),
40+
.din(din),
41+
.parity_en(parity),
42+
.dout(data),
43+
.frame_err(frame_err),
44+
.done(des_done)
45+
);
46+
47+
// UART interface
48+
reg [WORD_WIDTH-1:0] dbuf;
49+
50+
always @(posedge clk or negedge rst_n) begin
51+
if (~rst_n) begin
52+
dbuf <= 0;
53+
parity_err <= 1'b0;
54+
overflow_err <= 1'b0;
55+
rd_valid <= 1'b0;
56+
end else begin
57+
if (rd_valid && rd_ready)
58+
rd_valid <= 1'b0;
59+
// order matters here, fresh data added even if consumed in same cycle
60+
if (des_done) begin
61+
if (parity && (data[DATA_WIDTH-1] != ~(^data[DATA_WIDTH-2:0])))
62+
parity_err <= 1'b1;
63+
else begin
64+
dbuf <= data[DATA_WIDTH-2:0];
65+
if (rd_valid) // valid data but we write new data
66+
overflow_err <= 1'b1;
67+
rd_valid <= 1'b1;
68+
end
69+
end
70+
end
71+
end
72+
73+
assign rd_data = dbuf;
74+
1775
endmodule

hdl/uart/uart_rx_des.v

+14-11
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
`default_nettype none
22

3-
module uart_rx_des
4-
#( parameter WORD_WIDTH = 8,
5-
parameter OVERSAMPLING = 16) (
3+
module uart_rx_des #(
4+
parameter WORD_WIDTH = 8,
5+
parameter OVERSAMPLING = 16
6+
) (
67
input wire clk,
78
input wire rst_n,
89
input wire tick,
910
input wire din,
1011
input wire parity_en,
11-
output wire ready_tick,
12-
output wire [DATA_WIDTH-1:0] dout
12+
output wire [DATA_WIDTH-1:0] dout,
13+
output reg frame_err,
14+
output reg done
1315
);
1416

1517
localparam TICK_MID_VAL = OVERSAMPLING / 2 - 1;
@@ -21,7 +23,7 @@ localparam [2:0]
2123
DATA = 3'b010,
2224
STOP_BIT = 3'b011;
2325

24-
reg [2:0 ] state, state_nxt;
26+
reg [2:0] state, state_nxt;
2527

2628
// config
2729
reg parity, parity_nxt;
@@ -32,8 +34,7 @@ reg [$clog2(DATA_WIDTH)-1:0 ] bit_ctr, bit_ctr_nxt;
3234
wire [$clog2(DATA_WIDTH)-1:0] N = parity ? DATA_WIDTH : WORD_WIDTH;
3335

3436
// outputs
35-
reg [DATA_WIDTH-1:0 ] d, d_nxt;
36-
reg ready;
37+
reg [DATA_WIDTH-1:0] d, d_nxt;
3738

3839
always @(posedge clk or negedge rst_n) begin
3940
if (~rst_n) begin
@@ -57,7 +58,8 @@ always @(*) begin
5758
bit_ctr_nxt = bit_ctr;
5859
d_nxt = d;
5960
parity_nxt = parity;
60-
ready = 1'b0;
61+
done = 1'b0;
62+
frame_err = 1'b0;
6163

6264
case (state)
6365
IDLE: begin
@@ -94,15 +96,16 @@ always @(*) begin
9496
if (tick_ctr == 0) begin
9597
state_nxt = IDLE;
9698
if (din) // check data line deasserted
97-
ready = 1'b1;
99+
done = 1'b1;
100+
else
101+
frame_err = 1'b1;
98102
end else
99103
tick_ctr_nxt = tick_ctr - 1;
100104
end
101105
end
102106
endcase
103107
end
104108

105-
assign ready_tick = ready;
106109
assign dout = d;
107110

108111
endmodule

0 commit comments

Comments
 (0)