How to Drive TFT Display Through RGB Interface

Background

To drive a TFT display through an RGB interface, you need to send parallel R, G, and B data signals along with HSYNC (horizontal sync) and VSYNC (vertical sync) signals to a microcontroller or a dedicated display controller. The host system sends pixel data, and the sync signals tell the display when to start a new row or frame, which is a process that can be handled asynchronously with a frame buffer or by continuously sending data.

MCU connect LCD via RGB

To illustrate how to implement driving TFT display with RGB interface, we are using Tianman 10.1 inch TFT LCD TM101DDHG06 and i.MX RT1050 MCU with Arm Cortex-M7 core, 528 MHz max frequency, 512 kB SRAM from NXP Semiconductor.

Part 1 — Theory: driving a TFT via RGB interface

1.1 Introduction to the RGB Interface

The RGB interface is a common way to connect a microprocessor (MCU) to a TFT LCD. It's a parallel interface, meaning it sends a lot of data at once, which makes it fast enough for high-resolution displays. The key signals are:

Pixel Clock (PCLK): This is the heartbeat of the interface. On each clock cycle, one pixel's data is sent to the display.

Horizontal Sync (HSYNC): This signal tells the display when a new line of pixels is starting.

Vertical Sync (VSYNC): This signal tells the display when a new frame (a full screen of pixels) is starting.

Data Enable (DE): This signal indicates when the pixel data on the data lines is valid.

RGB signals

Red, Green, and Blue Data Lines (R, G, B): These are the actual data lines that carry the color information for each pixel. A 24-bit RGB interface, for example, will have 8 lines for red, 8 for green, and 8 for blue

1.2 What the TM101DDHG06 panel expects (key facts)

10.1" TFT, resolution 1024 × 3(RGB) × 600, TTL / RGB888 parallel interface. It exposes pins: R0..R7, G0..G7, B0..B7, DCLK (pixel clock), HS (Hsync), VS (Vsync), DE (data enable) plus power pins (VDD, AVDD, VGH/VGL), RESET and control pins (SHLR, UPDN, DITHB). See the datasheet for full pinout and required rail voltages.

Important electrical values: VDD = 3.3 V (typical 3.3V), AVDD ≈ 11 V, VGH ≈ +22 V, VGL ≈ -7 V. The backlight LED needs ~9.6 V @ ~224 mA (panel’s LED connector). Follow the recommended power-on/off sequencing in the datasheet to avoid panel damage.

1.3 What capabilities the MCU (i.MX RT1052) must provide

A dedicated LCD Controller: This is a specialized peripheral on the MCU that handles the timing (generate pixel clock, HSYNC, VSYNC, DE) and data transfer to the LCD. On the i.MX RT1052, this is called the eLCDIF (enhanced Liquid Crystal Display Interface). It's crucial because it offloads the CPU from the intensive task of constantly refreshing the display.

Sufficient RAM for a Framebuffer: A framebuffer is a section of RAM that stores the color data for every pixel on the screen. MCU's eLCDIF DMA reads from this framebuffer to know what to display. The size of the framebuffer depends on the resolution and color depth of the display. For our 10.1-inch display with a resolution of 1024x600 and 24-bit color (3 bytes per pixel), the framebuffer size would be:

1024 pixels * 600 pixels * 3 bytes/pixel = 1,843,200 bytes or about 1.84 MB. The i.MX RT1052 has 512KB of on-chip RAM, so we'll need to use external SDRAM for the framebuffer.

Sufficient I/O Pins: Many MCU pins are multiplexed. We need to map the eLCDIF signals to physical pins with the proper IOMUX config.

A Fast Core: While the LCD controller handles the display refresh. It needs a pixel clock derived from a system PLL or dedicated LCD PLL. For 1024×600 panels typical pixel clocks depend on chosen timings (often ~33–70 MHz depending on H/V porch and blanking). The MCU must provide and route that clock. The ARM Cortex-M7 core in the i.MX RT1052 is fast enough to run the application logic and update the framebuffer to display dynamic content.

Power rails & LED driver: The MCU board must not attempt to generate AVDD/VGH/VGL; you usually use a dedicated power solution (boost converters) or rely on the panel vendor recommended power supply circuits. The MCU controls RESET and optionally the backlight enable via a GPIO and a suitable LED driver / transistor.

1.4 Overall high-level flow to drive an RGB TFT

Hardware preparation

  • Provide required panel rails (VDD, AVDD, VGH, VGL) with correct sequencing.
  • Connect backlight LED rails with a proper LED driver or resistor+MOSFET.
  • Map eLCDIF signals (DCLK, HSYNC, VSYNC, DE and data lines) to MCU IOMUX pins. Ensure signal integrity for parallel bus (short runs, good ground).
  • Provide level matching (panel TTL levels are 0..VDD); ensure MCU IO is 3.3V tolerant and matched.

Pin/clock configuration

  • Configure IOMUX for eLCDIF function on the selected pins.
  • Configure an LCD pixel clock (from PLL) at the frequency required by your timing.

Frame buffer allocation

  • Reserve external SDRAM space for one or two frame buffers (double buffering recommended for smoother display).
  • Ensure buffer alignment and cache management (if caches are present, flush/invalidate as required before eLCDIF reads the buffer).

LCD Controller Initialization

The MCU's LCD controller (eLCDIF) needs to be programmed with resolution (1024×600), pixel format (RGB888), horizontal/vertical timing parameters (active pixels, front/back porch, sync pulse widths) using values from the panel datasheet.

Start display

  • Program eLCDIF to read the buffer via DMA and generate DOTCLK/HSYNC/VSYNC/DE automatically.
  • Release panel RESET, apply the correct power sequence and enable backlight.

Graphics update

Use double buffering: write to back buffer, flush cache, switch buffer pointer to eLCDIF, then draw next frame.

1.5 Timing and DE vs SYNC modes

The panel supports DE mode (MODE=H) or SYNC mode (MODE=L) according to datasheet pin MODE. DE mode is commonly used: DE indicates valid pixel data and HS/VS may be unused or tied accordingly. Check the datasheet’s timing diagrams and set the eLCDIF accordingly.

Part 2 — Practical project: drive TM101DDHG06 with i.MX RT1052

2.1 Assumptions & prerequisites

  • You have an i.MX RT1052 development board (MIMXRT1050-EVK, Embedded Artists module, or custom board) with external SDRAM available.
  • You will use NXP MCUXpresso SDK and its eLCDIF (elcdif_rgb) example as a starting point. The example implements buffer feeding and timings.
  • A 50-pin FPC connector/adapter to connect the LCD to the EVK.

2.2 Hardware Connections

The connection between the i.MX RT1052 EVK and the LCD will be as follows. You'll need to consult the EVK's user manual to find the exact pin locations on the board's headers.

Panel signal MCU signal (example)
R0..R7 LCD_DATA0..LCD_DATA7
G0..G7 LCD_DATA8..LCD_DATA15
B0..B7 LCD_DATA16..LCD_DATA23
DCLK LCD_CLK (DOTCLK)
HSYNC LCD_HSYNC
VSYNC LCD_VSYNC
DE LCD_DE
RESET GPIOx (panel reset, active low)
MODE GPIOy (tie to H for DE mode or L for SYNC)
SHLR / UPDN GPIOs (if you need flip/mirroring)
LEDA / LEDK External LED driver + GPIO enable

 

2.3 Power sequencing

Follow datasheet sequence precisely (this is a condensed checklist — use datasheet step table):

  1. Power up VDD (digital) stable.
  2. Enable AVDD (analog) and then VGH/VGL (gate drivers) in order — use boost converters as required.
  3. Release RESET (after analog/gate rails are ready).
  4. Apply pixel clock and enable MCU output signals.
  5. Enable backlight (via LED driver) last.

Power-off is reverse order: backlight off → stop pixel clock → assert RESET → remove VGH/VGL → remove AVDD → remove VDD. Failure to follow sequencing may damage the panel.

2.4 Software: MCUXpresso SDK approach

  • Install MCUXpresso SDK for i.MX RT1052 and open the elcdif_rgb example. This example demonstrates eLCDIF initialization and basic framebuffer DMA.
  • Configure:
    • Pixel clock frequency and PLL.
    • eLCDIF parameters: width=1024, height=600, pixel format RGB888.
    • Horizontal/vertical timing values: use panel’s recommended Htotal, Hsync width, Hfp/Hbp and Vsync/porches from datasheet timing table.
  • Allocate two frame buffers in external SDRAM (heap or static). Align to 32 byte or as required.
  • Implement a simple framebuffer fill function that paints test patterns (color bars) to validate connections.
  • Start eLCDIF in controller master mode to pull the frame buffer and generate DOTCLK/HS/VS.
  • For updates, use double buffering: prepare back buffer, then swap pointer (use eLCDIF frame buffer pointer update API), ensuring data cache is flushed.

2.5 Code Implementation

Here are the key code snippets and explanations.

1. Pin Muxing

First, we need to configure the MCU's pins to be used by the eLCDIF peripheral. This is done using the IOMUXC module.

#include "fsl_iomuxc.h"

void BOARD_InitLcdPins(void)
{
    // Configure the pins for the LCD data lines, clock, and control signals.
    // This is just a conceptual example. The actual pin names will vary based on the EVK.
    IOMUXC_SetPinMux(IOMUXC_GPIO_B0_00_LCD_DATA00, 0U);
    // ... repeat for all 24 data lines ...
    IOMUXC_SetPinMux(IOMUXC_GPIO_B1_03_LCD_CLK, 0U);
    IOMUXC_SetPinMux(IOMUXC_GPIO_B1_04_LCD_HSYNC, 0U);
    IOMUXC_SetPinMux(IOMUXC_GPIO_B1_05_LCD_VSYNC, 0U);
    IOMUXC_SetPinMux(IOMUXC_GPIO_B1_06_LCD_ENABLE, 0U);
}

2. Clock Configuration

Next, we configure the pixel clock. The TM101DDHG06 datasheet specifies a typical pixel clock of 51.2 MHz.

#include "fsl_clock.h"

void BOARD_InitLcdClocks(void)
{
    // Configure the PLL that will be the source for the LCD clock.
    // The target is 51.2 MHz.
    clock_video_pll_config_t pll_config = {
        .loopDivider = 42,
        .postDivider = 3,
        .numerator   = 0,
        .denominator = 0,
    };
    CLOCK_InitVideoPll(&pll_config);

    // Set the clock divider for the eLCDIF peripheral.
    CLOCK_SetMux(kCLOCK_LcdifPreMux, 2); // Use the video PLL
    CLOCK_SetDiv(kCLOCK_LcdifPreDiv, 3);
}

3. eLCDIF Initialization

This is where we configure the eLCDIF with the timing parameters from the LCD datasheet.

#include "fsl_elcdif.h"

#define APP_LCD_WIDTH     1024
#define APP_LCD_HEIGHT    600
#define APP_HSW           20
#define APP_HFP           140
#define APP_HBP           160
#define APP_VSW           3
#define APP_VFP           12
#define APP_VBP           20
#define APP_LCD_POL_FLAGS kELCDIF_DataEnableActiveHigh | kELCDIF_VsyncActiveLow | kELCDIF_HsyncActiveLow | kELCDIF_PixelClockActiveHigh

void APP_InitLcd(void)
{
    elcdif_rgb_mode_config_t config;

    config.panelWidth    = APP_LCD_WIDTH;
    config.panelHeight   = APP_LCD_HEIGHT;
    config.hsw           = APP_HSW;
    config.hfp           = APP_HFP;
    config.hbp           = APP_HBP;
    config.vsw           = APP_VSW;
    config.vfp           = APP_VFP;
    config.vbp           = APP_VBP;
    config.polarityFlags = APP_LCD_POL_FLAGS;
    config.pixelFormat   = kELCDIF_PixelFormatRGB888;
    config.dataBus       = kELCDIF_DataBus24Bit;

    // Point the LCD controller to the framebuffer
    config.bufferAddr = (uint32_t)s_frameBuffer;

    ELCDIF_RgbModeInit(ELCDIF, &config);
}

4. Framebuffer

We'll declare the framebuffer in external SDRAM. The linker script needs to be configured to place this array in the SDRAM section.

// Place the framebuffer in SDRAM
AT_NONCACHEABLE_SECTION_ALIGN(uint32_t s_frameBuffer[APP_LCD_HEIGHT][APP_LCD_WIDTH], 64);

5. Drawing a Simple Pattern

Here's a function to fill the framebuffer with a solid blue color.

void APP_FillFrameBuffer(void)
{
    uint32_t color = 0x000000FF; // Blue in RGB888 format

    for (int y = 0; y < APP_LCD_HEIGHT; y++)
    {
        for (int x = 0; x < APP_LCD_WIDTH; x++)
        {
            s_frameBuffer[y][x] = color;
        }
    }
}

6. The Main Function

Finally, let's put it all together.

int main(void)
{
    // Initialize the board's hardware
    BOARD_InitPins();
    BOARD_InitLcdPins();
    BOARD_InitLcdClocks();
    BOARD_InitSdram(); // Initialize the external SDRAM

    // Initialize the LCD controller
    APP_InitLcd();

    // Fill the framebuffer with a color
    APP_FillFrameBuffer();

    // Start the LCD controller
    ELCDIF_RgbModeStart(ELCDIF);

    while (1)
    {
        // Your application code goes here.
        // You can update the framebuffer to change what's on the screen.
    }
}

2.6 Debugging tips & common pitfalls

  • No image / garbage: check DE vs SYNC mode (MODE pin), and ensure you have correct timing and pixel format.
  • Partial columns / shifted image: check DCLK polarity (panel latches on falling/raising edge — the datasheet indicates latch edge) and SHLR/UPDN for scan direction.
  • Flicker / unstable: wrong pixel clock frequency or missing stabilization of the analog rails (AVDD/VGH/VGL).
  • Corrupted colors: byte ordering mismatch (MCU buffer storing BGR vs panel expecting RGB) — swap channels if needed.
  • Too slow updates: make sure DMA from SDRAM is used; actively use PXP/2D engine for scaling/rotation if needed.

A Final Word

Driving a display is a complex topic, and there's a lot more to learn, such as using DMA to update the framebuffer more efficiently, implementing graphics libraries, and handling touchscreens. However, with this foundation, you should be well-equipped to start your journey into embedded graphics development! 

If you want to chat more about TFT display solution, please reach us.

Back to blog