2023-08-21 02:47 PM - edited 2023-08-21 02:48 PM
Hi,
I'm currently trying to understand the recommended MPU config (when settings up an 8 bit LCD connected via the FMC on an STM32H742. Everything is currently working, but I haven't been able to wrap my head around why configuring the MPU regions with size MPU_REGION_SIZE_32B is working correctly. The recommended config can be found here: https://www.st.com/content/st_com/en/support/learning/stm32-education/stm32-moocs/STM32_MPU_tips.html
I'm configuring the system to use FMC bank 1 with NE2, A18 as data select. The MPU is configured so that regions in FMC bank1 are strongly ordered, similar to that below:
MPU_Region_InitTypeDef configMPU = {0};
HAL_MPU_Disable();
// Configure regions for FMC LCD
configMPU.Enable = MPU_REGION_ENABLE;
configMPU.Number = MPU_REGION_NUMBER1;
configMPU.BaseAddress = 0x64000000U;
configMPU.Size = MPU_REGION_SIZE_32B;
configMPU.SubRegionDisable = 0x0U;
configMPU.TypeExtField = MPU_TEX_LEVEL0;
configMPU.AccessPermission = MPU_REGION_FULL_ACCESS;
configMPU.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
configMPU.IsShareable = MPU_ACCESS_SHAREABLE;
configMPU.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
configMPU.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
HAL_MPU_ConfigRegion(&configMPU);
// Configure region for FMC LCD data
configMPU.Enable = MPU_REGION_ENABLE;
configMPU.Number = MPU_REGION_NUMBER2;
configMPU.BaseAddress = 0x64040000U;
configMPU.Size = MPU_REGION_SIZE_32B; // How does this work when writing past this?
configMPU.SubRegionDisable = 0x0U;
configMPU.TypeExtField = MPU_TEX_LEVEL0;
configMPU.AccessPermission = MPU_REGION_FULL_ACCESS;
configMPU.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
configMPU.IsShareable = MPU_ACCESS_SHAREABLE;
configMPU.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
configMPU.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
HAL_MPU_ConfigRegion(&configMPU);
// Enable the MPU
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
SRAM_HandleTypeDef hsram1;
FMC_NORSRAM_TimingTypeDef Timing = {0};
// Init FMC for LCD
hsram1.Instance = FMC_NORSRAM_DEVICE;
hsram1.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
hsram1.Init.NSBank = FMC_NORSRAM_BANK2;
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_ENABLE;
hsram1.Init.PageSize = FMC_PAGE_SIZE_NONE;
// Timing etc. initialised here
HAL_SRAM_Init(&hsram1, &Timing, NULL)
I think this makes sense if performing small writes (less than 32B) to addresses 0x64000000U (commands) and 0x64040000U (data). However, for data, I'm currently using MDMA to transfer larger chunks of data far larger than 32B and everything continues to work as expected. MDMA is set up like this:
MDMA_HandleTypeDef hmdma_mdma_channel40_sw_0 = {0};
// Configure MDMA request hmdma_mdma_channel40_sw_0 on MDMA_Channel0
hmdma_mdma_channel40_sw_0.Instance = MDMA_Channel1;
hmdma_mdma_channel40_sw_0.Init.Request = MDMA_REQUEST_SW;
hmdma_mdma_channel40_sw_0.Init.TransferTriggerMode = MDMA_REPEAT_BLOCK_TRANSFER;
hmdma_mdma_channel40_sw_0.Init.Priority = MDMA_PRIORITY_MEDIUM;
hmdma_mdma_channel40_sw_0.Init.Endianness = MDMA_LITTLE_BYTE_ENDIANNESS_EXCHANGE;
hmdma_mdma_channel40_sw_0.Init.SourceInc = MDMA_SRC_INC_HALFWORD;
hmdma_mdma_channel40_sw_0.Init.DestinationInc = MDMA_DEST_INC_HALFWORD;
hmdma_mdma_channel40_sw_0.Init.SourceDataSize = MDMA_SRC_DATASIZE_HALFWORD;
hmdma_mdma_channel40_sw_0.Init.DestDataSize = MDMA_DEST_DATASIZE_HALFWORD;
hmdma_mdma_channel40_sw_0.Init.DataAlignment = MDMA_DATAALIGN_PACKENABLE;
hmdma_mdma_channel40_sw_0.Init.BufferTransferLength = 128U;
hmdma_mdma_channel40_sw_0.Init.SourceBurst = MDMA_SOURCE_BURST_SINGLE;
hmdma_mdma_channel40_sw_0.Init.DestBurst = MDMA_DEST_BURST_SINGLE;
hmdma_mdma_channel40_sw_0.Init.SourceBlockAddressOffset = 0U;
hmdma_mdma_channel40_sw_0.Init.DestBlockAddressOffset = 0U;
// Callbacks
hmdma_mdma_channel40_sw_0.XferCpltCallback = TransferCompleteMDMA;
hmdma_mdma_channel40_sw_0.XferErrorCallback = TransferErrorMDMA;
HAL_MDMA_Init(&hmdma_mdma_channel40_sw_0);
MDMA transfers of pixel data are triggered like this (where w = 320 and h is usually >= 40):
// Init MDMA transfer
ret = HAL_MDMA_Start_IT(&hmdma_mdma_channel40_sw_0, (uint32_t) pixels, (uint32_t) 0x64040000U, w * 2U, h);
So my question is, how is this MPU config working when I'm seemingly writing past the end of the configured region? If fact, even if I change the line above and make the MPU write to address 0x64040100U, everything seems to continue working. If I remove the MPU REGION 2 all together, it no longer works.
I'm leaning towards applying one config to the entire bank to make it strongly ordered but before making any further decisions would like to wrap my head around how the current config is working.
Regards,
Ben
Solved! Go to Solution.
2023-08-22 04:58 AM
Hi,
MPU is internal to CPU. Only CPU accesses are affected by the MPU. All other masters accesses are not!
Attached the block diagram of the CM7 showing the MPU block:
2023-08-22 04:12 AM
DMA controllers are not affected by the MPU at all.
2023-08-22 04:58 AM
Hi,
MPU is internal to CPU. Only CPU accesses are affected by the MPU. All other masters accesses are not!
Attached the block diagram of the CM7 showing the MPU block: