cancel
Showing results for 
Search instead for 
Did you mean: 

Screen flickering while using TFT-LCD with LTDC

Kim KyungTack
Associate III

Hi.

A custom board was built using the STM32H753XI. The board contains 16MB SDRAM and we want to use it with an LTDC to display a screen on a TFT-LCD.

I used the embedded wizard to create the UI and verified that it displays correctly on the LCD screen.

However, flickering occurs on the LCD when the screen is switched or parts of the screen change.

I rechecked the clock, SDRAM, LTDC settings, etc. but couldn't find the cause.

I've attached the datasheets for the parts I used as files.

 

1. TFT-LCD (JWS070NA-23A-1)

  • 7" TFT-LCD
  • Resolution: 1024 x 600
  • using LVDS ( STM32H753 (LTDC)   ----  LVDS Transmiiter  ----- TFT-LCD )
  • LCD-Timing.png

 

2. SDRAM (MT48LC8M16A)

  • 16MByte SDRAM
  • Speed grade : -6A type
  • CL (CAS latency) = 3

 

3. Clock configuration

Clock.png

  • using 480 MHz
  • FMC Clock: 200 MHz
  • LTDC Clock: 51.2 MHz

 

4. FMC

4.1. FMC configuration

 

/* FMC initialization function */
static void MX_FMC_Init(void) {

    /* USER CODE BEGIN FMC_Init 0 */

    /* USER CODE END FMC_Init 0 */

    FMC_SDRAM_TimingTypeDef SdramTiming = {0};

    /* USER CODE BEGIN FMC_Init 1 */

    /* USER CODE END FMC_Init 1 */

    /** Perform the SDRAM1 memory initialization sequence
    */
    hsdram1.Instance = FMC_SDRAM_DEVICE;
    /* hsdram1.Init */
    hsdram1.Init.SDBank = FMC_SDRAM_BANK2;
    hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;
    hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;
    hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
    hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
    hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;
    hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
    hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
    hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
    hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_1;
    /* SdramTiming */
    SdramTiming.LoadToActiveDelay = 2;
    SdramTiming.ExitSelfRefreshDelay = 7;
    SdramTiming.SelfRefreshTime = 5;
    SdramTiming.RowCycleDelay = 6;
    SdramTiming.WriteRecoveryTime = 3;
    SdramTiming.RPDelay = 2;
    SdramTiming.RCDDelay = 2;

    if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK) {
        Error_Handler();
    }

    /* USER CODE BEGIN FMC_Init 2 */
    // initialize sdram sequence
    init_sdram_handle(&hsdram1, FMC_SDRAM_CMD_TARGET_BANK2);
    /* USER CODE END FMC_Init 2 */
}

 

 

4.2. Initialize sequence for FMC

SDRAM.BANK = FMC_SDRAM_CMD_TARGET_BANK2
SDRAM.P = &hsdram1

 

static HAL_StatusTypeDef sdram_init_sequence(void) {

    HAL_StatusTypeDef res = HAL_OK;
    FMC_SDRAM_CommandTypeDef cmd = {0,};
    uint32_t tmp = (uint32_t) SDRAM_MODEREG_BURST_LENGTH_1 | SDRAM_MODEREG_CAS_LATENCY_3 | SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;

    // configure a clock configuration enable command
    cmd.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
    cmd.CommandTarget = SDRAM.BANK;
    cmd.AutoRefreshNumber = 1;
    cmd.ModeRegisterDefinition = 0;
    // send command
    res |= HAL_SDRAM_SendCommand(SDRAM.P, &cmd, SDRAM_TIMEOUT);

    // insert 100 us minimum delay
    HAL_Delay(1);

    // configure a PALL (pre-charge all) command
    cmd.CommandMode = FMC_SDRAM_CMD_PALL;
    cmd.CommandTarget = SDRAM.BANK;
    cmd.AutoRefreshNumber = 1;
    cmd.ModeRegisterDefinition = 0;
    // send command
    res |= HAL_SDRAM_SendCommand(SDRAM.P, &cmd, SDRAM_TIMEOUT);

    // configure a auto refresh command
    cmd.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
    cmd.CommandTarget = SDRAM.BANK;
    cmd.AutoRefreshNumber = 2;
    cmd.ModeRegisterDefinition = 0;
    // send command
    res |= HAL_SDRAM_SendCommand(SDRAM.P, &cmd, SDRAM_TIMEOUT);

    // program the external memory mode register
    cmd.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
    cmd.CommandTarget = SDRAM.BANK;
    cmd.AutoRefreshNumber = 1;
    cmd.ModeRegisterDefinition = tmp;
    // send command
    res |= HAL_SDRAM_SendCommand(SDRAM.P, &cmd, SDRAM_TIMEOUT);

    // set the refresh rate counter
    res |= HAL_SDRAM_ProgramRefreshRate(SDRAM.P, SDRAM_REFRESH_COUNT);

    // result
    return res;
}

 

 

5. LTDC

5.1. defined setting

 

#define EW_USE_DOUBLE_BUFFER            1

#define EW_DISPLAY_WIDTH                1024
#define EW_DISPLAY_HEIGHT               600

#define EW_FRAME_BUFFER_WIDTH           1024
#define EW_FRAME_BUFFER_HEIGHT          600

/* calculated addresses for framebuffer(s) */
#define SDRAM_BASE_ADDR       0xD0000000
#define EW_FRAME_BUFFER_ADDR  SDRAM_BASE_ADDR
#define EW_FRAME_BUFFER_SIZE  (EW_FRAME_BUFFER_WIDTH * EW_FRAME_BUFFER_HEIGHT * EW_FRAME_BUFFER_DEPTH)

#if EW_USE_DOUBLE_BUFFER == 1

/* locate double-buffer at the end of the last SDRAM bank - this ensures
   that front/back-buffer are located within different banks of the SDRAM */
#define EW_DOUBLE_BUFFER_ADDR  (SDRAM_BASE_ADDR + SDRAM_SIZE_BYTES - EW_FRAME_BUFFER_SIZE)
#define EW_DOUBLE_BUFFER_SIZE  EW_FRAME_BUFFER_SIZE

 

5.2. LTDC configuration

 

/*******************************************************************************
* FUNCTION:
*   EwBspDisplayInit
*
* DESCRIPTION:
*   The function EwBspDisplayInit initializes the display hardware and returns
*   the display parameter.
*
* ARGUMENTS:
*   aGuiWidth,
*   aGuiHeight   - Size of the GUI in pixel.
*   aDisplayInfo - Display info data structure.
*
* RETURN VALUE:
*   Returns 1 if successful, 0 otherwise.
*
*******************************************************************************/
int EwBspDisplayInit(int aGuiWidth, int aGuiHeight, XDisplayInfo *aDisplayInfo) {
    EW_UNUSED_ARG(aGuiWidth);
    EW_UNUSED_ARG(aGuiHeight);

    /* check and clean display info structure */
    if (!aDisplayInfo)
        return 0;
    memset(aDisplayInfo, 0, sizeof(XDisplayInfo));

    /* initialize given framebuffer */
    EwZero((void *) EW_FRAME_BUFFER_ADDR, EW_FRAME_BUFFER_WIDTH * EW_FRAME_BUFFER_HEIGHT * EW_FRAME_BUFFER_DEPTH);

#if EW_USE_OPERATING_SYSTEM == 1

    /* create the LCD update semaphore */
    LcdUpdateSemaphore = EwBspOsSemaphoreCreate( 1, 1 );

#endif

    /* Polarity configuration */
    /* Initialize the horizontal synchronization polarity as active low */
    hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AH;
    /* Initialize the vertical synchronization polarity as active low */
    hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AH;
    /* Initialize the data enable polarity as active low */
    hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL;
    /* Initialize the pixel clock polarity as input pixel clock */
    hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC;

// for some reason the display content is shifted.... ??? msy
#define SHIFT 1

    /* Timing configuration for LCD */
    /* Horizontal synchronization width = Hsync - 1 */
    hltdc.Init.HorizontalSync = 108 - SHIFT;
    /* Vertical synchronization height = Vsync - 1 */
    hltdc.Init.VerticalSync = 13 - SHIFT;
    /* Accumulated horizontal back porch = Hsync + HBP - 1 */
    hltdc.Init.AccumulatedHBP = 108 + 106 - SHIFT;
    /* Accumulated vertical back porch = Vsync + VBP - 1 */
    hltdc.Init.AccumulatedVBP = 13 + 11 - SHIFT;
    /* Accumulated active width = Hsync + HBP + Active Width - 1 */
    hltdc.Init.AccumulatedActiveW = 108 + 106 + 1024 - SHIFT;
    /* Accumulated active height = Vsync + VBP + Active Height - 1 */
    hltdc.Init.AccumulatedActiveH = 13 + 11 + 600 - SHIFT;
    /* Total width = Hsync + HBP + Active Width + HFP - 1 */
    hltdc.Init.TotalWidth = 108 + 106 + 1024 + 106 - SHIFT;
    /* Total height = Vsync + VBP + Active Height + VFP - 1 */
    hltdc.Init.TotalHeigh = 13 + 11 + 600 + 11 - SHIFT;

    /* Configure R,G,B component values for LCD background color */
    hltdc.Init.Backcolor.Blue = 0;
    hltdc.Init.Backcolor.Green = 0;
    hltdc.Init.Backcolor.Red = 0;

    hltdc.Instance = LTDC;

    /* Layer1 Configuration */
    LayerConfig.WindowX0 = 0;
    LayerConfig.WindowX1 = EW_FRAME_BUFFER_WIDTH;
    LayerConfig.WindowY0 = 0;
    LayerConfig.WindowY1 = EW_FRAME_BUFFER_HEIGHT;

    /* Pixel Format configuration: translate framebuffer color format into LTDC mode */
    LayerConfig.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;

    /* Start Address will be set by Graphics Engine */
    LayerConfig.FBStartAdress = (uint32_t) EW_FRAME_BUFFER_ADDR;

    /* Alpha constant (255 totally opaque) */
    LayerConfig.Alpha = 255;

    /* Default Color configuration (configure A,R,G,B component values) */
    LayerConfig.Alpha0 = 0;
    LayerConfig.Backcolor.Blue = 0;
    LayerConfig.Backcolor.Green = 0;
    LayerConfig.Backcolor.Red = 0;

    /* Configure blending factors */
    LayerConfig.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;
    LayerConfig.BlendingFactor2 = LTDC_BLENDING_FACTOR1_PAxCA;

    /* Configure the number of lines and number of pixels per line */
    LayerConfig.ImageWidth = EW_FRAME_BUFFER_WIDTH;
    LayerConfig.ImageHeight = EW_FRAME_BUFFER_HEIGHT;

    /* Configure the LTDC */
    if (HAL_LTDC_Init(&hltdc) != HAL_OK)
        EwPrint("EwBspDisplayInit: Could not configure LTDC!\n");

    /* Configure the Layer */
    if (HAL_LTDC_ConfigLayer(&hltdc, &LayerConfig, LAYER_INDEX) != HAL_OK)
        EwPrint("EwBspDisplayInit: Could not configure layer!\n");

#if EW_USE_OPERATING_SYSTEM == 1

    /* initially take the LcdUpdate token for the first LCD update */
    EwBspOsSemaphoreWait( LcdUpdateSemaphore, 1000 );

#endif

#if EW_USE_DOUBLE_BUFFER == 1

    /* Configure the vsync */
    if (HAL_LTDC_ProgramLineEvent(&hltdc, 0) != HAL_OK)
        EwPrint("EwBspDisplayInit: Could not configure interrupt for vsync!\n");

#endif

    /* return the current display configuration */
    aDisplayInfo->FrameBuffer = (void *) EW_FRAME_BUFFER_ADDR;
    aDisplayInfo->DoubleBuffer = (void *) EW_DOUBLE_BUFFER_ADDR;
    aDisplayInfo->BufferWidth = EW_FRAME_BUFFER_WIDTH;
    aDisplayInfo->BufferHeight = EW_FRAME_BUFFER_HEIGHT;
    aDisplayInfo->DisplayWidth = EW_DISPLAY_WIDTH;
    aDisplayInfo->DisplayHeight = EW_DISPLAY_HEIGHT;

#if EW_USE_DOUBLE_BUFFER == 1
    aDisplayInfo->UpdateMode = EW_BSP_DISPLAY_UPDATE_NORMAL;
#else
    aDisplayInfo->UpdateMode   = EW_BSP_DISPLAY_UPDATE_PARTIAL;
#endif

    return 1;
}

 

 

6. DMA2D

 

int EwBspGraphicsInit(uint32_t aDstColorMode) {
    /* clear entire accelerator struct including layer configurations */
    memset(&hdma2d, 0, sizeof(DMA2D_HandleTypeDef));

    /* prepare configuration of the DMA2D graphics accelerator */
    hdma2d.Instance = DMA2D;
    hdma2d.Init.Mode = DMA2D_M2M;
    hdma2d.Init.ColorMode = DMA2D_OUTPUT_RGB565;
    hdma2d.Lock = HAL_UNLOCKED;
    hdma2d.State = HAL_DMA2D_STATE_RESET;

    TransferInProgress = 0;

    /* initialize the DMA2D graphics accelerator */
    if (HAL_DMA2D_Init(&hdma2d) != HAL_OK)
        return 0;

    return 1;
}

 

 

6. Video

 

Help me.
Thank you.

1 ACCEPTED SOLUTION

Accepted Solutions
STOne-32
ST Employee

Dear @Kim KyungTack ,

It seems you already checked this application Note : https://www.st.com/resource/en/application_note/an4861-lcdtft-display-controller-ltdc-on-stm32-mcus-stmicroelectronics.pdf

 

few hints to try :

1) the color format seems 16b (RGB565) : to be confirmed  (if yes this excludes 1KB crossing issue described in AN4861)

2) section 4.6.1 : Disable FMC bank1 if not used .

3) to reduce pixel clock from 51MHz to 40MHz or less to see what happens .

Please let us know if you progressed on such behavior .

Cheers,

STOne-32

View solution in original post

3 REPLIES 3
STOne-32
ST Employee

Dear @Kim KyungTack ,

It seems you already checked this application Note : https://www.st.com/resource/en/application_note/an4861-lcdtft-display-controller-ltdc-on-stm32-mcus-stmicroelectronics.pdf

 

few hints to try :

1) the color format seems 16b (RGB565) : to be confirmed  (if yes this excludes 1KB crossing issue described in AN4861)

2) section 4.6.1 : Disable FMC bank1 if not used .

3) to reduce pixel clock from 51MHz to 40MHz or less to see what happens .

Please let us know if you progressed on such behavior .

Cheers,

STOne-32

Thank you. Since lowering the clock to 40Mhz, it works fine.

 

STOne-32
ST Employee

So Most probably it seems a Bandwidth optimization .   Is that possible to have the same video with 40MHz Clock ?