Main stack watermarking

Hi i’m using MIMXRT1020 (arm cortex m7) , i wanted to know if there’s a way using freertos to trace a watermark of the main stack ?
If not I would appreciate to get suggestions/references on how it can be done

To be clear, you want to get the amount of main stack used? If so, you can fill your main stack with a known pattern from your startup code and at a later point examine the memory to get an idea of how much of the stack was used.

Thanks.

Yes I understand the concept of watermarking , I tried doing it without success . Was wondering if there any rederence I can use / or there any freertos infastracture I can re-use

How the main stack gets allocated is dependent on the development tools, and how the main stack gets initialised is dependent on the C start up code which executes before main() is called. FreeRTOS code only starts running after main() is called. So you can do one of two things - either update your C startup code so it writes a known pattern into the main stack as by default it will get zeroed out, or alternatively know the address of the end of your stack (from the linker script or linker variables) and write a known pattern to the end of the stack when you enter main(). If you do the latter you cannot overwrite the whole stack as part of it will be in use by then - although very little of it.

You have to be careful to not corrupt the main stack while initializing it. You will most probably need to write this initialization code in assembly to ensure that the main stack is not corrupted during initialization. You will want to disable interrupts during initialization too.

I wrote the below example for another Cortex-M7 hardware I have which can give you an idea:

static void fillMainStack( void ) __attribute__((naked));
static void fillMainStack( void ) /* __attribute__((naked)) */
{
    /* The linker script reserves 0x400 bytes for main stack at the end of
     * RAM_D1. When this function is called some of the main stack is already in
     * use and we do not touch it. We initialize the remaining main stack with
     * 0xA5.
     *                            <------------- 0x400 ---------------->
     * +--------------------------+--------------------------+---------+
     * |                          |  Fill with 0xA5          |Used MSP |
     * +--------------------------+--------------------------+---------+
     *                            ^                          ^         ^
     *                            |                          |         |
     *                       End of Main              Current MSP   Start of Main
     *                          Stack                                 Stack
     */

    /* The code below does the following:
     * 1. Disable interrupts globally so that we do not end up corrupting the
     *    main stack while initializing it.
     * 2. Read current MSP and calulcate end of main stack. In my case, the
     *    linker script exports a variable _estack (which in the above image is
     *    start of main stack). I substract the size of the main stack (0x400)
     *    to get the end of main stack.
     * 3. Fill the area from end of main stack to current MSP with 0xA5.
     * 4. Enable interrupts before leaving the function. */
    __asm volatile
    (
        " cpsid i                           \n"
        " dsb                               \n"
        " isb                               \n"
        "                                   \n"
        " mrs r1, msp                       \n"
        " ldr r0, =_estack                  \n"
        " subs r0, #0x400                   \n"
        " mov r2, #0xA5                  \n"
        "                                   \n"
        " LoopFillPattern:                  \n"
        "    cmp r0, r1                     \n"
        "    beq Done                       \n"
        "    strb r2, [r0], #1              \n"
        "    b LoopFillPattern              \n"
        "                                   \n"
        " Done:                             \n"
        "    cpsie i                        \n"
        "                                   \n"
        " bx lr                             \n"
        " .align 4                          \n"
    );
}

static uint32_t getLastUsedMainStackAddress( void )
{
    uint32_t endOfMainStack;
    const uint8_t * pStackByte;

    /* This function does not block interrupts as it only reads the main stack.
     * As a result, it may happen that the stack gets used by an interrupt while
     * this function is calculating the last used address - in which the returned
     * value may be inaccurate by the time it is returned. */
    endOfMainStack = 0x24080000 - 0x400;

    pStackByte = ( const uint8_t * )endOfMainStack;
    while( *pStackByte == ( uint8_t ) 0xA5U )
    {
        pStackByte++;
    }

    return ( uint32_t ) pStackByte;
}

Thanks.

1 Like

Looks good , thank you!!! i’ll use it