cancel
Showing results for 
Search instead for 
Did you mean: 

TouchGFX STM32L4R9I-EVAL : Why it's working using internal but not external SRAM ?

Tooky
Associate II

Dear all,

Sorry if my english is not clear, and let me know if something is not clear.

I need help...

Using  an STM32L4R9i Eval and the following "modules" HW and SW : Round TFT (MB1314), touchGFX, FMC (External SRAM), DSI/MIPI (LTDC), DMA2D.

I'm struggling since few days to a display issue.

OK : Using the internal SRAM and all the related configuration for previous modules everything is working fine.

NOK : Changing the previous configuration but using the external SRAM, available on the evaluation board (through the FMC), my picture, in that case is not correctly displayed.

But I can see that the external SRAM is correctly fill, through the debugger.

I guess that it should come from a synchronization between the FMC, DMA2D and the LTDC... but this is a completely new topic for me, and I'm not an expert.

Does someone can help me, to know in which direction I should look for ?

Let me know if you need more details, code or

Thank you in advance for your help.

1 ACCEPTED SOLUTION

Accepted Solutions
Tooky
Associate II

I succeeded to solve my issue, it was coming from a wrong configuration of the FMC timing :

Before :

  Timing.AddressSetupTime = 15;
  Timing.AddressHoldTime = 15;
  Timing.DataSetupTime = 255;
  Timing.DataHoldTime = 0;
  Timing.BusTurnAroundDuration = 15;
  Timing.CLKDivision = 16;
  Timing.DataLatency = 17;
  Timing.AccessMode = FMC_ACCESS_MODE_A;

After :

  Timing.AddressSetupTime       = 2;
  Timing.AddressHoldTime        = 1;                    
  Timing.DataSetupTime          = 1;
  Timing.DataHoldTime           = 1;
  Timing.BusTurnAroundDuration  = 0;
  Timing.CLKDivision            = 2;                    
  Timing.DataLatency            = 2;  

View solution in original post

4 REPLIES 4
MM..1
Chief II

Your info is unusable for support. Use external SRAM require perfect clock config and init memory.

You dont show how you create NOK change...

Tooky
Associate II

Thank you for your answer MM!

Below this is my clock configuration (using the IDE generator)

0693W00000Nrz2BQAR.png 

Let me know if you need me to display the related code generated.

The init code for the FMC (For SRAM interface) :

void MX_FMC_Init(void)
{
  FMC_NORSRAM_TimingTypeDef Timing = {0};
 
  hsram1.Instance = FMC_NORSRAM_DEVICE;
  hsram1.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
  hsram1.Init.NSBank = FMC_NORSRAM_BANK1;
  hsram1.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
  hsram1.Init.MemoryType = FMC_MEMORY_TYPE_SRAM;
  hsram1.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_16;
  hsram1.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE;
  hsram1.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW;
  hsram1.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
  hsram1.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
  hsram1.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
  hsram1.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
  hsram1.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE;
  hsram1.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
  hsram1.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
  hsram1.Init.WriteFifo = FMC_WRITE_FIFO_ENABLE;
  hsram1.Init.NBLSetupTime = 0;
  hsram1.Init.PageSize = FMC_PAGE_SIZE_NONE;
  Timing.AddressSetupTime = 15;
  Timing.AddressHoldTime = 15;
  Timing.DataSetupTime = 255;
  Timing.DataHoldTime = 0;
  Timing.BusTurnAroundDuration = 15;
  Timing.CLKDivision = 16;
  Timing.DataLatency = 17;
  Timing.AccessMode = FMC_ACCESS_MODE_A;
  if (HAL_SRAM_Init(&hsram1, &Timing, NULL) != HAL_OK)
  {
    Error_Handler( );
  }
}

The DMA2D init part :

void MX_DMA2D_Init(void)
{
  hdma2d.Instance = DMA2D;
  hdma2d.Init.Mode = DMA2D_M2M;
  hdma2d.Init.ColorMode = DMA2D_OUTPUT_RGB888;
  hdma2d.Init.OutputOffset = 0;
  hdma2d.Init.BytesSwap = DMA2D_BYTES_REGULAR;
  hdma2d.Init.LineOffsetMode = DMA2D_LOM_PIXELS;
  hdma2d.LayerCfg[1].InputOffset = 0;
  hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_RGB888;
  hdma2d.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;
  hdma2d.LayerCfg[1].InputAlpha = 0;
  hdma2d.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;
  hdma2d.LayerCfg[1].RedBlueSwap = DMA2D_RB_REGULAR;
  if (HAL_DMA2D_Init(&hdma2d) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) != HAL_OK)
  {
    Error_Handler();
  }
}

The DSI part :

void MX_DSIHOST_DSI_Init(void)
{
  DSI_PLLInitTypeDef PLLInit = {0};
  DSI_HOST_TimeoutTypeDef HostTimeouts = {0};
  DSI_PHY_TimerTypeDef PhyTimings = {0};
  DSI_LPCmdTypeDef LPCmd = {0};
  DSI_CmdCfgTypeDef CmdCfg = {0};
 
  hdsi.Instance = DSI;
  hdsi.Init.AutomaticClockLaneControl = DSI_AUTO_CLK_LANE_CTRL_DISABLE;
  hdsi.Init.TXEscapeCkdiv = 4;
  hdsi.Init.NumberOfLanes = DSI_ONE_DATA_LANE;
  PLLInit.PLLNDIV = 125;
  PLLInit.PLLIDF = DSI_PLL_IN_DIV4;
  PLLInit.PLLODF = DSI_PLL_OUT_DIV1;
  if (HAL_DSI_Init(&hdsi, &PLLInit) != HAL_OK)
  {
    Error_Handler();
  }
  HostTimeouts.TimeoutCkdiv = 1;
  HostTimeouts.HighSpeedTransmissionTimeout = 0;
  HostTimeouts.LowPowerReceptionTimeout = 0;
  HostTimeouts.HighSpeedReadTimeout = 0;
  HostTimeouts.LowPowerReadTimeout = 0;
  HostTimeouts.HighSpeedWriteTimeout = 0;
  HostTimeouts.HighSpeedWritePrespMode = DSI_HS_PM_DISABLE;
  HostTimeouts.LowPowerWriteTimeout = 0;
  HostTimeouts.BTATimeout = 0;
  if (HAL_DSI_ConfigHostTimeouts(&hdsi, &HostTimeouts) != HAL_OK)
  {
    Error_Handler();
  }
  PhyTimings.ClockLaneHS2LPTime = 28;
  PhyTimings.ClockLaneLP2HSTime = 33;
  PhyTimings.DataLaneHS2LPTime = 15;
  PhyTimings.DataLaneLP2HSTime = 25;
  PhyTimings.DataLaneMaxReadTime = 0;
  PhyTimings.StopWaitTime = 0;
  if (HAL_DSI_ConfigPhyTimer(&hdsi, &PhyTimings) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_DSI_ConfigFlowControl(&hdsi, DSI_FLOW_CONTROL_BTA) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_DSI_SetLowPowerRXFilter(&hdsi, 10000) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_DSI_ConfigErrorMonitor(&hdsi, HAL_DSI_ERROR_NONE) != HAL_OK)
  {
    Error_Handler();
  }
  LPCmd.LPGenShortWriteNoP = DSI_LP_GSW0P_DISABLE;
  LPCmd.LPGenShortWriteOneP = DSI_LP_GSW1P_DISABLE;
  LPCmd.LPGenShortWriteTwoP = DSI_LP_GSW2P_DISABLE;
  LPCmd.LPGenShortReadNoP = DSI_LP_GSR0P_DISABLE;
  LPCmd.LPGenShortReadOneP = DSI_LP_GSR1P_DISABLE;
  LPCmd.LPGenShortReadTwoP = DSI_LP_GSR2P_DISABLE;
  LPCmd.LPGenLongWrite = DSI_LP_GLW_DISABLE;
  LPCmd.LPDcsShortWriteNoP = DSI_LP_DSW0P_DISABLE;
  LPCmd.LPDcsShortWriteOneP = DSI_LP_DSW1P_DISABLE;
  LPCmd.LPDcsShortReadNoP = DSI_LP_DSR0P_DISABLE;
  LPCmd.LPDcsLongWrite = DSI_LP_DLW_DISABLE;
  LPCmd.LPMaxReadPacket = DSI_LP_MRDP_DISABLE;
  LPCmd.AcknowledgeRequest = DSI_ACKNOWLEDGE_DISABLE;
  if (HAL_DSI_ConfigCommand(&hdsi, &LPCmd) != HAL_OK)
  {
    Error_Handler();
  }
  CmdCfg.VirtualChannelID = 0;
  CmdCfg.ColorCoding = DSI_RGB888;
  CmdCfg.CommandSize = 390;
  CmdCfg.TearingEffectSource = DSI_TE_DSILINK;
  CmdCfg.TearingEffectPolarity = DSI_TE_RISING_EDGE;
  CmdCfg.HSPolarity = DSI_HSYNC_ACTIVE_HIGH;
  CmdCfg.VSPolarity = DSI_VSYNC_ACTIVE_LOW;
  CmdCfg.DEPolarity = DSI_DATA_ENABLE_ACTIVE_HIGH;
  CmdCfg.VSyncPol = DSI_VSYNC_FALLING;
  CmdCfg.AutomaticRefresh = DSI_AR_ENABLE;
  CmdCfg.TEAcknowledgeRequest = DSI_TE_ACKNOWLEDGE_DISABLE;
  if (HAL_DSI_ConfigAdaptedCommandMode(&hdsi, &CmdCfg) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_DSI_SetGenericVCID(&hdsi, 0) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_DSI_Start(&hdsi) != HAL_OK)
    {
      Error_Handler();
    }
    RCC_PeriphCLKInitTypeDef PeriphClkInit;
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_DSI;
    PeriphClkInit.DsiClockSelection    = RCC_DSICLKSOURCE_DSIPHY;
    HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
}

And the LTDC configuration :

void MX_LTDC_Init(void)
{
  LTDC_LayerCfgTypeDef pLayerCfg = {0};
 
  hltdc.Instance = LTDC;
  hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL;
  hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL;
  hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL;
  hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
  hltdc.Init.HorizontalSync = 4;
  hltdc.Init.VerticalSync = 4;
  hltdc.Init.AccumulatedHBP = 9;
  hltdc.Init.AccumulatedVBP = 9;
  hltdc.Init.AccumulatedActiveW = 399;
  hltdc.Init.AccumulatedActiveH = 399;
  hltdc.Init.TotalWidth = 400;
  hltdc.Init.TotalHeigh = 400;
  hltdc.Init.Backcolor.Blue = 0;
  hltdc.Init.Backcolor.Green = 255;
  hltdc.Init.Backcolor.Red = 255;
  if (HAL_LTDC_Init(&hltdc) != HAL_OK)
  {
    Error_Handler();
  }
  pLayerCfg.WindowX0 = 0;
  pLayerCfg.WindowX1 = 390;
  pLayerCfg.WindowY0 = 0;
  pLayerCfg.WindowY1 = 390;
  pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB888;
  pLayerCfg.Alpha = 255;
  pLayerCfg.Alpha0 = 0;
  pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA;
  pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA;
  pLayerCfg.FBStartAdress = 0;
  pLayerCfg.ImageWidth = 390;
  pLayerCfg.ImageHeight = 390;
  pLayerCfg.Backcolor.Blue = 255;
  pLayerCfg.Backcolor.Green = 0;
  pLayerCfg.Backcolor.Red = 0;
  if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_DSI_ShortWrite(&hdsi, 0, DSI_DCS_SHORT_PKT_WRITE_P0, DSI_EXIT_SLEEP_MODE, 0x00) != HAL_OK)
    {
      Error_Handler();
    }
  HAL_Delay(120);
}

In the main function :

MX_GPIO_Init();
  MX_USART3_UART_Init();
  MX_LTDC_Init();
  MX_DSIHOST_DSI_Init();
  MX_CRC_Init();
  MX_DMA_Init();
  MX_TIM6_Init();
  MX_FMC_Init();
  MX_DMA2D_Init();
  MX_TouchGFX_Init();
 
  /*##-2- SRAM memory read/write access ######################################*/
    /* Fill the buffer to write */
    Fill_Buffer(aTxBuffer, BUFFER_SIZE, 0xC20F);
 
    /* Write data to the SRAM memory */
    for(uwIndex = 0; uwIndex < BUFFER_SIZE; uwIndex++)
    {
      *(__IO uint32_t *)(SRAM_BANK_ADDR + WRITE_READ_ADDR + 4 * uwIndex) = aTxBuffer[uwIndex];
    }
 
    /* Read back data from the SRAM memory */
    for(uwIndex = 0; uwIndex < BUFFER_SIZE; uwIndex++)
    {
      aRxBuffer[uwIndex] = *(__IO uint32_t *)(SRAM_BANK_ADDR + WRITE_READ_ADDR + 4 * uwIndex);
    }
 
    uwWriteReadStatus = Buffercmp(aTxBuffer, aRxBuffer, BUFFER_SIZE);
 
    if(uwWriteReadStatus != PASSED)
    {
      /* KO */
      /* Turn on LED2 */
      BSP_LED_On(LED2);
    }
    else
    {
      /* OK */
      /* Turn on LED1 */
      BSP_LED_On(LED1);
    }

From there everything is ok and the LED1 is ON.

/* Reset the LCD by activation of XRES (active low) */
    BSP_IO_Init();
    HAL_TIM_Base_Start(&htim6);
    HAL_Delay(200);
 
    /* Configure the GPIO connected to XRES signal */
    BSP_IO_ConfigPin(IO_PIN_9, IO_MODE_OUTPUT);
    /*Configure GPIO pin Output Level */
    /* Activate XRES (active low) */
    BSP_IO_WritePin(IO_PIN_9, GPIO_PIN_RESET);
    /* Wait at least 1 ms (reset low pulse width) */
    HAL_Delay(200);
    /* Deactivate XRES */
    BSP_IO_WritePin(IO_PIN_9, GPIO_PIN_SET);
 
    /* Wait reset complete time (maximum time is 5ms when LCD in sleep mode and 120ms when LCD is not in sleep mode) */
    HAL_Delay(200);
 
    /* Initialize the LCD   */
/* Sending all the sequence needed for LCD initialization */
    if(LCD_Config() != LCD_OK)
    {
      Error_Handler();
    }
 
    HAL_Delay(200);
  while (1)
  {
  MX_TouchGFX_Process();
}

And from there the SRAM (watched through the debugger seems to be correcly filled, comparing the internal in the previous configuration and the current external RAM), But not correctly sent to the LCD

Let me know if you need more details.

Tooky
Associate II

Additional information : I have continously the following callback : HAL_LTDC_ErrorCallback

Tooky
Associate II

I succeeded to solve my issue, it was coming from a wrong configuration of the FMC timing :

Before :

  Timing.AddressSetupTime = 15;
  Timing.AddressHoldTime = 15;
  Timing.DataSetupTime = 255;
  Timing.DataHoldTime = 0;
  Timing.BusTurnAroundDuration = 15;
  Timing.CLKDivision = 16;
  Timing.DataLatency = 17;
  Timing.AccessMode = FMC_ACCESS_MODE_A;

After :

  Timing.AddressSetupTime       = 2;
  Timing.AddressHoldTime        = 1;                    
  Timing.DataSetupTime          = 1;
  Timing.DataHoldTime           = 1;
  Timing.BusTurnAroundDuration  = 0;
  Timing.CLKDivision            = 2;                    
  Timing.DataLatency            = 2;