- Created on Tuesday, 10 April 2012 18:11
- Last Updated on Tuesday, 18 June 2013 09:49
- Written by Ben Popoola
In the last part of the tutorial we managed to establish a beachhead into the design by demonstrating a UART loop-back test. Although our test procedure was rudimentary, it allowed us to pass a very significant milestone. We were able to prove the connectivity between the PC, the UART to USB serial converter module and the DE0 Nano development kit. Also, two important aims of the project have been achieved.
Firstly, the loop-back test has allowed us to prove that the UART core appears to work as expected. Secondly, we have been able to setup a Quartus II project for our design. Although setting us the Quartus project may seem trivial, compared to the overall task, it is actually an important step. By doing so we have been able to allocate the correct FPGA pins for our design and setup the project's timing constraints. Proving continuity, from the PC to the FPGA, means that there are no more external interfaces and component boundaries to cross, with their inherent timing uncertainties.
The source code (GPL), for this and other tutorials, will be available as soon as I have time to install a download manager. Visit the Bulletin section for announcements and updates - B.P .
Hence, all that is required now, to complete this design tutorial, is writing logic internal to the FPGA. Any mistakes from this point on will be entirely our own. We will be unable to blame shoddy PCB workmanship, bad soldering joints or an incomplete Operating System (OS). For those of us confident in our digital design, at this stage, we might be prepared to predict the inevitable, that it is only a matter of time before the whole design is completed. It could be the time to begin browsing, online stores, for ankle-length robes and sandals. However, there is still quite a lot of work to do, so lets not get ahead of ourselves. Anyway, given the weather at the moment it might be more appropriate to search for raincoats and wellies! [wellies = rain boots - B.P].
In this part of the tutorial we will implement the protocol wrapper core. Also, we will pay further consideration to the software application on the PC and attempt to use it to perform regression testing of the hardware implemented so far. The design hierarchy of the UART and the protocol wrapper can be seen in the figure below.
Figure 1.2.1: The design hierarchy of the communication protocol showing the relationship between the UART and protocol wrapper cores.
1.2.2 The Protocol Wrapper Requirements
As before, like in the implementation of the UART, the protocol wrapper is broken down into two separate modules, that are architected, implemented and simulated independently. The two modules are the protocol wrapper TX core and the protocol wrapper RX core. Outgoing messages are prefixed with an opcode by the protocol wrapper TX core. Conversely, the protocol wrapper RX core is used to strip the opcode from incoming messages and direct the payload of the packet to its destination register. The message types expected by the protocol wrapper can be seen, in Figure 1.2.2, below.
Figure 1.2.2: The messages currently expected are write register, read register and user defined instructions.
The protocol wrapper RX core is considered presently. The core examines the first byte, the opcode, of every incoming message, received by the UART. It compares the opcode to the three expected opcodes, which are 0x01, the write register opcode (opcode_write), 0x03, the read register opcode (opcode_read) and the user defined opcode 0x05 (opcocde_user). If the incoming opcode is matched a controller, a Finite State Machine (FSM), coordinates the activity of receiving the rest of the message and notifying the receiving process. If a match to the received opcode does not occur the FSM assertes an error flag.
The error flag is is used to generate an unknown opcode error. In the current implementation the state machine returns to the IDLE state, after receiving an unknown opcode, and the next incoming byte is treated as an opocde. Hence, all the bytes of an unknown message type will, typically, generate an error. A highly-level state machine diagram can be seen, in Figure 1.2.3, below. The state machine also has the responsibility of insuring that the correct number of bytes are received for each message.
Figure 1.2.3: The state machine diagram of the protocol wrapper RX core.
220.127.116.11 The Protocol Wrapper RX Implementation
When the ready signal is asserted, and the controller is in the IDLE state, the rxdata is registered as the opcode and the state machine transitions to the OPCODE state. The registered opcocde is compared to the three known opcodes, opcode_rd, opcode_wr and opcodce_user. If the opcode is matched to the register read or write opcodes the state machine transitions to the state, REG_NUM, it is in this state that the destination register number, of the message, is retrieved. In this state the multiplexer, that determines the additional number of bytes to read, is set.
Figure 1.2.4: The algorithmic diagram of the protocl wrapper RX core.
The state machine transitions to the number of bytes state, NUM_BYTES, when the user defined message type is matched. If no opcode is matched, as stated previously, the state machine enters the ERROR state. In the num_bytes state the source of the multiplexer is set to the number of incoming bytes to read in a user defined message. The output of the multiplexer is loaded into a down counter, that counts in the number of incoming bytes. As bytes are received the state machine, which at this stage is in the READ, WRITE or USER states, asserts the appropriate enable flag. Each enable flag is ANDed with the ready flag to notify the downstream process that data is available.
18.104.22.168 Protocol Wrapper RX VHDL Simulation Results
To simulate the Protocol wrapper RX core the outputs of the UART receiver are connected to the inputs of the core. Then, test data, simulating the different types of opcdes, are injected into the UART. The setup of the UART and the Protocol Wrapper RX core can be seen, in Figure 1.2.5. below.
Figure 1.2.5: The protocol wrapper core's inputs consist of the UART RX core's outputs.
Figure 1.2.6: The result of simulating the protocol wrapper RX core, in Modelsim, can be seen in this figure. A write register message type consisting of the bytes 0x01, 0x06, 0xDE, 0xAD, 0xFE and 0xEF has been injected, serially, into the UART. The output of the UART receiver, the rx_data and ready signals, are used to excite the core under test. Here, it can be seen that the opcode, 0x01, is recognised and registered as the write register opcode. Secondly, the number of the destination register to write to, 0x06, has also been correctly captured. Finally, the 32-bit value, 0xDEADBEEF is output a byte at a time when the write register enable, wr_reg_en, signal is asserted.
Figure 1.2.7: In this example, after the write message type, in figure 1.2.6 above, is received, a read message type is received. The read register opcode, 0x03, is proceeded by the register number to read from 0x02. The read register enable flag is correctly asserted when this message is received.
Figure 1.2.8: A user defined message type is demonstrated in this simulation. A user defined opcode, 0x05, is received containing eight bytes, 0x08. The user register enable flag is asserted when each one of the eight bytes is received.
Before we do anything else, it could be a good idea to recap and reflect upon what has been achieved so far. The output from the UART receiver has been fed into the Protocol Wrapper RX. When known serial messages have been injected into the UART the simulation results have been very encouraging. When the overall architecture is viewed, as can be seen in Figure 1.2.9, the design looks quite fascinating..
Figure 1.2.9: The top-level architecture of the DE0 Nano Serial Protocol.
The original goals of this series were to complete the protocol wrapper and implement some kind of rudimentary software communication with the DE0 Nano development kit. However, now that I have mapped out the top-level architecture I am quite intrigued about how the registers will interact with the data received from the protocol wrapper RX module. Also, there does not appear to be a natural loopback path from the protocol wrapper RX to the protocol wrapper TX module. Hence, we may be better off not implement the wrapper TX module until we have data to process through it.
So the work of the next part of the tutorial series will investigate implementing the statistic engine, as well as the control, status, error and user defined registers.