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 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
// 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
|