Quality RTOS & Embedded Software

 Real time embedded FreeRTOS RSS feed 
Real time embedded FreeRTOS mailing list 
Quick Start Supported MCUs PDF Books Trace Tools Ecosystem TCP & FAT Training




Loading

Tickless with just one task broken?

Posted by Travis Griggs on 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.

RE: Tickless with just one task broken?

Posted by Richard on January 31, 2013
“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.”


Remember that the sleep function is called by the idle task. Printf() can (depending on how it is implemented) use masses of stack space. The idle task stack size is configured by the configMINIMAL_STACK_SIZE FreeRTOSConfig.h setting - it is possible that you may need to increase the configMINIMAL_STACK_SIZE value [this may be unrelated to your post though, just a comment].

I will try and replicate this here by setting my system to use 16 bit ticks. My experimentation with the SAM4L was using a single task though.

Am I right in thinking you are running this on an AVR? Will it run in the AVRStudio simulator? If so I may ask for a copy of your code if I can't find anything.

Regards.


RE: Tickless with just one task broken?

Posted by Richard on January 31, 2013
Ok I have replicated your system as closely as I can. I have:

1) Taken my SAM4L project as a starting point.
2) Replaced my task with your task (cut from your post above).
3) Set configUSE_16_BIT_TICKS to 1
4) Set configTICK_RATE_HZ to 1000 [if it is set >1000 then portTICK_RATE_MS cannot be used. The kernel does not use portTICK_RATE_MS itself, but the demo application files do although they are not used in this case either]
5) Added "printf("%d\r\n", xExpectedIdleTime);" to the start of the sleep function [it occurred to me while doing that that the sleep function is called with the scheduler locked, therefore if your printf() implementation relies on the scheduler you may have problems - in my case it was fine]

I found the task printed out once, and the expected idle time printed out once. Then the stack overflow hook got hit (as per my previous post, the idle task stack is by default only large enough to do nothing). So I:

6) Increased configMINIMAL_STACK_SIZE in FreeRTOSConfig.h

Now I find everything is running as expected. The print out (via a UART through the J-Link) looks as below. Note I have chosen this section of the print out because it shows an overflow being managed:

1998
---one
1998
---one
1998
---one
1998
---one
1998
---one
1677
320
---one
1998
---one
1998
---one
1998
---one
1998
---one
1998
---one
1998
---one
1998
---one
1998
---one
1998
---one



Regards.

RE: Tickless with just one task broken?

Posted by Travis Griggs on January 31, 2013
The AVR printf is pretty lightweight (relatively speaking), but I did increase the MINIMAL_STACK_SIZE to 384 just to be sure. It doesn't change the behavior for me.

“Am I right in thinking you are running this on an AVR? Will it run in the AVRStudio simulator? If so I may ask for a copy of your code if I can't find anything.”


The target is the AVR xmega256a3 found inside of an LSResearch SiFLEX02 radio module. We've been using avr-gcc provided for OSX by the CrossPack folks. So I don't really know how well it compiles with AVRStudio or if it runs in the simulator. But we're fully prepared (obligated even) to publish our port. Just been trying to get these bugs fixed.

I was going to despair that we seem to be getting different results. And then... I had a spark of inspiration....

What do you have USE_PREEMPTION set to? Mine was set to 0. I'm betting yours is 1, because when I changed mine to 1, then things started working as expected. Nice regular two second pauses! If that's not it, perhaps the port code affected by that setting is to blame? Our tick ISR looks like this:

#if configUSE_PREEMPTION == 1
/*
* Tick ISR for preemptive scheduler. We can use a naked attribute as
* the context is saved at the start of vPortYieldFromTick(). The tick
* count is incremented after the context is saved.
*/
ISR(RTC_OVF_vect)
{
vPortYieldFromTick();
}
#else
/*
* Tick ISR for the cooperative scheduler. All this does is increment the
* tick count. We don't need to switch context, this can only be done by
* manual calls to taskYIELD();
*/

ISR(RTC_OVF_vect)
{
vTaskIncrementTick();
}
#endif


and

/*
* Context switch function used by the tick. This must be identical to
* vPortYield() from the call to vTaskSwitchContext() onwards. The only
* difference from vPortYield() is the tick count is incremented as the
* call comes from the tick ISR.
*/
void vPortYieldFromTick( void ) __attribute__ ( ( naked ) );
void vPortYieldFromTick( void )
{

portSAVE_CONTEXT();
vTaskIncrementTick();
vTaskSwitchContext();
portRESTORE_CONTEXT();

asm volatile ( "ret" );
}

RE: Tickless with just one task broken?

Posted by Richard on January 31, 2013
Yes, I have preemption on.

What do you have configIDLE_SHOULD_YIELD set to?

I think, without actually trying it, if you have preemption off then you should get something like this:

- Enter the sleep function.
- You next interrupt occurs in 2 seconds, the interrupt will call the increment tick function, but its actions will be held pending because the sleep function called with the scheduler locked.
- After the interrupt has executed your sleep function will also exit.
- When you leave the sleep function the scheduler is unlocked, and the tick will get incremented. Incrementing the tick will move the task that runs every two seconds out of the Blocked state and into the ready state - but the task won't run because preemption is off.
- The Idle task (from which the sleep function was called) will loop back around and if configIDLE_SHOULD_YIELD is set to 1 call taskYIELD because there is a task of higher priority than itself in the ready state. The yield should then make your unblocked task run.

Regards.

RE: Tickless with just one task broken?

Posted by Travis Griggs on January 31, 2013
This is the configuration that creates the stall:

#define configUSE_PREEMPTION        0
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ ( ( unsigned long ) 33554432 )
#define configTICK_RATE_HZ ( ( portTickType ) 1024 )
#define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 10 )
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 250 )
#define configTOTAL_HEAP_SIZE ( (size_t ) ( 2048 ) )
#define configMAX_TASK_NAME_LEN ( 1 )
#define configUSE_TRACE_FACILITY 0
#define configUSE_16_BIT_TICKS 1
#define configIDLE_SHOULD_YIELD 1
#define configQUEUE_REGISTRY_SIZE 0

#define configUSE_MUTEXES 1

/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )

/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */

#define INCLUDE_vTaskPrioritySet 0
#define INCLUDE_uxTaskPriorityGet 0
#define INCLUDE_vTaskDelete 0
#define INCLUDE_vTaskCleanUpResources 0
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1

#define INCLUDE_uxTaskGetStackHighWaterMark 1

#define portSUPPRESS_TICKS_AND_SLEEP( xIdleTime ) sleepXmega( xIdleTime )

RE: Tickless with just one task broken?

Posted by Richard on January 31, 2013
Well I turned preemption off but it's still running fine.

If you are able to get your code running in the simulator then let me know and I can try it out to see if I can find the cause. I think you can build the code externally, then load it into the simulator (provided it is build using the debug info the simulator expects), provided you tell the simulator where to find the source files.

Regards.


[ Back to the top ]    [ About FreeRTOS ]    [ Sitemap ]    [ ]




Copyright (C) 2004-2010 Richard Barry. Copyright (C) 2010-2016 Real Time Engineers Ltd.
Any and all data, files, source code, html content and documentation included in the FreeRTOSTM distribution or available on this site are the exclusive property of Real Time Engineers Ltd.. See the files license.txt (included in the distribution) and this copyright notice for more information. FreeRTOSTM and FreeRTOS.orgTM are trade marks of Real Time Engineers Ltd.

Latest News:

FreeRTOS V9.0.0 is now available for download.


Free TCP/IP and file system demos for the RTOS


Sponsored Links

⇓ Now With No Code Size Limit! ⇓
⇑ Free Download Without Registering ⇑


FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

Renesas Electronics Gold Alliance RTOS Partner.jpg

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

Atmel RTOS partner supporting ARM Cortex-M3 and AVR32 microcontrollers

STMicro RTOS partner supporting ARM7, ARM Cortex-M3, ARM Cortex-M4 and ARM Cortex-M0

Xilinx Microblaze and Zynq partner

Silicon Labs low power RTOS partner

Altera RTOS partner for Nios II and Cortex-A9 SoC

Freescale Alliance RTOS Member supporting ARM and ColdFire microcontrollers

Infineon ARM Cortex-M microcontrollers

Texas Instruments MCU Developer Network RTOS partner for ARM and MSP430 microcontrollers

Cypress RTOS partner supporting ARM Cortex-M3

Fujitsu RTOS partner supporting ARM Cortex-M3 and FM3

Microsemi (previously Actel) RTOS partner supporting ARM Cortex-M3

Atollic Partner

IAR Partner

Keil ARM Partner

Embedded Artists