travisgriggs wrote on Thursday, January 31, 2013:
I think I have found a bug/misfeature with tickless support. I have this example code (configured with a tick rate of 1024 Hz):
void task1(void *_)
{
portTickType clock = xTaskGetTickCount();
for (; ;)
{
printf("---one\n");
vTaskDelayUntil(&clock, 2000);
}
}
void task2(void *_)
{
portTickType clock = xTaskGetTickCount();
vTaskDelayUntil(&clock, 1000);
for (; ;)
{
printf("two---\n");
vTaskDelayUntil(&clock, 2000);
}
}
xTaskHandle Task1, Task2;
int main(void)
{
configureProcessor();
initializeUART_STDOUT();
xTaskCreate(
task1,
NULL,
128,
NULL,
tskIDLE_PRIORITY + 1,
&Task1);
xTaskCreate(
task2,
NULL,
128,
NULL,
tskIDLE_PRIORITY + 1,
&Task2);
vTaskStartScheduler();
return 0;
}
This launches two tasks, each outputing every 2000 ticks. The second task is offset by 1000 ticks originally, so they’re half out of phase with each other, generating some sort of output between the two effectively every 1000 ticks.
I placed a printf() in my sleep() function so I could see the amount of time being fed to it by FreeRTOS. For this case, it dutifully feeds it 1000 every time. And I can watch it emit the alternating ‘–one’ and ‘two–’ reliably.
However, if I #if 0 out the launch of the second task, things get unregular. Now it should just output every 2000 ticks. The first sleep time fed to the sleep function will be 2000. But the next sleep time will be 63535 (which is conveniently 0xFFFF - 2000). After that time is expired and tick is incremented, it will suddenly unwind a series of outputs all at once (basically all of the outputs that should have happened while asleep for the 63535 we were asleep). I’ll then get the overflow remainder amount with one regular output, and then the whole long delay (til the next overflow basically) again.
That this particular case appears to be broken is particularly problematic, because it was my intent to use a simple example like this, driving a pin with a scope, to tune my sleep function for any skew.
My theory, based on Richard Barry’s wonderful answers to my previous questions and perusing the code and how the blocked lists are managed, is that basically after the original sleep/tick, there is no blocked processes yet (because it hasn’t redelayed?) so the xNextWakeupTime has been set to the max overflow value. When there’s two processes, there’s always one in the queue to make sure we have a real delay computed, rather than the overflow point.