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.
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.
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.
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.
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:
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 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.
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 1280×800 pixel display, but it isn’t easy :-).
Pherhaps you have some tipps….
Best regards
Jürgen
@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
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!
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?
@Viktor
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
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.
@Viktor
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
Hi Thomas,
I am wondering if the breakout board is necessary? Can I just connect VGA cables?
@Inez
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
Hi,
I need Universal JTAG for this part no IC0400C778BF.
if u have please contact me. My ID cooldivakar2008@gmail.com
@Dhivakar.M
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.
Hi,
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
Thanks.
@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.
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″ 800×480 TFT LCD.
https://www.adafruit.com/products/2354
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.
Thanks
@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
hi i need help interfacing any sensore (humidity,temprature ,IR,Ultrasonic sensor ,or gyrosensor) with spatrn 3 board i dont know i to code it i know interfacing making counters flipflops adder multiplexor but .. confused how i take analogue input and display its value on seven segment .I really apreciate if you let me know how can i do it.
@Umer
You can only take in an analog input if you use some kind of Analog to Digital converter circuitry, this can either be in an IC which you can communicate with over I2C, SPI etc., or you can make your own simple RC based analog to digital reader circuit.
For the Ultrasound sensor the output is usually digital. IR and gyroscope sensors can also be found in digital versions which will make your life much easier when trying to integrate it with your Spartan 3 board.