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:
Timer service task - priority 9
My dummy task - priority 1 staticvoiddummy_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);
}
}
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.
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?
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?
/* 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;
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.
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.
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.