Skip to content

Commit

Permalink
Rework MPU config for unaligned access to external memory
Browse files Browse the repository at this point in the history
- Add MPU config to ORGPAL3 and ORGPALX to allow unaligned access to external memory.
- Remove MPU config for non cached memory in ChibiOS mcu config for ORGPAL3 and ORGPALX. Now are in Target_ConfigNonCacheableMemory().
- Rework call to MPU config in ORGPAL3 and ORGPALX.
- Migrate ST_STM32F769I_DISCOVERY MPU config to use ST HAL API.
  • Loading branch information
josesimoes committed Nov 21, 2024
1 parent 9498e56 commit ec25d8a
Show file tree
Hide file tree
Showing 11 changed files with 172 additions and 82 deletions.
3 changes: 2 additions & 1 deletion targets/ChibiOS/ORGPAL_PALTHREE/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ nf_setup_target_build(
CLR_EXTRA_SOURCE_FILES
# the next one is required is the target implements and it's using external memory
${CMAKE_CURRENT_SOURCE_DIR}/target_external_memory.c

${CMAKE_CURRENT_SOURCE_DIR}/target_mpu_config.c

BOOTER_EXTRA_COMPILE_DEFINITIONS
USBH_DEBUG_MULTI_HOST=0

Expand Down
4 changes: 4 additions & 0 deletions targets/ChibiOS/ORGPAL_PALTHREE/nanoCLR/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

extern int32_t hal_lfs_config();
extern void hal_lfs_mount();
extern void Target_ConfigMPU();

// need to declare the Receiver thread here
osThreadDef(ReceiverThread, osPriorityHigh, 2048, "ReceiverThread");
Expand Down Expand Up @@ -93,6 +94,9 @@ int main(void)
crcStart(NULL);
#endif

// MPU configuration
Target_ConfigMPU();

// config and init external memory
// this has to be called after osKernelInitialize, otherwise an hard fault will occur
Target_ExternalMemoryInit();
Expand Down
5 changes: 1 addition & 4 deletions targets/ChibiOS/ORGPAL_PALTHREE/nanoCLR/mcuconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,7 @@
/*
* Memory attributes settings.
*/
#define STM32_NOCACHE_ENABLE TRUE
#define STM32_NOCACHE_MPU_REGION MPU_REGION_0
#define STM32_NOCACHE_RBAR 0x20000000U
#define STM32_NOCACHE_RASR MPU_RASR_SIZE_128K
#define STM32_NOCACHE_ENABLE FALSE

/*
* HAL driver system settings.
Expand Down
43 changes: 43 additions & 0 deletions targets/ChibiOS/ORGPAL_PALTHREE/target_external_memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,46 @@ void Target_ExternalMemoryInit()
fsmcSdramInit();
fsmcSdramStart(&SDRAMD, &sdram_cfg);
}

void Target_ExternalMemoryConfigMPU()
{
// ARM: STM32F7: hard fault caused by unaligned Memory Access
// reference https://www.keil.com/support/docs/3777%20%20.htm
// SYMPTOM
// If you use an STM32F7xx microcontroller with an external SDRAM,
// the Cortex-M7 core may unexpectedly run into the hard fault handler because of unaligned access.
// This may happen for example, when the frame buffer of an LCD, a RAM filesystem or any other data is
// located into the SDRAM address range 0xC0000000 - 0xC03FFFFF (max. 4MB).
// The hard fault is executed although the bit UNALIGN_TRP (bit 3) in the CCR register is not enabled.

// CAUSE
// In general, RAM accesses on Cortex-M7 based devices do not have to be aligned in any way.
// The Cortex-M7 core can handle unaligned accesses by hardware.
// Usually, variables should be naturally aligned because these accesses are slightly faster than unaligned
// accesses.

// STM32F7xx devices have the external SDRAM mapped to the
// address range 0xC0000000 - 0xC03FFFFF (max. 4MB).
// According to the ARMv7-M Architecture Reference Manual chapter B3.1 (table B3-1),
// the area 0xC0000000-0xDFFFFFFF (32MB) is specified as Device Memory Type.
// According to chapter A3.2.1, all accesses to Device Memory Types must be naturally aligned.
// If they are not, a hard fault will execute no matter if the bit UNALIGN_TRP (bit 3) in the CCR register is
// enabled or not.

MPU_Region_InitTypeDef MPU_InitStruct;

// Configure the MPU attributes for SDRAM
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0xD0000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_8MB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);
}
40 changes: 40 additions & 0 deletions targets/ChibiOS/ORGPAL_PALTHREE/target_mpu_config.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//

#include <ch.h>
#include <hal.h>
#include <stm32_registry.h>
#include <hal_nf_community.h>

extern void Target_ExternalMemoryConfigMPU();

void Target_ConfigNonCacheableMemory()
{
// region
MPU->RNR = ((uint32_t)MPU_REGION_1);

// base address
MPU->RBAR = ((uint32_t)0x20000000U);

// size and other configs
MPU->RASR =
((uint32_t)MPU_RASR_ATTR_AP_RW_RW | MPU_RASR_ATTR_NON_CACHEABLE | MPU_RASR_ATTR_S | MPU_RASR_SIZE_128K |
MPU_RASR_ENABLE);
}

void Target_ConfigMPU()
{
// disable MPU
HAL_MPU_Disable();

// config MPU for external memory
Target_ExternalMemoryConfigMPU();

// config MPU for non cacheable memory
Target_ConfigNonCacheableMemory();

// enable MPU
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
1 change: 1 addition & 0 deletions targets/ChibiOS/ORGPAL_PALX/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ nf_setup_target_build(
CLR_EXTRA_SOURCE_FILES
# the next one is required is the target implements and it's using external memory
${CMAKE_CURRENT_SOURCE_DIR}/target_external_memory.c
${CMAKE_CURRENT_SOURCE_DIR}/target_mpu_config.c

BOOTER_EXTRA_COMPILE_DEFINITIONS
-DUSBH_DEBUG_MULTI_HOST=0
Expand Down
4 changes: 4 additions & 0 deletions targets/ChibiOS/ORGPAL_PALX/nanoCLR/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

extern int32_t hal_lfs_config();
extern void hal_lfs_mount();
extern void Target_ConfigMPU();

// need to declare the Receiver thread here
osThreadDef(ReceiverThread, osPriorityHigh, 2048, "ReceiverThread");
Expand Down Expand Up @@ -93,6 +94,9 @@ int main(void)
crcStart(NULL);
#endif

// MPU configuration
Target_ConfigMPU();

// config and init external memory
// this has to be called after osKernelInitialize, otherwise an hard fault will occur
Target_ExternalMemoryInit();
Expand Down
5 changes: 1 addition & 4 deletions targets/ChibiOS/ORGPAL_PALX/nanoCLR/mcuconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,7 @@
/*
* Memory attributes settings.
*/
#define STM32_NOCACHE_ENABLE TRUE
#define STM32_NOCACHE_MPU_REGION MPU_REGION_0
#define STM32_NOCACHE_RBAR 0x20000000U
#define STM32_NOCACHE_RASR MPU_RASR_SIZE_128K
#define STM32_NOCACHE_ENABLE FALSE

/*
* HAL driver system settings.
Expand Down
54 changes: 17 additions & 37 deletions targets/ChibiOS/ORGPAL_PALX/target_external_memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@
#define SDRAM_SIZE (8 * 1024 * 1024)
#define SDRAM_START ((void *)FSMC_Bank6_MAP_BASE)

void SetupDeviceMemoryToEliminateUnalignedAccess();

// SDRAM driver configuration structure.
static const SDRAMConfig sdram_cfg = {
.sdcr = (uint32_t)FMC_ColumnBits_Number_8b | FMC_RowBits_Number_12b | FMC_SDMemory_Width_16b |
Expand All @@ -94,12 +92,11 @@ static const SDRAMConfig sdram_cfg = {

void Target_ExternalMemoryInit()
{
SetupDeviceMemoryToEliminateUnalignedAccess();
fsmcSdramInit();
fsmcSdramStart(&SDRAMD, &sdram_cfg);
}

void SetupDeviceMemoryToEliminateUnalignedAccess()
void Target_ExternalMemoryConfigMPU()
{
// ARM: STM32F7: hard fault caused by unaligned Memory Access
// reference https://www.keil.com/support/docs/3777%20%20.htm
Expand All @@ -124,37 +121,20 @@ void SetupDeviceMemoryToEliminateUnalignedAccess()
// If they are not, a hard fault will execute no matter if the bit UNALIGN_TRP (bit 3) in the CCR register is
// enabled or not.

// Solution recommended by KEIL

#define MPU_REGION_ENABLE ((uint8_t)0x01U)
#define MPU_REGION_SIZE_8MB ((uint8_t)0x16U)
#define MPU_REGION_FULL_ACCESS ((uint8_t)0x03U)
#define MPU_ACCESS_NOT_BUFFERABLE ((uint8_t)0x00U)
#define MPU_ACCESS_NOT_CACHEABLE ((uint8_t)0x00U)
#define MPU_ACCESS_NOT_SHAREABLE ((uint8_t)0x00U)
#define MPU_ACCESS_NOT_SHAREABLE ((uint8_t)0x00U)
#define MPU_REGION_NUMBER0 ((uint8_t)0x00U)
#define MPU_TEX_LEVEL1 ((uint8_t)0x01U)
#define MPU_INSTRUCTION_ACCESS_DISABLE ((uint8_t)0x01U)
#define MPU_PRIVILEGED_DEFAULT ((uint32_t)0x00000004U)

// Disable the MPU
__DMB();
SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk;
MPU->CTRL = 0;

// Configure the region
MPU->RNR = MPU_REGION_NUMBER0;
MPU->RBAR = 0xC0000000;
MPU->RASR = (MPU_INSTRUCTION_ACCESS_DISABLE << MPU_RASR_XN_Pos) | (MPU_REGION_FULL_ACCESS << MPU_RASR_AP_Pos) |
(MPU_TEX_LEVEL1 << MPU_RASR_TEX_Pos) | (MPU_ACCESS_NOT_SHAREABLE << MPU_RASR_S_Pos) |
(MPU_ACCESS_NOT_CACHEABLE << MPU_RASR_C_Pos) | (MPU_ACCESS_NOT_BUFFERABLE << MPU_RASR_B_Pos) |
(0x00 << MPU_RASR_SRD_Pos) | (MPU_REGION_SIZE_8MB << MPU_RASR_SIZE_Pos) |
(MPU_REGION_ENABLE << MPU_RASR_ENABLE_Pos);

// Enable the MPU
MPU->CTRL = MPU_PRIVILEGED_DEFAULT | MPU_CTRL_ENABLE_Msk;
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
__DSB();
__ISB();
MPU_Region_InitTypeDef MPU_InitStruct;

// Configure the MPU attributes for SDRAM
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0xD0000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_8MB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);
}
40 changes: 40 additions & 0 deletions targets/ChibiOS/ORGPAL_PALX/target_mpu_config.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//

#include <ch.h>
#include <hal.h>
#include <stm32_registry.h>
#include <hal_nf_community.h>

extern void Target_ExternalMemoryConfigMPU();

void Target_ConfigNonCacheableMemory()
{
// region
MPU->RNR = ((uint32_t)MPU_REGION_1);

// base address
MPU->RBAR = ((uint32_t)0x20000000U);

// size and other configs
MPU->RASR =
((uint32_t)MPU_RASR_ATTR_AP_RW_RW | MPU_RASR_ATTR_NON_CACHEABLE | MPU_RASR_ATTR_S | MPU_RASR_SIZE_128K |
MPU_RASR_ENABLE);
}

void Target_ConfigMPU()
{
// disable MPU
HAL_MPU_Disable();

// config MPU for external memory
Target_ExternalMemoryConfigMPU();

// config MPU for non cacheable memory
Target_ConfigNonCacheableMemory();

// enable MPU
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
55 changes: 19 additions & 36 deletions targets/ChibiOS/ST_STM32F769I_DISCOVERY/target_external_memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
#define SDRAM_SIZE (16 * 1024 * 1024)
#define SDRAM_START ((void *)FSMC_Bank5_MAP_BASE)

void SetupDeviceMemoryToEliminateUnalignedAccess();
void Target_ExternalMemoryConfigMPU();

// SDRAM driver configuration structure.
static const SDRAMConfig sdram_cfg = {
Expand All @@ -94,12 +94,12 @@ static const SDRAMConfig sdram_cfg = {

void Target_ExternalMemoryInit()
{
SetupDeviceMemoryToEliminateUnalignedAccess();
Target_ExternalMemoryConfigMPU();
fsmcSdramInit();
fsmcSdramStart(&SDRAMD, &sdram_cfg);
}

void SetupDeviceMemoryToEliminateUnalignedAccess()
void Target_ExternalMemoryConfigMPU()
{
// ARM: STM32F7: hard fault caused by unaligned Memory Access
// reference https://www.keil.com/support/docs/3777%20%20.htm
Expand All @@ -124,37 +124,20 @@ void SetupDeviceMemoryToEliminateUnalignedAccess()
// If they are not, a hard fault will execute no matter if the bit UNALIGN_TRP (bit 3) in the CCR register is
// enabled or not.

// Solution recommended by KEIL

#define MPU_REGION_ENABLE ((uint8_t)0x01U)
#define MPU_REGION_SIZE_4MB ((uint8_t)0x15)
#define MPU_REGION_FULL_ACCESS ((uint8_t)0x03U)
#define MPU_ACCESS_NOT_BUFFERABLE ((uint8_t)0x00U)
#define MPU_ACCESS_NOT_CACHEABLE ((uint8_t)0x00U)
#define MPU_ACCESS_NOT_SHAREABLE ((uint8_t)0x00U)
#define MPU_ACCESS_NOT_SHAREABLE ((uint8_t)0x00U)
#define MPU_REGION_NUMBER0 ((uint8_t)0x00U)
#define MPU_TEX_LEVEL1 ((uint8_t)0x01U)
#define MPU_INSTRUCTION_ACCESS_DISABLE ((uint8_t)0x01U)
#define MPU_PRIVILEGED_DEFAULT ((uint32_t)0x00000004U)

// Disable the MPU
__DMB();
SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk;
MPU->CTRL = 0;

// Configure the region
MPU->RNR = MPU_REGION_NUMBER0;
MPU->RBAR = 0xC0000000;
MPU->RASR = (MPU_INSTRUCTION_ACCESS_DISABLE << MPU_RASR_XN_Pos) | (MPU_REGION_FULL_ACCESS << MPU_RASR_AP_Pos) |
(MPU_TEX_LEVEL1 << MPU_RASR_TEX_Pos) | (MPU_ACCESS_NOT_SHAREABLE << MPU_RASR_S_Pos) |
(MPU_ACCESS_NOT_CACHEABLE << MPU_RASR_C_Pos) | (MPU_ACCESS_NOT_BUFFERABLE << MPU_RASR_B_Pos) |
(0x00 << MPU_RASR_SRD_Pos) | (MPU_REGION_SIZE_4MB << MPU_RASR_SIZE_Pos) |
(MPU_REGION_ENABLE << MPU_RASR_ENABLE_Pos);

// Enable the MPU
MPU->CTRL = MPU_PRIVILEGED_DEFAULT | MPU_CTRL_ENABLE_Msk;
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
__DSB();
__ISB();
MPU_Region_InitTypeDef MPU_InitStruct;

// Configure the MPU attributes for SDRAM
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0xC0000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_8MB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);
}

0 comments on commit ec25d8a

Please sign in to comment.