EECS 151/251A Lab 4: Serial I/O – UART solved

$30.00

Category: You will Instantly receive a download link for .zip solution file upon Payment || To Order Original Work Click Custom Order?

Description

5/5 - (2 votes)

EECS 151/251A FPGA Lab
1 Before You Start This Lab
Before you proceed with the contents of this lab, we suggest that you get acquainted with what a
ready/valid handshake is. Read the document in labs_sp17/docs/Verilog/ready_valid_interface.pdf.
It may be helpful to draw out the timing diagrams for the ready/valid handshake to gain understanding. If you are having trouble, ask a TA. Please note that the serial line itself is not a
ready/valid interface. Rather, it is the modules you will work with in this lab (UATransmit and
UAReceive) that have the ready/valid handshake for interfacing with other modules on the FPGA.
In this lab you will implement a UART (Universal Asynchronous Receiver / Transmitter) device,
otherwise known as a serial interface. Your working UART from this lab will be used in your
project to talk to your workstation (desktop) over a serial line.
This lab will be done individually, but the next 2 labs will be done with a partner. If
you have not found one yet, now is the time to do so. The deliverable for this lab will be used in
your final project. Once you have a group of two, please email the TAs (bob.linchuan@berkeley.edu
1
and vighnesh.iyer@berkeley.edu) with the names and Github ID’s of both group members so that
we can create your team project repositories. You can complete the lab without having your project
repository yet; you’ll only need it for the project.
2 Lab Setup
Run git pull in the labs_sp17 folder to fetch the latest skeleton files. You will need to copy over
your debouncer.v, edge_detector.v, and synchronizer.v from Lab 3 to labs_sp17/lab4/src/.
3 Serial Device
You are responsible only for implementing the transmit side of the UART for this lab. As you
should have inferred from reading the ready/valid tutorial, the UART transmit and receive modules
use a ready/valid interface to communicate with other modules on the FPGA.
Both the UARTs receive and transmit modules will have their own separate set of ready/valid
interfaces connected appropriately to external modules.
3.1 Framing
On the ML505 board, the physical signaling aspects (such as voltage level) of the serial connection
are taken care of by off-FPGA devices. From the FPGA’s perspective, there are two signals,
FPGA_SERIAL_RX and FPGA_SERIAL_TX, which correspond to the receive-side and transmit-side
pins of the serial port. The FPGA’s job is to correctly frame characters going back and forth across
the serial connection. Figure 1 below shows a single character frame being transmitted and will be
extremely useful in understanding the protocol.
Figure 1: UART Frame Structure
2
In the idle state the serial line is held high. When the TX side is ready to send a character, it pulls
the line low. This is called the start bit. Because UART is an asynchronous protocol, all timing
within the frame is relative to when the start bit is first sent (or detected, on the receive side).
The frame is divided up in to 10 uniformly sized bits: the start bit, 8 data bits, and then the stop
bit. The width of a bit in cycles of the system clock is then naturally given by the system clock
frequency divided by the baudrate. The baudrate is the number of bits sent per second; in this lab
the baudrate will be 115200. Notice that both sides must agree on a baudrate for this scheme to
be feasible.
3.2 Transmitting
Let us first think about sending a character using this scheme. Once we have a character that we
want to send out, transmitting it is simply a matter of shifting each bit of the character, plus the
start and stop bits, out of a shift register on to the serial line.
Remember, the serial baudrate is much slower than the system clock, so we must wait SymbolEdgeT ime =
ClockF req
BaudRate cycles between changing the character we’re putting on the serial line. After we have
shifted all 10 bits out of the shift register, we are done unless we see another transmission immediately after.
3.3 Receiving
The receive side is a bit more complicated. Fortunately, we will provide the receiver module. Open
lab4/src/uart_receiver.v so you can see the explanation below implemented.
Like the transmit side, the receive side of the serial device is essentially just a shift register, but this
time we are shifting bits from the serial line into the shift register. However, care must be taken
into determining when to shift bits in. If we attempt to sample the serial signal directly on the
edge between two symbols, we are exceedingly likely to sample on the wrong side of the edge (or
worse, when the signal is transitioning) and get the wrong value for that bit. The correct solution
is to wait halfway into a cycle (until SampleTime on the diagram) before reading a bit in to the
shift register.
One other subtlety of the receive side is correctly implementing the ready/valid interface. Once
we have received a full character over the serial port, we want to hold the valid signal high until
the ready signal goes high, after which the valid signal will be driven low until we receive another
character.
This requires using an extra flip-flop (the has_byte reg in uart_receiver.v) that is set when the
last character is shifted in to the shift register and cleared when the ready signal is asserted. This
allows us to correctly implement the ready/valid handshake.
3
3.4 Putting It All Together
Although the receive side and transmit side of the UART you will be building are essentially
orthogonal, we are packaging them into one UART module to keep things tidy. If you look at
uart.v, you will see that this module is mostly straightforward instantiations of uart_receiver
and uart_transmitter, but there are also two iob registers that the serial lines are fed through.
What are these for? An iob is simply a register that attempts to pack itself into a special block
called an IOB, which is used to drive and sense from the IO pins. Using an iob helps ensure that
you will have a nice, clean, well-behaved off-chip signal to use as an input or output to your serial
modules.
The diagram below shows the entire setup:
Figure 2: High Level Diagram
3.5 Simulation
We have provided a simple testbench, called uart_testbench that will run some basic tests on
two instantiations of the UART module with their RX and TX signals crossed so that they can
talk to each other. There is also a .do file that will run the test. You should note that this test
bench reporting success is not by itself a good indication that your UART is working properly.
The testbench does not attempt to test back to back UART transmissions so you will have to add
that test in yourself. Due to the way x’s are treated by Modelsim if many signals in your design
are undefined the testbench may erroneously pass. Make sure to look at the waveform to see that
everything appears to be working properly and that you adequately purge your simulation of high
Z and undefined X signals.
If the testbench prints out # it means that it timed out; this indicates that the testbench
was stuck on a line, likely due to a condition that never became true. Inspect the waveform and
match it up to the testbench code to see where it hangs and why. You shouldn’t need to increase
any of the timeouts in the .do files.
4
3.6 Echo
Your UART will eventually be used to interact with your CPU from your workstation. Since you
don’t have a CPU yet, you need some other way to test that your UART works on the board.
We have provided this for you. The provided ml505top contains a very simple finite state machine
that does the following continuously:
• Pulls a received character from the uart_receiver using ready/valid
• If the received character is an ASCII letter (A-Z or a-z), its case is inverted (lower to upper
case or upper or lower case)
• If the received character isn’t an ASCII letter, it is unmodified
• The possibly modified character is sent to the uart_transmitter using ready/valid to be
sent over the serial line one bit at a time
Before programming your board, check with the provided echo_testbench.v testbench that everything works as it should in simulation. This testbench is heavily commented to help you understand
the communication between the 2 UARTs and the communication over the ready/valid interface.
The file often refers to the UART on the workstation as the off-chip UART and the UART on the
FPGA as the on-chip UART.
Once you have echo working in simulation, it is time to try it on the board. Synthesize your design
and impact the board with it just like you have done in previous labs. You may see up to 3 warnings
about rx_shift<0> being unconnected or unused; these are expected and can be safely ignored.
Now, make sure the USB serial cable is plugged in between the ML505 board and your workstation
and then run:
screen $SERIALTTY 115200
This tells screen, a highly versatile terminal emulator, to open up the serial device with a baud
rate of 115200. When you type a character into the terminal, it is sent to the FPGA over the
FPGA_SERIAL_RX line, encoded in ASCII. The state machine in ml505top may modify the character
you sent it and will then push a new character over the FPGA_SERIAL_TX line to your workstation.
When screen receives a character, it will display it in the terminal.
Now, if you have a properly working design, you should be able to tap a few characters into the
terminal and have them echoed to you (with inverted case if you type letters). Make sure that if
you type really fast that all characters still display properly. If you see some weird garbage symbols
then the data is getting corrupted and something is likely wrong. If you see this happening very
infrequently, don’t just hope that it won’t happen while the TA is doing the checkoff; take the time
now to figure out what is wrong. UART bugs are a common source of headaches for groups during
the first project checkpoint.
To close screen, type Ctrl-a then Shift-k and answer y to the confirmation prompt. If you don’t
close screen properly, other students won’t be able to access the serial port. If you try opening
screen and it terminates after a few seconds with an error saying ”Sorry, can’t find a PTY” or
5
”Device is busy”, execute the command killscreen which will kill all open screen sessions that
other students may have left open. Then run screen again.
Use screen -r to re-attach an improperly closed screen session. You can also reboot the computer
to clear all active screen sessions.
3.7 Checkoff
Show your TA that you can successfully type characters on the keyboard and have them echoed
back to display on your screen session.
6