You are here: HomeTutorialsTutorial 1 - A Serial Communication FPGA Debug ModuleTutorial 1: Part 5 - Verifying and Testing the FSDM UART Core

Tutorial 1: Part 5 - Verifying and Testing the FSDM UART Core

1.5.1 Introduction

100038Previously, in the first installment of the tutorials, a standalone UART core has been developed, which can transmit and receive data at a fixed rate of 115,200 Baud. This rate has been considered to be general enough for the core to be useful experimentally. This indeed has been the case and the UART IP core has been demonstrated to  communicate between the USB port of a PC and a DE0-Nano Development Kit using a USB to Serial UART converter (CP2102). Before continuing development, with the implementation of the transmitter path of the protocol wrapper, we shall look at verifying and testing the UART core in this part.

To begin the verification process a standard HDL simulation tool will be used to verify the functionality of the UART IP core, which for the purposes of this tutorial will be Mentor's Modelsim. The de facto standard, IOHO, when it comes to simulating HDL code. The simulation test will only involve a test of the pre-synthesis, or RTL VHDL code. It will not involve  performing a post-synthesis simulation of the gate-level VHDL code, neither will a post-place and route simulation test, of the routed output produced by Quartus II, be performed.

Once it has been demonstrated that the simulation tests, or test in this case, are successful, we shall proceed to demonstrating the UART core operating, in loop-back mode, on actual hardware. For this purpose the hardware setup will consist of the DE0-Nano Development kit  connected to the 2 x 13 Way Mixed Signal Dilettante Board. The Dilettante board will be populated with a  RS232RL breakout board (see FTDI RS232RL), which performs the USB to serial conversion. The test hardware setup can be seen, in Figure 1, below.

To ease the accumulation and analysis of any data obtained we will need to write test software on a PC. Hence, to this end, we will begin to look at multi-threaded software using pthreads in the C programming language FTDI Chip's  ftd2xx libraries on a LINUX platform, ChrUbuntu LINUX to be exact, will be used to interface between our application software and the FT232RL USB to serial converter. Well if that doesn't set the scene nothing will, so lets crack on.  

100057

Figure 1: Test Hardware: (1) FT232RL Serial to USB Converter breakout board. (2) DE0 Nano Development Kit. (3) 2 x 13 Way Mixed Signal Dilettante Board. (4) ChrUbuntu LINUX PC with 16GB of memory. (5) UART IP Core, configured in loop-back mode, downloaded onto the Cyclone IV FPGA.

1.5.2 The Simulation Testbench

Testbenches typically provide stimulus into a Unit Under Test (UUT), which is used to verify the units output. In this exercise the UUT is our UART IP Core shown, in the Figure 2, below. Note that the UART RX and UART TX sub-cores, which form the heart of the UUT and developed in part 1 of the series, have also been used to provide the serialised input and deserialised output, to and from, the UART core. Hence, the UART core is effectively being tested with a crossed over version of itself. Although this is a less than ideal verification setup, as it does not provide an independent test  procedure, it is not untypical of the technique used in resource stretched setups.

100041

Figure 2: The UART IP core  is connected in loopback mode for testing. Stimulus data is injected into the core, which is then verified with the core's looped-back output.

As the core matures more robust testbenches are expected to  be developed, for now this rudimentary test should do.  At the heart of the testbench are read (READ_REG_PROC) and write (WRITE_REG_PROC) procedures that can be used to generate packets of data. Currently, the packets of data resemble FSDM read and write register messages only. As the functionality of the FPGA Serial Debug Monitor grows so too will the number of test procedures and consequently the number of tests that will be carried out.

Hence, for now, in a simple UART loop-back configuration a data generator with minimal packet formatting should suffice as a stimulus generator. Also, in the future the individual UART RX and UART TX cores should be replaced with independently written serial receiver and transmitter data generators. 

To test the RTL VHDL code, of the UART, a Modelsim project has been created and the UART's VHDL files and the VHDL testbench file have been imported into it. Then, in Modelsim, all the associated VHDL entities and packages have been compiled, after which the testbench has been loaded into the  simulator.

Modelsim's wave output shown, in Figure 3, below demonstrates a control register write message and a status register read message being executed by the test procedure when the UART core has been placed in loop-back mode. The figure shows the received message, coloured in purple, injected into the core and the expected corresponding and identical loop back message, in cyan, being transmitted out of the core. It also shows, correctly, that on each assertion of the rdy flag 8-bits of data have been received by the core. 

 100032

 Figure 3: Shows the waveform of the UART core when performing a testbench simulation.

If we had performed a post-place and route simulation it would have been necessary to import the relevant output files generated by Quartus II during the compilation stage of the project. These are, typically, the .vho and .sdf files. The .vho file is the post-place and route simulator compatible output, while the .sdf contains the Standard Delay Format (SDF) timing data. The SDF data, typically, consists of the minimum, typical and maximum gate-level timing data used by the simulator.

1.5.3  The Test Data

Ideally, we should aim to use the same test data generated for use in the simulation as in the real-time hardware tests. This allows for a direct comparison between the simulation results (Figure 3) and real-time results (Figure 4). In our work we have found that having two sets of identical results can prove to be extremely useful, when one is at one's wits end, trying do debug an IP core.  The test data, used in the simulation, described above, essentially consists of bytes of data that resemble a read register message, <op>,<reg num> and a write register message <op>, <reg num>, <32-bit data>.

However, as can be seen, in Figure 4, below our real-time tests  consisted of a different dataset set, which was generated by a test program  available  on the website of FTDI, the USB-to Serial Converter manufacturer. We used this program to test our code, see Listing 1 below, as initially our test software did not work as expected. We think that this is due to the way in which multiple RS232RL devices are discovered and opened. 

100040

Figure 4: Real-time Test Results.

In this program, called simple, probably due to the uncomplicated nature of its test algorithm, 16 bytes of data are injected into the UART core, which is expected to send the same data back. On each successive transition of a byte, the byte's value is incremented by 1.

1.5.4 Hardware Test

As mentioned previously the test hardware consists of a prototype of our new 2 x 13 Way Mixed Signal Dilettante Board fitted with a RS232RL Breakout Board as  can be seen in the Figure 5 below. In this picture the reworked, red and green wires, can be seen. This has been done in order to connect the RS232RL TXD output to RX_I  and its RXD input to TX_O. This connection is totally the opposite case when connecting the DE0 Nano to Silicon Lab's CP2102 device as noted in Part 1 of the tutorials. 

Ordinarily, we should have been able to reconfigure the FPGA's pin, in order to swap the connections of the RX and TX signals. However, on this board, the RX signal is connected to a FPGA dedicated input pin and hence we could not simply swap pin configurations. In case your wondering why, it is because the 2 x 13 way header on the DE0 Nano only has a limited number of bi-directional I/O , which are connected elsewhere on the board.

 100042

Figure 5: The 2 x 13 Way Mixed Signal Dilettante Board fitted with a RS232RL Breakout Board. To connect the RS232RL USB to Serial Converter it is necessary to connect the TXD pin to the UART IP core's RX_I input and the RX pin to the TX_O.

A list of the FPGA and RX232RL pins along with the signal names found on the 2 x 13 way header can be seen,in Table 1, below 

Signal Nane FPGA Pin 2x 13 Way Header RS232RL Description
nRST J15 N.C N.C Active low debounced input.
CLK R8 N.C N.C 50MHz system clock.
RX B16 GPIO_2[1] TXD UART IP receiver input.
TX M16 GPIO_2_IN[2] RXD UART IP transmitter output.
N.C - Not connected.    

1.5.5 Signal Tap II Logic Analyser

Signal Tap II is a RTL debugger, or FPGA embedded logic analyser tool, integrated into Quartus II that provides an FPGA designer with a storage scope. It is used to debug an FPGA core in real-time and should be considered to be an FPGA designers best friend. Signals of interest are firstly captured in the FPGA on a set trigger value. Then the captured values are  acquired from the FPGA, by typically, using the FPGA's JTAG connector port or in the case of the DE0-Nano the built-in USB Blaster. A data output window, as seen in Figure 6 below, is used to display the results of the acquired data. 

 100043

Figure 6: Signal Tap II: Quartus' RTL Debugger. Probably a man's best friend in today's world of multi-million gate FPGAs.

In the captured output shown, in Figure 6 above, the internal scope has been triggered on the UART's ready signal, rx_rdy, that is when the Serial-in-Parallel-Out module on the UART module's receiver datapath has completed the parallellisation of 8-bits of incoming data into a byte. On the first three assertions of the en_I signal, which corresponds with the rx_rdy signal, the data values captured are 0x00, 0x01 and 0x02 as expected.

As FPGA's have become more complicated using a FPGA logic analyser like Signal Tap 2 or Synplify's Identify is essential when trying to locate the source of errors, especially when commissioning new hardware, as we found out. (You can read Ben's Blog article when commissioning the RS232RL breakout board here).

1.5.6 Test Software

The listing 1 below is the example program simple.c provided by FTDI, which has been used to test the UART IP Core in loopback mode. Without using the RS232RL device listing algorithm, provided in this program, we could not correctly locate the RS232RL device on the breakout board. The part of the algorithm used to detect devices that use the ftd2xx.lib, the D2XXdirect drivers, will be incorporated into the next version of our software.

 /*gcc -o simple main.c -L. -lftd2xx -Wl,-rpath /usr/local/lib
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "../ftd2xx.h"

#define BUF_SIZE 0x10

#define MAX_DEVICES		5



static void dumpBuffer(unsigned char *buffer, int elements)
{
	int j;

	printf(" [");
	for (j = 0; j < elements; j++)
	{
		if (j > 0)
			printf(", ");
		printf("0x%02X", (unsigned int)buffer[j]);
	}
	printf("]\n");
}



int main()
{
	unsigned char 	cBufWrite[BUF_SIZE];
	unsigned char * pcBufRead = NULL;
	char * 	pcBufLD[MAX_DEVICES + 1];
	char 	cBufLD[MAX_DEVICES][64];
	DWORD	dwRxSize = 0;
	DWORD 	dwBytesWritten, dwBytesRead;
	FT_STATUS	ftStatus;
	FT_HANDLE	ftHandle[MAX_DEVICES];
	int	iNumDevs = 0;
	int	i, j;
	int	iDevicesOpen;	
	
	for(i = 0; i < MAX_DEVICES; i++) {
		pcBufLD[i] = cBufLD[i];
	}
	pcBufLD[MAX_DEVICES] = NULL;
	
	ftStatus = FT_ListDevices(pcBufLD, &iNumDevs, FT_LIST_ALL | FT_OPEN_BY_SERIAL_NUMBER);
	
	if(ftStatus != FT_OK) {
		printf("Error: FT_ListDevices(%d)\n", (int)ftStatus);
		return 1;
	}

	for(i = 0; ( (i <MAX_DEVICES) && (i < iNumDevs) ); i++) {
		printf("Device %d Serial Number - %s\n", i, cBufLD[i]);
	}

	for(j = 0; j < BUF_SIZE; j++) {
		cBufWrite[j] = j;
	}
	
	for(i = 0; ( (i <MAX_DEVICES) && (i < iNumDevs) ) ; i++) {
		/* Setup */
		if((ftStatus = FT_OpenEx(cBufLD[i], FT_OPEN_BY_SERIAL_NUMBER, &ftHandle[i])) != FT_OK){
			/* 
				This can fail if the ftdi_sio driver is loaded
		 		use lsmod to check this and rmmod ftdi_sio to remove
				also rmmod usbserial
		 	*/
			printf("Error FT_OpenEx(%d), device %d\n", (int)ftStatus, i);
			printf("Use lsmod to check if ftdi_sio (and usbserial) are present.\n");
			printf("If so, unload them using rmmod, as they conflict with ftd2xx.\n");
			return 1;
		}
	
		printf("Opened device %s\n", cBufLD[i]);

		iDevicesOpen++;
		if((ftStatus = FT_SetBaudRate(ftHandle[i], 115200)) != FT_OK) {
			printf("Error FT_SetBaudRate(%d), cBufLD[i] = %s\n", (int)ftStatus, cBufLD[i]);
			break;
		}

		printf("Calling FT_Write with this write-buffer:\n");
		dumpBuffer(cBufWrite, BUF_SIZE);
		
		/* Write */
		ftStatus = FT_Write(ftHandle[i], cBufWrite, BUF_SIZE, &dwBytesWritten);
		if (ftStatus != FT_OK) {
			printf("Error FT_Write(%d)\n", (int)ftStatus);
			break;
		}
		if (dwBytesWritten != (DWORD)BUF_SIZE) {
			printf("FT_Write only wrote %d (of %d) bytes\n", 
			       (int)dwBytesWritten, 
			       BUF_SIZE);
			break;
		}
		sleep(1);
		
		/* Read */
		dwRxSize = 0;			
		while ((dwRxSize < BUF_SIZE) && (ftStatus == FT_OK)) {
			ftStatus = FT_GetQueueStatus(ftHandle[i], &dwRxSize);
		}
		if(ftStatus == FT_OK) {
			pcBufRead = realloc(pcBufRead, dwRxSize);
			memset(pcBufRead, 0xFF, dwRxSize);
			printf("Calling FT_Read with this read-buffer:\n");
			dumpBuffer(pcBufRead, dwRxSize);
			ftStatus = FT_Read(ftHandle[i], pcBufRead, dwRxSize, &dwBytesRead);
			if (ftStatus != FT_OK) {
				printf("Error FT_Read(%d)\n", (int)ftStatus);
				break;
			}
			if (dwBytesRead != dwRxSize) {
				printf("FT_Read only read %d (of %d) bytes\n",
				       (int)dwBytesRead,
				       (int)dwRxSize);
				break;
			}
			printf("FT_Read read %d bytes.  Read-buffer is now:\n",
			       (int)dwBytesRead);
			dumpBuffer(pcBufRead, (int)dwBytesRead);
			if (0 != memcmp(cBufWrite, pcBufRead, BUF_SIZE)) {
				printf("Error: read-buffer does not match write-buffer.\n");
				break;
			}
			printf("%s test passed.\n", cBufLD[i]);
		}
		else {
			printf("Error FT_GetQueueStatus(%d)\n", (int)ftStatus);	
		}

	}

	iDevicesOpen = i;
	/* Cleanup */
	for(i = 0; i < iDevicesOpen; i++) {
		FT_Close(ftHandle[i]);
		printf("Closed device %s\n", cBufLD[i]);
	}

	if(pcBufRead)
		free(pcBufRead);
	return 0;
}

[Listing: simple.c - made available  by FTDI Chip, as an example, as part of their f2dxx library.]

1.5.7 Conclusion

This part of the tutorial has been used to demonstrate the techniques that can be used to verify an IP Core, which in this case has been the UART in loop-back mode. On though only basic verification tests have been performed using simulation and real-time data comparison techniques the principles demonstrated here are not likely to change beyond developing into more complicated data stimulus generation, data analysis and regression testing.

In the next part of the series we have a choice of developing the protocol wrapper TX module or provide a more robust software  test environment. The protocol wrapper TX module should interface to the protocol wrapper RX module , which means that we should be able to connect the two to perform another loop-back test. However, to perform the loop-back test comprehensively, we should have the software in place first.

1.5.8 References

Standard Delay Format Specification, Open Verilog International, Ver 3.0, 1995

Go to comments start