Add diagrams and pictures
[clump.git] / uart.v
1 `timescale 1ns / 1ps
2 // Documented Verilog UART
3 // Copyright (C) 2010 Timothy Goddard (tim@goddard.net.nz)
4 // Distributed under the MIT licence.
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 // THE SOFTWARE.
23 //
24 module uart(
25 input clk, // The master clock for this module
26 input rst, // Synchronous reset.
27 input rx, // Incoming serial line
28 output tx, // Outgoing serial line
29 input transmit, // Signal to transmit
30 input [7:0] tx_byte, // Byte to transmit
31 output received, // Indicated that a byte has been received.
32 output [7:0] rx_byte, // Byte received
33 output is_receiving, // Low when receive line is idle.
34 output is_transmitting, // Low when transmit line is idle.
35 output recv_error // Indicates error in receiving packet.
36 );
37
38 parameter CLOCK_DIVIDE = 1302; // clock rate (50Mhz) / (baud rate (9600) * 4)
39
40 // States for the receiving state machine.
41 // These are just constants, not parameters to override.
42 parameter RX_IDLE = 0;
43 parameter RX_CHECK_START = 1;
44 parameter RX_READ_BITS = 2;
45 parameter RX_CHECK_STOP = 3;
46 parameter RX_DELAY_RESTART = 4;
47 parameter RX_ERROR = 5;
48 parameter RX_RECEIVED = 6;
49
50 // States for the transmitting state machine.
51 // Constants - do not override.
52 parameter TX_IDLE = 0;
53 parameter TX_SENDING = 1;
54 parameter TX_DELAY_RESTART = 2;
55
56 reg [21:0] rx_clk_divider = CLOCK_DIVIDE;
57 reg [21:0] tx_clk_divider = CLOCK_DIVIDE;
58
59 reg [2:0] recv_state = RX_IDLE;
60 reg [5:0] rx_countdown;
61 reg [3:0] rx_bits_remaining;
62 reg [7:0] rx_data;
63
64 reg tx_out = 1'b1;
65 reg [1:0] tx_state = TX_IDLE;
66 reg [5:0] tx_countdown;
67 reg [3:0] tx_bits_remaining;
68 reg [7:0] tx_data;
69
70 assign received = recv_state == RX_RECEIVED;
71 assign recv_error = recv_state == RX_ERROR;
72 assign is_receiving = recv_state != RX_IDLE;
73 assign rx_byte = rx_data;
74
75 assign tx = tx_out;
76 assign is_transmitting = tx_state != TX_IDLE;
77
78 always @(posedge clk) begin
79 if (rst) begin
80 recv_state = RX_IDLE;
81 tx_state = TX_IDLE;
82 end
83
84 // The clk_divider counter counts down from
85 // the CLOCK_DIVIDE constant. Whenever it
86 // reaches 0, 1/16 of the bit period has elapsed.
87 // Countdown timers for the receiving and transmitting
88 // state machines are decremented.
89 rx_clk_divider = rx_clk_divider - 1;
90 if (!rx_clk_divider) begin
91 rx_clk_divider = CLOCK_DIVIDE;
92 rx_countdown = rx_countdown - 1;
93 end
94 tx_clk_divider = tx_clk_divider - 1;
95 if (!tx_clk_divider) begin
96 tx_clk_divider = CLOCK_DIVIDE;
97 tx_countdown = tx_countdown - 1;
98 end
99
100 // Receive state machine
101 case (recv_state)
102 RX_IDLE: begin
103 // A low pulse on the receive line indicates the
104 // start of data.
105 if (!rx) begin
106 // Wait half the period - should resume in the
107 // middle of this first pulse.
108 rx_clk_divider = CLOCK_DIVIDE;
109 rx_countdown = 2;
110 recv_state = RX_CHECK_START;
111 end
112 end
113 RX_CHECK_START: begin
114 if (!rx_countdown) begin
115 // Check the pulse is still there
116 if (!rx) begin
117 // Pulse still there - good
118 // Wait the bit period to resume half-way
119 // through the first bit.
120 rx_countdown = 4;
121 rx_bits_remaining = 8;
122 recv_state = RX_READ_BITS;
123 end else begin
124 // Pulse lasted less than half the period -
125 // not a valid transmission.
126 recv_state = RX_ERROR;
127 end
128 end
129 end
130 RX_READ_BITS: begin
131 if (!rx_countdown) begin
132 // Should be half-way through a bit pulse here.
133 // Read this bit in, wait for the next if we
134 // have more to get.
135 rx_data = {rx, rx_data[7:1]};
136 rx_countdown = 4;
137 rx_bits_remaining = rx_bits_remaining - 1;
138 recv_state = rx_bits_remaining ? RX_READ_BITS : RX_CHECK_STOP;
139 end
140 end
141 RX_CHECK_STOP: begin
142 if (!rx_countdown) begin
143 // Should resume half-way through the stop bit
144 // This should be high - if not, reject the
145 // transmission and signal an error.
146 recv_state = rx ? RX_RECEIVED : RX_ERROR;
147 end
148 end
149 RX_DELAY_RESTART: begin
150 // Waits a set number of cycles before accepting
151 // another transmission.
152 recv_state = rx_countdown ? RX_DELAY_RESTART : RX_IDLE;
153 end
154 RX_ERROR: begin
155 // There was an error receiving.
156 // Raises the recv_error flag for one clock
157 // cycle while in this state and then waits
158 // 2 bit periods before accepting another
159 // transmission.
160 rx_countdown = 8;
161 recv_state = RX_DELAY_RESTART;
162 end
163 RX_RECEIVED: begin
164 // Successfully received a byte.
165 // Raises the received flag for one clock
166 // cycle while in this state.
167 recv_state = RX_IDLE;
168 end
169 endcase
170
171 // Transmit state machine
172 case (tx_state)
173 TX_IDLE: begin
174 if (transmit) begin
175 // If the transmit flag is raised in the idle
176 // state, start transmitting the current content
177 // of the tx_byte input.
178 tx_data = tx_byte;
179 // Send the initial, low pulse of 1 bit period
180 // to signal the start, followed by the data
181 tx_clk_divider = CLOCK_DIVIDE;
182 tx_countdown = 4;
183 tx_out = 0;
184 tx_bits_remaining = 8;
185 tx_state = TX_SENDING;
186 end
187 end
188 TX_SENDING: begin
189 if (!tx_countdown) begin
190 if (tx_bits_remaining) begin
191 tx_bits_remaining = tx_bits_remaining - 1;
192 tx_out = tx_data[0];
193 tx_data = {1'b0, tx_data[7:1]};
194 tx_countdown = 4;
195 tx_state = TX_SENDING;
196 end else begin
197 // Set delay to send out 2 stop bits.
198 tx_out = 1;
199 tx_countdown = 8;
200 tx_state = TX_DELAY_RESTART;
201 end
202 end
203 end
204 TX_DELAY_RESTART: begin
205 // Wait until tx_countdown reaches the end before
206 // we send another transmission. This covers the
207 // "stop bit" delay.
208 tx_state = tx_countdown ? TX_DELAY_RESTART : TX_IDLE;
209 end
210 endcase
211 end
212
213 endmodule
This page took 0.027481 seconds and 4 git commands to generate.