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 configTICK
RATEHZ is 100. Tracing back the interrupt timer, in vPortSetupTimerInterrupt (at tickless.c), I have the GLCK
GENERATOR5 with DIV 1:
~~~
tcconf.clock
source = GCLKGENERATOR
5;
tcconf.clockprescaler = TC
CLOCKPRESCALER
DIV1;
//Wavegen function Match Frequency is chosen to reload the count register on every CC0 match.//
tcconf.wavegeneration = TC
WAVEGENERATION
MATCHFREQ;
~~~
and in conf
clocks.h, the GCLKGENERATOR
5 has SYSTEMCLOCK
SOURCEULP32K 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 TIMER
HZ at tickless.c which I equaled to systemgclk
genget
hz(GCLKGENERATOR_5 ). I’m not sure if this is correct.
So, if the difference between the configTICK
RATEHZ 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.