cancel
Showing results for 
Search instead for 
Did you mean: 

Display Flicker After 30–40 Days on STM32H750IBTx with LTDC and SDRAM (IS42S16160J)

Fairoosali
Visitor

Hello,

I’m working on a design using the STM32H750IBTx (LQFP176) running at 400 MHz with FreeRTOS, and I’ve encountered a strange intermittent issue with the display that only appears after long periods of operation.

Problem Description:

  • After about 30–40 days of continuous operation, the display starts to flicker and glitch.

  • Once the flicker begins, it persists continuously for around 24 hours and then self-corrects without reboot.

  • Performing a power cycle or reset also immediately clears the issue.

  • No other functional failure is observed (system remains responsive, logs continue, etc.)

System Overview:

  • Display: 800×480 RGB LCD connected via LTDC interface (RGB565 format)

  • SDRAM: 32 MB IS42S16160J-6TLI, 8192 rows

  • QSPI: 64 MB MX25L51245G
  •  

    • Connected via FMC

    • FMC clock: 200 MHz, SDRAM clock: 100 MHz (FMC clock divided by 2)

    • Refresh rate: Configured for standard 64 ms / 8192 = ~7.8 µs
      REFRESH_COUNT and other parameters are set as below

      #define REFRESH_COUNT ((uint32_t)1539) /* SDRAM refresh counter 200MHz FMC clock and 100Mhz SDRAM clock) */
      //
      //Refresh Count (RC) = (tREFI * f) / N 

      //                   =  (64ms * 200MHz)/2^13    
      //                   =  (64 * 10^-3 * 200*10^6)/2^13
      //                   = 1562.5 → 1562 → 1562 - 23 = 1539

      int32_t SDRAM_Startup(void)
      {
      SDRAM_HandleTypeDef sdramHandle;
      static FMC_SDRAM_TimingTypeDef Timing;
      static FMC_SDRAM_CommandTypeDef Command;
      __IO uint32_t tmpmrd = 0;
      static uint8_t sdramstatus ;

      /* SDRAM device configuration */
      sdramHandle.Instance = FMC_SDRAM_DEVICE;

      /* Timing configuration for 100Mhz as SDRAM clock frequency (System clock is up to 200Mhz) */
      Timing.LoadToActiveDelay = 2;
      Timing.ExitSelfRefreshDelay = 7;
      Timing.SelfRefreshTime = 5;
      Timing.RowCycleDelay = 7;
      Timing.WriteRecoveryTime = 5;
      Timing.RPDelay = 2;
      Timing.RCDDelay = 2;

      sdramHandle.Init.SDBank = FMC_SDRAM_BANK1;
      sdramHandle.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;
      sdramHandle.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;
      sdramHandle.Init.MemoryDataWidth = SDRAM_MEMORY_WIDTH;
      sdramHandle.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
      sdramHandle.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;
      sdramHandle.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
      sdramHandle.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
      sdramHandle.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
      sdramHandle.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;

      /* SDRAM controller initialization */

      SDRAM_MspInit();

      if(HAL_SDRAM_Init(&sdramHandle, &Timing) != HAL_OK)
      {
      sdramstatus = MEMORY_ERROR;
      }
      else
      {
      /* SDRAM initialization sequence */
      /* Step 1: Configure a clock configuration enable command */
      Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
      Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
      Command.AutoRefreshNumber = 1;
      Command.ModeRegisterDefinition = 0;

      /* Send the command */
      HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT);

      /* Step 2: Insert 100 us minimum delay */
      /* Inserted delay is equal to 1 ms due to systick time base unit (ms) */
      HAL_Delay(1);

      /* Step 3: Configure a PALL (precharge all) command */
      Command.CommandMode = FMC_SDRAM_CMD_PALL;
      Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
      Command.AutoRefreshNumber = 1;
      Command.ModeRegisterDefinition = 0;

      /* Send the command */
      HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT);

      /* Step 4: Configure an Auto Refresh command */
      Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
      Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
      Command.AutoRefreshNumber = 8;
      Command.ModeRegisterDefinition = 0;

      /* Send the command */
      HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT);

      /* Step 5: Program the external memory mode register */
      tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 |\
      SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |\
      SDRAM_MODEREG_CAS_LATENCY_3 |\
      SDRAM_MODEREG_OPERATING_MODE_STANDARD |\
      SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;

      Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
      Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
      Command.AutoRefreshNumber = 1;
      Command.ModeRegisterDefinition = tmpmrd;

      /* Send the command */
      HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT);

      /* Step 6: Set the refresh rate counter */
      /* Set the device refresh rate */
      HAL_SDRAM_ProgramRefreshRate(&sdramHandle, REFRESH_COUNT);

      sdramstatus = MEMORY_OK;
      }
      RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};

      /** Initializes the peripherals clock
      */
      PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_FMC;
      PeriphClkInitStruct.FmcClockSelection = RCC_FMCCLKSOURCE_D1HCLK;
      if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
      {
      // Error_Handler();
      }

      /* Peripheral clock enable */
      __HAL_RCC_FMC_CLK_ENABLE();
      return sdramstatus;
      }

       

       

      MPU Configurations: Here are the MPU settings, MPU region for QSPI flash starting at 0x90000000, MPU region for SDRAM start at base address of 0xC0000000 and its of 32MB, 25 MB used for running code and data, storing images and 3MB used as frame buffer and the last 4MB used as DMA buffer.

      //In my bootloader code
      static void MPU_Config (void)
      {
      /* Disables the MPU */
      HAL_MPU_Disable();
      MPU_Region_InitTypeDef MPU_InitStruct = {0};

      /** Initializes and configures the Region and the memory to be protected
      */
      // Memory-mapped External Flash
      // Disable outside of allocation
      MPU_InitStruct.Number = MPU_REGION_NUMBER0;
      MPU_InitStruct.BaseAddress = 0x90000000;
      MPU_InitStruct.Size = MPU_REGION_SIZE_256MB;
      MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
      MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
      MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
      MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
      HAL_MPU_ConfigRegion(&MPU_InitStruct);


      // Memory-mapped SDRAM
      // Disable outside of allocation
      MPU_InitStruct.Number = MPU_REGION_NUMBER1;
      MPU_InitStruct.Enable = MPU_REGION_ENABLE;
      MPU_InitStruct.BaseAddress = 0xC0000000;
      MPU_InitStruct.Size = MPU_REGION_SIZE_256MB;
      MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
      MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
      MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
      MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
      HAL_MPU_ConfigRegion(&MPU_InitStruct);

      // Enable SDRAM if present, where 25MB used for code and data, code is running on SDRAM
      MPU_InitStruct.Number = MPU_REGION_NUMBER2;
      MPU_InitStruct.Size = MPU_REGION_SIZE_32MB;
      MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
      MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
      MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
      MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
      MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
      MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
      MPU_InitStruct.SubRegionDisable = 0x00;
      HAL_MPU_ConfigRegion(&MPU_InitStruct);

      //Set MPU config for the Graphics buffer/frame buffer area of 3MB
      /* ----------------------------------------------------------------------------
      * Region 3: frame buffer (0xC0000000 + 25 MB … +28 MB)
      * – Actual size 3 MB; last 1 MB of the 4 MB region is disabled via SubRegionDisable
      * ----------------------------------------------------------------------------
      */
      MPU_InitStruct.Enable = MPU_REGION_ENABLE;
      MPU_InitStruct.Number = MPU_REGION_NUMBER3;
      MPU_InitStruct.BaseAddress = 0xC1900000; //0xC0000000 + 25*1024*1024;
      MPU_InitStruct.Size = MPU_REGION_SIZE_4MB; // region size must be a power of two
      MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; // RW for CPU & GPU/DMA
      MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; // no code execution
      MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE; // preferred for performance
      MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
      MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
      MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
      // Disable subregions 6 & 7 (highest 1 MB out of 4 MB)
      MPU_InitStruct.SubRegionDisable = (1 << 6) | (1 << 7); //Subregion size: If your region size is 4MB, each subregion will be 4MB / 8 = 0.5MB (512KB).
      //To isable the last 1MB set SubRegionDisable = b11000000 = 0xC0
      HAL_MPU_ConfigRegion(&MPU_InitStruct);

      /* Enable the MPU */
      HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
      }

      //In my functional firmware
      // MPU is already configured by the bootloader - just
      // need to define any specific app requirements.
      // Disable caching for the DMA-affected regions
      void MPU_Manual_Config(void)
      {
      MPU_Region_InitTypeDef MPU_InitStruct = {0};

      // Disable cache for the DMA-affected regions.
      // The address is taken from the linker file, but
      // the size MUST be manually maintained as the correct size.
      // It is important to ensure that the region number is also correct
      // in relation to those regions configured in the bootloader.
      MPU_InitStruct.Enable = MPU_REGION_ENABLE;
      MPU_InitStruct.Number = MPU_REGION_NUMBER4;
      MPU_InitStruct.BaseAddress = (uint32_t) &_dma_buffer_section;
      MPU_InitStruct.Size = MPU_REGION_SIZE_4MB;
      MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
      MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
      MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
      MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
      MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
      MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;

      HAL_MPU_ConfigRegion(&MPU_InitStruct);
      }

 Memory Usage:

  • Firmware is stored in external QSPI flash, and during boot:

    • Code is copied to SDRAM and executed from there (i.e., SDRAM is used in XIP mode)

    • Images are copied to SDRAM from QSPI flash
    • A graphics buffer of ~3 MB is also placed in SDRAM

    • A DMA buffer of 4 MB is allocated in SDRAM for image transfers

Questions:

  1. Could this be caused by MPU misconfiguration or cache coherency issues specific to long-term operation?

  2. Is it possible the SDRAM self-refresh or retention is failing after a long uptime despite correct timing setup?

  3. Could this relate to speculative AXI accesses or improper cache alignment?

  4. Any suggestions to trace the source of this 24-hour flicker cycle?

I would appreciate any insights or similar experiences regarding this kind of long-uptime flicker behavior involving SDRAM and LTDC. Happy to share more information if needed.

Thanks in advance!

 

0 REPLIES 0