cancel
Showing results for 
Search instead for 
Did you mean: 

Horizontal glitches on LTDC display during I2C/FRAM transfers with DMA

CiuppaPT
Associate III

 

Hi,
I am working with an STM32F769 MCU driving a 480×272 RGB565 TFT display through LTDC.

Architecture:

  • Framebuffer in external SDRAM (IS42S16800F-7TL, 16 MB) connected via FMC.

  • LTDC + DMA2D used for graphics update (TouchGFX).

  • I²C + DMA used to read/write parameters on an external FRAM.

  • System managed with FreeRTOS.

Problem:
When a long I²C DMA transfer is running (FRAM read/write for parameter storage), I see horizontal glitches on the display: objects temporarily shift to the right (as if some pixels were missing).

The curious part is that the phenomenon only happens if I change the initialization sequence in main() from this:

 

MX_LTDC_Init();
HAL_Delay(1000);  // avoid flickering on display
MX_TouchGFX_Init();
HAL_Delay(200);  // avoid flickering on display
osKernelInitialize();

…to this:

MX_LTDC_Init();
HAL_Delay(1000);  // avoid flickering on display
MX_TouchGFX_Init();
HAL_Delay(200);  // avoid flickering on display
__NOP();   // added
__NOP();   // added
osKernelInitialize();

adding only 2 _NOP();
really can’t explain why just adding, in this init sequence, two NOP  instructions makes the glitch appear.

21 REPLIES 21

Ok as I said, it could not solve the issue but that's something recommended. 

Could you please share your full MPU configuration? are you sure you called MPU_Config() in main() just before the cache enable?

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

I share  my actual MPU_config 

void MPU_Config(void)
{
  MPU_Region_InitTypeDef MPU_InitStruct = {0};

  /* Disables the MPU */
  HAL_MPU_Disable();

  /* Configure the MPU as Strongly ordered for not defined regions */
   MPU_InitStruct.Enable = MPU_REGION_ENABLE;
   MPU_InitStruct.BaseAddress = 0x00;
   MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;
   MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
   MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
   MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
   MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
   MPU_InitStruct.Number = MPU_REGION_NUMBER0;
   MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
   MPU_InitStruct.SubRegionDisable = 0x87;
   MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;

   HAL_MPU_ConfigRegion(&MPU_InitStruct);


  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER0;
  MPU_InitStruct.BaseAddress = 0x90000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_256MB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);


  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER1;
  MPU_InitStruct.BaseAddress = 0xC0000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_16MB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;


  HAL_MPU_ConfigRegion(&MPU_InitStruct);

  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Number = MPU_REGION_NUMBER2;
  MPU_InitStruct.BaseAddress = 0x90000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_64MB;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);

  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Number = MPU_REGION_NUMBER3;
  MPU_InitStruct.BaseAddress = 0xC00C0000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_1MB;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);

  MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
  MPU_InitStruct.BaseAddress      = 0xC0000000;        // Base SDRAM framebuffer
  MPU_InitStruct.Size             = MPU_REGION_SIZE_256KB;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;
  MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE; // MPU_ACCESS_CACHEABLE;   // Non-cacheable
  MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;       // opzionale, dipende se altri core/DMA accedono
  MPU_InitStruct.Number           = MPU_REGION_NUMBER4;
  MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
  MPU_InitStruct.SubRegionDisable = 0x00;                     // tutte abilitate
  MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_DISABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);

//  HAL_MPU_ConfigRegion(&MPU_InitStruct);

  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Number = MPU_REGION_NUMBER5;
  MPU_InitStruct.BaseAddress = 0XC01C8000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_32KB;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /* Enables the MPU */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

}

 

You kept the region number = 0 for the second region which overwrites the first one:

MPU_InitStruct.Number = MPU_REGION_NUMBER0;

You need to increment all the region numbers starting from the QSPI region:

MPU_InitStruct.Number = MPU_REGION_NUMBER1;

 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
CiuppaPT
Associate III

I share also Linker script file

/* Memories definition */
MEMORY
{
  RAM_DMA					(xrw)						: ORIGIN = 0x20000000,   LENGTH = 128K
  RAM    					(xrw)    					: ORIGIN = 0x20020000,   LENGTH = (512K - 128K)
  FLASH   					(rx)    					: ORIGIN = 0x08000000,   LENGTH = (1024K - 8) 	/* flash size has been halved to allow for dual-bank */
  FLASH_METADATA			(rx)						: ORIGIN = 0x080FFFF8,	 LENGTH = 8
  QUADSPI 					(rx)   						: ORIGIN = 0x90000000,   LENGTH = 16M           /* external flash size has been halved to allow for dual-bank */
  QUADSPI_COMMON_DATA   	(rx)						: ORIGIN = 0x92000000,   LENGTH = 32M
  /* the fist 256K are declared for the HMI frame buffer and cannot be used by others */
  EXTERNAL_RAM_DS 			(xrw)						: ORIGIN = 0xC0040000,   LENGTH = 512K
  /*EXTERNAL_RAM_FREERTOS_HEAP(xrw) 					: ORIGIN = 0xC00C0000,   LENGTH = 512K */
  /*EXTERNAL_RAM_LWIP     	(xrw)						: ORIGIN = 0xC0140000,   LENGTH = 16K  */
  /*EXTERNAL_RAM_DATA			(xrw)					: ORIGIN = 0xC0144000,   LENGTH = (16M - 256K -512K - 512K - 16K) */
 
  /* aumentato da 512K a 768K */
  EXTERNAL_RAM_FREERTOS_HEAP  (xrw)                     : ORIGIN = 0xC00C0000,   LENGTH = 1M
  /* LWIP rimane invariato */
  EXTERNAL_RAM_LWIP           (xrw)                     : ORIGIN = 0xC01C0000,   LENGTH = 32K

  EXTERNAL_RAM_LWIP_HEAP      (xrw)                     : ORIGIN = 0XC01C8000,   LENGTH = 32K
  EXTERNAL_RAM_DATA           (xrw)                     : ORIGIN = 0xC01D0000,   LENGTH = (16M - 256K - 1M - 512K - 32K - 32K) 

}
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MPU Configuration--------------------------------------------------------*/
  MPU_Config();

  /* Enable the CPU Cache */

  /* Enable I-Cache---------------------------------------------------------*/
  SCB_EnableICache();

  /* Enable D-Cache---------------------------------------------------------*/
  SCB_EnableDCache();

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

You're right, I forgot to update the order when I added the foreground init but now that I've done so, when It call MX_FMC_init(), it fall into MemManage_Handler(). 
Did I forget to add some sections to MPU_config?

Try to reorganize your MPU config many scattered regions, maybe there is something not correct when you are using the same config for the next region.

For example, this MPU region config is not useful:

  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER0;
  MPU_InitStruct.BaseAddress = 0x90000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_256MB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);

That was already disabled by the background region.

Reorganize the MPU config of the SDRAM by incremental address, you have many scattered regions there, and don't use an already initialized member in the MPU structure. Set it again in the new region etc ..

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
CiuppaPT
Associate III

Couldn’t this be the cause of our problem? Reference from AN4861.

CiuppaPT_0-1758211241052.png

 


@CiuppaPT wrote:

Couldn’t this be the cause of our problem? Reference from AN4861.

CiuppaPT_0-1758211241052.png

 


The first MPU config, I provided to you (the background config) prevents that issue to occur. Moreover, the workaround of that limitation was already implemented in the system_stm32f7xx.c file / line 632:

  /*
   * Disable the FMC bank1 (enabled after reset).
   * This, prevents CPU speculation access on this bank which blocks the use of FMC during
   * 24us. During this time the others FMC master (such as LTDC) cannot use it!
   */
  FMC_Bank1->BTCR[0] = 0x000030d2;
  
  (void)(tmp);
}

Now, as I said, try to reorganize your MPU config.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
CiuppaPT
Associate III

My system_stm32f7xx.c ends at line 268 ( CMSIS Device version number V1.2.8 ) and not include line line 632 with the...

 FMC_Bank1->BTCR[0] = 0x000030d2;