| // Oversampling UART receiver. | |
| module UART_RX( | |
| input rst, clk, baud_edge, rx, | |
| output [7:0] data, | |
| output data_ready, framing_error | |
| ); | |
| parameter OVERSAMPLE = 8; | |
| localparam FIND_EDGE = 3'd1, START = 3'd2, DATA = 3'd3, END = 3'd4; | |
| reg prev_rx; | |
| reg [7:0] data_reg; | |
| reg [2:0] data_counter; | |
| reg [2:0] state = 0; | |
| reg [$clog2(OVERSAMPLE+OVERSAMPLE/2)-1:0] over_sample_counter = 0; | |
| reg data_ready_reg = 0; | |
| reg framing_error_reg = 0; | |
| assign data = data_reg; | |
| assign data_ready = data_ready_reg; | |
| assign framing_error = framing_error_reg; | |
| always @(posedge clk) begin | |
| if(rst) begin | |
| data_reg <= 0; | |
| prev_rx <= 0; | |
| data_ready_reg <= 0; | |
| state <= FIND_EDGE; | |
| data_counter <= 0; | |
| over_sample_counter <= 0; | |
| end else if(baud_edge) begin | |
| case(state) | |
| FIND_EDGE: begin | |
| prev_rx <= rx; | |
| if(prev_rx & !rx) begin | |
| state <= START; | |
| prev_rx <= 0; | |
| over_sample_counter <= 0; | |
| end | |
| end | |
| START: begin | |
| // Align sample edge in the middle of the pulses. | |
| if(over_sample_counter == OVERSAMPLE/2-1) begin | |
| over_sample_counter <= 0; | |
| data_counter <= 0; | |
| state <= DATA; | |
| end else begin | |
| over_sample_counter <= over_sample_counter + 1; | |
| end | |
| end | |
| DATA: begin | |
| if(over_sample_counter == OVERSAMPLE-1) begin | |
| over_sample_counter <= 0; | |
| data_reg[data_counter] <= rx; | |
| if(data_counter == 7) begin | |
| state <= END; | |
| data_counter <= 0; | |
| end else begin | |
| data_counter <= data_counter + 1; | |
| end | |
| end else begin | |
| over_sample_counter <= over_sample_counter + 1; | |
| end | |
| end | |
| END: begin | |
| if(over_sample_counter == OVERSAMPLE-1) begin | |
| if(rx) begin | |
| data_ready_reg <= 1; | |
| end else begin | |
| framing_error_reg <= 1; | |
| end | |
| state <= FIND_EDGE; | |
| end else begin | |
| over_sample_counter <= over_sample_counter + 1; | |
| end | |
| end | |
| default: begin | |
| data_ready_reg <= 0; | |
| state <= FIND_EDGE; | |
| end | |
| endcase | |
| end else begin | |
| data_ready_reg <= 0; | |
| framing_error_reg <= 0; | |
| end | |
| end | |
| endmodule |