FreeRTOS MPU v10.3.1 with STM32H7 Core

Has anyone ported the FreeRTOS v10.3.1 with MPU Support with M7? I am facing multiple problems in doing so eg. LDREX instruction throwing a HardFault, Cache issues in context switching (task heap corruption), 16 MPU ports instead of 8 (v10.3.1 does not have the dedicated macro for maximum mpu regions, I am not in a state to port an entirely new version of FreeRTOS as I need to make this work fast but seem to have hit a dead end.

I am using AXI SRAM mostly because DTCM is too small for my project requirements, there seem to be multiple posts suggesting disabling D-Cache but that doesn’t seem to be an option for me as it causes further issues with HardFault and MemFault, not sure how to make it work with non-cacheable or cacheable AXI-SRAM.

I also made the SRAM non - shareable but seems like there is no global monitor in STM32H757AI, it still causes HardFault in LDREX instruction when using OpenAMP library.

I used SCB_CleanInvalidateDCache in port.c in the function

Still my project doesn’t work, giving PRECISERR when privileged task accesses unprivileged data memory. Also for now all tasks in my project have been declared to be privileged.

I am attaching my mpu config and linker here for reference:

/*###ICF### Section handled by ICF editor, don't touch! ****/
/*-Editor annotation file-*/
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */

/*-Specials-*/
define symbol __ICFEDIT_intvec_start__ = 0x08000000;

/*===========================================================
  Memory Region Symbols
===========================================================*/

/*--- Flash ---*/

/*--- Internal ---*/
/* Flash Organization
*  1. Privileged Code:
*      Start   : 0x08000000
*      End     : 0x08007FFF
*      Size    : 32 Kbytes
*  2. System calls:
*      Start   : 0x08008000
*      End     : 0x0800FFFF
*      Size    : 32 Kbytes
*  3. Unprivileged Code:
*      Start   : 0x08010000
*      End     : 0x080FFFFF
*      Size    : 988 Kbytes
*/

define symbol __ICFEDIT_region_ROM_start__      = 0x08000000;
define symbol __ICFEDIT_region_ROM_end__        = 0x080FFFEF;

define symbol __ICFEDIT_region_ROM_PRIV_FUNC_start__      = __ICFEDIT_region_ROM_start__;
define symbol __ICFEDIT_region_ROM_PRIV_FUNC_end__        = 0x08007FFF;

define symbol __ICFEDIT_region_ROM_SYS_CALL_start__       = 0x08008000;
define symbol __ICFEDIT_region_ROM_SYS_CALL_end__         = 0x08008FFF;

define symbol __ICFEDIT_region_ROM_UNPRIV_start__         = 0x08009000;
define symbol __ICFEDIT_region_ROM_UNPRIV_end__           = __ICFEDIT_region_ROM_end__;

define symbol __ICFEDIT_region_ROM_VER_start__            = 0x080FFFF0;
define symbol __ICFEDIT_region_ROM_VER_end__              = 0x080FFFFF;

/*--- Internal SRAM ---*/
/* RAM Organization
*  1. Privileged Data:
*      Start   : 0x24000000
*      End     : 0x2400FFFF
*      Size    : 64 Kbytes
*  2. Unprivileged Data:
*      Start   : 0x24010000
*      End     : 0x2407FFFF
*      Size    : 448 Kbytes
*/

define symbol __ICFEDIT_region_DTCM_start__     = 0x20000000;  // DTCM - 128KB (stack/heap)
define symbol __ICFEDIT_region_DTCM_end__       = 0x2001FFFF;

define symbol __ICFEDIT_region_RAM_start__      = 0x24000000;  // AXI SRAM D1 - 512KB
define symbol __ICFEDIT_region_RAM_end__        = 0x2407FFFF;

define symbol __ICFEDIT_region_PRIV_RAM_start__      = __ICFEDIT_region_RAM_start__; // AXI SRAM - 64K Privileged Data
define symbol __ICFEDIT_region_PRIV_RAM_end__        = 0x2400FFFF;

define symbol __ICFEDIT_region_UNPRIV_RAM_start__    = 0x24010000;  // AXI SRAM - 448K Unprivileged Data
define symbol __ICFEDIT_region_UNPRIV_RAM_end__      = __ICFEDIT_region_RAM_end__;

define symbol __ICFEDIT_region_ITCMRAM_start__  = 0x00000000;  // ITCM - 64KB
define symbol __ICFEDIT_region_ITCMRAM_end__    = 0x0000FFFF;

define symbol __ICFEDIT_region_SRAM1_start__    = 0x30000000;  // D2 SRAM1 - 128KB
define symbol __ICFEDIT_region_SRAM1_end__      = 0x3001FFFF;

define symbol __ICFEDIT_region_SRAM2_start__    = 0x30020000;  // D2 SRAM2 - 128KB
define symbol __ICFEDIT_region_SRAM2_end__      = 0x3003FFFF;

define symbol __ICFEDIT_region_SRAM3_start__    = 0x30040000;  // D2 SRAM3 - 32KB
define symbol __ICFEDIT_region_SRAM3_end__      = 0x30047FFF;

define symbol __ICFEDIT_region_SRAM4_start__    = 0x38000000;  // D3 SRAM4 - 64KB
define symbol __ICFEDIT_region_SRAM4_end__      = 0x3800FFFF;

define symbol __ICFEDIT_region_BKPSRAM_start__  = 0x38800000;  // Backup SRAM - 4KB
define symbol __ICFEDIT_region_BKPSRAM_end__    = 0x38800FFF;

/*--- External Memory ---*/
define symbol __ICFEDIT_region_QSPI_start__     = 0x90000000;  // QSPI Flash
define symbol __ICFEDIT_region_QSPI_end__       = 0x9FFFFFFF;

define symbol __ICFEDIT_region_SDRAM_start__    = 0xC0000000;  // FMC SDRAM - framebuffer
define symbol __ICFEDIT_region_SDRAM_end__      = 0xC0783FFF;

define symbol __ICFEDIT_region_SDRAM1_start__   = 0xC0784000;  // FMC SDRAM - overflow
define symbol __ICFEDIT_region_SDRAM1_end__     = 0xC3FFFFFF;

/*===========================================================
  Stack and Heap Sizes
===========================================================*/
define symbol __ICFEDIT_size_cstack__  = 0x8000;   // 32KB  - MSP stack (ISR + startup)
define symbol __ICFEDIT_size_heap__    = 0x20000;  // 128KB - FreeRTOS heap (all task stacks)

/**** End of ICF editor section. ###ICF###*/

/*===========================================================
  OpenAMP Shared Memory (D3 SRAM4)
===========================================================*/
define symbol __OPENAMP_region_start__ = 0x38000400;
define symbol __OPENAMP_region_size__  = 0xFC00;
export symbol __OPENAMP_region_start__;
export symbol __OPENAMP_region_size__;

/*===========================================================
  Memory Map
===========================================================*/
define memory mem with size = 4G;

define region ROM_region                = mem:[from __ICFEDIT_region_ROM_start__              to __ICFEDIT_region_ROM_end__];
define region ROM_region_privileged     = mem:[from __ICFEDIT_region_ROM_PRIV_FUNC_start__    to __ICFEDIT_region_ROM_PRIV_FUNC_end__];
define region ROM_region_system_calls   = mem:[from __ICFEDIT_region_ROM_SYS_CALL_start__     to __ICFEDIT_region_ROM_SYS_CALL_end__];
define region ROM_region_unprivileged   = mem:[from __ICFEDIT_region_ROM_UNPRIV_start__       to __ICFEDIT_region_ROM_UNPRIV_end__];

define region RAM_region_privileged     = mem:[from __ICFEDIT_region_PRIV_RAM_start__         to __ICFEDIT_region_PRIV_RAM_end__];
define region RAM_region_unprivileged   = mem:[from __ICFEDIT_region_UNPRIV_RAM_start__       to __ICFEDIT_region_UNPRIV_RAM_end__];
define region VER_region                = mem:[from __ICFEDIT_region_ROM_VER_start__          to __ICFEDIT_region_ROM_VER_end__];
define region DTCM_region               = mem:[from __ICFEDIT_region_DTCM_start__             to __ICFEDIT_region_DTCM_end__];
define region ITCMRAM_region            = mem:[from __ICFEDIT_region_ITCMRAM_start__          to __ICFEDIT_region_ITCMRAM_end__];
define region SRAM1_region              = mem:[from __ICFEDIT_region_SRAM1_start__            to __ICFEDIT_region_SRAM1_end__];
define region SRAM2_region              = mem:[from __ICFEDIT_region_SRAM2_start__            to __ICFEDIT_region_SRAM2_end__];
define region SRAM3_region              = mem:[from __ICFEDIT_region_SRAM3_start__            to __ICFEDIT_region_SRAM3_end__];
define region SRAM4_region              = mem:[from __ICFEDIT_region_SRAM4_start__            to __ICFEDIT_region_SRAM4_end__];
define region BKPSRAM_region            = mem:[from __ICFEDIT_region_BKPSRAM_start__          to __ICFEDIT_region_BKPSRAM_end__];

/*--- External ---*/
define region QSPI_region    = mem:[from __ICFEDIT_region_QSPI_start__    to __ICFEDIT_region_QSPI_end__];
define region SDRAM_region   = mem:[from __ICFEDIT_region_SDRAM_start__   to __ICFEDIT_region_SDRAM_end__];
define region SDRAM1_region  = mem:[from __ICFEDIT_region_SDRAM1_start__  to __ICFEDIT_region_SDRAM1_end__];
/*--- OpenAMP resource table (D3 SRAM4, first 1KB) ---*/
define region RSC_TAB_region = mem:[from 0x38000000 to 0x380003FF];

/*===========================================================
  Blocks
===========================================================*/
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
define block HEAP   with alignment = 8, size = __ICFEDIT_size_heap__   { };

/*===========================================================
  Initialization
===========================================================*/
initialize by copy { readwrite };
do not initialize  { section .noinit };
do not initialize  { section TouchGFX_Framebuffer };
do not initialize  { section TestFramebuffer };

/*===========================================================
  Placement
===========================================================*/

/*--- Flash ---*/
place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
place at address mem:0x08100000               { section .cm4_code };


place in ROM_region_privileged      { readonly section privileged_functions };
place in ROM_region_system_calls    { readonly section freertos_system_calls };
place in ROM_region_unprivileged    { readonly,
                                      section IntFlashSection,
                                      section FontFlashSection,
                                      section TextFlashSection };

place in VER_region  { section VerNumberSection };
place in QSPI_region { section ExtFlashSection };

/*--- DTCM: Stack only (32KB, CPU-only, fastest) ---*/
place in DTCM_region { block CSTACK };

/*--- AXI SRAM D1: Heap + general data + audio ---*/
place in RAM_region_privileged      { readwrite section privileged_data };
place in RAM_region_unprivileged    { readwrite,
                                      block HEAP };
/*--- D3 SRAM4: OpenAMP resource table ---*/
place in RSC_TAB_region { readwrite section .resource_table };

/*--- SDRAM: Framebuffers ---*/
place in SDRAM_region  { section TouchGFX_Framebuffer };
place in SDRAM1_region { section TestFramebuffer };

/*
  D2 SRAM1/SRAM2/SRAM3 and Backup SRAM are defined but currently
  unpopulated. Use them for DMA buffers, ETH/USB buffers, or
  persistent fault logs as the application grows:
    place in SRAM1_region   { section DMA_BUF_SECTION };
    place in SRAM2_region   { section ETH_BUF_SECTION };
    place in SRAM3_region   { section USB_BUF_SECTION };
    place in BKPSRAM_region { section FAULT_LOG_SECTION };
*/

/* Exported symbols. */
define exported symbol __FLASH_segment_start__          = __ICFEDIT_region_ROM_start__;
define exported symbol __FLASH_segment_end__            = __ICFEDIT_region_ROM_end__;
define exported symbol __SRAM_segment_start__           = __ICFEDIT_region_RAM_start__;
define exported symbol __SRAM_segment_end__             = __ICFEDIT_region_RAM_end__;
 
define exported symbol __privileged_functions_start__   = __ICFEDIT_region_ROM_PRIV_FUNC_start__;
define exported symbol __privileged_functions_end__     = __ICFEDIT_region_ROM_PRIV_FUNC_end__;
define exported symbol __privileged_data_start__        = __ICFEDIT_region_PRIV_RAM_start__;
define exported symbol __privileged_data_end__          = __ICFEDIT_region_PRIV_RAM_end__;
 
define exported symbol __syscalls_flash_start__         = __ICFEDIT_region_ROM_SYS_CALL_start__;
define exported symbol __syscalls_flash_end__           = __ICFEDIT_region_ROM_SYS_CALL_end__;

define exported symbol __DTCM_RAM_start__          = __ICFEDIT_region_DTCM_start__;
define exported symbol __DTCM_RAM_end__            = __ICFEDIT_region_DTCM_end__;

define exported symbol __SRAM4_D3_RAM_start__          = __ICFEDIT_region_SRAM4_start__;
define exported symbol __SRAM4_D3_RAM_end__            = __ICFEDIT_region_SRAM4_end__;

mpu configuration:

void MPU_Config(void)
{
  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 = (uint32_t)__privileged_functions_start__;
  MPU_InitStruct.Size = MPU_REGION_SIZE_1MB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_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.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER1;
  MPU_InitStruct.BaseAddress = (uint32_t)__privileged_data_start__;
  MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_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.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER2;
  MPU_InitStruct.BaseAddress = (uint32_t)__privileged_functions_start__;
  MPU_InitStruct.Size = MPU_REGION_SIZE_32KB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.AccessPermission = MPU_REGION_PRIV_RO;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_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.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER3;
  MPU_InitStruct.BaseAddress = (uint32_t)__syscalls_flash_start__;
  MPU_InitStruct.Size = MPU_REGION_SIZE_4KB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);

  /** Initializes and configures the Region and the memory to be protected
  */

  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER4;
  MPU_InitStruct.BaseAddress = (uint32_t)__privileged_data_start__;
  MPU_InitStruct.Size = MPU_REGION_SIZE_64KB;
  MPU_InitStruct.AccessPermission = MPU_REGION_PRIV_RW;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_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.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER5;
  MPU_InitStruct.BaseAddress = (uint32_t)__SRAM4_D3_RAM_start__;
  MPU_InitStruct.Size = MPU_REGION_SIZE_64KB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
  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_NOT_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);

  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER6;
  MPU_InitStruct.BaseAddress = (uint32_t)__DTCM_RAM_start__;
  MPU_InitStruct.Size = MPU_REGION_SIZE_128KB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
  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_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.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER7;
  MPU_InitStruct.BaseAddress = (uint32_t)PERIPHERALS_START_ADDRESS;
  MPU_InitStruct.Size = MPU_REGION_SIZE_512MB;
  MPU_InitStruct.AccessPermission = MPU_REGION_PRIV_RW;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  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_NOT_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /* Enables the MPU */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

}

Are you using MPU port or non-MPU port?

Why do you need to do this explicitly?

You can probably refer this project as example: FreeRTOS/FreeRTOS/Demo/CORTEX_MPU_M7_NUCLEO_H743ZI2_GCC_IAR_Keil/Projects/IAR at main · FreeRTOS/FreeRTOS · GitHub.

Don’t I need to use the controller MPU hardware to restrict memory region access to privileged and unprivileged regions? Or should I completely rely on FreeRTOS port handling it? Shouldn’t MPU hardware be compatible with the FreeRTOS port implementation? Also could you tell me what should be the port configuration for 16 MPU regions supported by STM32H7 in v10.3.1? Right now I am using default port.c given in ARM_CM4F_MPU.

One more point, this project works with a newer version of FreeRTOS as it has

#define configTOTAL_MPU_REGIONS 16

Do you have a configuration compatible with v10.3.1 as it doesn’t contain this macro definition.

Do not do it explicitly. As you are using MPU port (ARM_CM4F_MPU), the FreeRTOS port will handle the MPU programming.

Support for 16 MPU regions for IAR M4 port was added in 10.4.0: FreeRTOS-Kernel/portable/IAR/ARM_CM4F_MPU/portasm.s at V10.4.0-kernel-only · FreeRTOS/FreeRTOS-Kernel · GitHub. So either you need to update to 10.4.0 or you’ll be able to use 8 MPU regions only.

One more thing I would suggest is to start with a minimal application containing a single task that does nothing other than call vTaskDelay:

void Task( void * param )
{
    for( ;; )
    {
        vTaskDelay( pdMS_TO_TICKS( 1000 ) );
    }
}

Once you have this working, add your application logic on top of it.

the other question is why you want to specifically use v10.3.1 we are now living in the v11.3 era

I did a migration to kernel v10.4.0 and was able to make it work by disabling D-Cache, setting #define configTEX_S_C_B_SRAM ( 0x08UL )
#define configTOTAL_MPU_REGIONS 16 and removing my MPU config function. Thanks for the support, will post here if I face any other issues.

Glad to know that you are able to make it work. Why do you need to disable D-Cache?

I have utilized AXI SRAM for the regions here but was facing multiple issues with cache enabled 1. The OpenAMP communication between M7 and M4 was giving issues after enabling MPU ports.
2. I have data in external NOR flash which was not being fetched correctly most likely due to cache coherency issues. But when I didn’t enable MPU ports the data was getting fetched correctly with cache enabled.
3. I was facing issues with context switching of the kernel where it used to get stuck in vTaskSwitchContext handler, due to time constraints I disabled D-Cache entirely for now and it worked.
Let me know if you have any recommendations I can try.

How did you determine this 0x08 value? Per this table, your settings are:

TEX=001, S=0, C=0, B=0

Which makes SRAM non-cacheable. Try the following to mark both SRAM and FLASH as cacheable:

#define configTEX_S_C_B_SRAM						( 0x03UL )
#define configTEX_S_C_B_FLASH						( 0x03UL )

I had deliberately set it to non-cacheable due to above mentioned issues I was facing.

I see - that is how you disabled D-cache. Which means it would need more debugging to find out why it is not working with cache enabled.