STM32H7S3L8: MPU non-cacheable SRAM2 region prevents CPU writes
Hi,
I am using an STM32H7S3L8 with D-Cache enabled and want to place DMA buffers in a dedicated non-cacheable SRAM region.
My linker script places the DMA section in SRAM2:
SRAMAHB (rw) : ORIGIN = 0x30000000, LENGTH = 16K
SRAM_DMA (xrw) : ORIGIN = 0x30004000, LENGTH = 16K
.dma_buffer (NOLOAD) :
{
. = ALIGN(32);
__dma_buffer_start__ = .;
KEEP(*(.dma_buffer))
KEEP(*(.dma_buffer*))
. = ALIGN(32);
__dma_buffer_end__ = .;
} > SRAM_DMAThe DMA buffer is correctly linked at 0x30004000.
I configured the MPU according to the non-cacheable DMA buffer strategy described in ST's article. The relevant configuration is:
static void MPU_Config(void)
{
MPU_Region_InitTypeDef MPU_InitStruct = {0};
/* Disables the MPU */
HAL_MPU_Disable();
/* Disables all MPU regions */
for(uint8_t i=0; i<__MPU_REGIONCOUNT; i++)
{
HAL_MPU_DisableRegion(i);
}
/** 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 = 0x0;
MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;
MPU_InitStruct.SubRegionDisable = 0x87;
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);
/** Initializes and configures the Region and the memory to be protected
*/
MPU_InitStruct.Number = MPU_REGION_NUMBER1;
MPU_InitStruct.BaseAddress = 0x70000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_32MB;
MPU_InitStruct.SubRegionDisable = 0x0;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_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_NUMBER7;
MPU_InitStruct.BaseAddress = 0x30004000;
MPU_InitStruct.Size = MPU_REGION_SIZE_16KB;
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);
/* Enables the MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}Immediately after initialization I tested SRAM1 and SRAM2 directly:
volatile uint32_t *p1 = (volatile uint32_t *)0x30000000;
volatile uint32_t *p2 = (volatile uint32_t *)0x30004000;
*p1 = 0x11223344;
*p2 = 0x55667788;
// __DSB();
volatile uint32_t a = *p1;
volatile uint32_t b = *p2;The result is:
a = 0x11223344 // OK
b = 0x00000000 // unexpectedIf I completely disable the MPU, both accesses work and b == 0x55667788.
I also tried disabling all other MPU regions and leaving only region 7 enabled, with the same result: SRAM1 works but SRAM2 reads back as zero.
The MPU registers for region 7 look correct:
RBAR = 0x30004007
RASR = 0x1300001bDecoded:
Base = 0x30004000
Region = 7
Size = 16 KB
AP = 3 (Full Access)
TEX = 0
S = 0
C = 0
B = 0I have also tested TEX = 1 and different shareable settings without success.
Since 0x30004000 works correctly when the MPU is disabled, but becomes unwritable/read-as-zero when the MPU region is enabled, I suspect I am missing an STM32H7S3-specific MPU/SRAM2 requirement.
Is there anything special required to configure SRAM2 (0x30004000) as non-cacheable DMA memory on STM32H7S3L8?
Thanks!
