alvaromuro wrote on Thursday, November 09, 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.oled1_tickless_xpro_example.saml21_xplained_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 configUSE_TICKLESS_IDLE 2
#define configCPU_CLOCK_HZ ( system_gclk_gen_get_hz(GCLK_GENERATOR_0) )
#define configTICK_RATE_HZ ( ( portTickType ) 100 )
My main Clock is set up at 12MHz from OSC16M:
/* Configure GCLK generator 0 (Main Clock) */
# define CONF_CLOCK_GCLK_0_ENABLE true
# define CONF_CLOCK_GCLK_0_RUN_IN_STANDBY false
# define CONF_CLOCK_GCLK_0_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC16M
# define CONF_CLOCK_GCLK_0_PRESCALER 1
# define CONF_CLOCK_GCLK_0_OUTPUT_ENABLE false
/* SYSTEM_CLOCK_SOURCE_OSC16M configuration - Internal 16MHz oscillator */
# define CONF_CLOCK_OSC16M_FREQ_SEL SYSTEM_OSC16M_12M
# define CONF_CLOCK_OSC16M_ON_DEMAND true
# define CONF_CLOCK_OSC16M_RUN_IN_STANDBY false
I have clocked the tick with the ultra low power oscillator ULPOSC32k:
in conf_clocks.h
/* Configure GCLK generator 5 */
# define CONF_CLOCK_GCLK_5_ENABLE true
# define CONF_CLOCK_GCLK_5_RUN_IN_STANDBY false
# define CONF_CLOCK_GCLK_5_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_ULP32K
# define CONF_CLOCK_GCLK_5_PRESCALER 1
# define CONF_CLOCK_GCLK_5_OUTPUT_ENABLE false
and modified the vPortSetupTimerInterrupt as follows:
void vPortSetupTimerInterrupt(void)
{
// Struct for configuring TC
struct tc_config tcconf;
// Set up configuration values
tc_get_config_defaults(&tcconf);
tcconf.clock_source = GCLK_GENERATOR_5;
tcconf.counter_size = TC_COUNTER_SIZE_32BIT;
tcconf.run_in_standby = true;
tcconf.clock_prescaler = TC_CLOCK_PRESCALER_DIV1;
tcconf.wave_generation = TC_WAVE_GENERATION_MATCH_FREQ;
// 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 <portmacro.h>
void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
#endif
#define portSUPPRESS_TICKS_AND_SLEEP vPortSuppressTicksAndSleep
I also have the following timer configuration:
//! Frequency of timer
//#define TIMER_HZ ( configCPU_CLOCK_HZ )
#define TIMER_HZ ( system_gclk_gen_get_hz(GCLK_GENERATOR_5 ))
//! Value per os tick of timer
#define TIMER_RELOAD_VALUE_ONE_TICK ( TIMER_HZ / configTICK_RATE_HZ )
//! Maximum value of timer
#define TIMER_MAX_COUNT ( 0xffffffff )
//! Maximum possible suppressed ticks with timer
#define TIMER_MAX_POSSIBLE_SUPPRESSED_TICKS ( TIMER_MAX_COUNT / TIMER_RELOAD_VALUE_ONE_TICK )
And finally the call to delay the task is:
/* Block until 3000ms */
vTaskDelay ( pdMS_TO_TICKS (3000) );
/* Definition of pdMS_TO_TICKS function*/
#ifndef pdMS_TO_TICKS
#define pdMS_TO_TICKS( xTimeInMs ) ( ( TickType_t ) ( ( ( TickType_t ) ( xTimeInMs ) * ( TickType_t ) configTICK_RATE_HZ ) / ( TickType_t ) 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.