Home > Development boards, FPGA, Guides > Drive LCD TFT displays with an FPGA

Drive LCD TFT displays with an FPGA

FPGA’s can be very advanced to get started using, especially if you are used to microcontrollers.
But when you first get the right feeling and the proper mindset you will soon see the endless possibilities with the programmable logic.

One of the great aspects of the logic is the speed and the full control of what happens at every single clock cycle.
With this full control it doesn’t takes many lines of code to generate a very time-critical signal such as a video signal.

In this short post I will walk thru our current test setup with an FPGA, the Spartan 3E, controlling a 18-bit 7″ 800×480 TFT display.

Spartan 3E controlling a 800×480 TFT LCD

In the image above you can the TFT display at the top and the FPGA board at the bottom.
In between of these you will see a small green connector board, which is our own 7-inch LCD Breakout board with the required switch-mode power supply for powering the LED backlight, together with the interface connector with the 18-bit color signals, Pixel Clock, Data Enable and PWM.

7″ LCD Breakout board

The schematic of the board can be found here: A5-LCD_Breakout.pdf

The FPGA board itself is the inexpensive, low-level, “Spartan 3E Sample Pack“.
Though any FPGA board with the required I/O pins available can of course be used.

“Spartan 3E Sample Pack” FPGA board

The VHDL code for this project, including the Xilinx Project files, can be downloaded here: FPGA_LCD_TFT_Control.zip
I will try to do a short summary of what happens in the code and why I have decided to make it such.

VHDL Code walkthru
To control a TFT display you have to generate the following two timed signals: DCLK (Pixel clock) and DE (Data Enable).
In the datasheet of the display you will be able to find the specific timing parameters of these signals, which also explains when to display the color data of each pixel.
At page 6 of the datasheet of our display we can see the timing table. From this table we will notice the required CLK frequency of around 33.26MHz. Generating this Pixel clock source is one of the major aspects of generating the video signal.

Clock: entity work.DCM_Module(Behavioral)
generic map (PERIOD => 20.0, DIV => 27, MUL => 18)
port map (CLK_IN => CLK, CLK_OUT => PixelClock);

Within the code for the FPGA I have decided to use the built in DCM (Digital Clock Manager) periphiral of the FPGA’s, to generate 33.33MHz from the on board 50MHz oscillator. This is done by diving the Input frequency by 27 and then multiply this by 18.
50MHz / 27 = 1.85MHz * 18 = 33.33MHz

Now when we have this clock signal internally in the FPGA too, we can use this signal to count the clock pulses, equal to each ‘pixel’, and then we are ready to create the timing of the DE signal.
According to the datasheet we have an 800 pixels (clock cycles, Tcph, too) wide display area where the Data Enable has to be on.
For every line scan we have a total of between 1000 and 1200 ‘pixels’, whereof between 200 and 400 are outside of the screen. These ‘off-screen’ pixels are used to sync the video signal.

When we have done a single line scan there is 479 more to go within the visisble display area. Yet again we do also have some ‘off-screen’ lines, in this case between 10 and 110 lines, to do the sync.

To ease the generation of the Data Enable signal and to take care of the current scan/pixel position, I have made two counters: Hcount and Vcount.
The Hcount is used to take care of the current Horizontal pixel, going from 0 to 799 when inside the visible display area, and then continuing from 799 to about 1200 for the ‘off-screen’ pixels.
The Vcount is used to take care of the current Vertical pixel, going from 0 to 479 when inside the visible display area, and then continuing from 479 to about 590 for the ‘off-screen’ pixels.

The Data Enable pin is then controlled by this single line of code:

DE <= '1' when ((Hcount < TDEH) and (Vcount < TDE)) else '0';

Where the TDEH and TDE are definitions as found in the datasheet. In the top of our VHDL code all these timing definitions has been programmed as constants:

constant TDEH: integer := 800;
constant TDEL: integer := 256;
constant TDEB: integer := 45;  
constant TDE: integer := 480;

So now we have managed to generate both the DCLK (Pixel clock) and the required DE (Data Enable) signal with the proper timing parameters.
The Hcounter will keep counting up to (TDEH+TDEL), which is the total horizontal pixel count (including the ‘off-screen’ pixels). Afterwards it resets to 0 and increase 1 to the Vcount, moving the “cursor” one line down.
This is then repeated until the Vcounter reaches the end at (TDE+TDEB) where it resets to 0 too.

Finally it is now just a matter of setting the 18-bit digital color lines to the proper pixel color at each clock cycle and then we have a functioning display system.

Categories: Development boards, FPGA, Guides Tags:
  1. Jürgen Dürrwang
    March 27th, 2013 at 11:55 | #1

    Hi Thomas,

    really nice projekt. Have you ever tried to interface an tft via lvds? At the moment I try to implement 5 chanel lvds for a 1280x800 pixel display, but it isn’t easy :-).

    Pherhaps you have some tipps….

    Best regards

  2. March 28th, 2013 at 12:49 | #2

    @Jürgen Dürrwang
    Hi Jürgen.
    Yes, we have been driving LVDS displays with FPGA’s -- we have even made a MCU to LVDS display controller board: http://blog.tkjelectronics.dk/2012/10/lvds-display-controller-for-microprocessors/
    It is not that difficult. You need almost the same code as for this project, the only difference is that you need to serialize the data into the LVDS channels.

    Regards Thomas

  3. ananth
    April 23rd, 2013 at 19:38 | #3

    Awesome Sauce. Just what I was looking for to dive in to FPGA based Graphics processing for a application that I have in mind.

    Keep up the good work!

  4. Viktor
    September 20th, 2013 at 20:49 | #4

    Hi Thomas,
    Please help me to write the firmware.
    iMPACT requested file *.mcs, but it is not present in the project :(
    (I work in a version Xilinx ISE DS 14.3)
    File main.bit is not enough, why not?

  5. September 23rd, 2013 at 20:18 | #5

    You should be able to use iMPACT to program a .bit file into the FPGA.

    To do so you need to create a new project in iMPACT, do a boundary scan or manually add the Xilinx device you have.
    When done you should see the Xilinx chip in the white area of the program. Right click this chip and select “Assign New Configuration File”.
    You should now be able to select the main.bit file.
    Finally right click the device again and select “Program”.

    Now your FPGA device will be programmed with the selected .bit file.

    Regards Thomas

  6. Viktor
    October 2nd, 2013 at 12:57 | #6

    Thank you for responding.
    I managed to flash the project, but:
    after power-loading an old project.
    -if you do not turn the power off, then on a scope not seen sinaly Pixel Clock, Data Enable: (

    Regards, Victor
    Translated from Russian to English, translate Google.

  7. October 3rd, 2013 at 20:41 | #7

    Hi Viktor.
    I am not sure about the problem you are referring to.
    Which JTAG programmer are you using and are you just programming the External flash with it or are you programming the FPGA itself.
    Because if you just program the connected External flash and not the FPGA itself (it’s two steps), you WILL have to repower/restart the FPGA to initialize the FPGA ‘program’ from the flash.

    Regards Thomas

  8. Inez
    October 19th, 2013 at 09:16 | #8

    Hi Thomas,

    I am wondering if the breakout board is necessary? Can I just connect VGA cables?

  9. October 19th, 2013 at 17:46 | #9

    Hi Inez.
    This project is specifically intended for driving LCD displays with 24-bit digital lines or similar.
    Driving a VGA display is still possible with almost the same code, though you will have to change the digital interface to an analog one (convert it with either R2R or a DAC) and furthermore you will have to change the timing appropriately.
    If so, yes then you don’t need the breakout board for the LCD.

    Regards Thomas

  10. Dhivakar.M
    June 30th, 2014 at 11:19 | #10

    I need Universal JTAG for this part no IC0400C778BF.
    if u have please contact me. My ID cooldivakar2008@gmail.com

  11. June 30th, 2014 at 11:30 | #11

    According to the datasheet the C version doesn’t have any JTAG interface.
    It’s only the IC0400K778BF who does!
    So you can’t use the Universal JTAG to debug your device.

  12. Moha Deeb
    July 27th, 2015 at 13:42 | #12

    Thanks for the great project.

    I can’t see the VSYNC, HSYNC signals in the schematic

    I though we can’t interface TFT-LCD without them


  13. July 28th, 2015 at 19:53 | #13

    @Moha Deeb
    As written in the datasheet of this display the VSYNC and HSYNC signals are integrated into the Data Enable (DE) signal.
    So it is correct that you can’t find these specific signals.
    Some displays use individual sync signals while others use a DE line or similar.

  14. February 15th, 2016 at 17:13 | #14

    Hey, thanks for posting this.

    I’ve done VGA before which is very similar. I’m now trying to interface to an adafruit 2354 without luck. It’s a 7.0″ 800x480 TFT LCD.


    Did you need any particular initialization sequence? I don’t see mention of this.

    I’m tying the backlight pin to ground to enable it. I can see a white screen (the backlight?) come on as soon as the ON/OFF signal is tied to ground to enable it.


  15. February 17th, 2016 at 22:38 | #15

    @Keith Monahan
    How are you driving the Adafruit display? Please keep in mind that the display have no built-in-controller so you need to have the timing right, which is most easily done with an FPGA.
    The display needs to be driven similarily to the one that I’m using in this video, but you might have to adjust the timing parameters to get it to work with this Adafruit display.
    Please refer to the datasheet: https://www.adafruit.com/images/product-files/2354/adafruit_SPEC-YX700WV03_REV.A-787880.pdf

  1. No trackbacks yet.