Skip to content

Instantly share code, notes, and snippets.

@rndtrash
Created November 11, 2023 21:34
Show Gist options
  • Select an option

  • Save rndtrash/cf4e7393774a92be95da5b001daa1ca7 to your computer and use it in GitHub Desktop.

Select an option

Save rndtrash/cf4e7393774a92be95da5b001daa1ca7 to your computer and use it in GitHub Desktop.

Revisions

  1. rndtrash created this gist Nov 11, 2023.
    125 changes: 125 additions & 0 deletions uart_rx.v
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,125 @@
    // TODO: this module occasionally reads garbage

    `define BAUD_RATE 9_600
    `define CLOCK 27_000_000

    module uart_rx #(TICKS_PER_BIT=2_812) (clk, reset, re, rx, data, received, busy, valid);

    input clk;
    input reset;
    input re;
    input rx;
    output reg [7:0] data = 8'h00;
    output reg received = 0;
    output reg busy = 0;
    output reg valid = 0;

    localparam STATE_INITIAL = 3'd0;
    localparam STATE_START_BIT = 3'd1;
    localparam STATE_DATA_BITS = 3'd2;
    localparam STATE_STOP_BIT = 3'd3;
    localparam STATE_PADDING = 3'd4;

    localparam BIT_COUNTER_INITIAL = 3'd0;

    reg [2:0] state = STATE_INITIAL; // [0; 8)
    reg [18:0] counter = 0; // [0; 524 288)
    reg [2:0] bit_counter = BIT_COUNTER_INITIAL; // [0; 8)

    wire rx_neg_edge;
    negedge_detector ned(.clk(clk), .rst(reset), .a(rx), .detected(rx_neg_edge));

    always @(posedge clk)
    if (reset)
    begin
    state <= STATE_INITIAL;
    busy <= 0;
    received <= 0;
    valid <= 0;
    end
    else
    case (state)
    STATE_INITIAL:
    begin
    if (re && rx_neg_edge)
    begin
    state <= STATE_START_BIT;
    busy <= 1;
    received <= 0;

    counter <= 0;
    end
    end

    STATE_START_BIT:
    begin
    // a half of the bit interval to read from the middle
    if (counter == TICKS_PER_BIT / 2)
    if (~ rx)
    begin
    state <= STATE_DATA_BITS;
    valid <= 0;

    counter <= 0;
    bit_counter <= BIT_COUNTER_INITIAL;
    end
    else
    begin
    state <= STATE_INITIAL;
    busy <= 0;
    end
    else
    counter <= counter + 19'd1;
    end

    STATE_DATA_BITS:
    begin
    if (counter == TICKS_PER_BIT)
    begin
    data[bit_counter] <= rx;
    counter <= 0;

    if (bit_counter == 7)
    state <= STATE_STOP_BIT;
    else
    begin
    bit_counter <= bit_counter + 3'd1;
    end
    end
    else
    counter <= counter + 19'd1;
    end

    STATE_STOP_BIT:
    begin
    if (counter == TICKS_PER_BIT)
    begin
    busy <= 0;

    if (rx)
    begin
    state <= STATE_PADDING;
    received <= 1;
    valid <= 1;

    counter <= 0;
    end
    else
    state <= STATE_INITIAL;
    end
    else
    counter <= counter + 19'd1;
    end

    STATE_PADDING:
    begin
    received <= 0;

    if (counter == TICKS_PER_BIT / 2)
    state <= STATE_INITIAL;
    else
    counter <= counter + 19'd1;
    end
    endcase

    endmodule