FreeRTOS v11.1 R5F MPU Error

Hi Folks,
I am trying to using the MPU feature on R5F with FreeRTOS v11.1, below is my ld script file:

_STACK_SIZE = 2*0x400;
_HEAP_SIZE = 2*0x400;

_SYSTEM_STACK_SIZE = 2 * 1024;
_ABORT_STACK_SIZE = 512;
_SUPERVISOR_STACK_SIZE = 2 * 1024;
_IRQ_STACK_SIZE = 2 * 512;
_FIQ_STACK_SIZE = 2 * 512;
_UNDEF_STACK_SIZE = 512;

_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000;
_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x2000;

_ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024;
_SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 1024;
_IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024;
_FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024;
_UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024;

MEMORY
{
  /*flash (rx)  : ORIGIN = 0x5100000, LENGTH = 256K - 2 */ /* -2 for CRC16 */
  TCM (rwx) : ORIGIN = 0x40, LENGTH = 0x7FC0        /*32K - 64bytes Bytes*/
  /*SRAM (rwx) : ORIGIN = 0x5140000, LENGTH = 192K */ /*448K Bytes*/
  SRAM (rwx) : ORIGIN = 0x5100000, LENGTH = 0x70000 /*448K Bytes*/
}

__privileged_functions_region_size__  = 64K;  /*64K*/
__privileged_data_region_size__       = 32K;  /*64K*/

__FLASH_segment_start__               = ORIGIN(SRAM);
__FLASH_segment_end__                 = __FLASH_segment_start__ + 256K;

__SRAM_segment_start__                = ORIGIN(SRAM) + 256K;
__SRAM_segment_end__                  = __SRAM_segment_start__ + 192K;

__privileged_functions_start__        = __FLASH_segment_start__;
__privileged_functions_end__          = __FLASH_segment_start__ + __privileged_functions_region_size__;

__privileged_data_start__             = __SRAM_segment_start__;
__privileged_data_end__               = __SRAM_segment_start__ + __privileged_data_region_size__;

/* Specify the default entry point to the program */
ENTRY(__vector_table)

SECTIONS
{
    .privileged_functions :
    {
        . = ALIGN(4);
        KEEP(*(.intvecs))
        KEEP (*(.freertos_vectors))
        KEEP (*(.vectors))
        KEEP(*(.fw_infos_section))
        KEEP(*(.isr_vector)) /* Startup code. */
        . = ALIGN(4);
        *(privileged_functions)
        . = ALIGN(4);
        /* Fill rest of the region with a known value */
        FILL(0xADDEADDE);
        /* Ensure that non-privileged code is placed after the region reserved for
        * privileged kernel code. This is done for MPU Region Alignment */
        /* Note that dot (.) actually refers to the byte offset from the start of
        * the current section (.privileged_functions in this case). As a result,
        * setting dot (.) to a value sets the size of the section. */
        . = __privileged_functions_region_size__;
    } >SRAM

    .freertos_system_calls :
    {
        . = ALIGN(4);
        /* Place the FreeRTOS System Calls first in the unprivileged region. */
        __syscalls_flash_start__ = .;
        *(freertos_system_calls)
        __syscalls_flash_end__ = .;
        . = ALIGN(4);
    } >SRAM

    .text :
    {
        . = ALIGN(4);
        *(.boot)
        . = ALIGN(4);
        *(.text)
        *(.text.*)
        *(.gnu.linkonce.t.*)
        *(.plt)
        *(.gnu_warning)
        *(.gcc_execpt_table)
        *(.glue_7)
        *(.glue_7t)
        *(.vfp11_veneer)
        *(.ARM.extab)
        *(.gnu.linkonce.armextab.*)
    } > SRAM

    /* FreeRTOS kernel data. */
    .privileged_data :
    {
        . = ALIGN(4);
        *(privileged_data)
        . = ALIGN(4);
        _erelocate = .;
        /* FILL(0xDEAD); */
        /* Ensure that un-privileged data is placed after the region reserved
         * for privileged kernel data. */
        /* Note that dot (.) actually refers to the byte offset from the start
         * of the current section (.privileged_data in this case). As a result,
         * setting dot (.) to a value sets the size of the section. */
        . = __privileged_data_region_size__;
    } > SRAM

    .mem_tcm(NOLOAD) : ALIGN(4)
    {
        _tcm_start = .;
        KEEP (*(.mem_tcm))
        _tcm_end = .;
    } > TCM

    .init :
    {
        KEEP (*(.init))
    } > SRAM

    .fini :
    {
        KEEP (*(.fini))
    } > SRAM

    .interp :
    {
        KEEP (*(.interp))
    } > SRAM

    .note-ABI-tag :
    {
        KEEP (*(.note-ABI-tag))
    } > SRAM

    .ctors :
    {
        __CTOR_LIST__ = .;
        ___CTORS_LIST___ = .;
        KEEP (*crtbegin.o(.ctors))
        KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors))
        KEEP (*(SORT(.ctors.*)))
        KEEP (*(.ctors))
        __CTOR_END__ = .;
        ___CTORS_END___ = .;
    } > SRAM

    .dtors :
    {
        __DTOR_LIST__ = .;
        ___DTORS_LIST___ = .;
        KEEP (*crtbegin.o(.dtors))
        KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors))
        KEEP (*(SORT(.dtors.*)))
        KEEP (*(.dtors))
        __DTOR_END__ = .;
        ___DTORS_END___ = .;
    } > SRAM

    .fixup :
    {
        *(.fixup)
    } > SRAM

    .eh_frame :
    {
        *(.eh_frame)
    } > SRAM

    .eh_framehdr :
    {
        *(.eh_framehdr)
    } > SRAM

    .gcc_except_table :
    {
        *(.gcc_except_table)
    } > SRAM

    .rodata : ALIGN(4)
    {
        *(.rodata)
        *(.rodata.*)
        *(.gnu.linkonce.r.*)
    } > SRAM

    .rodata1 : ALIGN(4) {
        *(.rodata1)
        *(.rodata1.*)

        _shell_command_start = .;
        KEEP (*(shellCommand))
        _shell_command_end = .;
    } > SRAM

    .data : ALIGN(4)
    {
        *(.data)
        *(.data.*)
        *(.gnu.linkonce.d.*)
        *(.jcr)
        *(.got)
        *(.got.plt)
    } > SRAM

    .got :
    {
        *(.got)
    } > SRAM

    .mmu_tbl (ALIGN(16384)) :
    {
        *(.mmu_tbl)
    } > SRAM

    .ARM.exidx :
    {
        *(.ARM.exidx*)
        *(.gnu.linkonce.armexidix.*.*)
    } > SRAM

    .preinit_array :
    {
        KEEP (*(SORT(.preinit_array.*)))
        KEEP (*(.preinit_array))
    } > SRAM

    .init_array :
    {
        KEEP (*(SORT(.init_array.*)))
        KEEP (*(.init_array))
    } > SRAM

    .fini_array :
    {
        KEEP (*(SORT(.fini_array.*)))
        KEEP (*(.fini_array))
    } > SRAM

    .ARM.attributes :
    {
        *(.ARM.attributes)
    } > SRAM

    .sbss (NOLOAD) : ALIGN(4)
    {
        __sbss_start__ = .;
        *(.sbss)
        *(.sbss.*)
        __sbss_end__ = .;
    } > SRAM

    .bss (NOLOAD) : ALIGN(4)
    {
        __bss_start__ = .;
        *(.bss)
        *(.bss.*)
        *(.gnu.linkonce.b.*)
        *(COMMON)
        __bss_end__ = .;
    } > SRAM

    /* Allocate Stack and Heap definitions */
    .heap (NOLOAD) :
    {
        . = ALIGN(16);
        _heap = .;
        HeapBase = .;
        _heap_start = .;
        PROVIDE(end = .);
        . += _HEAP_SIZE;
        _heap_end = .;
        HeapLimit = .;
    } > SRAM

    .stack (NOLOAD) :
    {
        _stack_end = .;
        . += _STACK_SIZE;
        . = ALIGN(16);
        __sys_stack_start__ = .;

        _irq_stack_end = .;
        . += _IRQ_STACK_SIZE;
        . = ALIGN(16);
        __irq_stack_start__ = .;

        _supervisor_stack_end = .;
        . += _SUPERVISOR_STACK_SIZE;
        . = ALIGN(16);
        __supervisor_stack_start__ = .;

        _abort_stack_end = .;
        . += _ABORT_STACK_SIZE;
        . = ALIGN(16);
        __abort_stack_start__ = .;

        _fiq_stack_end = .;
        . += _FIQ_STACK_SIZE;
        . = ALIGN(16);
        __fiq_stack_start__ = .;

        _undef_stack_end = .;
        . += _UNDEF_STACK_SIZE;
        . = ALIGN(16);
        __undef_stack_start__ = .;
  } > SRAM
}

It blocked in function vPortStartFirstTask of file portASM.S:
/*

  • void vPortStartFirstTask( void );
    /
    .align 4
    .global vPortStartFirstTask
    .type vPortStartFirstTask, %function
    vPortStartFirstTask:
    /
    This function is called from System Mode to start the FreeRTOS-Kernel.
    • As described in the portRESTORE_CONTEXT macro, portRESTORE_CONTEXT cannot
    • be called from the System mode. We, therefore, switch to the Supervisor
    • mode before calling portRESTORE_CONTEXT. */
      CPS #SVC_MODE
      portRESTORE_CONTEXT

Can any one help to take a look ?
Many thanks!

Hi @Allenhe123
Welcome to the FreeRTOS Community Forums!

Can you debug through the code in vPortStartFirstTask and see in which part of the assembly code, its getting stuck ?

Also can you provide the entire code, or the number of tasks you are creating, which helps us determine if your _STACK_SIZE( 2KB ) and _HEAP_SIZE( 2 KB ) are sufficient.

thanks for your reply.
Some update:

  1. CPS #SVC_MODE stucked.
  2. I have not created any task. the main codes just like bellow:
FUNC(void, OS_CODE)
  StartupTask(void)
{
       TaskHandle_t xHandle = NULL;
	int* p = 0xB7000000;
	*p = 0x6688;
       taskENTER_CRITICAL();

       xCreatedEventGroup[EVENT_GROUP_WDG_ID] = xEventGroupCreate();
    	
	*p = 0x6699;
       ipc_trans_layer_start(0, 0);
    	
	*p = 0x7788;
       portTASK_USES_FLOATING_POINT();
    	
	*p = 0x8888;
       taskEXIT_CRITICAL();
    	
      *p = 0x9999;
       vTaskStartScheduler();
    *p = 0x1111;
}

p = 0x** just used for debug.

  1. github . com / Allenhe123 / FreeRTOS_test
    (i can not put a link here because i am a new fish :), the above url can be used by remove space)

the call stack is:
vTaskStartScheduler();
→ xPortStartScheduler()
→ vPortStartFirstTask();

In the project
two ports ARM_CR5 and ARM_CRx_MPU are added.

  1. You can try removing ARM_CR5 because in this port, MPU is disabled.
  2. configENABLE_FPU is not set in FreeRTOSConfig.h, but you are calling portTASK_USES_FLOATING_POINT() .
    This can lead to hanging at CPS #19 (SVC mode) because the system tries to access an uninitialized FPU.

Can you try out these two steps and update the findings?

Hi,

  1. files in ARM_CR5 directory were not used, just ARM_CRx_MPU was used.
  2. add: #define configENABLE_FPU 1U
  3. change stack and heap size:

_STACK_SIZE = 16 * 20x400;
_HEAP_SIZE = 16 * 2
0x400;

_SYSTEM_STACK_SIZE = 16 * 2 * 1024;
_ABORT_STACK_SIZE = 512;
_SUPERVISOR_STACK_SIZE = 16 * 2 * 1024;

But the problem remains.

If i try to add a task in StartupTask function, the code will be stucked in below function:
void * pvPortMalloc( size_t xWantedSize )

void vTaskFunction(void* p) {
    printf("hhahahhhah\n");

}

/* Fill in a TaskParameters_t structure to define the task - this is the
   structure passed to the xTaskCreateRestricted() function. */
static const TaskParameters_t xTaskDefinition =
{
    vTaskFunction, /* pvTaskCode */
    "A task", /* pcName */
    128, /* usStackDepth - defined in words, not bytes. */
    NULL, /* pvParameters */
    1, /* uxPriority - priority 1, start in User mode. */
    xTaskStack, /* puxStackBuffer - the array to use as the task stack. */

    /* xRegions - In this case only one of the three user definable regions is
       actually used. The parameters are used to set the region to read only. */
    {
        /* Base address Length Parameters */
        { cReadOnlyArray, 512, tskMPU_REGION_READ_ONLY },
        { 0, 0, 0 },
        { 0, 0, 0 },
    }
};

FUNC(void, OS_CODE)
  StartupTask(void)
{
       TaskHandle_t xHandle = NULL;
	int* p = 0xB7000000;
	*p = 0x6688;
       taskENTER_CRITICAL();

 **xTaskCreateRestricted( &xTaskDefinition, NULL );**

       xCreatedEventGroup[EVENT_GROUP_WDG_ID] = xEventGroupCreate();
    	
	*p = 0x6699;
       ipc_trans_layer_start(0, 0);
    	
	*p = 0x7788;
       portTASK_USES_FLOATING_POINT();
    	
	*p = 0x8888;
       taskEXIT_CRITICAL();
    	
      *p = 0x9999;
       vTaskStartScheduler();
    *p = 0x1111;
}

the call stack is:
xTaskCreateRestricted( &xTaskDefinition, NULL ); – >
BaseType_t MPU_xTaskCreateRestricted(…) – >
xTaskCreateRestricted() – >
prvCreateRestrictedTask() – >
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );

I have debug and got the failed line:
heap_4.c
void * pvPortMalloc( size_t xWantedSize )

    #if ( configUSE_MALLOC_FAILED_HOOK == 1 )
        {            
            if( pvReturn == NULL )
            {
                extern void vApplicationMallocFailedHook( void );
                *vApplicationMallocFailedHook();*
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }

the malloc failed and call vApplicationMallocFailedHook(); which is a function user defined.
So the problem now is the malloc failed, Can any one help to take a look and give some advice? thanks a lot !

Could you please try setting configENABLE_MPU to 0U and verify whether the rest of the code logic functions as expected? If it does, that would confirm the issue is related to the MPU configuration.

If pvPortMalloc() is failing, it means FreeRTOS is running out of heap memory.

Before calling pvPortMalloc(), check available heap:

UBaseType_t freeHeap = xPortGetFreeHeapSize();
printf("Free heap before malloc: %lu bytes\n", freeHeap);

This helps you see how much memory is left.

Since you’re using MPU, ensure that the heap is in a region accessible to tasks. Otherwise, an MPU fault could block memory allocation.
You are passing xTaskStack as the stack buffer, how is it defined? It needs to be placed in a MPU-accessible region.

Thanks for your advice.
I changed configENABLE_MPU = 0 and do some tests, results :

  1. built the project using ARM_CR5, it’s running OK.
  2. built the project using ARM_CRx_MPU, below errors:
    undefined reference to FreeRTOS_SWI_Handler' undefined reference to FreeRTOS_Tick_Handler’

The above two functions can be found in ARM_CR5/portASM.S, but disappear in ARM_CRx_MPU/portASM.S.

My current solution is copy the two functions from ARM_CR5/portASM.S to ARM_CRx_MPU/portASM.S. Is it right?

thank you, adopt bhoomrs’s advice, I changed configENABLE_MPU = 0 and do some tests, results :

  1. built the project using ARM_CR5, it’s running OK.
  2. built the project using ARM_CRx_MPU, below errors:
    undefined reference to FreeRTOS_SWI_Handler' undefined reference to FreeRTOS_Tick_Handler’

The above two functions can be found in ARM_CR5/portASM.S, but disappear in ARM_CRx_MPU/portASM.S.

My current solution is copy the two functions from ARM_CR5/portASM.S to ARM_CRx_MPU/portASM.S. Is it right? Or there are other functions to replace the above two functions when using MPU ?

FreeRTOS_SWI_Handler(Software Interrupt Handler) maps to FreeRTOS_SVC_Handler(Supervisor Call Handler) in ARM_CRx_MPU.
You can use it directly, but keep a lookout for the MPU privilege escalations.

FreeRTOS_Tick_Handler is not implemented in ARM_CRx_MPU and is expected to be provided in the application code. You can use the one provided in ARM_CR5/port.c or here

thank you for your guide.
some update:

  1. built the project using ARM_CR5, it’s running OK.
  2. built the project using ARM_CRx_MPU:
    2.1. using FreeRTOS_SVC_Handler to replace FreeRTOS_SWI_Handler;
    2.2. using void FreeRTOS_Tick_Handler( void ) as below:
void FreeRTOS_Tick_Handler( void )
{
    uint32_t ulInterruptStatus;

    ulInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();

    /* Increment the RTOS tick. */
    if( xTaskIncrementTick() != pdFALSE )
    {
        ulPortYieldRequired = pdTRUE;
    }

    portCLEAR_INTERRUPT_MASK_FROM_ISR( ulInterruptStatus );

    configCLEAR_TICK_INTERRUPT();
}

2.3. using configs as:

#define configENABLE_MPU                                       0U
#define configENABLE_FPU                                       1U
#define configUSE_MPU_WRAPPERS_V1                              0U
#define configTOTAL_MPU_REGIONS 16
#define configSYSTEM_CALL_STACK_SIZE 2048
#define configPROTECTED_KERNEL_OBJECT_POOL_SIZE 128
#define INCLUDE_xTaskGetSchedulerState 1
#define configUSE_EVENT_GROUPS 1

Still stuck on line CPS #SVC_MODE :

/*
 * void vPortStartFirstTask( void );
 */
.align 4
.global vPortStartFirstTask
.type vPortStartFirstTask, %function
vPortStartFirstTask:
    /* This function is called from System Mode to start the FreeRTOS-Kernel.
     * As described in the portRESTORE_CONTEXT macro, portRESTORE_CONTEXT cannot
     * be called from the System mode. We, therefore, switch to the Supervisor
     * mode before calling portRESTORE_CONTEXT. */
    **CPS #SVC_MODE**
    portRESTORE_CONTEXT

The newest codes have been uploaded to GitHub - Allenhe123/FreeRTOS_test

Could you please help to check, thanks a lot.

PS:

The origin code of FreeRTOS_Tick_Handler in our CR5 as below, try this one, still the same error.

void FreeRTOS_Tick_Handler( void )
{
    /*
     * Set interrupt mask before altering scheduler structures.   The tick
     * handler runs at the lowest priority, so interrupts cannot already be masked,
     * so there is no need to save and restore the current mask value.  It is
     * necessary to turn off interrupts in the CPU itself while the ICCPMR is being
     * updated.
     */
    portCPU_IRQ_DISABLE();
    portICCPMR_PRIORITY_MASK_REGISTER = ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
    __asm volatile ( "dsb       \n"
                     "isb       \n" ::: "memory" );
    portCPU_IRQ_ENABLE();

    /* Increment the RTOS tick. */
    if( xTaskIncrementTick() != pdFALSE )
    {
        ulPortYieldRequired = pdTRUE;
    }

    /* Ensure all interrupt priorities are active again. */
    portCLEAR_INTERRUPT_MASK();
    configCLEAR_TICK_INTERRUPT();
}

Is this the complete code? Your boot code seem to configure bunch of MPU regions which likely will interfere with the MPU regions configured by FreeRTOS. Why do you have these MPU configurations in the boot code?

Which hardware are you using? Do you have a working bare metal project for your hardware?

In fact this is almost the complete code except few init codes which i think are not related to this issue.
Maybe the configuration code of some MPU regions are just copied from bare metal project which is used to verify the hardware function.
The hardware is ARMv7 R5F, only 1 core.

So i think i can remove the MPU regions in boot.S and take a try?

It will still be good to add all the project files.

Is it a custom built core or did you get it from a vendor? If later, what is the part number?

Yes, please. Try and see if that works.

Tkank you.

  1. i have added the main.c to GitHub - Allenhe123/FreeRTOS_test

  2. The Cortex-R5F processor is a Cortex-R5 processor that includes the optional Floating Point Unit (FPU) extension.
    Revision: r1p2 .

  3. I have done a try.
    If i removed the MPU regions in boot.S, the project will can not run.
    With the MPU regions in boot.S, the project will stuck in CPS #SVC_MODE just the same error as above.
    PS: I have disabled MPU using:
    #define configENABLE_MPU 0U
    So it seems not related to MPU now?

Since you are not telling the part number, I cannot lookup the datasheet myself. I’ll try to answer based on the information you have provided. Reading this, I assume your hardware has 16 MPU regions. If so, you can update your boot code to use MPU regions numbers 8-15 and set configTOTAL_MPU_REGIONS to 8 so that FreeRTOS will use MPU region numbers 0-7.

If you do not want to use MPU, you need to use ARM_CR5 port. This flag is not used in ARM_CRx_MPU port and therefore, does not disable MPU.

It may be a good idea to first get the non-MPU port working.

Thank you.

  1. It seems we can not set MPU regions to 8:
#include "FreeRTOSConfig.h"

#ifndef configTOTAL_MPU_REGIONS
    #error "Set configTOTAL_MPU_REGIONS to the humber of MPU regions in FreeRTOSConfig.h"
#elif( configTOTAL_MPU_REGIONS == 12 )
    #define portMPU_TOTAL_REGIONS ( 12UL )
#elif( configTOTAL_MPU_REGIONS == 16 )
    #define portMPU_TOTAL_REGIONS ( 16UL )
#else
    #error "Set configTOTAL_MPU_REGIONS to the number of MPU regions in FreeRTOSConfig.h"
#endif /* configTOTAL_MPU_REGIONS */
  1. I have figured out that non-MPU port working fine.
  2. I not very clear what;s the part number mean, i have the Technical Reference Manual pdf, if you need i can provide.

Cortex-R5
Technical Reference Manual
Copyright © 2010-2011 ARM. All rights reserved.