Quality RTOS & Embedded Software

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




Loading

Tickless Idle Sleep on SAML21 Xplained Pro - vTaskDelay time error

Posted by alvaromuro on November 9, 2017

I am configuring the Atmel SAM L21 Xplained pro A board (ATSAML21J18A), with Atmel Studio 7 and FreeRTOS v8.0.1 to work with Tickless Idle sleep, based on the files of an ASF example called [FreeRTOS tickless demo using OLED1 Xplained Pro]http://asf.atmel.no/docs/3.21.0/common.services.freertos.oled1ticklessxproexample.saml21xplained_pro/html/index.html).

I have created a simple task which just blinks a LED and after calls vTaskDelay and blocks for 3000 ms. I run it first without activating tickless mode, and the program works perfectly. The task blinks, then blocks for 3000 ms, and starts again.

When I activate tickless mode, the led Blinks at the same right rate, the system then enters the sleep mode correctly, and wakes up again to blink, but the delay is not what it should be, it's shorter, around 1000 ms instead of 3000 ms.

In FreeRTOSConfig.h I have:

~~~

define configUSETICKLESSIDLE 2
define configCPUCLOCKHZ ( systemgclkgengethz(GCLKGENERATOR0) )
define configTICKRATEHZ ( ( portTickType ) 100 )

~~~

My main Clock is set up at 12MHz from OSC16M:

~~~ /* Configure GCLK generator 0 (Main Clock) */

define CONFCLOCKGCLK0ENABLE true
define CONFCLOCKGCLK0RUNINSTANDBY false
define CONFCLOCKGCLK0CLOCKSOURCE SYSTEMCLOCKSOURCEOSC16M
define CONFCLOCKGCLK0PRESCALER 1
define CONFCLOCKGCLK0OUTPUT_ENABLE false

/* SYSTEMCLOCKSOURCE_OSC16M configuration - Internal 16MHz oscillator */

define CONFCLOCKOSC16MFREQSEL SYSTEMOSC16M12M
define CONFCLOCKOSC16MONDEMAND true
define CONFCLOCKOSC16MRUNIN_STANDBY false

~~~

I have clocked the tick with the ultra low power oscillator ULPOSC32k: in conf_clocks.h ~~~ /* Configure GCLK generator 5 */

define CONFCLOCKGCLK5ENABLE true
define CONFCLOCKGCLK5RUNINSTANDBY false
define CONFCLOCKGCLK5CLOCKSOURCE SYSTEMCLOCKSOURCEULP32K
define CONFCLOCKGCLK5PRESCALER 1
define CONFCLOCKGCLK5OUTPUT_ENABLE false

~~~

and modified the vPortSetupTimerInterrupt as follows:

~~~ void vPortSetupTimerInterrupt(void) { // Struct for configuring TC struct tcconfig tcconf; // Set up configuration values tcgetconfigdefaults(&tcconf); tcconf.clocksource = GCLKGENERATOR5;
tcconf.countersize = TCCOUNTERSIZE32BIT; tcconf.runinstandby = true; tcconf.clockprescaler = TCCLOCKPRESCALERDIV1; tcconf.wavegeneration = TCWAVEGENERATIONMATCHFREQ;

// Initialize the TC
tc_init(&tc, TICK_TC, &tcconf);

// Register and enable callback for freeRTOS tick handler
tc_register_callback(&tc, (tc_callback_t) xPortSysTickHandler, TC_CALLBACK_CC_CHANNEL0);
tc_enable_callback(&tc, TC_CALLBACK_CC_CHANNEL0);

// Set top value equal to one os tick
tc_set_top_value(&tc, TIMER_RELOAD_VALUE_ONE_TICK);

// Enable the timer
tc_enable(&tc);

}

~~~

and in FreeRTOSConfig.h the example has the following definitions which I asssume are correct:

~~~ /* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS standard names - or at least those used in the unmodified vector table. */

define vPortSVCHandler SVC_Handler
define xPortPendSVHandler PendSV_Handler
if defined (GNUC) || defined (ICCARM)
include

void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );

endif
define portSUPPRESSTICKSAND_SLEEP vPortSuppressTicksAndSleep

~~~

I also have the following timer configuration:

~~~ //! Frequency of timer //#define TIMERHZ ( configCPUCLOCK_HZ )

define TIMERHZ ( systemgclkgengethz(GCLKGENERATOR_5 ))

//! Value per os tick of timer

define TIMERRELOADVALUEONETICK ( TIMERHZ / configTICKRATE_HZ )

//! Maximum value of timer

define TIMERMAXCOUNT ( 0xffffffff )

//! Maximum possible suppressed ticks with timer

define TIMERMAXPOSSIBLESUPPRESSEDTICKS ( TIMERMAXCOUNT / TIMERRELOADVALUEONETICK )

~~~

And finally the call to delay the task is: ~~~ /* Block until 3000ms */ vTaskDelay ( pdMSTOTICKS (3000) );

/* Definition of pdMSTOTICKS function*/

ifndef pdMSTOTICKS
define pdMSTOTICKS( xTimeInMs ) ( ( TickTypet ) ( ( ( TickTypet ) ( xTimeInMs ) * ( TickTypet ) configTICKRATEHZ ) / ( TickTypet ) 1000 ) )
endif

~~~

I would very much appreciate any insight on why the vTaskDelay doesn't respect the given 3000 ms and resumes the task faster than it should.


Tickless Idle Sleep on SAML21 Xplained Pro - vTaskDelay time error

Posted by rtel on November 9, 2017

I'm not sure that we have M0 code with tickless idle? Maybe I am wrong.

You say you run the code first without tickless idle and the blink rate is correct, then with tickless idle, and the blink rate is wrong. Is the clock setup the same in both cases - so in both cases you are using the low power oscillator to generate the tick interrupt rather than the SysTick?


Tickless Idle Sleep on SAML21 Xplained Pro - vTaskDelay time error

Posted by alvaromuro on November 10, 2017

Thanks for your prompt reply. In Atmel Studio 7 there are tickless mode working examples for SAML21, SAMD20 and D21 and SAM R21 and R30, which use M0. I suppose they are rigth.

No, with tickless idle the LED blink rate is also right, but the delay of the task generated with vTaskDelay is shorter than it should. That is, the time the system is in idle task sleep, should be 3000 ms but instead is just 1000 ms.

In relation of using the low power oscillator in tickless idle, I'm not sure how to check that. This is what I found:

At the beginning of the tickless.c demo file, where vPortSetupTimerInterrupt and vPortSuppressTicksAndSleep are defined, it says:

The tickless feature is implemented using a timer, configured with the desired timeout value, to wake the device. The same timer is also used to generate the system tick, so that time is kept in the optimal way, eliminating drift in most cases.

And rigth before the definition of vPortSetupTimerInterrupt, it says: > Function that sets up a timer to use for os tick. The same timer is also used as the sleep timer.

Here is the code of vPortSuppressTicksAndSleep, is there something here that can cause that?:

~~~ * Function to configure timer for sleep, and calculate time slept. */ void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) {

// Reconfigure the timer to act as sleep timer
tc_disable_callback(&tc, TC_CALLBACK_CC_CHANNEL0);
tc_unregister_callback(&tc, TC_CALLBACK_CC_CHANNEL0);
tc_register_callback(&tc, empty_callback, TC_CALLBACK_CC_CHANNEL0);
tc_enable_callback(&tc, TC_CALLBACK_CC_CHANNEL0);

// Check that the offset is not greater than the range of the timer
if (xExpectedIdleTime > TIMER_MAX_POSSIBLE_SUPPRESSED_TICKS)
{
	xExpectedIdleTime = TIMER_MAX_POSSIBLE_SUPPRESSED_TICKS;
}

// Set sleep time, -1 because we want to wake up before the last tick
tc_set_top_value(&tc, (xExpectedIdleTime - 1) * TIMER_RELOAD_VALUE_ONE_TICK);

// Clear overflow interrupt flag
tc.hw->COUNT32.INTFLAG.reg = TC_INTFLAG_OVF;

// Check if we still should sleep
if (eTaskConfirmSleepModeStatus() == eAbortSleep)
{
	// Reset the timer to act as SysTick
	tc_disable_callback(&tc, TC_CALLBACK_CC_CHANNEL0);
	tc_unregister_callback(&tc, TC_CALLBACK_CC_CHANNEL0);
	tc_register_callback(&tc, (tc_callback_t) xPortSysTickHandler, TC_CALLBACK_CC_CHANNEL0);
	tc_enable_callback(&tc, TC_CALLBACK_CC_CHANNEL0);
	tc_set_top_value(&tc, TIMER_RELOAD_VALUE_ONE_TICK);
}
else
{
	if (xExpectedIdleTime > 0)
	{
		// Data sync barrier before sleep
		__asm volatile ("dsb");
		// Go to sleep
		__asm volatile ("wfi");

		// If OVF interrupt flag is set, we know the timer has wrapped
		if (tc.hw->COUNT32.INTFLAG.reg & TC_INTFLAG_OVF)
		{
			vTaskStepTick(xExpectedIdleTime - 1);
		}
		// We do not know how long we've slept
		else
		{
			// Calculate from Counter how long we've slept
			// Reset counter to less than one os tick
			// This might result in a tiny drift in time.
			uint32_t count_val = tc_get_count_value(&tc);
			vTaskStepTick(count_val / TIMER_RELOAD_VALUE_ONE_TICK);
			tc_set_count_value(&tc, count_val % TIMER_RELOAD_VALUE_ONE_TICK);
		}
	}
	// Reset the timer to act as SysTick
	tc_disable_callback(&tc, TC_CALLBACK_CC_CHANNEL0);
	tc_unregister_callback(&tc, TC_CALLBACK_CC_CHANNEL0);
	tc_register_callback(&tc, (tc_callback_t) xPortSysTickHandler, TC_CALLBACK_CC_CHANNEL0);
	tc_enable_callback(&tc, TC_CALLBACK_CC_CHANNEL0);
	tc_set_top_value(&tc, TIMER_RELOAD_VALUE_ONE_TICK);

	// Make sure that the counter hasn't passed the CC before callback was registered
	if ( tc_get_count_value(&tc) > TIMER_RELOAD_VALUE_ONE_TICK )
	{
		// If so, reload count value, and step one tick */
		tc_set_count_value(&tc, tc_get_count_value(&tc) % TIMER_RELOAD_VALUE_ONE_TICK);
		vTaskStepTick(1);
	}
}

} ~~~

Also, I see another possible cause related with http://www.freertos.org/low-power-ARM-cortex-rtos.html, in the following instruction for the cases when you use a clock other than Systick:

Provide an implementation of vPortSetupTimerInterrupt() that generates an interrupt at the frequency specified by the configTICKRATEHZ FreeRTOSConfig.h constant.

I'm not sure how to get the interrupt frequency properly configured. My configTICKRATEHZ is 100. Tracing back the interrupt timer, in vPortSetupTimerInterrupt (at tickless.c), I have the GLCKGENERATOR5 with DIV 1:

~~~ tcconf.clocksource = GCLKGENERATOR5;
tcconf.clockprescaler = TCCLOCKPRESCALERDIV1; //Wavegen function Match Frequency is chosen to reload the count register on every CC0 match.// tcconf.wavegeneration = TCWAVEGENERATIONMATCHFREQ; ~~~

and in confclocks.h, the GCLKGENERATOR5 has SYSTEMCLOCKSOURCEULP32K also with prescaler at 1. Thus it looks that the input frequency of the interrupt is 32k, am I right?

Also there is a definition of TIMERHZ at tickless.c which I equaled to systemgclkgengethz(GCLKGENERATOR_5 ). I'm not sure if this is correct.

So, if the difference between the configTICKRATEHZ and the interrupt frequency at vPortSetupTimerInterrupt is the cause, how could I configure it? I tried changing the values of both prescalers but with no luck.

Please see the attached files for clarification, I feel I'm getting closer to the solution thanks to your support.

Attachments

FreeRTOSConfig.h (5763 bytes)
conf_clocks.h (9478 bytes)
tickless.c (7972 bytes)

Tickless Idle Sleep on SAML21 Xplained Pro - vTaskDelay time error

Posted by rtel on November 10, 2017

and in confclocks.h, the GCLKGENERATOR5 has SYSTEMCLOCKSOURCEULP32K also with prescaler at 1. Thus it looks that the input frequency of the interrupt is 32k, am I right?

No idea - that is way outside the scope of RTOS support.

I'm afraid this is very hard to support that kind of question directly, especially as I don't think this is code we provided, and we can't get into device specific register settings (we run on LOTS of different devices and would have to get the data sheets out and experiment with settings on real hardware to get into clock settings on individual peripherals on individual parts - just not practical).

My advise would be to start at the bottom of the system, ensuring each part is working correctly and as expected before working your way up. For example, ensure the input frequency of the clock is what you expect (probably with an oscilloscope), then set up the clock and check the output frequency is what you expect. Then check the variables in the software have the frequency that is actually output from the clock......and keep working up until you get into the 'suppress ticks and sleep' function - and see that, given the inputs, a hand calculation of the time at which the clock should be programmed to generate an interrupt next matches the time actually calculated in the code.


Tickless Idle Sleep on SAML21 Xplained Pro - vTaskDelay time error

Posted by alvaromuro on November 13, 2017

Yes, I was also thinking this is more related with the atmel code than to the FreeRTOS. I will follow your advise to go from bottom to top, your support has been very helpful, thanks!


Tickless Idle Sleep on SAML21 Xplained Pro - vTaskDelay time error

Posted by alvaromuro on November 17, 2017

Solved. Just in case it helps somebody: It was a problem related with the configuration of the timer that generates the OS tick in vPortSuppressTicksAndSleep: changing the Timer instance from TC4 to TC2 solves the issue.

~~~ // Initialize the TC tcinit(&tc, TICKTC, &tcconf);

//! Timer/Counter instance to use as tick timer //#define TICKTC TC4 - Commented out as it's not working #define TICKTC TC2 ~~~

Now it generates a correct tick frequency independently of the CPU clock frequency configured, and thus the vTaskDelay works properly.

However, I will still have to see the implications this will have when I activate the low power modes, as it seems the TC4 is the only timer active in Power Domain 0 (PD0)(the lowest power domain).

Thanks for your help.


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




Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.

Latest News

FreeRTOS kernel V10 is available for immediate download. Now MIT licensed.


FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

IAR Partner

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

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

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

OpenRTOS and SafeRTOS