aboutsummaryrefslogtreecommitdiffstats
path: root/atk16_fpga/uart_rx.v
blob: 5d6129e0b7ccd30e32ca427f33a310c42565b8a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
module uart_rx (
    input  wire       clk,   // System clock: 100 MHz
    input  wire       rx,    // Serial RX line
    output reg  [7:0] data,  // Received data byte
    output reg        done   // Goes high for one clock cycle when a frame is received
);

    // CLK / baudrate cycles per bit.
    //parameter CLKS_PER_BIT = 10417; // 9600 baud rate
    parameter CLKS_PER_BIT = 868;  // 115200 baud rate

    // Define states for the state machine.
    localparam STATE_IDLE = 2'd0;
    localparam STATE_START = 2'd1;
    localparam STATE_DATA = 2'd2;
    localparam STATE_STOP = 2'd3;

    reg [ 1:0] state = STATE_IDLE;
    reg [13:0] clk_count = 14'd0;
    reg [ 2:0] bit_index = 3'd0;  // Will count 0 to 7 for the 8 data bits.
    reg [ 7:0] rx_shift_reg = 8'd0;

    // Synchronous state machine.
    always @(posedge clk) begin
        case (state)
            STATE_IDLE: begin
                done <= 1'b0;
                clk_count <= 14'd0;
                bit_index <= 3'd0;
                if (rx == 1'b0) begin
                    // Detected start bit. Go to START state.
                    state <= STATE_START;
                end else begin
                    state <= STATE_IDLE;
                end
            end

            STATE_START: begin
                // Wait for half a bit period, then sample the start bit.
                if (clk_count == (CLKS_PER_BIT - 1) / 2) begin
                    // Sample start bit: it must be 0.
                    if (rx == 1'b0) begin
                        clk_count <= 14'd0;
                        state <= STATE_DATA;
                    end else begin
                        // False start; return to idle.
                        state <= STATE_IDLE;
                    end
                end else begin
                    clk_count <= clk_count + 1;
                end
            end

            STATE_DATA: begin
                // Wait for a full bit period then sample the data bit.
                if (clk_count < CLKS_PER_BIT - 1) begin
                    clk_count <= clk_count + 1;
                end else begin
                    clk_count <= 14'd0;
                    // Sample the current data bit.
                    rx_shift_reg[bit_index] <= rx;
                    if (bit_index == 3'd7) begin
                        state <= STATE_STOP;
                    end else begin
                        bit_index <= bit_index + 1;
                    end
                end
            end

            STATE_STOP: begin
                // Wait one bit period for the stop bit.
                if (clk_count < CLKS_PER_BIT - 1) begin
                    clk_count <= clk_count + 1;
                end else begin
                    clk_count <= 14'd0;
                    // Optionally, you could check that rx is high (stop bit).
                    data      <= rx_shift_reg;  // Latch the received data.
                    done      <= 1'b1;  // Signal that a frame has been received.
                    state     <= STATE_IDLE;  // Go back to idle for the next frame.
                end
            end

            default: state <= STATE_IDLE;
        endcase
    end

endmodule