Skip to main content
DanMI
Associate
April 24, 2023
Question

STM32H755BIT DMA2D + FMC + External SRAM Write Issue

  • April 24, 2023
  • 1 reply
  • 1913 views

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.

This topic has been closed for replies.

1 reply

DanMI
DanMIAuthor
Associate
April 25, 2023

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.