This manual was originally written in the Year 2014 by the Lecturer Holguer A. Becerra for the FPGA course of UPB 31289, and now republished and revised for FPGAlover by the same author.


Quartus Project:

Pre-Compiled Binaries(See QSF for Pin Connections):

LVDS Pinout of DE0-NANO(Download):


LVDS GPIOs on DE0-NANO      
GPIO_1_[1] PIN_T15 N 4 4 LVDS_E_3R - 320 640
GPIO_1_[2] PIN_T14 P 5 4 LVDS_E_3R - 320 640
GPIO_1_[3] PIN_T13 N 6 4 LVDS_E_3R - 320 640
GPIO_1_[4] PIN_R13 P 7 4 LVDS_E_3R - 320 640
GPIO_1_[5] PIN_T12 N 8 4 LVDS_E_3R - 320 640
GPIO_1_[6] PIN_R12 P 9 4 LVDS_E_3R - 320 640
GPIO_1_[7] PIN_T11 N 10 4 LVDS_E_3R - 320 640
GPIO_1_[9] PIN_R11 P 14 4 LVDS_E_3R - 320 640
GPIO_1_[16] PIN_L16 N 21 5 TRUE LVDS/LVDS_E_3R 420/- 420/320 840/640
GPIO_1_[19] PIN_L15 P 24 5 TRUE LVDS/LVDS_E_3R 420/- 420/320 840/640
GPIO_1_[17] PIN_K16 N 22 5 TRUE LVDS/LVDS_E_3R 420/- 420/320 840/640
GPIO_1_[31] PIN_K15 P 38 5 TRUE LVDS/LVDS_E_3R 420/- 420/320 840/640
GPIO_1_[18] PIN_R16 P 23 5 TRUE LVDS/LVDS_E_3R 420/- 420/320 840/640
GPIO_1_[21] PIN_P16 N 26 5 TRUE LVDS/LVDS_E_3R 420/- 420/320 840/640
GPIO_1_[22] PIN_R14 N 27 4 LVDS_E_3R - 320 640
GPIO_1_[25] PIN_P14 P 32 4 LVDS_E_3R - 320 640
GPIO_1_[23] PIN_N16 N 28 5 TRUE LVDS/LVDS_E_3R 420/- 420/320 840/640
GPIO_1_[24] PIN_N15 P 31 5 TRUE LVDS/LVDS_E_3R 420/- 420/320 840/640
GPIO_0_[0] PIN_D3 P 2 8 LVDS_E_3R - 320 640
GPIO_0_[1] PIN_C3 N 4 8 LVDS_E_3R - 320 640
GPIO_0_[2] PIN_A2 N 5 8 LVDS_E_3R - 320 640
GPIO_0_[3] PIN_A3 P 6 8 LVDS_E_3R - 320 640
GPIO_0_[5] PIN_B4 P 8 8 LVDS_E_3R - 320 640
GPIO_0_[6] PIN_A4 N 9 8 LVDS_E_3R - 320 640
GPIO_0_[7] PIN_B5 P 10 8 LVDS_E_3R - 320 640
GPIO_0_[8] PIN_A5 N 13 8 LVDS_E_3R - 320 640
GPIO_0_[10] PIN_B6 P 15 8 LVDS_E_3R - 320 640
GPIO_0_[11] PIN_A6 N 16 8 LVDS_E_3R - 320 640
GPIO_0_[12] PIN_B7 P 17 8 LVDS_E_3R - 320 640
GPIO_0_[14] PIN_A7 N 19 8 LVDS_E_3R - 320 640
GPIO_0_[20] PIN_E8 N 25 8 LVDS_E_3R - 320 640
GPIO_0_[21] PIN_F8 P 26 8 LVDS_E_3R - 320 640
GPIO_0_[24] PIN_C9 N 31 7 LVDS_E_3R - 320 640
GPIO_0_[25] PIN_D9 P 32 7 LVDS_E_3R - 320 640
GPIO_0_[30] PIN_A12 N 37 7 LVDS_E_3R - 320 640
GPIO_0_[33] PIN_B12 P 40 7 LVDS_E_3R - 320 640
GPIO_0_[31] PIN_D11 N 38 7 LVDS_E_3R - 320 640
GPIO_0_[32] PIN_D12 P 39 7 LVDS_E_3R - 320 640
GPIO_2_[2] PIN_C14 N 7 7 LVDS_E_3R - 320 640
GPIO_2_[7] PIN_D14 P 12 7 LVDS_E_3R - 320 640
GPIO_2_[3] PIN_C16 N 8 6 TRUE LVDS/LVDS_E_3R 420/- 420/320 840/640
GPIO_2_[4] PIN_C15 P 9 6 TRUE LVDS/LVDS_E_3R 420/- 420/320 840/640
GPIO_2_[8] PIN_F15 P 13 6 TRUE LVDS/LVDS_E_3R 420/- 420/320 840/640
GPIO_2_[9] PIN_F16 N 14 6 TRUE LVDS/LVDS_E_3R 420/- 420/320 840/640
GPIO_2_[11] PIN_G16 N 16 6 TRUE LVDS/LVDS_E_3R 420/- 420/320 840/640
GPIO_2_[12] PIN_G15 P 17 6 TRUE LVDS/LVDS_E_3R 420/- 420/320 840/640




Instructions (Read explanation before you proceed)

1. Obtain an HDMI cable and cut one end of it (These cut cable ends will be connected to the LVDS to TMDS translator).

2. Download the template and review where the LVDS channels are assigned(See .QSF) so that you can connect them to the LVDS to TMDS translator.

3. Once you have set up the external scheme for the FPGA, generate the .sof file, connect the HDMI cable to the display, and program the FPGA.

4. What appears on the screen? What resolution and frequency is it displaying? (You should see what is on the video results)

5. On line 46 of the template, modify the parameters, regenerate the .sof file, and verify each of the resolutions.


Relevant Documents 

  1. LVDS Owner’s Manual
  2. Video Connectivity Using TMDS I/O in Spartan-3A FPGAs
  3. Implementing a TMDS Video Interface in the Spartan-6 FPGA
  4. Double Data Rate I/O (ALTDDIO_IN, ALTDDIO_OUT, and ALTDDIO_BIDIR) Megafunctions
  5. KYANITE Schematic
  7. Support HDMI 1.3 12-Bit Deep Color With the TMDS341A



In this practice, we will understand HDMI (High Definition Multimedia Interface) video interface built for the DE0-NANO. To do this, we must understand how TMDS (Transition Minimized Differential Signaling) transmission works and develop a Verilog HDL transmission module capable of controlling this type of video interface using the DE0-NANO (Cyclone IV).

TMDS, or Transition Minimized Differential Signaling, shares similarities with LVDS (Low Voltage Differential Signaling). Both standards involve differential signaling for the input and output of HDMI connectors. However, they differ in terms of voltage parameters and operating ranges, including VIH (High-level input voltage), VIL (Low-level input voltage), VOH (High-level output voltage), and VOL (Low-level output voltage). It's important to note that TMDS is more closely related to Current Mode Logic (CML).", as seen in the following figure.


As shown in the figure, LVDS varies with voltage ranges between 1 and 1.4 V, with a swing of +-350mV and maximum transmission speeds of up to 3.125 Gbps, while CML transmission supports speeds of up to 10 Gbps with operating voltages ranging between 2.7V and 3.4 V and a swing of +-800mV. The following table illustrates the differences between LVDS and CML in terms of their configuration for reception and transmission, information you can read in the "LVDS Owner's Manual" by Texas Instruments.


Similar to CML, TMDS transmission has 50 Ohm pull-up resistors in its receivers and transmitters. Its input and output voltage parameters are also similar, as shown in the table below, which displays the operating ranges of TMDS and the conceptual scheme.


Why is it important to understand TMDS and its differences compared to LVDS?

Altera's Cyclone IV FPGAs do not yet have standards for handling TMDS-type signals. However, this doesn't mean that you can't design an HDMI transmission system. In this case, the Cyclone IV FPGA has LVDS differential channels that can be adapted to TMDS with either AC or DC coupling, as explained in the manual "Interfacing LVDS with other differential I/O types."

What does an HDMI transmitter look like?

An HDMI TX consists of 4 TMDS channels:

Channel 0: It is responsible for transmitting the blue video component and the VSYNC and HSYNC synchronization pulses, similar to what we saw in the VGA practice.

Channel 1: It is responsible for transmitting the green video component and some control commands and encoded audio.

Channel 2: It is responsible for transmitting the red video component and some control commands and encoded audio.

Clock channel: It is responsible for sending the base clock, which VSYNC and HSYNC rely on.

Note: All channels are encoded using the TMDS algorithm, which converts 8-bit video signals per color component into 10-bit encoded signals. The ninth bit is produced through something called "Transition Minimizing," and the tenth bit is produced to maintain an appropriate DC balance in relation to the number of zeros and ones generated after adding the ninth bit.

After the encoding stage of each channel, data serialization follows, where 10 bits must be transmitted per channel. These 10 bits can represent a video pixel, header, or audio sent through the TMDS channels, as shown in the following figure.

HDMI is composed of three TMDS operating modes:

  1. Video Data Period: When visible video is transmitted.
  2. Data Island Period: When video is not visible and is used to transmit audio and auxiliary data.
  3. Control Period: During this period, the necessary headers for transmitting audio and video are sent.


The TMDS clock signal is the pixel_clock signal generated in the original video synchronizer. Each of the 10 bits must be serialized within the period of this signal. This means that the serialization stage must operate with a clock 10 times faster than the pixel_clock.

For example:

  • To send a 800x600@60Hz SVGA video signal, assuming the pixel_clock is 40MHz, a clock of 400MHz would be needed to serialize the data properly.
  • To send a 1280x720@60Hz 720p video signal, assuming the pixel_clock is 74.25MHz, a clock of 742.5MHz would be required to serialize the data.

Note: The Cyclone IV in the DE0-NANO can generate signals up to 475MHz with its internal PLLs. However, this doesn't mean that you can't create an HDTV video interface for 720p or 1080i. There are other techniques, such as using DDIOs to generate double data rates, to achieve data transmission frequencies of up to 840Mbps using the Cyclone IV's LVDS channels.

In the following image designed by Xilinx Corp (modern FPGAs from this brand are compatible with TMDS standards and don't require coupling), you can observe an HDMI transmitter more closely. In the blue box, you can see the encoding stage, in the red box, the data synchronization stage, in the green box, the signal stage based on the original video clock signal, in the magenta box, the data serialization stage, and in the cyan box, the TMDS differential channels.

Just like when building the VGA synchronizer, the first thing we need to know is the HDMI connector, where:

  • Pins 1 and 3 are the channel 2 signals in TMDS.
  • Pins 7 and 9 are the channel 0 signals in TMDS.
  • Pins 4 and 6 are the channel 1 signals in TMDS.
  • Pins 10 and 12 are the clock channel signals in TMDS.
  • Pin 13 is the CEC (Consumer Electronics Control) used for sending control commands between devices.
  • Pins 15 and 16 are dedicated to DDC (Display Data Channel), used for EDID (Extended Display Identification Channel) communications that use the i2C protocol for information exchange between peripherals.
  • Pin 18 is an output that supplies low current at 5V.
  • Pin 19 is an input for detecting HDMI cable connection or disconnection.

In the following image, you can observe various boxes. The main box contains the description of the hardware that the Cyclone IV in the DE0-NANO will use for HDMI TX. External to the FPGA, there is additional hardware required to translate LVDS to TMDS, necessary to make LVDS mode compatible with HDMI's native TMDS.


The design within the Cyclone IV(DE0-NANO) includes:

  • Video Sync: Responsible for generating signals relative to video activation signals with their respective timing.
  • PLL: Responsible for generating the clock signal, maintaining phase, one controlling the video synchronizer, and another multiplying the reference signal of the video synchronizer PCLK (Pixel Clock Reference) by x5. All clock signals go to the FPGA's global clocks.
  • TMDS encoder: Encodes RGB, VSYNC, HSYNC, VDE, AUX, and ADE signals.
  • LVDS DRIVER: True LVDS I/O mode in the Cyclone IV.
  • DDIO: Double Data rate, responsible for sending data outputs at double the necessary frequency (see more).
  • Synchronizer: Data synchronizer between low-frequency and high-frequency clocks.
  • Serializer: 10:2 data serializer, serializing a bus of 10 bits two by two to send them to the DDIO, which is responsible for sending the data at double the speed in Mbps.

You will have as a foundation the Video Sync, the PLLs, the TMDS encoder, the DDIO, and a small serializer;


you should assemble circuit converter that appears in the image

Note: According to the LVDS Owner's Reference Manual from Texas Instruments, most CML/TMDS receivers have AC coupling at the input, which allows an LVDS output to be connected directly to HDMI inputs without the need for the previous circuit. So good news!, do it under your own risk, FPGAlover does not take any responsibility if you burn or damage your FPGA.


















































































Written by Holguer Andres

PSP Screen Video Using Nios II
PSP Screen Touch Stand Alone
PSP Screen Touch Using Nios II
PSP Screen Video and Touch Stand Alone
PSP Screen Examples
PSP Screen Pinout
PSP Screen Documents

Parte HW:
  1. Descargue la siguiente plantilla(Download this file ( y descomprimala en una ruta sin espacios y corta.
  2. Revise las conexiones del pinout y haga las respectivas conexiones de la pantalla con la DE0-NANO.
    1. Ver LCD Datasheet.
    2. Ver Pinout.
  3. Ahora abra el proyecto Quartus y abra Qsys(Seleccione system.qsys).
  4. Una vez en Qsys, agregue el modulo llamado "Frame Reader" y configure de la siguiente manera: 
    1. El Frame Reader, leerá directamente de la RAM una sección de memoria con las características que están en el recuadro
  5. Ahora conecte el Frame reader de la siguiente manera: 
  6. Ahora agregue el modulo "Clocked Video Output" y configure de la siguiente forma:


  7. La razon por la cual se configura el "Clocked Video Output" de esta manera usted la puede encontrar en las paginas  63 y pagina 65 del Download this file (KT43B0E8257-40A (1).pdf)datasheet.
  8. Ahora conecte el modulo "Clocked Video Output" de la siguiente forma:
  9. Ahora se debe hacer un pequeño calculo matemático para seleccionar desde antes donde queremos guardar nuestro Frame de video, si queremos que no vaya a ver problemas con la memoria de heap o stack del sistema. El calculo es el siguiente, si queremos un frame de 480x272 que es la resolución que se quiere alcanzar en la pantalla, necesitamos saber ¿Cuanto espacio gasta esto en bytes?, lo cual se puede encontrar multplicando 480x272x4, donde el 4 significa que por cada pixel se gastaran 4 Bytes por color(un int).
    480x272x4=522240 Bytes=0x7f800 Bytes ==> si se quiere 1 Frame.
    480x272x4x2=1044480 Bytes=0xff000 Bytes==> si se quiere 2 Frame.
    En nuestro diseño dejaremos 2 Frames entonces necesitamos dejar un espacio destinado a Video del tamaño de 480x272x4x2=1044480 Bytes=0xff000 Bytes
  10. Ahora en el Qsys abra las opciones de la CPU y modifique "Exception Vector Offset" con el valor de 0xff000 + 0x20, los 32 Bytes de mas es por estandar que
    deben ser agregados al Exception Vector.

    Esto se hace para que el procesador se limite a trabajar desde este punto de partida, y no existan problemas de tener Video donde no debemos tenerlo.
  11. Ahora guarde los cambios y oprima en "Generate".
  12. En el Modulo Top de Quartus usted tiene instanciado en el Nios lo siguiente(Donde TFT_DCLK, proviene de un PLL y transporta un reloj de 9 MHz segun las  paginas 63 y pagina 65 del Download this file (HX8257.pdf)HX8257.pdf): 
Parte SW:
    1. Abra el Nios II Software Build y cree un nuevo proyecto(Nios II Application and BSP from Template) llamado "video_test".
    2. Descargue el siguiente this file ( y copie en el proyecto "video_test" los archivos que hay en el.
    3. Ahora haga "Clean Project" tanto de la carpeta de aplicación como de la de BSP.
    4. Genere el BSP.
    5. Build Project.
    6. Luego corra el proyecto con "Run As->Nios II Hardware"
    7. Una vez programe deberá tener sobre su pantalla la siguiente figura.
    8. Usted puede quitar el comentario de la linea 15 para tener Double Frame(Mientras dibuja en un frame muestra el otro).
    9. Si se da cuenta en la lineas 11 y 12 puede ver la ubicación en memoria de los Frames de 480x272 en la SDRAM.
    10. Para aumentar la velocidad de dibujo puede cambiar el Nios II a Fast o podría hacer acceleración por HW.

To use the TouchScreen of the Screen, we will be driving the chip XPT2046(Download this file (KT43B0E8257-40A (1).pdf)KT43B0E8257-40A (1).pdf), and it can be driven using the following Verilog Hardware Description, you can connect the pins of the screen wherever you want on the FPGA GPIO, and use it.

Download this file (4.3inch-480x272-Touch-LCD-B-Code.7z)Touch Driver Verilog Code Download

assign GPIO[0] =1'bz;
assign TFT_ADC_DOUT=GPIO[0] ;
assign GPIO[1]=TFT_ADC_DIN;
assign GPIO[2]=TFT_ADC_DCLK;		
assign GPIO[3]=TFT_ADC_CS_N;
wire	[11:0] 	x_coord;
wire	[11:0] 	y_coord;
reg	[11:0] 	x_coord_reg;
reg	[11:0] 	y_coord_reg;
wire			new_coord;	

localparam X_ADC_UPPER_RIGTH=3975;
localparam X_POS_UPPER_RIGTH=479;
localparam X_ADC_LOWER_LEFT=112;
localparam X_POS_LOWER_LEFT=0;

localparam Y_ADC_UPPER_RIGTH=4032;
localparam Y_POS_UPPER_RIGTH=0;
localparam Y_ADC_LOWER_LEFT=110;
localparam Y_POS_LOWER_LEFT=271;

wire [11:0]  x_coord;
wire [11:0]  y_coord;
wire new_coord; 
adc_spi_controller u2 (
wire [31:0] numeratorX=(y_coord-X_ADC_LOWER_LEFT)*(X_POS_UPPER_RIGTH-X_POS_LOWER_LEFT);
wire [31:0] denominatorX=X_ADC_UPPER_RIGTH-X_ADC_LOWER_LEFT; 
reg [31:0] real_x;

wire [31:0] numeratorY=(x_coord-Y_ADC_LOWER_LEFT)*(Y_POS_LOWER_LEFT-Y_POS_UPPER_RIGTH);
wire [31:0] denominatorY=Y_ADC_UPPER_RIGTH-Y_ADC_LOWER_LEFT; 
reg[31:0] real_y;

always@(posedge CLOCK_50)
 if(!TFT_ADC_PENIRQ_N && new_coord)
 real_y<= Y_POS_LOWER_LEFT-(numeratorY/denominatorY);
 real_x<= (numeratorX/denominatorX)+X_POS_LOWER_LEFT;

On the Verilog code you will find that the Buses "real_x and real_y" are carring the coordingates where the touch screen is being pressed, and that the wire TFT_ADC_PENIRQ_N carries the interruption so you can determine when the screen was touched.

You can use this implementation, and wire it up to any soft processor, FSM, or logic you desire.




Based on the Stand Alone Touch screen, now we can connect our nios II system using a simple PIO interface to the external touch screen driver, this to keep it simple, though you could create a custom hardware if that is what you want and you can do it by reading the article Nios II Custom Hardware - DE0-NANO-SOC.
For this implementation a Nios II is added on the decription using Qsys, and hooked up to a PIO of 21 bits, which carry the registers "the negated touch screen IRQ, real_x and real_y"
wire [20:0]touch_to_nios={~TFT_ADC_PENIRQ_N,real_x[9:0],real_y[9:0]};​


system u0 (
        .clk_clk              (sys_clk),              //           clk.clk
        .reset_reset_n        (reset_n),        //         reset.reset_n
		  .clk_io_clk                  (io_clk),                  //               clk_io.clk
        .reset_io_reset_n            (reset_n),   

        .epcs_sdo             (EPCS_ASDO),             //          epcs.sdo
        .epcs_data0           (EPCS_DATA0),           //              .data0
        .epcs_dclk            (EPCS_DCLK),            //              .dclk
        .epcs_sce             (EPCS_NCSO),             //              .sce
        .sdram_dqm            (DRAM_DQM),            //         sdram.dqm
        .sdram_ras_n          (DRAM_RAS_N),          //              .ras_n
        .sdram_cs_n           (DRAM_CS_N),           //              .cs_n
        .sdram_we_n           (DRAM_WE_N),           //              .we_n
        .sdram_dq             (DRAM_DQ),             //              .dq
        .sdram_cke            (DRAM_CKE),            //              .cke
        .sdram_addr           (DRAM_ADDR),           //              .addr
        .sdram_ba             (DRAM_BA),             //              .ba
        .sdram_cas_n          (DRAM_CAS_N),          //              .cas_n
		  //Touch Screen
		  .touch_screen_export  (touch_to_nios[20:0]));
for the Nios II software you can use the following driver(Download this file (TOUCH_EVENT.h)TOUCH_EVENT.h Download this file (TOUCH_EVENT.c)TOUCH_EVENT.c) to use it on your Nios II designs or use it as guidance to port it over other soft core, and test it with the following main code.

 *  Created on: 1/04/2014
 *      Author: Holguer A. Becerra
 *      This email address is being protected from spambots. You need JavaScript enabled to view it.

#include <stdio.h>
#include <unistd.h>  // usleep (unix standard?)
#include "io.h" // I/O access
#include "system.h" // HAL system

#include "./touch_driver/TOUCH_EVENT.h"

int main(){

	// init Touch
	int result;
	int event=0;
	int pos_x,pos_y;

		event=event_is_up(&pos_x, &pos_y);
			printf("Evento down x=%d y=%d\n",pos_x,pos_y);
		  else if(event==1){
			  printf("Evento UP x=%d y=%d\n",pos_x,pos_y);


	return 0;
You can download the full Quartus example by clicking on this link(Download this file ( Nios

So if you wondered, how one could use this as standalone, without Nios II, here the template and example.
If you go over the manual where it is explained all about VGA syynchronization, and if you read the datasheet of the screen, you realize the TFT Screen works exactly the same, just in a smaller scale than an standard VGA. so here the calculations if you want to modify or write a VGA synchronizer(Download this file (4.3inch-480x272-Touch-LCD-B-Code.7z)PSPVideoSync) for this particular TFT.
knowing that you need a 9MHz clock, you will need to instantiate a PLL to generate that frequency, so for that you need to open up the megawizard or ip catalog, and create 




 Once you have created the clock and as you have already the video sync verilog file, you can hook them up on the top file of your Quartus project. if you implemented the following example you will see on the TFT screen, a red background with a blue box drawn on the coordinates(x=10,y=55) with a width of 70 pixels, and height of 70 pixels.

wire TFT_DSIP;
wire TFT_DCLK;
wire TFT_DE;
reg [7:0]TFT_RED;
reg [7:0]TFT_GREEN;
reg [7:0]TFT_BLUE;

wire [10:0]CounterX;
wire [10:0]CounterY;

assign GPIO[29]=TFT_DSIP;
assign GPIO[31]=TFT_DCLK;
assign GPIO[33]=TFT_DE;

assign GPIO[32]=TFT_HSYNC;
assign GPIO[30]=TFT_VSYNC; 

//TFT Colors
assign GPIO[12:5]=TFT_RED[7:0];
assign GPIO[20:13]=TFT_GREEN[7:0];
assign GPIO[28:21]=TFT_BLUE[7:0];

assign TFT_DSIP=1'b1;
assign TFT_BACKLIGHT=1'b1;

//////////////////PLL VGA /////////////

pll_9MHZ	pll_9MHZ_inst (
	.inclk0 ( CLOCK_50 ),
	.c0 ( TFT_DCLK )// RELOJ 9MHZ

////////////////// SINCRONIZADOR VGA ////////////

mi_vga mi_vga_inst
	.clk(TFT_DCLK) ,	// input  clk_sig
	.h_sync(TFT_HSYNC) ,	// output  h_sync_sig
	.v_sync(TFT_VSYNC) ,	// output  v_sync_sig
	.video_on(TFT_DE) ,	// output  video_on_sig
	.pixel_x(CounterX) ,	// output [N-1:0] pixel_x_sig
	.pixel_y(CounterY) 	// output [N-1:0] pixel_y_sig

wire square_on= (CounterX > 11'd10) && (CounterX < 11'd80) &&(CounterY > 11'd55) && (CounterY < 11'd125);

/////MUX DE VIDEO ////
always@(negedge TFT_DCLK)
		  TFT_GREEN <=8'd0;
		  TFT_BLUE <=8'd0;
		 TFT_BLUE <=8'h00;
			TFT_BLUE <=8'hFF;


GUI on TFT using Only Verilog

So let's say now you wanted to implement a GUI using only Verilog, and taking advantage that you have access to a touch screen as well. Imagine you need to create a GUI of three buttons, which we could simply describe as boxes, as it is shown in the following image.


Once you have drawn these 3 boxes on the screen, you could now bind them to a touch screen action, using the stand alone touch screen module given in the section stand alone touch screen


after instantiating the touch screen verilog module on your top module, you can use "real_x, and real_y" to know the position where the screen is being touched, and the PENIRQ to determine if the screen is pressed. The above instantiation, has a new output named "PEN_DOWN", which is simply a delayed or anti bouncer representation of TFT_ADC_PENIRQ_N, which is useful to avoid bouncing.

You can download this modified touched driver here Download this file (touch.v)touch.v

To correlate the position of the touchscreen and the drawn boxes, you can simple add the condition using the buses "real_x, and real_y" in the following way

wire box_on= (CounterX > 11'd300) && (CounterX < 11'd400) &&(CounterY > 11'd100) && (CounterY < 11'd200);
wire box_on1= (CounterX > 11'd0) && (CounterX < 11'd100) &&(CounterY > 11'd0) && (CounterY < 11'd80);
wire box_on2= (CounterX > 11'd150) && (CounterX < 11'd250) &&(CounterY > 11'd50) && (CounterY < 11'd100);

wire box_oprimido=((PEN_DOWN==1'b0) & (real_x[31:0]>11'd300) & (real_x[31:0]<11'd400) &   (real_y[31:0]>11'd100) & (real_y[31:0]<11'd200));
wire [23:0]color_box=box_oprimido?24'h00ff00:24'h0000ff;

wire box_oprimido_1=((PEN_DOWN==1'b0) & (real_x[31:0]>11'd0) & (real_x[31:0]<11'd100) &   (real_y[31:0]>11'd0)   & (real_y[31:0]<11'd80));
wire [23:0]color_box_1=box_oprimido_1?24'h0000ff:24'h00ff00;

wire box_oprimido_2=((PEN_DOWN==1'b0) & (real_x[31:0]>11'd150) & (real_x[31:0]<11'd250) & (real_y[31:0]>11'd50)  & (real_y[31:0]<11'd100));
wire [23:0]color_box_2=box_oprimido_2?24'h000000:24'hf00ff0;

So the wire "box_oprimido" carries the condition if the touchscreen is being pressed, the real_x is greater than the position 300 and less than 400, and the real_y is greater than the position 100 and less than 200, this wire will be set to 1. So for our logic this means that the "box_on" has been pressed by the user.

You can also use this wire to act  the input of a color multiplexer, so if you want to change the color of the box when you press the button, you can.

Here the modified code to make this example work.

Note: You need to add to the PLL a clock of 2KHz to make sure the touch screen driver works accordingly for the antibouncer(PEN_DOWN)

wire TFT_ADC_CS_N;

wire [31:0]  real_x; 
wire [31:0]  real_y;

wire PEN_DOWN;

wire TFT_DSIP;
wire TFT_DCLK;
wire TFT_DE;
reg [7:0]TFT_RED;
reg [7:0]TFT_GREEN;
reg [7:0]TFT_BLUE;

wire [10:0]CounterX;
wire [10:0]CounterY;

assign TFT_ADC_DOUT=GPIO[0] ;
assign GPIO[1]=TFT_ADC_DIN;
assign GPIO[2]=TFT_ADC_DCLK;		
assign GPIO[3]=TFT_ADC_CS_N;

assign GPIO[29]=TFT_DSIP;
assign GPIO[31]=TFT_DCLK;
assign GPIO[33]=TFT_DE;

assign GPIO[32]=TFT_HSYNC;
assign GPIO[30]=TFT_VSYNC; 

//TFT Colors
assign GPIO[12:5]=TFT_RED[7:0];
assign GPIO[20:13]=TFT_GREEN[7:0];
assign GPIO[28:21]=TFT_BLUE[7:0];

assign TFT_DSIP=1'b1;
assign TFT_BACKLIGHT=1'b1;

wire reset_n=1'b1;

//////////////////PLL VGA /////////////

pll_9MHZ	pll_9MHZ_inst (
	.inclk0 ( CLOCK_50 ),
	.c0 ( TFT_DCLK ),// RELOJ 9MHZ
	.c1(CLK_2KHz) //anti bouncer clock

////////////////// SINCRONIZADOR VGA ////////////

mi_vga mi_vga_inst
	.clk(TFT_DCLK) ,	// input  clk_sig
	.h_sync(TFT_HSYNC) ,	// output  h_sync_sig
	.v_sync(TFT_VSYNC) ,	// output  v_sync_sig
	.video_on(TFT_DE) ,	// output  video_on_sig
	.pixel_x(CounterX) ,	// output [N-1:0] pixel_x_sig
	.pixel_y(CounterY) 	// output [N-1:0] pixel_y_sig

///////////////// TOUCH ///////////////////

touch touch_inst
	.CLOCK_50(CLOCK_50) ,	// input  CLOCK_50_sig
	.reset_n(reset_n) ,	// input  reset_n_sig
	.TFT_ADC_DIN(TFT_ADC_DIN) ,	// output  TFT_ADC_DIN_sig
	.TFT_ADC_CS_N(TFT_ADC_CS_N) ,	// output  TFT_ADC_CS_N_sig
	.real_x(real_x) ,	// output [31:0] real_x_sig
	.real_y(real_y) ,	// output [31:0] real_y_sig
	.CLK_2KHz(CLK_2KHz) ,	// input  CLK_2KHz_sig
	.PEN_DOWN(PEN_DOWN) 	// output  PEN_DOWN_sig

assign LED[1]=PEN_DOWN;

/// GUI logic
wire box_on= (CounterX > 11'd300) && (CounterX < 11'd400) &&(CounterY > 11'd100) && (CounterY < 11'd200);
wire box_on1= (CounterX > 11'd0) && (CounterX < 11'd100) &&(CounterY > 11'd0) && (CounterY < 11'd80);
wire box_on2= (CounterX > 11'd150) && (CounterX < 11'd250) &&(CounterY > 11'd50) && (CounterY < 11'd100);

wire box_oprimido=((PEN_DOWN==1'b0) & (real_x[31:0]>11'd300) & (real_x[31:0]<11'd400) &   (real_y[31:0]>11'd100) & (real_y[31:0]<11'd200));
wire [23:0]color_box=box_oprimido?24'h00ff00:24'h0000ff;

wire box_oprimido_1=((PEN_DOWN==1'b0) & (real_x[31:0]>11'd0) & (real_x[31:0]<11'd100) &   (real_y[31:0]>11'd0)   & (real_y[31:0]<11'd80));
wire [23:0]color_box_1=box_oprimido_1?24'h0000ff:24'h00ff00;

wire box_oprimido_2=((PEN_DOWN==1'b0) & (real_x[31:0]>11'd150) & (real_x[31:0]<11'd250) & (real_y[31:0]>11'd50)  & (real_y[31:0]<11'd100));
wire [23:0]color_box_2=box_oprimido_2?24'h000000:24'hf00ff0;

/////MUX DE VIDEO ////
always@(negedge TFT_DCLK)
		 TFT_GREEN[7:0] <=8'd0;
		 TFT_BLUE[7:0] <=8'd0;
		 else if(box_on1)
		 else if(box_on2)


 Then the results will be what is shown in the video below



You can download the template or example if you want from here: Download this file (DE0_NANO_TFT_GUI_VERILOG.qar)DE0_NANO_TFT_GUI_VERILOG.qar

Some examples you can download and use to verify your connections with your DE0-NANO
  • Test Video With PCEngine(.sof) & Pinout(GPIO_1[27]=AUDIO_L; assign GPIO_1[29]=AUDIO_R).
    • Utilizando el control panel de la DE0-NANO(Download this file (, programe la EPCS desde la posición 0x7d000 con el archivo siguiente(.pce): JackieChan.pce
      • Open Control panel, once opened, click on Memory, then on Memory type list select "EPCS", select the check "File Length", on the address of section Sequential Write  type "07d000" and then click on the button write file to memory.
      • Select the file  JackieChan.pce, and OK.
      • Then wait until the EPCS is written.

      • Note: if it does not let you write, first click on Erase "Chip Erase (70 sec)"
    • Luego programe el .sof, ponga los SW[3:1] en la posición 3'b011 y oprima el KEY[0] para ver en funcionamiento el juego sobre su pantalla.

1 IRQ Touch screen interrupt output Low level while the touch screen detects pressing
2 5V 5V power supply input 5V power supply
3 MOSI Touch screen SPI data input input Connects to SPI MOSI
4 MISO Touch screen SPI data output output Connects to SPI MISO
5 SCK Touch screen SPI clock input Connects to SPI SCK
6 SSEL Touch screen chip select input Low active
7 PWM Backlight brightness adjustment input Control the backlight brightness via PWM
8 GND Ground input GND
9 BUSY Touch screen busy output  
10 NC      
11 R0 Data pin input Red data
12 R1
13 R2
14 R3
15 R4
16 R5
17 R6
18 R7
19 G0 Data pin input Green data
20 G1
21 G2
22 G3
23 G4
24 G5
25 G6
26 G7
27 B0 Data pin input Blue data
28 B1
29 B2
30 B3
31 B4
32 B5
33 B6
34 B7
35 DCLK LCD clock input LCD clock signal
36 DSIP NC    
37 HSYNC Horizontal Synchronization input Horizontal synchronous signal input
38 VSYNC Vertical Synchronization input Vertical synchronous signal input
39 DE Control mode selection input DE = 0 : SYNC mode
DE = 1 : DE mode
40 GND Ground input GND






Author:  Edgar Rodrigo Mancipe Toloza




ABSTRACT: The main objective of this paper is to present the steps of how to program a PID controller in a FPGA, and in that way to control a DC motor using Pulse Width Modulation. Also we want to give some ideas to people interested in program embedded controllers in hardware.

During the project we will use some tools to help us to visualize the behavior of the controller on the computer screen through rs232 communication and LabView chart to plot, and LCD display for visualize the Set Point, gains and the current value.


KEYWORDS: PID, Control, FPGA, DE0-Nano, Embedded.




Nowadays FPGA's have increased their popularity due the many ways to acquire it, reliability, and low costs. As a consequence of that, we can see more FPGA's applications in control systems.

For many years, microcontrollers used to be on the top of this field due their low-cost, but through years FPGA's have turned into a striking option, thanks to its main property of controlling many systems in parallel in the same embedded system.[1]. 

In this project we want to show in a quick way, how to program a PID control in FPGA using Verilog language, also we will change the values of Gain variables to see the behavior of the controlled value.

This article is not intended to give a definitive PID algorithm, the intention is to introduce and give some ideas for the readers of how to create and implement their own PID equation embedded in FPGA.



This section will show the name of the main objects used in the analog and digital interface of the project for signal conditioning and power circuit.

  • DE0-NANO BOARD: The development board selected for this Project is the DE0-Nano, which contains the following characteristics: [2]
    • Altera FPGA Cyclone IV EP4CE22F17C6
    • Analog-to-digital converter ADC128S022
    • Configuration device EPCS16 for non-volatile data storage
    • 4 dip-switch
    • 2 push buttons
    • 8 LED's

      Figure 1. DE0-Nano Board.

  • GEARMOTOR: The gearmotor selected have the next characteristics:

    • Torque 18Kg*cm
    • 80RPM
    • Power supply 12Vdc
      • Quadrature encoder of 8384 pulses per round 3v.

        Figure 2. Gearmotor. [3]

  • DISPLAY HD44780 2x16:  Monochromatic display 2X16 that will be use to visualize de set-point, current variable, proportional, integral and derivative gain

    Figure 3. LCD 2x16. [4]

  • H BRIDGE: the control circuit and power circuit, a L293D H Bridge is the selected option, so in that way the control circuit send digital signals to the chip for select the rotation of the motor. [5]

    Figure 4. L293D Block Diagram.

  • SERIAL-TO-USB CONVERTER:  For visualize the behavior of the variables in the computer screen, we decided to use a serial-to-usb FTDI FT232RL converter. So through a serial RS232 algorithm coming from the embedded we can send the information of the data's. [6]

    Figure 5. Serial-to-USB converter FT232RL.



Before start to program the FPGA, is necessary defining a strategy through a block diagram. In the Figure 6, we can see that the Set Point is selected using a Dip- switch and the feedback signal is coming from the quadrature encoder coupled to the DC motor. The error is the difference between Set Point and feedback (Encoder), and the error sign defines the rotation of the motor through the H Bridge. A Pulse Width Modulation (PWM) is the output signal of the PID algorithm that will change its Duty Cycle depending of the controller result.