In the last chapter we created one-way communication from the FPGA to a PC. It would be really good if we could send data from the PC back to the FPGA too.
To allow this to happen we need to be able to recover the sender’s clock - a process called clock recovery.
Synchronising with an incoming signal is usually a hard problem to solve. But for short transfers using low bit rates (like RS-232) it is pretty easy to solve by oversampling the incoming signal. Although this isn’t the most efficient method it is easy to understand and implement.
If the incoming signal has a bit rate of 9600 baud, your design oversamples the signal at four times this speed (38400), ensuring that for each received bit we will have at least two good samples.
The next challenge is then to work out which pairs of bits are good, and where a frame starts and ends. Here’s my solution.
As discussed in the last chapter an RS-232 frame starts with a start bit (low), has eight data bits and ends with a stop bit (high). To receive this data, use a 40-bit shift register initialised to '1’s, and then capture the incoming signal into the left-hand end of a shift register.
After 40 samples we will have the following bits where '-' is 'don’t care' and '??' are pairs of matching 'LL' or 'HH' bits (as they will have been sampled in the sample bit windows):
(MSB) (LSB) -HH--??--??--??--??--??--??--??--??--LL- Stop 7 6 5 4 3 2 1 0 start
If we see this pattern we know have a valid frame, and can then make use of the data
The test to see if we have received a valid frame we need to check the following:
-
Check that bits(38 downto 37) = '1'
-
Check that bits(34) are bits(33) the same
-
Check that bits(30) are bits(29) the same
-
Check that bits(26) are bits(25) the same
-
Check that bits(22) are bits(21) the same
-
Check that bits(18) are bits(17) the same
-
Check that bits(14) are bits(13) the same
-
Check that bits(10) are bits(9) the same
-
Check that bits(6) are bits(5) the same
-
Check that bits(2 downto 1) are both '0'
If all this is true we can capture the byte, and set a signal to indicate receiving of the byte then reset the shift register back to the empty state, preventing false triggering:
value <= bits(34) & bits(30) & bits(26) & bits(22) & bits(18) & bits(14) & bits(10) & bits(6);
byte_received <= '1';
bits <= (others => '1');
Wow - much easier than expected. So what is the catch?
The main problem with this solution is that the sender’s clock and the receiver’s clock must be closely matched. A drift of 2.5% (1/40) in clocks will be enough that the sampling of the start bit and stop bit will be one sample out of step from each other - but will still work with a very 'crisp' signal.
If there is a difference of 5% in timing the first and last sample will be two sample periods out of step, and the design will never be able to receive the data correctly.
Project - Build a UART ~~~~---------- * Create a project that receives characters over RS-232 and displays them on the LEDs or seven segment display * Merge the code from the previous project, creating your own RS-232 RX/TX component