Only one task can run

Hi Community,

I got a new port with demo for Aurix TC4x from Infineon. Somehow, it can only run one task. The demo has total three tasks:

  1. Timer service task - priority 9

  2. My dummy task - priority 1
    static void dummy_task(void* pvParameters)

    {

    (void)pvParameters;
    
    uint32 count = 0;
    
    /* Infinite loop */
    
    while (1)
    
    {
    
        /* Block the task for the defined time - 1 second */
    
        vTaskDelay(1000);
    
        printf("count is %ld\n", ++count);
    
    }
    

    }

  3. Idle task - priority 0

If I enable all three tasks, only the timer service task will run all the time. If I disable the timer service task ( #define configUSE_TIMERS ( 0 ) ), my dummy task is running all the time and vTaskDelay() seems never be dealyed at all. If I disable both timer service and dummy tasks, then idle task gets run. If I make dummy task priority the same as idle task and disable timer service task, idle task will run once and then run dummy task all the time.

Tick count seems working fine and vTaskStartScheduler() never returns as expected.

I really appreciate if you can provide some insights how I can solve the problem.

Thanks,

Charles

How do you determine the tick interrupt is running?

Assuming the tick interrupt is running, then it sounds like the trap or interrupt handler used to perform the switch from one task to the other isn’t being called. Is it installed?

Hi Richard,

Thank you very much for your reply.

I hooked up debugger and put a breakpoint inside vPortSystemTickHandler() and it stopped periodically. I also measured the accuracy of tick count. In two and half minutes, I saw the tick count increased by very close to 150,000 (my tick clock rate HZ is 1000).

Which kernel function(s) performs the switch from one task to the other? Which trap(s) or interrupt(s) should the kernel function(s) be installed into? I’m using GCC toolchain and the following code snippets maybe what you’re talking about. Do you see any out of ordinary stuff below?

void attribute( ( interrupt_handler ) ) vPortSystemContextHandler()
{
/* Disable interrupts to protect section*/
_disable();

/* Do a save, switch, execute */
vPortSaveContext( 0 );
vTaskSwitchContext();
vPortLoadContext( 0 );

_enable();

}

#define STR( x ) # x
#define XSTR( s ) STR( s )
asm (
" .pushsection .intvec_tc" XSTR( configCPU_NR ) “_” XSTR( configCONTEXT_INTERRUPT_PRIORI@progbit@progbit@progbitsY ) “,“ax”,@progbits\n”
" .align 5\n"
" _intvec_entry" XSTR( configCONTEXT_INTERRUPT_PRIORITY ) “:\n”
" svlcx\n"
" movh.a %a14, hi:vPortSystemContextHandler\n"
" lea %a14, [%a14]lo:vPortSystemContextHandler\n"
" ji %a14\n"
" .org 32\n"
" .popsection\n" );

void vPortLoadContext( unsigned char ucCallDepth )
{
uint32_t ** ppxTopOfStack;
uint32_t uxLowerCSA;

/* Dsync is required for save CSA access */
_dsync();

/* Load the new CSA id from the stack and update the stack pointer */
ppxTopOfStack = ( uint32_t ** ) pxCurrentTCB;
uxLowerCSA = **ppxTopOfStack;
( *ppxTopOfStack )++;
uxCriticalNesting = **ppxTopOfStack;
( *ppxTopOfStack )++;

/* Store the lower context directly if inside the syscall or interrupt,
 * else replace the lower context in the call stack. */
if( !ucCallDepth )
{
    /* Update the link register */
    _mtcr( portCPU_PCXI, uxLowerCSA );
    _isync();
}
else
{
    /* Update previous lower context */
    uint32_t * pxCSA = pxPortCsaToAddress( _mfcr( portCPU_PCXI ) );
    int i;

    for(i = 0; i < ucCallDepth - 1; i++)
    {
        pxCSA = pxPortCsaToAddress( pxCSA[ 0 ] );
    }

    pxCSA[ 0 ] = uxLowerCSA;
}

}

void vPortSaveContext( unsigned char ucCallDepth )
{
uint32_t ** ppxTopOfStack;
uint32_t * pxLowerCSA, * pxUpperCSA;
uint32_t uxLowerCSA;

/* Dsync is required for save CSA access */
_dsync();

/* Get the current context information. */
uxLowerCSA = _mfcr( portCPU_PCXI );

/* If this function is used inside a function from the syscall or interrupt,
 * load the correct context from the call stack */
if( ucCallDepth )
{
    uint32_t * pxCSA = pxPortCsaToAddress( uxLowerCSA );
    int i;

    for(i = 0; i < ucCallDepth - 1; i++)
    {
        pxCSA = pxPortCsaToAddress( pxCSA[ 0 ] );
    }

    uxLowerCSA = pxCSA[ 0 ];
}

pxLowerCSA = pxPortCsaToAddress( uxLowerCSA );
pxUpperCSA = pxPortCsaToAddress( pxLowerCSA[ 0 ] );

/* Load the stack pointer */
ppxTopOfStack = ( uint32_t ** ) pxCurrentTCB;
/* Update the stack info in the TCB */
*ppxTopOfStack = ( uint32_t * ) pxUpperCSA[ 2 ];
/* Place ucNestedContext */
( *ppxTopOfStack )--;
**ppxTopOfStack = uxCriticalNesting;
/* Place the lower CSA id on the stack */
( *ppxTopOfStack )--;
**ppxTopOfStack = uxLowerCSA;

}

vTaskSwitchContext.

Yes, that is right. Is vPortSystemContextHandler getting called?

No, it doesn’t get called at all.

That is the problem. It is likely that this ISR is not correctly installed. You mentioned that it is a new port from Infineon. I’d suggest reaching out to them.

Thanks for the reply.

It looks like is installed, but never triggered. I assume this is a software interrupt which is triggered by software instructions not by hardware. Can you tell me what condition and where in the code will trigger this interrupt?

There are many conditions but the easiest one to check is your timer interrupt. Create 2 tasks of equal priority and assuming you have enabled preemption and time slicing, tick interrupt should keep switching between them.

I’m not at all familiar with the architecture of the Aurix TC4x but I took a look at a TC3x demo I found here AURIX_code_examples/code_examples/iLLD_TC375_ADS_FreeRTOS_Basic at master · Infineon/AURIX_code_examples · GitHub .

Context switches can happen in one of two ways (at least from my understanding - please correct me if I’m wrong @aggarg):

  1. A call to taskYIELD(); in non-ISR code. Assuming taskYIELD is implemented in the same way for your port this should trigger an SVC call with 0, and the SVC handler (see AURIX_code_examples/code_examples/iLLD_TC375_ADS_FreeRTOS_Basic/OS/FreeRTOS/portable/GCC/TC3/port.c at 4c8985aa5275b11be13a730c031ce08944621d75 · Infineon/AURIX_code_examples · GitHub ) on your device should be setup such that SVC 0 calls vPortSyscallYield (see AURIX_code_examples/code_examples/iLLD_TC375_ADS_FreeRTOS_Basic/OS/FreeRTOS/portable/GCC/TC3/port.c at 4c8985aa5275b11be13a730c031ce08944621d75 · Infineon/AURIX_code_examples · GitHub ) that handles saving, switching context, and loading the new context.
  2. An interrupt triggers that pends a yield by calling portYIELD_FROM_ISR. This call should be in your tick interrupt handler. Looking at the example I linked for the TC3x port, this call pends the software interrupt that triggers the call to vPortSystemContextHandler (see AURIX_code_examples/code_examples/iLLD_TC375_ADS_FreeRTOS_Basic/OS/FreeRTOS/portable/GCC/TC3/portmacro.h at 4c8985aa5275b11be13a730c031ce08944621d75 · Infineon/AURIX_code_examples · GitHub )

So I would suggest confirming that the first path works as expected by disabling timeslicing and just have two tasks of equal priority yield to each other to confirm that the SVC handler is yielding correctly. E.g: Task 1 prints “Task 1” then calls taskYIELD in a loop and Task 2 does the same. You should see them printing one after the other as they yield to each other.

Then to confirm the second path, enable timeslicing and remove the taskYIELD calls from the tasks as now the tick interrupt should cause the tasks to pre-empt each other for their timeslice and you should see similar behavior e.g. Task1 prints then Task 2 prints, however, depending on the thread safety of your printf implementation/how many times each task can call printf in its timeslice may cause the resulting prints to look garbled, but should see a trend of Task 1 printing, then Task 2 printing, etc.. Hope this helps.

1 Like

Hello.

Where can I get demo for Aurix TC4x from Infineon?

GitHub - Infineon/AURIX_code_examples: This repository contains code example projects for the AURIX™ Development Studio. has Aurix demos

Thanks but only the example that I could find was TC375 FreeRTOS example in the github. Is it reusable for TC4x as well?

I’d recommend to reach out to Infineon for this question.

The repo I’ve linked mentions the following

If you’re looking for specific board support, you’ll need to reach out to Infineon.