| // A simple design demonstrating receiving and sending of RS232 signals |
| // |
| // With this design loaded, connect with a serial terminal to the USB serial |
| // port of the icestick (with 9600 BAUD) and use the number keys 1..5 to toggle |
| // the LEDs. |
| |
| module top ( |
| input clk, |
| input RX, |
| output TX, |
| output LED1, |
| output LED2, |
| output LED3, |
| output LED4, |
| output LED5 |
| ); |
| parameter integer BAUD_RATE = 9600; |
| parameter integer CLOCK_FREQ_HZ = 12000000; |
| localparam integer PERIOD = CLOCK_FREQ_HZ / BAUD_RATE; |
| |
| rs232_recv #( |
| .HALF_PERIOD(PERIOD / 2) |
| ) recv ( |
| .clk (clk ), |
| .RX (RX ), |
| .LED1 (LED1), |
| .LED2 (LED2), |
| .LED3 (LED3), |
| .LED4 (LED4), |
| .LED5 (LED5) |
| ); |
| |
| rs232_send #( |
| .PERIOD(PERIOD) |
| ) send ( |
| .clk (clk ), |
| .TX (TX ), |
| .LED1 (LED1), |
| .LED2 (LED2), |
| .LED3 (LED3), |
| .LED4 (LED4), |
| .LED5 (LED5) |
| ); |
| endmodule |
| |
| module rs232_recv #( |
| parameter integer HALF_PERIOD = 5 |
| ) ( |
| input clk, |
| input RX, |
| output reg LED1, |
| output reg LED2, |
| output reg LED3, |
| output reg LED4, |
| output reg LED5 |
| ); |
| reg [7:0] buffer; |
| reg buffer_valid; |
| |
| reg [$clog2(3*HALF_PERIOD):0] cycle_cnt; |
| reg [3:0] bit_cnt = 0; |
| reg recv = 0; |
| |
| initial begin |
| LED1 = 1; |
| LED2 = 0; |
| LED3 = 1; |
| LED4 = 0; |
| LED5 = 1; |
| end |
| |
| always @(posedge clk) begin |
| buffer_valid <= 0; |
| if (!recv) begin |
| if (!RX) begin |
| cycle_cnt <= HALF_PERIOD; |
| bit_cnt <= 0; |
| recv <= 1; |
| end |
| end else begin |
| if (cycle_cnt == 2*HALF_PERIOD) begin |
| cycle_cnt <= 0; |
| bit_cnt <= bit_cnt + 1; |
| if (bit_cnt == 9) begin |
| buffer_valid <= 1; |
| recv <= 0; |
| end else begin |
| buffer <= {RX, buffer[7:1]}; |
| end |
| end else begin |
| cycle_cnt <= cycle_cnt + 1; |
| end |
| end |
| end |
| |
| always @(posedge clk) begin |
| if (buffer_valid) begin |
| if (buffer == "1") LED1 <= !LED1; |
| if (buffer == "2") LED2 <= !LED2; |
| if (buffer == "3") LED3 <= !LED3; |
| if (buffer == "4") LED4 <= !LED4; |
| if (buffer == "5") LED5 <= !LED5; |
| end |
| end |
| endmodule |
| |
| module rs232_send #( |
| parameter integer PERIOD = 10 |
| ) ( |
| input clk, |
| output TX, |
| input LED1, |
| input LED2, |
| input LED3, |
| input LED4, |
| input LED5 |
| ); |
| reg [7:0] buffer; |
| reg buffer_valid; |
| |
| reg [$clog2(PERIOD):0] cycle_cnt = 0; |
| reg [4:0] bit_cnt = 0; |
| reg [5:0] byte_cnt = 60; |
| |
| always @(posedge clk) begin |
| cycle_cnt <= cycle_cnt + 1; |
| if (cycle_cnt == PERIOD-1) begin |
| cycle_cnt <= 0; |
| bit_cnt <= bit_cnt + 1; |
| if (bit_cnt == 10) begin |
| bit_cnt <= 0; |
| byte_cnt <= byte_cnt + 1; |
| end |
| end |
| end |
| |
| reg [7:0] data_byte; |
| reg data_bit; |
| |
| always @* begin |
| data_byte = 'bx; |
| case (byte_cnt) |
| 0: data_byte <= "\r"; |
| 1: data_byte <= LED1 ? "*" : "-"; |
| 2: data_byte <= LED2 ? "*" : "-"; |
| 3: data_byte <= LED3 ? "*" : "-"; |
| 4: data_byte <= LED4 ? "*" : "-"; |
| 5: data_byte <= LED5 ? "*" : "-"; |
| endcase |
| end |
| |
| always @(posedge clk) begin |
| data_bit = 'bx; |
| case (bit_cnt) |
| 0: data_bit <= 0; // start bit |
| 1: data_bit <= data_byte[0]; |
| 2: data_bit <= data_byte[1]; |
| 3: data_bit <= data_byte[2]; |
| 4: data_bit <= data_byte[3]; |
| 5: data_bit <= data_byte[4]; |
| 6: data_bit <= data_byte[5]; |
| 7: data_bit <= data_byte[6]; |
| 8: data_bit <= data_byte[7]; |
| 9: data_bit <= 1; // stop bit |
| 10: data_bit <= 1; // stop bit |
| endcase |
| if (byte_cnt > 5) begin |
| data_bit <= 1; |
| end |
| end |
| |
| assign TX = data_bit; |
| endmodule |