Error with mpu_wrappers_v2.c

The mcu is pending on xPortStartScheduler and I don’t know why. Do I have the right port.c and portmacro.h for cortex M4? Do you have an idea on what can be the cause of the problem?
When I use gdb to execute the program, it stops on the function portYIELD()

You need to use these files.

portYIELD is defined as the following -

#define portYIELD()    __asm volatile ( "   SVC %0  \n" ::"i" ( portSVC_YIELD ) : "memory" )

The SVC instruction should take you to this line. Can you step through the assembly and see if the control reaches there? If it does, let the code run and then break in the debugger and get the callstack and share.

This is the callstack:

Now, it doesn’t stop at a point but the tasks are not being executed. I don’t know why. Is It normal to have a call to prvProcessTimerOrBlockTask?
This is another callstack picture:

This all seems normal. How do you determine that the tasks are not being executed? Start simple and create just one task that increments a counter:

static uint32_t counter = 0;

void Task( void * param )
{
    ( void ) param;

    for( ;; )
    {
        counter += 1;
        vTaskDelay( pdMS_TO_TICKS( 1000 ) );
    }
}

Use the debugger to examine if the counter is incrementing.

The program stop at the line counter +=1; and called Dummy_Handler in the file startupsamg55.c. Dummy Handler print all the values mentionned in the picture and then start an infinite loop with while(1){}


Screenshot_20240718_102438

In the documentation of the mcu, I find that phantomISR = 4 means there is a memory management fault. Do you think it is still link to the linkerscript?
Do you have any idea about the cause of the problem?

I think it is because you did not grant the task access to counter. By default, a task has access to its stack and you need to grant access to all other memory locations explicitly. You can change the code to the following to confirm -

void Task( void * param )
{
    uint32_t counter = 0;

    ( void ) param;

    for( ;; )
    {
        counter += 1;
        vTaskDelay( pdMS_TO_TICKS( 1000 ) );
    }
}

With the modification, the memfault does not appear but the counter is not incrementing. It seems that the program ignored the line. I can not even put a breakpoint on it, the breakpoint is automatically put on the vTaskDelay line and the message is: “Note: automatically using hardware breakpoints for read-only addresses”. Even if I try to write something on the uart in the task,it doesn’t work but printing on the uart works in the callback of a timer. I share with you the main.c (it is on the repo). Do you think I have correctly set the memory regions while creating the task(I use xTaskCreateRestrictedStatic and this is how I create the xTaskDefinition:

static portSTACK_TYPE xTaskStack1[ 256 ] __attribute__((aligned(256*4)));

    /* Declare an array that will be accessed by the task.  The task should only
    be able to read from the array, and not write to it. */
    char cReadOnlyArray1[ 512 ] __attribute__((aligned(512)));

    /* Fill in a TaskParameters_t structure to define the task - this is the
    structure passed to the xTaskCreateRestricted() function. */
    static const TaskParameters_t xTaskDefinition1 =
    {
        task1,   /* pvTaskCode */
        "Task 1",        /* pcName */
        140,             /* usStackDepth - defined in words, not bytes. */
        NULL,            /* pvParameters */
        5,               /* uxPriority - priority 1, start in User mode. */
        xTaskStack1,      /* 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 */
            { cReadOnlyArray1, mainREAD_ONLY_ALIGN_SIZE, portMPU_REGION_READ_ONLY },
            { 0,	          0,                        0                        },
            { 0,	          0,                        0                        },
        },
        &xTaskBuffer1
    };

TaskHandle_t xTask1;

xTaskCreateRestrictedStatic( &xTaskDefinition1, &xTask1 );

Do you think it is correct?

I have to precise that the program works correctly when I use privileged non static tasks instead of non-privileged tasks or privileged static tasks(with privileged static tasks I have a stack overflow even when the length of the StackType_t table is the double of the uxStackdepth used for non-static tasks) .

That is most likely because the variable is optimized out by the compiler. Turn off the compiler optimizations and declare the counter as volatile -

void Task( void * param )
{
    volatile uint32_t counter = 0;

    ( void ) param;

    for( ;; )
    {
        counter += 1;
        vTaskDelay( pdMS_TO_TICKS( 1000 ) );
    }
}

Looks correct. Just make sure that cReadOnlyArray1 is not declared on stack to ensure that it is available when the task tries to access it.

If you are getting memfault with unprivileged task and not with privileged task, it means you are trying to access a memory location which the task does not have access to. Just FYI - you can make a task privileged by ORing the priority value with portPRIVILEGE_BIT:

static const TaskParameters_t xTaskDefinition1 =
    {
        task1,   /* pvTaskCode */
        "Task 1",        /* pcName */
        140,             /* usStackDepth - defined in words, not bytes. */
        NULL,            /* pvParameters */
        5 | portPRIVILEGE_BIT,               /* uxPriority - priority 1, start in User mode. */
        xTaskStack1,      /* 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 */
            { cReadOnlyArray1, mainREAD_ONLY_ALIGN_SIZE, portMPU_REGION_READ_ONLY },
            { 0,	          0,                        0                        },
            { 0,	          0,                        0                        },
        },
        &xTaskBuffer1
    };

This may be helpful in quickly determining if the issue is related to privilege.

It works correctly now, thank you.

How can I check it?

Yes, I have used it to see that it works correctly with privileged tasks before mentioning it in my previous post.

I have also seen a memfault when I try to write on uart in an unprivileged task. Have you seen it before?
This is the code of the function:

static inline size_t uart_dma_write(uart_dma_t uart_dma, const void* data, size_t data_size) {
    uart_dma_frame_t* p_tx_frame = uart_dma_tx_get_frame_buffer(uart_dma);
    if (NULL == p_tx_frame) {
        // BUSY
        return 0;  // no bytes written
    }

    const size_t nb = uart_dma_frame_add(p_tx_frame, data, data_size);
    uart_dma_tx_send_frame(uart_dma);

    return nb;
}

extern uart_dma_frame_t* uart_dma_tx_get_frame_buffer(uart_dma_t uart_dma) {
    if (false == is_uart_valid(uart_dma)) return NULL;  // GUARD
    uart_data_t* p_uart_data = get_uart_data(uart_dma);
    if (false == p_uart_data->init_done) {
        return NULL;
    }

    if (p_uart_data->tx_ongoing) {
        return NULL;
    }
    p_uart_data->tx_frame.len = 0;
    return &p_uart_data->tx_frame;
}
static inline uart_data_t* get_uart_data(uart_dma_t uart_dma) {
    static uart_data_t uart_data2 = {};

            return &uart_data2;
}

The memfault occurs in the function uart_dma_tx_get_frame_buffer( in the second line of the function)

When you declare a variable inside a function definition without static, it is allocated on the stack -

void Function( void )
{
    int onStack; /* This variable is allocated on stack. */
    static in onStack; /* This variable is NOT allocated on stack because it is static. */
}

The systematic way to address these faults is -

  1. Find out the memory location that is causing the fault. You can use MMFAR register to find out that. This doc provides good details - https://www.keil.com/appnotes/files/apnt209.pdf.
  2. Grant your task the required access to the memory location figured in the previous step.