1 |
4 |
sumanta.ch |
module async_receiver(clk, RxD, RxD_data_ready, RxD_data, RxD_endofpacket, RxD_idle);
|
2 |
|
|
input clk, RxD;
|
3 |
|
|
output RxD_data_ready; // onc clock pulse when RxD_data is valid
|
4 |
|
|
output [7:0] RxD_data;
|
5 |
|
|
|
6 |
8 |
sumanta.ch |
//parameter ClkFrequency = 62500000; // 50MHz
|
7 |
|
|
parameter ClkFrequency = 50000000; // 50MHz
|
8 |
|
|
//parameter ClkFrequency = 27000000; // 27MHz
|
9 |
4 |
sumanta.ch |
parameter Baud = 115200;
|
10 |
|
|
|
11 |
|
|
// We also detect if a gap occurs in the received stream of characters
|
12 |
|
|
// That can be useful if multiple characters are sent in burst
|
13 |
|
|
// so that multiple characters can be treated as a "packet"
|
14 |
|
|
output RxD_endofpacket; // one clock pulse, when no more data is received (RxD_idle is going high)
|
15 |
|
|
output RxD_idle; // no data is being received
|
16 |
|
|
|
17 |
|
|
// Baud generator (we use 8 times oversampling)
|
18 |
|
|
parameter Baud8 = Baud*8;
|
19 |
|
|
parameter Baud8GeneratorAccWidth = 16;
|
20 |
|
|
parameter Baud8GeneratorInc = ((Baud8<<(Baud8GeneratorAccWidth-7))+(ClkFrequency>>8))/(ClkFrequency>>7);
|
21 |
|
|
reg [Baud8GeneratorAccWidth:0] Baud8GeneratorAcc;
|
22 |
|
|
always @(posedge clk) Baud8GeneratorAcc <= Baud8GeneratorAcc[Baud8GeneratorAccWidth-1:0] + Baud8GeneratorInc;
|
23 |
|
|
wire Baud8Tick = Baud8GeneratorAcc[Baud8GeneratorAccWidth];
|
24 |
|
|
|
25 |
|
|
////////////////////////////
|
26 |
|
|
reg [1:0] RxD_sync_inv;
|
27 |
|
|
always @(posedge clk) if(Baud8Tick) RxD_sync_inv <= {RxD_sync_inv[0], ~RxD};
|
28 |
|
|
// we invert RxD, so that the idle becomes "0", to prevent a phantom character to be received at startup
|
29 |
|
|
|
30 |
|
|
reg [1:0] RxD_cnt_inv;
|
31 |
|
|
reg RxD_bit_inv;
|
32 |
|
|
|
33 |
|
|
always @(posedge clk)
|
34 |
|
|
if(Baud8Tick)
|
35 |
|
|
begin
|
36 |
|
|
if( RxD_sync_inv[1] && RxD_cnt_inv!=2'b11) RxD_cnt_inv <= RxD_cnt_inv + 1;
|
37 |
|
|
else
|
38 |
|
|
if(~RxD_sync_inv[1] && RxD_cnt_inv!=2'b00) RxD_cnt_inv <= RxD_cnt_inv - 1;
|
39 |
|
|
|
40 |
|
|
if(RxD_cnt_inv==2'b00) RxD_bit_inv <= 0;
|
41 |
|
|
else
|
42 |
|
|
if(RxD_cnt_inv==2'b11) RxD_bit_inv <= 1;
|
43 |
|
|
end
|
44 |
|
|
|
45 |
|
|
reg [3:0] state;
|
46 |
|
|
reg [3:0] bit_spacing;
|
47 |
|
|
|
48 |
|
|
// "next_bit" controls when the data sampling occurs
|
49 |
|
|
// depending on how noisy the RxD is, different values might work better
|
50 |
|
|
// with a clean connection, values from 8 to 11 work
|
51 |
|
|
wire next_bit = (bit_spacing==10);
|
52 |
|
|
|
53 |
|
|
always @(posedge clk)
|
54 |
|
|
if(state==0)
|
55 |
|
|
bit_spacing <= 0;
|
56 |
|
|
else
|
57 |
|
|
if(Baud8Tick)
|
58 |
|
|
bit_spacing <= {bit_spacing[2:0] + 1} | {bit_spacing[3], 3'b000};
|
59 |
|
|
|
60 |
|
|
always @(posedge clk)
|
61 |
|
|
if(Baud8Tick)
|
62 |
|
|
case(state)
|
63 |
|
|
4'b0000: if(RxD_bit_inv) state <= 4'b1000; // start bit found?
|
64 |
|
|
4'b1000: if(next_bit) state <= 4'b1001; // bit 0
|
65 |
|
|
4'b1001: if(next_bit) state <= 4'b1010; // bit 1
|
66 |
|
|
4'b1010: if(next_bit) state <= 4'b1011; // bit 2
|
67 |
|
|
4'b1011: if(next_bit) state <= 4'b1100; // bit 3
|
68 |
|
|
4'b1100: if(next_bit) state <= 4'b1101; // bit 4
|
69 |
|
|
4'b1101: if(next_bit) state <= 4'b1110; // bit 5
|
70 |
|
|
4'b1110: if(next_bit) state <= 4'b1111; // bit 6
|
71 |
|
|
4'b1111: if(next_bit) state <= 4'b0001; // bit 7
|
72 |
|
|
4'b0001: if(next_bit) state <= 4'b0000; // stop bit
|
73 |
|
|
default: state <= 4'b0000;
|
74 |
|
|
endcase
|
75 |
|
|
|
76 |
|
|
reg [7:0] RxD_data;
|
77 |
|
|
always @(posedge clk)
|
78 |
|
|
if(Baud8Tick && next_bit && state[3]) RxD_data <= {~RxD_bit_inv, RxD_data[7:1]};
|
79 |
|
|
|
80 |
|
|
reg RxD_data_ready, RxD_data_error;
|
81 |
|
|
always @(posedge clk)
|
82 |
|
|
begin
|
83 |
|
|
RxD_data_ready <= (Baud8Tick && next_bit && state==4'b0001 && ~RxD_bit_inv); // ready only if the stop bit is received
|
84 |
|
|
RxD_data_error <= (Baud8Tick && next_bit && state==4'b0001 && RxD_bit_inv); // error if the stop bit is not received
|
85 |
|
|
end
|
86 |
|
|
|
87 |
|
|
reg [4:0] gap_count;
|
88 |
|
|
always @(posedge clk) if (state!=0) gap_count<=0; else if(Baud8Tick & ~gap_count[4]) gap_count <= gap_count + 1;
|
89 |
|
|
assign RxD_idle = gap_count[4];
|
90 |
|
|
reg RxD_endofpacket; always @(posedge clk) RxD_endofpacket <= Baud8Tick & (gap_count==15);
|
91 |
|
|
|
92 |
|
|
endmodule
|