// 9-bit Serial port receiver // It's very simple, just single sample halfway of each bit. // If start bit is not zero or stop bit is not one, an error will be signaled. // In general, this module is prone to glitches in signal. First of all, any glitch > Tclk will trigger the reception process. // RX is high on idle. // Baud rate is programmable via clk_divisor // clk_divisor ids internally divided by 2 to get in the middle of bit, so need to be at least 2. `timescale 100 ps / 100 ps module serial_rx ( input wire clk, // full-speed clock input wire rst, // reset input wire [7:0] clk_divisor, // defines baudrate input wire rx, // rx serial connection output wire newdata, // pulses for new data received output wire [8:0] data, // data to send output wire error, // bad start or stop bit output wire idle // 1 if receiver in idle state ); reg [1:0] state; //State of the state machine localparam STATE_IDLE = 0; //waiting for enable localparam STATE_DATA = 1; //sending data localparam STATE_FINISH = 2; //finished reg [4:0] rx_ctr; //counter of received data words reg [7:0] downctr; //counter to generate baudrate reg [10:0] buffer; //internal latch/shift register with start and stop bit reg [8:0] reg_data; //latched received data reg reg_error; //latched error //The state machine always @(posedge clk or posedge rst) begin if (rst) begin state <= STATE_IDLE; reg_data <= 0; reg_error <= 0; end else case(state) STATE_IDLE: begin if (~rx) begin state <= STATE_DATA; rx_ctr <= 10; downctr[6:0]<= clk_divisor[7:1]; //wait half a bit downctr[7] <= 0; buffer <= 0; end end STATE_DATA: begin downctr = downctr - 1; if (downctr == 0) begin downctr <= clk_divisor; rx_ctr <= rx_ctr - 1; buffer[9:0] <= buffer[10:1]; buffer[10] <= rx; if (rx_ctr == 0) state <= STATE_FINISH; end end STATE_FINISH: begin reg_data[8:0] <= buffer[9:1]; reg_error <= buffer[0] | ~buffer[10]; //high start or low stop bit state <= STATE_IDLE; end default: state <= STATE_IDLE; endcase end //assignments assign idle = (state == STATE_IDLE) ? 1 : 0; assign data = reg_data; assign error = reg_error; endmodule