Skip to content

Commit

Permalink
Rework MPU config for unaligned access to external memory (nanoframew…
Browse files Browse the repository at this point in the history
…ork#3044)

***NO_CI***
  • Loading branch information
josesimoes authored and TerryFogg committed Dec 3, 2024
1 parent 79e0d60 commit 63eb93a
Show file tree
Hide file tree
Showing 15 changed files with 214 additions and 90 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
2 changes: 1 addition & 1 deletion targets/ChibiOS/ORGPAL_PALTHREE/stm32f7xx_hal_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ extern "C"
// #define HAL_NAND_MODULE_ENABLED
// #define HAL_NOR_MODULE_ENABLED
// #define HAL_SRAM_MODULE_ENABLED
// #define HAL_SDRAM_MODULE_ENABLED
#define HAL_SDRAM_MODULE_ENABLED
// #define HAL_HASH_MODULE_ENABLED
// #define HAL_GPIO_MODULE_ENABLED
// #define HAL_I2C_MODULE_ENABLED
Expand Down
46 changes: 45 additions & 1 deletion targets/ChibiOS/ORGPAL_PALTHREE/target_external_memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

#include <ch.h>
#include "hal.h"
#include "fsmc_sdram_lld.h"
#include <fsmc_sdram_lld.h>
#include <stm32f7xx_hal.h>

// SDRAM Mode definition register defines
#define FMC_SDCMR_MRD_BURST_LENGTH_1 ((uint16_t)0x0000)
Expand Down Expand Up @@ -95,3 +96,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_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);
}
44 changes: 44 additions & 0 deletions targets/ChibiOS/ORGPAL_PALTHREE/target_mpu_config.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// 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();

// SRAM1 base address
#define SRAM1_SIZE_128K (1UL << 16) // 2^17 bytes
#define MPU_REGION_SRAM1 MPU_REGION_1

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

// base address
MPU->RBAR = SRAM1_BASE;

// 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
2 changes: 1 addition & 1 deletion targets/ChibiOS/ORGPAL_PALX/stm32f7xx_hal_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ extern "C"
// #define HAL_FLASH_MODULE_ENABLED
// #define HAL_NAND_MODULE_ENABLED
// #define HAL_NOR_MODULE_ENABLED
// #define HAL_SRAM_MODULE_ENABLED
#define HAL_SDRAM_MODULE_ENABLED
// #define HAL_SDRAM_MODULE_ENABLED
// #define HAL_HASH_MODULE_ENABLED
// #define HAL_GPIO_MODULE_ENABLED
Expand Down
59 changes: 20 additions & 39 deletions targets/ChibiOS/ORGPAL_PALX/target_external_memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
//

#include <ch.h>
#include "hal.h"
#include "fsmc_sdram_lld.h"
#include <hal.h>
#include <fsmc_sdram_lld.h>
#include <stm32f7xx_hal.h>

// SDRAM Mode definition register defines
#define FMC_SDCMR_MRD_BURST_LENGTH_1 ((uint16_t)0x0000)
Expand Down Expand Up @@ -69,8 +70,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 +93,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 +122,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_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);
}
44 changes: 44 additions & 0 deletions targets/ChibiOS/ORGPAL_PALX/target_mpu_config.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// 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();

// SRAM1 base address
#define SRAM1_SIZE_128K (1UL << 16) // 2^17 bytes
#define MPU_REGION_SRAM1 MPU_REGION_1

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

// base address
MPU->RBAR = SRAM1_BASE;

// 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);
}
2 changes: 1 addition & 1 deletion targets/ChibiOS/ST_STM32F769I_DISCOVERY/CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"RTOS": "ChibiOS",
"TARGET_SERIES": "STM32F7xx",
"CHIBIOS_CONTRIB_REQUIRED": "OFF",
"STM32_CUBE_PACKAGE_REQUIRED": "OFF",
"STM32_CUBE_PACKAGE_REQUIRED": "ON",
"SUPPORT_ANY_BASE_CONVERSION": "ON",
"NF_FEATURE_DEBUGGER": "ON",
"NF_FEATURE_RTC": "ON",
Expand Down
23 changes: 23 additions & 0 deletions targets/ChibiOS/ST_STM32F769I_DISCOVERY/stm32f7xx_hal_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,26 @@ extern "C"
#endif

#define HAL_DMA_MODULE_ENABLED
#define HAL_SDRAM_MODULE_ENABLED
#define HAL_QSPI_MODULE_ENABLED
#define HAL_RCC_MODULE_ENABLED
#define HAL_CORTEX_MODULE_ENABLED

// ########################### System Configuration #########################
// This is the HAL system configuration section

// Value of VDD in mv
#define VDD_VALUE (3300U)
// tick interrupt priority
#define TICK_INT_PRIORITY (0x0FU)
#define USE_RTOS 0U
#define PREFETCH_ENABLE 1U
// To enable instruction cache and prefetch
#define ART_ACCELERATOR_ENABLE 1U

#define USE_HAL_DMA2D_REGISTER_CALLBACKS 0U /* DMA2D register callback disabled */
#define USE_HAL_QSPI_REGISTER_CALLBACKS 0U /* QSPI register callback disabled */
#define USE_HAL_SDRAM_REGISTER_CALLBACKS 0U /* SDRAM register callback disabled */

#ifdef HAL_RCC_MODULE_ENABLED
#include "stm32f7xx_hal_rcc.h"
Expand All @@ -33,6 +48,14 @@ extern "C"
#include "stm32f7xx_hal_qspi.h"
#endif /* HAL_QSPI_MODULE_ENABLED */

#ifdef HAL_SDRAM_MODULE_ENABLED
#include "stm32f7xx_hal_sdram.h"
#endif /* HAL_SDRAM_MODULE_ENABLED */

#ifdef HAL_CORTEX_MODULE_ENABLED
#include "stm32f7xx_hal_cortex.h"
#endif /* HAL_CORTEX_MODULE_ENABLED */

#ifdef USE_FULL_ASSERT
/**
* @brief The assert_param macro is used for function's parameters check.
Expand Down
Loading

0 comments on commit 63eb93a

Please sign in to comment.