pxCurrentTCB overwritten

Hi, I was using FreeRTOS v10.1.1 with MSP430F5438a.

I noticed that things are working fine if the portSAVE_CONTEXT is not called twice before a portRESTORE_CONTEXT has been called. However, if a second portSAVE_CONTEXT is called before the portRESTORE_CONTEXT has been called, the pxCurrentTCB would have changed based on the second portSAVE_CONTEXT. Later on, when the program try to restore the context from the first call, the old pxCurrentTCB is no longer known and the program end up going to the wrong place.

I have been trying to avoid this scenario by not allowing nested interrupt and ensuring that the interrupt stays disabled until the portRESTORE_CONTEXT has been called. However, when I try to use the tracealyzer to trace my program, the tracealyzer functions, which were called inside vTaskSwitchContext, enable my interrupt when the TRACE_EXIT_CRITICAL_SECTION() function is called, which allows the tick isr to trigger in the middle of a portyield and the above scenario happens.

I tried upgrading the FreeRTOS version to 10.4.6 but the same problem is still there.

Would like to know if I misunderstood something or am I missing something?

Regards
Kelvin

The MSP430 port doesn’t support interrupt nesting. Something must be manually re-enabling interrupts in the ISR.

yup, the TRACE_EXIT_CRITICAL_SECTION function is re-enabling the interrupts since the usCriticalNesting is 0 at exit. So is this an error on the tracealyzer library or freertos? I would like to understand where/how should I best fix this issue without messing up the intended flow.

Thanks
Kelvin

It will be in the tracealizer port. Where did you get the msp430 port from? If Percepio then they will appreciate you reporting it to them.

I am not sure if this is what you are referring to by msp430 port, but I got the portable/CCS/MSP430X folder from the freertos github under the 10.4.6 tag

TRACE_EXIT_CRITICAL_SECTION macro, which is causing problem, is from tracelyzer. @johankraft Do you have any suggestion here?

I am hoping to find the effective solutions as soon as possible.

For MSP430 Tracealyzer use portENTER_CRITICAL()/portEXIT_CRITICAL(). So this depends on the FreeRTOS port you use. So I guess it is either
Source\portable\GCC\MSP430F449
or
Source\portable\CCS\MSP430X

My first guess is it sounds like an ISR is using a non FromISR routine. ISRs should not be using non-FromISR critical sections, so portENTER_CRITICAL should never be called in an ISR.

I am using the portable\CCS\MSP430X port

I think the vPortYield is not called in ISR. However, interrupt was disabled before portSAVE_CONTEXT and should not be enabled until portRESTORE_CONTEXT load from the pxCurrentTCB. The issue occurred when portEXIT_CRITICAL called in vTaskSwitchContext by Tracealyzer enables the interrupt before portRESTORE_CONTEXT is called. Correct me if I am wrong, but I don’t think it was a violation of calling non FromISR routine in ISR but rather even when vPortYield is called outside ISR, interrupt should remain disabled.

The only trace macros in vTaskSwitchContext are traceTASK_SWITCHED_OUT and traceTASK_SWITCHED_IN. I tried to follow the definition of these macros in tracelyzer and the only enter/exit critical definition I can find is trcCRITICAL_SECTION_BEGIN_ON_CORTEX_M_ONLY which is for Cortex-M only and hence not applicable to your case. Which tracelyzer code are you using?

I tried installing Tracealyzer-4.6.3-windows64. Afterwards, I took the Percepio/Tracealyzer 4/FreeRTOS/TraceRecorder folder

Thank you for your response. I downloaded that code and looked more. I also found this article from percepio and I think you need to define TRACE_ENTER_CRITICAL_SECTION and TRACE_EXIT_CRITICAL_SECTION as mentioned in the article:

#define TRACE_ENTER_CRITICAL_SECTION() if (IN_TASK_CONTEXT) portENTER_CRITICAL()
#define TRACE_EXIT_CRITICAL_SECTION()  if (IN_TASK_CONTEXT) portEXIT_CRITICAL()

Is there a way on your hardware to determine if you are in an ISR which you can use for IN_TASK_CONTEXT above?

Thank you for the guidance. I have tried changing the macro in trcKernelPort.h to the following

/**

  • @brief Kernel specific way to properly allocate critical sections
    */
    #define TRC_KERNEL_PORT_ALLOC_CRITICAL_SECTION() \
    volatile uint16_t saved_gie

/**

  • @brief Kernel specific way to properly allocate critical sections
    */
    #define TRC_KERNEL_PORT_ENTER_CRITICAL_SECTION() \
    saved_gie = __get_SR_register() & GIE; \
    if (saved_gie != 0) {portENTER_CRITICAL()}

/**

  • @brief Kernel specific way to properly allocate critical sections
    */
    #define TRC_KERNEL_PORT_EXIT_CRITICAL_SECTION() \
    if (saved_gie != 0) {portEXIT_CRITICAL()}

and it seems to be working. I am using the GIE value to determine whether portENTER_CRITICAL and portEXIT_CRITICAL should be called since it seems like the GIE is automatically disabled when entering ISR and it seems like portENTER_CRITICAL and portEXIT_CRITICAL need/should not be called when GIE is disabled since interrupt nesting is not supported.

Do let me know if there are better alternatives.

Thanks

That seems correct. The only thing is that you should put those definitions in trcConfig.h as that file is specifically meant for user config options.