This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MCU-PLUS-SDK-AM243X: abort-handler usage

Part Number: MCU-PLUS-SDK-AM243X

Hello,

I want to use the abort-handler to store some data from the environment where the abort happened. once a colleague already answered me:
https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1265729/mcu-plus-sdk-am243x-change-in-abort-handling-in-sdk-08-06/4801821?tisearch=e2e-sitesearch&keymatch=%2525252525252520user%252525252525253A453845#4801821
So today I tried implementing this.

So I have two questions:

1. the repairing of the stackframe

Looking at HwiP_armv7r_handlers_nortos_asm.S this is what happens before the new HwiP_data_abort_handler_c -abort-handler is called:

        /*   Push used registers. */
        PUSH	{r0-r4, r12}

        /* SPSR has the snapshot of CPSR before data abort. Compare thumb state bit in SPSR */
        MRS r0, SPSR
        AND r1, r0, #0x20
        CMP R1, #0

        /* branches to label ARM_STATE if the thumb state bit is not set */
        BEQ ARM_STATE
        SUB lr, lr, #2
        ARM_STATE:
        SUB lr, lr, #4
        END:

        /*   Push the return address and SPSR. */
        PUSH	{lr}
        MRS	lr, SPSR
        PUSH	{lr}

        /*   Call the interrupt handler. */
        LDR	r1, HwiP_data_abort_handler_const
        BLX	r1

We an see some registers are pushed onto the stack, the LR is corrected and later on the HwiP_data_abort_handler_c is called.

So Abishek already wrote a solution to pop the correct LR to at least get the stackframe working again:

/* Restore used registers, LR and SPSR before returning. */
POP {LR}
MSR SPSR_cxsf, LR
POP {LR}
POP {r0-r4, r12}

unfortunately this is not working out of the box. I would've thought that calling the HwiP_data_abort_handler_c would push only two registers on the stack (for the ARM 8-byte-alignment) but unfortunately the correct registers are 16 Bytes away from the original LR.

For a better understanding let's look what happens in case of an abort:

we see in the LR the previous PC (+8) which caused the abort. That's good.

Then the corrected LR gets pushed onto the stack (see the memory view right hand):

as soon as the new HwiP_data_abort_handler_c is entered the LR is messed up:

also the stackframe is:

and check the SP. As soon as I step above the entry point of the function it progresses 16 bytes instead of my suggested 8 Bytes:

I now wanted to add the previous sugested solution but this does not work since of course the LR is not there to be popped. it's 16 Bytes away. That's because of the 00000d28:   E24DD008            sub        r13, r13, #8 instruction which I don't understand to be honest.

well it's not a problem to take that into account and to correct this value afterwards.

then it will look like this:

as you can see the LR is now correct. but unfortunately the stack-frame is not fixed again, it stays in the old view:

How can I force CCS to show the correct stack-frame again?

2. I want to store the occuring PC and SP

Well now we can at least get the PC/LR correctly. but what about the SP? In my example the SP before the abort would be:

as soon as the abort happens the SP is overwritten of course. But it is still available in the User-register:

How can I access the user register and retrieve the value from there? Unfortunately I am no arm-developer and I guess I can switch the mode to user mode and get it somehow but the documentation out there is not really helping and links to the arm-documentation are not reliable since it changes like every some years.

Best regards

Felix

  • Felix

    Is there in example on the MCU-PLUS-SDK-AM243X which you can provide a patch on to replicate this on the EVM?

    Regards

    Karan

  • Hey Karan,

    I modified the task_switch-example:

    /*
     *  Copyright (C) 2018-2021 Texas Instruments Incorporated
     *
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #include <stdio.h>
    #include <string.h>
    #include <inttypes.h>
    #include <kernel/dpl/DebugP.h>
    #include <kernel/dpl/ClockP.h>
    #include <kernel/dpl/HwiP.h>
    #include <FreeRTOS.h>
    #include <task.h>
    #include <semphr.h>
    #include "ti_drivers_open_close.h"
    #include "ti_board_open_close.h"
    
    /*
     * IMPORTANT NOTES:
     *
     * Alignment of stack is not strictly needed for R5F but debug is easier if stack is nicely
     * aligned.
     *
     * Task priority, 0 is lowest priority, configMAX_PRIORITIES-1 is highest
     * For this example any valid task priority can be set.
     *
     * See FreeRTOSConfig.h for configMAX_PRIORITIES and StackType_t type.
     * FreeRTOSConfig.h can be found under kernel/freertos/config/${device}/${cpu}/
     *
     * In this example,
     * We create task's, semaphore's, ISR's and stack for the tasks using static allocation.
     * We dont need to delete these semaphore's since static allocation is used.
     *
     * One MUST not return out of a FreeRTOS task instead one MUST call vTaskDelete instead.
     */
    
    #define NUM_TASK_SWITCHES      (1000000u)
    
    #define PING_INT_NUM           (20u)
    #define PONG_INT_NUM           (21u)
    
    #define PING_TASK_PRI  (2u)
    #define PONG_TASK_PRI  (3u)
    
    #define PING_TASK_SIZE (1024u)
    StackType_t gPingTaskStack[PING_TASK_SIZE] __attribute__((aligned(32)));
    
    #define PONG_TASK_SIZE (1024u)
    StackType_t gPongTaskStack[PONG_TASK_SIZE] __attribute__((aligned(32)));
    
    StaticTask_t gPingTaskObj;
    TaskHandle_t gPingTask;
    StaticSemaphore_t gPingSemObj;
    SemaphoreHandle_t gPingSem;
    HwiP_Object gPingHwiObj;
    
    StaticTask_t gPongTaskObj;
    TaskHandle_t gPongTask;
    StaticSemaphore_t gPongSemObj;
    SemaphoreHandle_t gPongSem;
    HwiP_Object gPongHwiObj;
    
    typedef void (*myFunc)(uint32_t myVal);
    
    struct AbortStruct_T
    {
        myFunc functionTest;
        uint32_t testVal;
    } AbortStruct;
    
    
    static void ping_isr(void *arg)
    {
        BaseType_t doTaskSwitch = 0;
    
        xSemaphoreGiveFromISR( gPongSem, &doTaskSwitch); /* wake up pong task */
        portYIELD_FROM_ISR( doTaskSwitch );
    }
    
    static void pong_isr(void *arg)
    {
        BaseType_t doTaskSwitch = 0;
    
        xSemaphoreGiveFromISR( gPingSem, &doTaskSwitch); /* wake up ping task */
        portYIELD_FROM_ISR( doTaskSwitch );
    }
    
    void ping_main(void *args)
    {
        uint32_t count; /* loop `count` times */
        uint64_t curTime;
        struct AbortStruct_T* abortStruct = (struct AbortStruct_T*)0x90000000;
        abortStruct->testVal = 43;
    
        DebugP_log("\r\n");
        DebugP_log("[FreeRTOS] ping task ... start !!!\r\n");
        { /* switch between ping and pong tasks using semaphores */
            count = NUM_TASK_SWITCHES;
            curTime = ClockP_getTimeUsec();
            while(count--)
            {
                xSemaphoreGive( gPongSem); /* wake up pong task */
                xSemaphoreTake( gPingSem, portMAX_DELAY); /* wait for pong to signal */
            }
            curTime = ClockP_getTimeUsec() - curTime;
    
            DebugP_log("\r\n");
            DebugP_log("execution time for task switches = %" PRId64 " us\r\n", curTime);
            DebugP_log("number of task switches = %" PRId32 " \r\n", (uint32_t)NUM_TASK_SWITCHES*2);
            DebugP_log("time per task switch (semaphore give/take) = %" PRId32 " ns\r\n", (uint32_t)(curTime*1000/(NUM_TASK_SWITCHES*2)));
        }
        { /* switch between ping and pong tasks using direct-to-task notifications */
            count = NUM_TASK_SWITCHES;
            curTime = ClockP_getTimeUsec();
            while(count--)
            {
                xTaskNotifyGive( gPongTask); /* wake up pong task */
                ulTaskNotifyTake( pdTRUE, portMAX_DELAY); /* wait for pong to signal */
            }
            curTime = ClockP_getTimeUsec() - curTime;
    
            DebugP_log("\r\n");
            DebugP_log("execution time for task switches = %" PRId64 " us\r\n", curTime);
            DebugP_log("number of task switches = %" PRId32 " \r\n", (uint32_t)NUM_TASK_SWITCHES*2);
            DebugP_log("time per task switch (direct-to-task notification give/take) = %" PRId32 " ns\r\n", (uint32_t)(curTime*1000/(NUM_TASK_SWITCHES*2)));
        }
        { /* switch from ping task to ISR to pong task and back to ping task using semaphores, here there is a task switch */
            HwiP_Params hwiParams;
    
            HwiP_Params_init(&hwiParams);
            hwiParams.intNum = PING_INT_NUM;
            hwiParams.callback = ping_isr;
            HwiP_construct(&gPingHwiObj, &hwiParams);
    
            count = NUM_TASK_SWITCHES;
            curTime = ClockP_getTimeUsec();
            while(count--)
            {
                HwiP_post(PING_INT_NUM);
                xSemaphoreTake( gPingSem, portMAX_DELAY); /* wait for ISR to signal */
            }
            curTime = ClockP_getTimeUsec() - curTime;
    
            HwiP_destruct(&gPingHwiObj);
    
            DebugP_log("\r\n");
            DebugP_log("execution time for task - ISR - task - task switches = %" PRId64 " us\r\n", curTime);
            DebugP_log("number of ISRs = %" PRId32 " \r\n", (uint32_t)NUM_TASK_SWITCHES*2);
            DebugP_log("time per task - ISR - task switch (semaphore give/take) = %" PRId32 " ns\r\n", (uint32_t)(curTime*1000/(2*NUM_TASK_SWITCHES)));
        }
    
        /* delay some time, just to show delay works */
        vTaskDelay( ClockP_usecToTicks(100*1000) );
        vTaskDelay( ClockP_usecToTicks(101*1000) );
    
        DebugP_log("\r\n");
        DebugP_log("[FreeRTOS] ping task ... done !!!\r\n");
        DebugP_log("\r\n");
        DebugP_log("All tests have passed!!\r\n");
    
        /* One MUST not return out of a FreeRTOS task instead one MUST call vTaskDelete */
        vTaskDelete(NULL);
    }
    
    void pong_main(void *args)
    {
        uint32_t count; /* loop `count` times */
    
        count = NUM_TASK_SWITCHES;
        while(count--)
        {
            xSemaphoreTake( gPongSem, portMAX_DELAY); /* wait for ping to signal */
            xSemaphoreGive( gPingSem); /* wakeup ping task */
        }
        count = NUM_TASK_SWITCHES;
        while(count--)
        {
            ulTaskNotifyTake( pdTRUE, portMAX_DELAY); /* wait for ping to signal */
            xTaskNotifyGive( gPingTask); /* wake up ping task */
        }
        {
            HwiP_Params hwiParams;
    
            HwiP_Params_init(&hwiParams);
            hwiParams.intNum = PONG_INT_NUM;
            hwiParams.callback = pong_isr;
            HwiP_construct(&gPongHwiObj, &hwiParams);
    
            count = NUM_TASK_SWITCHES;
            while(count--)
            {
                xSemaphoreTake( gPongSem, portMAX_DELAY); /* wait for ISR to signal */
                HwiP_post(PONG_INT_NUM);
            }
            HwiP_destruct(&gPongHwiObj);
        }
        /* One MUST not return out of a FreeRTOS task instead one MUST call vTaskDelete */
        vTaskDelete(NULL);
    }
    
    void task_switch_main(void *args)
    {
        /* Open drivers to open the UART driver for console */
        Drivers_open();
        Board_driversOpen();
    
        /* first create the semaphores */
        gPingSem = xSemaphoreCreateBinaryStatic(&gPingSemObj);
        configASSERT(gPingSem != NULL);
        vQueueAddToRegistry(gPingSem, "Ping Sem"); /* This makes the semaphore visible in ROV within CCS IDE */
    
        gPongSem = xSemaphoreCreateBinaryStatic(&gPongSemObj);
        configASSERT(gPongSem != NULL);
        vQueueAddToRegistry(gPongSem, "Pong Sem"); /* This makes the semaphore visible in ROV within CCS IDE */
    
        /* then create the tasks, order of task creation does not matter for this example */
        gPongTask = xTaskCreateStatic( pong_main,      /* Pointer to the function that implements the task. */
                                      "pong",          /* Text name for the task.  This is to facilitate debugging only. */
                                      PONG_TASK_SIZE,  /* Stack depth in units of StackType_t typically uint32_t on 32b CPUs */
                                      NULL,            /* We are not using the task parameter. */
                                      PONG_TASK_PRI,   /* task priority, 0 is lowest priority, configMAX_PRIORITIES-1 is highest */
                                      gPongTaskStack,  /* pointer to stack base */
                                      &gPongTaskObj ); /* pointer to statically allocated task object memory */
        configASSERT(gPongTask != NULL);
    
        gPingTask = xTaskCreateStatic( ping_main,      /* Pointer to the function that implements the task. */
                                      "ping",          /* Text name for the task.  This is to facilitate debugging only. */
                                      PING_TASK_SIZE,  /* Stack depth in units of StackType_t typically uint32_t on 32b CPUs */
                                      NULL,            /* We are not using the task parameter. */
                                      PING_TASK_PRI,   /* task priority, 0 is lowest priority, configMAX_PRIORITIES-1 is highest */
                                      gPingTaskStack,  /* pointer to stack base */
                                      &gPingTaskObj ); /* pointer to statically allocated task object memory */
        configASSERT(gPingTask != NULL);
    
        Board_driversClose();
        /* Dont close drivers to keep the UART driver open for console */
        /* Drivers_close(); */
    }
    
    void __attribute__((interrupt("ABORT"), section(".text.hwi"))) HwiP_data_abort_handler_c(void)
    {
        /* correct sp */
        __asm("ADD r13, r13, #8");
        /* two pops because we entered this function which incremented the stack */
        __asm("POP {IP, LR}");
        /* retrieving the correct values for LR */
        __asm("POP {LR}");
        __asm("MSR SPSR_cxsf, LR");
        __asm("POP {LR}");
        __asm("POP {r0-r4, r12}");
    #ifndef NDEBUG
        /* in debug builds we will break to identify the source of the abort */
        volatile uint32_t loop = 1;
        while(loop)
            ;
    #endif
    }
    
    

    just copy that in and you should be able to reproduce. Maybe set an breakpoint directly at the start of HwiP_data_abort_handler_c for better debugging because I am not sure about the NDEBUG-define. We have it in our project but I am not sure about the TI-examples. An please note that we are utilizing TCMA and TCMB for all interrupt-handlers, not the internal SRAM. so the addresses may look different.

    Edit: I noticed that the example does not work the same way our project does. Here it seems I need to increment the sp for the abort-stack two times more than in our project to get back the correct LR since the dissassembly pushes two more registers onto the stack:

    That makes things more complicated.

    Well we just want to achieve to get back the correct LR at least and at best the correct SP from exactly that line of code which produces the abort.

    It worked well with the previous SDK-versions but as soon as TI introduced the abort-handler with the "_c" at the end, we started to get problems. If there is no reliable solution we may switch back to the old handling, and remove the code from the abort-handler assembly-file.

    best regards

    Felix

  • Ok I changed the abort-stack-register-push-location based on the define for the Abort-stack-end, and based on that decremented to the pushed registers of LR and SPSR:

    /*
     *  Copyright (C) 2018-2021 Texas Instruments Incorporated
     *
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #include <stdio.h>
    #include <string.h>
    #include <inttypes.h>
    #include <kernel/dpl/DebugP.h>
    #include <kernel/dpl/ClockP.h>
    #include <kernel/dpl/HwiP.h>
    #include <FreeRTOS.h>
    #include <task.h>
    #include <semphr.h>
    #include "ti_drivers_open_close.h"
    #include "ti_board_open_close.h"
    
    /*
     * IMPORTANT NOTES:
     *
     * Alignment of stack is not strictly needed for R5F but debug is easier if stack is nicely
     * aligned.
     *
     * Task priority, 0 is lowest priority, configMAX_PRIORITIES-1 is highest
     * For this example any valid task priority can be set.
     *
     * See FreeRTOSConfig.h for configMAX_PRIORITIES and StackType_t type.
     * FreeRTOSConfig.h can be found under kernel/freertos/config/${device}/${cpu}/
     *
     * In this example,
     * We create task's, semaphore's, ISR's and stack for the tasks using static allocation.
     * We dont need to delete these semaphore's since static allocation is used.
     *
     * One MUST not return out of a FreeRTOS task instead one MUST call vTaskDelete instead.
     */
    
    #define NUM_TASK_SWITCHES      (1000000u)
    
    #define PING_INT_NUM           (20u)
    #define PONG_INT_NUM           (21u)
    
    #define PING_TASK_PRI  (2u)
    #define PONG_TASK_PRI  (3u)
    
    #define PING_TASK_SIZE (1024u)
    StackType_t gPingTaskStack[PING_TASK_SIZE] __attribute__((aligned(32)));
    
    #define PONG_TASK_SIZE (1024u)
    StackType_t gPongTaskStack[PONG_TASK_SIZE] __attribute__((aligned(32)));
    
    StaticTask_t gPingTaskObj;
    TaskHandle_t gPingTask;
    StaticSemaphore_t gPingSemObj;
    SemaphoreHandle_t gPingSem;
    HwiP_Object gPingHwiObj;
    
    StaticTask_t gPongTaskObj;
    TaskHandle_t gPongTask;
    StaticSemaphore_t gPongSemObj;
    SemaphoreHandle_t gPongSem;
    HwiP_Object gPongHwiObj;
    
    typedef void (*myFunc)(uint32_t myVal);
    
    struct AbortStruct_T
    {
        myFunc functionTest;
        uint32_t testVal;
    } AbortStruct;
    
    
    static void ping_isr(void *arg)
    {
        BaseType_t doTaskSwitch = 0;
    
        xSemaphoreGiveFromISR( gPongSem, &doTaskSwitch); /* wake up pong task */
        portYIELD_FROM_ISR( doTaskSwitch );
    }
    
    static void pong_isr(void *arg)
    {
        BaseType_t doTaskSwitch = 0;
    
        xSemaphoreGiveFromISR( gPingSem, &doTaskSwitch); /* wake up ping task */
        portYIELD_FROM_ISR( doTaskSwitch );
    }
    
    void ping_main(void *args)
    {
        uint32_t count; /* loop `count` times */
        uint64_t curTime;
        struct AbortStruct_T* abortStruct = (struct AbortStruct_T*)0x90000000;
        abortStruct->testVal = 43;
    
        DebugP_log("\r\n");
        DebugP_log("[FreeRTOS] ping task ... start !!!\r\n");
        { /* switch between ping and pong tasks using semaphores */
            count = NUM_TASK_SWITCHES;
            curTime = ClockP_getTimeUsec();
            while(count--)
            {
                xSemaphoreGive( gPongSem); /* wake up pong task */
                xSemaphoreTake( gPingSem, portMAX_DELAY); /* wait for pong to signal */
            }
            curTime = ClockP_getTimeUsec() - curTime;
    
            DebugP_log("\r\n");
            DebugP_log("execution time for task switches = %" PRId64 " us\r\n", curTime);
            DebugP_log("number of task switches = %" PRId32 " \r\n", (uint32_t)NUM_TASK_SWITCHES*2);
            DebugP_log("time per task switch (semaphore give/take) = %" PRId32 " ns\r\n", (uint32_t)(curTime*1000/(NUM_TASK_SWITCHES*2)));
        }
        { /* switch between ping and pong tasks using direct-to-task notifications */
            count = NUM_TASK_SWITCHES;
            curTime = ClockP_getTimeUsec();
            while(count--)
            {
                xTaskNotifyGive( gPongTask); /* wake up pong task */
                ulTaskNotifyTake( pdTRUE, portMAX_DELAY); /* wait for pong to signal */
            }
            curTime = ClockP_getTimeUsec() - curTime;
    
            DebugP_log("\r\n");
            DebugP_log("execution time for task switches = %" PRId64 " us\r\n", curTime);
            DebugP_log("number of task switches = %" PRId32 " \r\n", (uint32_t)NUM_TASK_SWITCHES*2);
            DebugP_log("time per task switch (direct-to-task notification give/take) = %" PRId32 " ns\r\n", (uint32_t)(curTime*1000/(NUM_TASK_SWITCHES*2)));
        }
        { /* switch from ping task to ISR to pong task and back to ping task using semaphores, here there is a task switch */
            HwiP_Params hwiParams;
    
            HwiP_Params_init(&hwiParams);
            hwiParams.intNum = PING_INT_NUM;
            hwiParams.callback = ping_isr;
            HwiP_construct(&gPingHwiObj, &hwiParams);
    
            count = NUM_TASK_SWITCHES;
            curTime = ClockP_getTimeUsec();
            while(count--)
            {
                HwiP_post(PING_INT_NUM);
                xSemaphoreTake( gPingSem, portMAX_DELAY); /* wait for ISR to signal */
            }
            curTime = ClockP_getTimeUsec() - curTime;
    
            HwiP_destruct(&gPingHwiObj);
    
            DebugP_log("\r\n");
            DebugP_log("execution time for task - ISR - task - task switches = %" PRId64 " us\r\n", curTime);
            DebugP_log("number of ISRs = %" PRId32 " \r\n", (uint32_t)NUM_TASK_SWITCHES*2);
            DebugP_log("time per task - ISR - task switch (semaphore give/take) = %" PRId32 " ns\r\n", (uint32_t)(curTime*1000/(2*NUM_TASK_SWITCHES)));
        }
    
        /* delay some time, just to show delay works */
        vTaskDelay( ClockP_usecToTicks(100*1000) );
        vTaskDelay( ClockP_usecToTicks(101*1000) );
    
        DebugP_log("\r\n");
        DebugP_log("[FreeRTOS] ping task ... done !!!\r\n");
        DebugP_log("\r\n");
        DebugP_log("All tests have passed!!\r\n");
    
        /* One MUST not return out of a FreeRTOS task instead one MUST call vTaskDelete */
        vTaskDelete(NULL);
    }
    
    void pong_main(void *args)
    {
        uint32_t count; /* loop `count` times */
    
        count = NUM_TASK_SWITCHES;
        while(count--)
        {
            xSemaphoreTake( gPongSem, portMAX_DELAY); /* wait for ping to signal */
            xSemaphoreGive( gPingSem); /* wakeup ping task */
        }
        count = NUM_TASK_SWITCHES;
        while(count--)
        {
            ulTaskNotifyTake( pdTRUE, portMAX_DELAY); /* wait for ping to signal */
            xTaskNotifyGive( gPingTask); /* wake up ping task */
        }
        {
            HwiP_Params hwiParams;
    
            HwiP_Params_init(&hwiParams);
            hwiParams.intNum = PONG_INT_NUM;
            hwiParams.callback = pong_isr;
            HwiP_construct(&gPongHwiObj, &hwiParams);
    
            count = NUM_TASK_SWITCHES;
            while(count--)
            {
                xSemaphoreTake( gPongSem, portMAX_DELAY); /* wait for ISR to signal */
                HwiP_post(PONG_INT_NUM);
            }
            HwiP_destruct(&gPongHwiObj);
        }
        /* One MUST not return out of a FreeRTOS task instead one MUST call vTaskDelete */
        vTaskDelete(NULL);
    }
    
    void task_switch_main(void *args)
    {
        /* Open drivers to open the UART driver for console */
        Drivers_open();
        Board_driversOpen();
    
        /* first create the semaphores */
        gPingSem = xSemaphoreCreateBinaryStatic(&gPingSemObj);
        configASSERT(gPingSem != NULL);
        vQueueAddToRegistry(gPingSem, "Ping Sem"); /* This makes the semaphore visible in ROV within CCS IDE */
    
        gPongSem = xSemaphoreCreateBinaryStatic(&gPongSemObj);
        configASSERT(gPongSem != NULL);
        vQueueAddToRegistry(gPongSem, "Pong Sem"); /* This makes the semaphore visible in ROV within CCS IDE */
    
        /* then create the tasks, order of task creation does not matter for this example */
        gPongTask = xTaskCreateStatic( pong_main,      /* Pointer to the function that implements the task. */
                                      "pong",          /* Text name for the task.  This is to facilitate debugging only. */
                                      PONG_TASK_SIZE,  /* Stack depth in units of StackType_t typically uint32_t on 32b CPUs */
                                      NULL,            /* We are not using the task parameter. */
                                      PONG_TASK_PRI,   /* task priority, 0 is lowest priority, configMAX_PRIORITIES-1 is highest */
                                      gPongTaskStack,  /* pointer to stack base */
                                      &gPongTaskObj ); /* pointer to statically allocated task object memory */
        configASSERT(gPongTask != NULL);
    
        gPingTask = xTaskCreateStatic( ping_main,      /* Pointer to the function that implements the task. */
                                      "ping",          /* Text name for the task.  This is to facilitate debugging only. */
                                      PING_TASK_SIZE,  /* Stack depth in units of StackType_t typically uint32_t on 32b CPUs */
                                      NULL,            /* We are not using the task parameter. */
                                      PING_TASK_PRI,   /* task priority, 0 is lowest priority, configMAX_PRIORITIES-1 is highest */
                                      gPingTaskStack,  /* pointer to stack base */
                                      &gPingTaskObj ); /* pointer to statically allocated task object memory */
        configASSERT(gPingTask != NULL);
    
        Board_driversClose();
        /* Dont close drivers to keep the UART driver open for console */
        /* Drivers_close(); */
    }
    
    void __attribute__((interrupt("ABORT"), section(".text.hwi"))) HwiP_data_abort_handler_c(void)
    {
        extern size_t __ABORT_STACK_END;
        size_t src = (size_t)&__ABORT_STACK_END;
        __asm("MOV r13, %0\n\t"
                :
                : "r" (src));
        /* correct sp */
        __asm("SUB r13, r13, #32");
        /* retrieving the correct values for LR */
        __asm("POP {LR}");
        __asm("MSR SPSR_cxsf, LR");
        __asm("POP {LR}");
        __asm("POP {r0-r4, r12}");
    #ifndef NDEBUG
        /* in debug builds we will break to identify the source of the abort */
        volatile uint32_t loop = 1;
        while(loop)
            ;
    #endif
    }
    
    

    With that you should be able to reproduce the problem I have. As you can see when you step through until line 280 the LR is loaded correctly. Somehow afterwards the volatile loop-variable corrupts the LR again... so no clue how to make this reliable for correcting the LR to the last PC where the problem occured, nor how to correct the stackframe in CCS.

  • unfortunately since there is still no answer I tried to proceed.

    At least my 2. case is not needed anymore.

    But I will still need a way to fix the wrong display of the CCS-stackframe. I need to see where we came from when I am debugging and not the previous address of the asm-abort-handler. In my understanding and further investigating this seems to be a CCS-issue and not an issue of the Registers of the AM243x, since now I have the correct LR but it is just ingoring it. So I guess it's part of a mini-trace or smth like that in CCS which is not possible to realign to the source of the abort.

    How can I fix this?

  • Since I got no answer I continued reverse engineering the problem.

    So I fixed it. It seems that the abort-stack-pointer - 9 contains the value that is used by CCS to show the stackframe correctly.
    A fix could look like this:

        size_t programCounter = 0x00000000;
        size_t spsrReg = 0x00000000;
        extern size_t __ABORT_STACK_END;    
        volatile size_t* src = (size_t*)&__ABORT_STACK_END;
        /* correct sp */
        src -= 7;
        programCounter = *src;
        src -= 1;
        spsrReg = *src;
        /* fix display in ccs: */   
        src -= 1;
        *src = programCounter;
        /* in debug builds we will break to identify the source of the abort */
        volatile uint32_t loop = 1;
        while(loop)
            ;

  • Thanks for all the detail Felix.