====== UART Receiver ====== In this laboratory you will create an asynchronous serial receiver that will allow you to send characters from your computer to the NEXYS4 board. Your design will closely follow last week's serial transmitter. That is, you will have handshaking with the receiver (but the signals are called Receive and Received). And, the receiver has similar components - a state machine, a bit counter, and a timer. A number of the details are different but it will have a similar organization. ===== Learning Outcomes ===== * Implement an asynchronous receiver * Strengthen behavioral SystemVerilog skills ===== Preliminary ===== A class lecture was given discussing how the receiver should work. That and the textbook section on the receiver will form the basis for the lab. However, you will note that far less of the design is provided to you this week. In this lab we will operate the receiver at a baud rate of 19,200. Using a 100 MHz clock, how many clock cycles does it take to reach the middle of the bit period using this baud rate? (see Figure 28.15) ===== Exercises ===== ==== Exercise #1 - Asynchronous Receiver Module ==== Begin your laboratory assignment by creating a receiver module that has the following parameters and ports: ^ Module Name = rx ^^^^ ^ Port Name ^ Direction ^ Width ^ Function ^ | clk | Input | 1 | 100 MHz System Clock | | Reset | Input | 1 | The system reset signal | | Sin | Input | 1 | Receiver serial input signal | | Receive | Output | 1 | Indicates that the receiver now has a byte it is asking to hand off on the Dout pins | | Received | Input | 1 | Indicates that the other circuitry has accepted the received byte on the Dout pins. Receive and Received serve as Req and Ack from Figure 28.7. However, the requestor who raises Receive is your rx module and the acknowledger who raises the Received signal is the testbench or other outside agent. | | Dout | Output | 8 | 8-bit data received by the receiver which is then output on pins | | parityErr | Output | 1 | Indicates that there was a parity error on the last byte reception.| Next, complete the full design of the receiver. See the textbook for more information. You will need: * Baud timer * Bit counter * Shift register * Parity checker ===Baud Timer=== This is very similar to your timer from last time except it needs to be able to tell you when a whole bit time has passed as well as when a half bit time has passed. Both are needed at some point in your state machine's operation. ===Shift Register=== The purpose of this is to collect the serially received bits as they come in. It is recommended that you shift all 8 data bits plus the parity bit into the shift register. But, you will only output the 8 data bits on the Dout pins. ===Parity Checker=== Once you have shifted all 9 bits into the shift register, you should check that the parity bit is correct (odd parity). If this is not true, you should raise the parityErr signal. The parityErr signal can be a combinational logic signal which is constantly reflecting the contents of the shift register. It will thus transition as things are shifted into the shift register and will only be an accurate error signal once you have shifted in the 9th bit (the parity bit). That is OK - the circuit that checks this will only look at the parityErr signal when Receive == 1. You need to think carefully - given the order that bits arrive - do you want the register to shift right or shift left? The textbook explicitly states which bit arrives first. Given that, should you feed the bits in from the left of the shift register and right shift each time or the other way around? All you care about is that when you are done that you can assign the bits to Dout for output. ===Finite State Machine=== You get to design this yourself from scratch. However, we suggest you pattern it somewhat after the transmitter state machine. Note that you have to have your timer get you over into the middle of each bit period and so your timer may have additional output signals. And, your state machine will need to be designed to control when the shift register shifts so that you collect the 8 data bits and parity bits. Finally, your state machine will need to handshake using the Receive and Received signals at the end of each byte reception. You may safely assume that a new byte will not start to arrive on the Sin signal before the Receive/Received handshake has completed. You can simulate that way and that will surely be the case when you hook everything up in hardware. **Exercise 1 Pass-off:** Show a TA a state graph of your state machine. Show how each of the components listed above are implemented in your rx module.\\ \\ ==== Exercise #2 - Simulation ==== After creating your rx module create a simple TCL file and simulate your module to make sure that there are no major errors. Then simulate your module with the following testbench file: {{ :labs:tb_rx.sv |}} Provide a copy of the console output from the testbench simulation in your lab report Include your 'rx' SystemVerilog module in your report **Exercise 2 Pass-off:** Show a TA your tcl script and your testbench output.\\ \\ ==== Exercise #3 - Top-Level Circuit ==== After simulating your receiver module and verifying it operates, begin a new top-level module with the following ports: ^ Module Name = uart_top ^^^^ ^ Port Name ^ Direction ^ Width ^ Function ^ | clk | Input | 1 | 100 MHz System Clock | | sw | Input | 8 | Slide switches to specify character to send | | btnc | Input | 1 | Send character control signal | | btnd | Input | 1 | Reset signal | | rx_in | Input | 1 | Receive signal | | tx_out | Output | 1 | Transmit signal | | segment | Output | 8 | Cathode signals for seven segment display | | anode | Output | 8 | Anode signals for each of the eight digits | | rx_error | Output | 1 | RX transfer error | | tx_debug | Output | 1 | TX Debug signal | | rx_debug | Output | 1 | RX Debug signal | In this exercise you will instance both your tx and rx modules. Begin by instancing your tx module just like the previous lab and make the following connections to your tx module: * Connect the tx_out output of your tx module to your top-level tx_out output * Connect the tx_out output of your tx module to the top_level tx_debug output * Connect an unused signal to the 'Sent' signal of your tx module ('Sent' will not be used in this circuit) * Connect the 8 switches to the 'Din' input of your tx module * Connect the top-level clock to the clk input of your tx module * Drive the tx "Send" signal with the same circuit you used in the top-level of your previous lab (attach to btnc, use a synchronizer and debouncer). * Drive the tx "Reset" signal the same way (attach to btnd, use a synchronizer and debouncer). After instancing your tx circuit, instance your rx circuit and connect it to your rx module. The rx_error output port at the top level is the parityErr on your rx module and it should be attached to LED[0] on the board. What to do with the Receive and Received handshaking signals? There is nothing on the board that can acknowledge each byte received. So, in your top level design create a signal called rxHandshake and use it to connect the Receive pin with the Received pin on your rx module. Now, when your rx module says it has a byte read (Receive=1) that will go right back in as Received to complete the handshake. Instance your seven segment display controller and connect the inputs to your controller as follows: * Attach the 8 switches to the lower 8-bits of the data in of the seven-segment controller (bottom two digits) * Attach the 8-bit signal "rx_in" to bits 23-16 of the data going to the seven segment controller (digits 5 and 4) * Only display the bottom two digits and digits 5 and 4 of the seven segment display * Do not use any of the digit points * Attach the anode and segment signals of the controller to the top-level outputs of the top-level module The following diagram illustrates the interconnections of different modules. {{ :labs:UART_tx_rx.png |}} Include a copy of your top-level module in your laboratory report **Exercise 3 Pass-off:** Show a TA your top level module and explain how we will know when the rx module has received a byte.\\ \\ ==== Exercise #4 - Implementation ==== Before synthesizing your design, you will need to create an .xdc file that contains the pin locations of each port in your design. Most of the pins used in this design are the same as pins used in previous designs (buttons, switches, seven-segment display, etc.). However, you will be using a new FPGA pin to connect to the UART/USB transceiver and the debug port. The following example code demonstrates how these I/O pins can be attached to your top-level FPGA pins: set_property -dict { PACKAGE_PIN C4 IOSTANDARD LVCMOS33 } [get_ports { rx_in }]; #IO_L7P_T1_AD6P_35 Sch=uart_txd_in set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { tx_out }]; #IO_L11N_T1_SRCC_35 Sch=uart_rxd_out set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { tx_debug }]; #IO_L20N_T3_A19_15 Sch=ja[1] set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { rx_debug }]; #IO_L21N_T3_DQS_A18_15 Sch=ja[2] Also, add an entry in your .xdc file for the led[0] which signals a receiver error. After completing your .xdc file, proceed with the synthesis of your design. Provide a summary of your synthesis warnings. After successfully synthesizing your design, proceed with the implementation and bitstream generation of your design. Indicate the number of Look-up Tables (LUT) and Input/Output (I/O) pins for your design. **Exercise 4 Pass-off:** There is no pass-off for this exercise.\\ \\ ==== Exercise #5 - Download and Putty ==== Once the bitstream has been generated, download your bitstream to the FPGA and test both your transmitter and receiver. Follow the [[tutorials:putty|PuTTY tutorial to set it up.]] Once you have Putty setup properly, type characters on the computer keyboard while in the Putty window and check to see what HEX values show up on your NEXYS 4's seven segment display. Then, using switches and buttons to transmit characters to Putty and see if they appear on the screen. ===== Final Pass Off ===== To pass off this laboratory, demonstrate to the TA the following: * Pass-offs for Exercises 1, 2, and 3 * Your working top-level uart transmitter/receiver circuit How many hours did you work on the lab? Please provide any suggestions for improving this lab in the future. ===== Personal Exploration ===== Here are some ideas for personal exploration in this laboratory: * Experiment with different baud rates and see if you can communicate with the PC at a different baud rate. * Send a variety of interesting characters over the terminal and see how they respond. * Hook up the tx debug signal to the oscilliscope and view the transfer of an 8-bit character. Describe your personal exploration activities [[labs:ta:uart_rx|TA Notes and Feedback]] /* ---- ====== Lab 11 : UART Receiver ====== ===== Objective ===== * Design and implement a Universal Asynchronous Receiver which will be used to accept ASCII characters from your keyboard via PuTTY. ===== Explanation ===== This is the second part of a two-part series of labs involved in the construction of a Universal Asynchronous Receiver/Transmitter (UART). In this second part you will design, code, test, and implement the receiver module. If you need a refresher about the USB-UART, refer to Page 10 of the [[http://ecen220wiki.groups.et.byu.net/dokuwiki/lib/exe/fetch.php?media=devel:nexys4ddr_rm.pdf|Nexys 4 Reference Manual]]. ===== Pre-Lab ===== If needed, refer to the USB-UART section of the [[http://ecen220wiki.groups.et.byu.net/dokuwiki/lib/exe/fetch.php?media=devel:nexys4ddr_rm.pdf|Nexys 4 Reference Manual]] found on Page 10. Otherwise, proceed unencumbered. ===== Procedure ===== ==== Receiver Design ==== The Universal Asynchronous Receiver you will build is very similar to the design of the Universal Asynchronous Transmitter you completed in the last lab. The design architecture is effectively the same as the transmitter, but the state machine will need to modified in order to perform the actions the receiver requires for operation. These changes include: * The manner by which we leave the IDLE state. In the transmitter's state machine, the IDLE state was exited when triggered by a button driven signal. In the case of the receiver, we will exit the IDLE state when the receiver recognizes it will soon begin to acquire data (see next point). * The manner by which we sample data. As compared to the transmitter module, the receiver module constantly monitors the data input (rx) port. It will leave the IDLE state when it recognizes the start bit, a low value on the rx input. * The timing of the state machine. The transmitter required a timer which would cause each bit transmission state to last for a full bit period. The receiver requires not only this timer, but a half-bit timer as well. The receiver module needs both of these timers so it can sample data as close as possible to the middle of a half-bit period. The desired timing of the receiver module is shown in Figure 1. {{ :devel:uart_rx_timing_diagram.jpg?600 | Figure 1 - Universal Asynchronous Receiver Timing Diagram}} === Timing/Sampling Overview === The receiver recognizes data is being sent to it when the START bit is found on the data input port (rx). The value of rx becomes low, causing the state machine to transition from the IDLE to the START state. This transition will also act as a synchronization event (reset) for the full- and half- bit timers; to ensure you sample the data correctly. When entering the START state, the machine will expect a low value for a full-bit period. The machine will then wait for a half-bit period so it can sample at the middle of the first bit which is input. The machine will then sample the input each full-bit period thereafter, shifting each value into a register. Sampling will occur until the STOP bit has been sampled. === Design Considerations === Unlike the procedure for the transmitter lab, you will not be given a state machine or datapath example to complete this lab. You will need to create your own state machine and datapath to guide your design. Create an ASMD for your receiver module. Consider the following when designing your diagram: * The delay from the the beginning of rx_in (also referred to as rx) to the time the first sample is taken from rx_in should be as close as possible to 1.5 full-bit periods. After this period you should sample every full-bit period until all the data (and STOP bit) has been received. One way of doing this is having a timer with a full-bit-period and half-bit-period output signals, each signifying when the bit-timer has reached a certain status. * Create a state machine output, rx_busy, which is asserted when the receiver is not idle and waiting for a new byte. This signal will be used by higher-level objects which will query the status of the receiver module. * Create an output signal named data_strobe. This output will assert for a single clock cycle when a valid new byte has been received. A valid byte has been received when you sample a valid stop bit (i.e., you sample rx_in = ’1’ during the stop-bit time period). Do not assert data_strobe if you sample rx_in = ’0’ during the stop-bit time period (i.e., the received byte will be ignored). Wait until the rx_in returns to ‘1’ before returning to an idle state. * Some UART transmitters may power-up with its TX line set to ‘0’. After its initial power-up sequence is over, its TX line will be set to ‘1’ indicating no transfer. If your UART receiver is connected to such a UART transmitter, your receiver may think that the initial ‘0’ is a start bit and assume a character is being transmitted. You will need to design your state machine to ignore the case when the transmitter powers up with a default ‘0’ on the TX line. Consider these suggestions for ignoring an initial ‘0’: * Create an initial “power-up” state that will remain in the power-up state as long as RX = ‘0’. Once RX = ‘1’, proceed out of the power-up state into a regular “Idle” state. * To make sure your “power-up” state is the initial state of your state machine when the FPGA is configured, make sure the power-up state is the first state listed in your state encoding: ''type state_type is (power_up, idle, ...'' Begin your lab by creating an ASMD diagram of your receiver circuit. This ASMD diagram should include all of the states and all of the RTL statements necessary to implement a complete UART receiver. Provide sufficient detail in your ASMD diagram that another person could implement the system without assistance. After completing the ASMD diagram, create a conceptual diagram of all of the registers used in your UART receiver. This diagram should include all registers (except the state register) and a conceptual diagram of the next state logic for each of these registers. ===Receiver Design(rx.v)=== ^ Port Name ^ Purpose ^ ^ Inputs ^^ |clk|50 MHz clock| |rst|Asynchronous reset| |rx_in|The input serial signal(connected to the rx input from the serial port)| ^ Outputs ^^ |data_out[7:0]|The byte that was received. This is only valid when data_strobe is asserted| |data_strobe|Asserted high for one cycle when a byte has been received and data_out is valid| |rx_busy|Asserted when the receiver is not in the idle state. When zero, the circuit is waiting for a new byte| ^ Parameters ^ Purpose ^ |CLK_RATE|Indicates the frequency of the input clock. Set to 100000000| |BAUD_RATE|Baud rate of the transmitter. Set to 19200| Like the transmitter lab, use parameters to determine the period of each bit time. Supporting these parameters will allow you to use your receiver with different input clocks and to receive characters with a different baud rate. After implementing your state machine and datapath, perform some simple tests to verify that your circuit is operating as you expect. Remove any obvious bugs before proceeding to the next exercise. Once your transmitter compiles without errors and performs a few basic tests, proceed to the next exercise. ===Testbench=== Copy the contents of the testbench [[devel:receiver_test_bench|here]] and add the file to your project as you did in the transmitter lab (remember, the file type is VHDL). This testbench will test your receiver under a number of conditions and if your receiver conforms to the specifications described in this lab. This testbench will simulate the sending of bytes to your receiver and perform a number of checks to make sure you received the data correctly. Simulate your receiver until the "DONE" message is printed on the console. Continue to edit and debug your design until it passes all of the tests without any errors. ===Top-Level Receiver Design=== After your receiver has successfully passed the test cases of the testbench, create a new top-level design which implements your receiver module. You will also need to include your seven-segment display, which will display hexadecimal value of the two most recently received characters. Some design considerations you will need to make are as follows: == Synchronizers == The input to your receiver is an asynchronous signal. Were we to sample this signal, we might experience some issues when reading the data. For this reason, we need to take the asynchronous input and make it synchronous. We will do this devices called synchronizers. To synchronize, we will add two flip-flops (also called buffers) between the rx_in of the top-level and the rx input of your receiver module. You will use the output of the second flip-flop to drive the rx input of your receiver module. {{ :devel:uart_rx_top_rx_synchronizers.jpg?300 |}} == Seven-Segment Display Input == You will want to design the input to your seven-segment controller such that the byte most recently received will display on the two rightmost digits. When another byte is received, the value which was displayed on the two rightmost bits should be shifted to the two leftmost digits, and the new byte should display on the two rightmost digits. This pattern should continue as data is received. Data will not be loaded into these registers at all times, only when data_strobe is asserted. To drive the display, use two registers like shown below. Each register should be 8 bits wide, each providing the data which will drive the two left and two right digits. Add appropriate logic to load the new byte into the register when data_strobe is asserted. {{ :devel:uart_rx_top_sev_seg_regs.jpg?300 |}} Create a reset signal on one of the buttons for an asynchronous reset to your design. Simulate the top-level design carefully to make sure your display logic is working properly. After verifying that your top-level design works, create a UCF file for your top-level design and synthesize your design. === Download and Test === Once you have created a bitfile, test your receiver by opening a putty terminal on your desktop terminal and setup the terminal with the proper UART settings. Press a few keys on the putty terminal and verify that when a key is pressed the corresponding ASCII value is displayed on your seven segment display. ==== Personal Exploration ==== For your personal exploration, modify the top-level design to add some additional features. Ideas include: * Modify the top-level design to include both the transmitter and receiver. Verify that you can both transmit and receive data. * Modify your top-level design to include you VGA text display circuit. Display characters received from UART on the display. * Play with the baud rate to see if your receiver works at different rates. ==== Pass Off ==== Demonstrate to the TA a working circuit on your board. The TA will experiment with your circuit to see if it operates correctly under a number of circumstances (i.e. the TA will test the transmission of several different characters). */