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