cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H755BIT DMA2D + FMC + External SRAM Write Issue

DanMI
Associate

I am using the DMA2D to transfer colour data to an external SRAM using the FMC with an 8-bit parallel hardware setup. I can use the following line of code on the CM7 CPU to write to any in-range address (0x68000000 base) with any pointer type (uint8_t, uint16_t, uint32_t, uint64_t) with no issues:

uint16_t * const externalRAM = (uint16_t*)0x68000000;
externalRAM[INDEX] = 0xFFFF;

The logic analyser output of a write with INDEX set to 2U (No issues):
_legacyfs_online_stmicro_images_0693W00000bihSEQAY.png 

To produce no issues when writing with the CPU, the MPU has been used to set up the external SRAM buffer region as non-cacheable (see config below). If this is NOT done, the FMC will write to a full 64-bit region even if a single-byte write attempt is made. The remaining bytes will be corrupted (suspected cache related).

MPU_Region_InitTypeDef MPU_InitStruct = {0};
 
  /* Disables the MPU */
  HAL_MPU_Disable();
 
  /** 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 = 0x68000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
 
  HAL_MPU_ConfigRegion(&MPU_InitStruct);
 
  /* Enables the MPU */
  HAL_MPU_Enable(MPU_HFNMI_PRIVDEF);
 

When using the DMA2D to write to the external buffer (with the MPU configured correctly), if the start or end addresses of a transaction don't align with a 64-bit boundary, the remaining bytes in that 64-bit region will be corrupted. This does not occur if the internal memory is used for the target buffer. See the following logic analyser output when starting a DMA2D transfer with the target address set to 0x68000002 and colour data set to 0xFFFF. The FMC is writing garbage data (0x00) to the first 2 bytes of the 64-bit region. If the DMA2D target address was set to 0x68000003, the first 3 bytes would become corrupted.


_legacyfs_online_stmicro_images_0693W00000bihT2QAI.png 

I have tried enabling DCache and manually clearing the cache before the start of each DMA2D transfer, but this has had no affect:

const    uint32_t colourData   = 0xFFFFFFFF;
  const    uint32_t baseAddress  = 0x68000000;
  volatile uint32_t bufferOffset = 0x02;
  const    uint32_t width        = 40U;
  const    uint32_t height       = 1U;    
  
  SCB_CleanDCache_by_Addr((uint32_t*)0x68000000, 261120);
  
  __DSB();
  
  if (HAL_DMA2D_Start(&_hdma2d, colourData, (baseAddress + bufferOffset), width, height) == HAL_OK)
  {
    HAL_DMA2D_PollForTransfer(&_hdma2d, 10);
  }
  
  __DSB();
  
  SCB_InvalidateDCache_by_Addr((uint32_t*)0x68000000, 261120);

I have tried slowing down the FMC timings, also to no effect. Manual write/read tests from the CM7 CPU pass for the full external buffer range. See FMC setup:

FunctionStatus_t FMC_Init(void)
{
  FunctionStatus_t statusReturn = FUNCTION_OK;
 
  FMC_NORSRAM_TimingTypeDef Timing = {0};
 
 
  /** Perform the SRAM1 memory initialization sequence
  */
  hsram1.Instance = FMC_NORSRAM_DEVICE;
  hsram1.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
  
  /* hsram1.Init */
  hsram1.Init.NSBank             = FMC_NORSRAM_BANK3;
  hsram1.Init.DataAddressMux     = FMC_DATA_ADDRESS_MUX_DISABLE;
  hsram1.Init.MemoryType         = FMC_MEMORY_TYPE_SRAM;
  hsram1.Init.MemoryDataWidth    = FMC_NORSRAM_MEM_BUS_WIDTH_8;
  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_DISABLE;
  hsram1.Init.PageSize           = FMC_PAGE_SIZE_NONE;
  
  /* Bus Timing Configuration */
  Timing.AddressSetupTime        = 1;
  Timing.AddressHoldTime         = 0; /* No Impact */
  Timing.DataSetupTime           = 5;
  Timing.BusTurnAroundDuration   = 0; /* No Impact */
  Timing.CLKDivision             = 0; /* No Impact */
  Timing.DataLatency             = 0; /* No Impact */
  Timing.AccessMode              = FMC_ACCESS_MODE_A;
 
  /* Init */
  if (HAL_SRAM_Init(&hsram1, &Timing, NULL) != HAL_OK)
  {
    statusReturn = FUNCTION_ERROR;
  }
  
  return (statusReturn);
}

I have tried using the following line to swap the external buffer base address to 0xC8000000 with no change in corrupted output after DMA2D transfer:

HAL_SetFMCMemorySwappingConfig(FMC_SWAPBMAP_SDRAM_SRAM);

DMA2D setup for reference:

_hdma2d.Instance          = DMA2D;
  _hdma2d.Init.Mode         = DMA2D_R2M;
  _hdma2d.Init.ColorMode    = DMA2D_OUTPUT_RGB565;
  _hdma2d.Init.OutputOffset = 0;
  
  HAL_NVIC_SetPriority(DMA2D_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2D_IRQn);
  
  if (HAL_DMA2D_Init(&_hdma2d) != HAL_OK)
  {
    Error_Handler();
  }

External SRAM MPN:

RMLV0408EGSP-4S2#CA1

Any guidance/advice is greatly appreciated.

1 REPLY 1
DanMI
Associate

I could adjust any line/rectangle draw functions to manually write the bytes that are not 64-bit aligned and then use the DMA2D for the remainder. However, the issue occurs whenever a new line starts/ends on a DMA2D rectangle draw before/after the offset from OOR is applied - making the rectangle draw functionality useless if the draw starts or ends on a non-64-bit aligned address.

Would it be possible to get someone from ST to confirm whether this behavior is expected when using the DMA2D + FMC + External SRAM with 8-bit hardware?

It feels like there is a low-level interoperability issue between the DMA2D and External SRAM but it would be great to be proven wrong. Thanks.