2
votes

When I call vTaskDelay, the delay lasts half of the supposed time. I have traced back the problem and I see that the Tick rate value is the double of what it should be as defined in configTICK_RATE_HZ. I checked this using the tick hook to toggle a led and measuring the frequency with an oscilloscope.

I am configuring the Atmel SAM L21 Xplained pro A board (ATSAML21J18A), with Atmel Studio 7 and FreeRTOS v8.0.1, based on the files of an ASF example called "FreeRTOS tickless demo using OLED1 Xplained".

My CPU clock runs at 12MHz from the SYSTEM_CLOCK_SOURCE_OSC16M. The configured tick rate is 100 Hz, from a timer clocked from GLCK_O(CPU clock). However, when I change the CPU clock rate at 4MHz instead 12 MHz, the Tick rate is correct, so I guess I'm missing some configuration somewhere for the timer which runs the OS tick.

Here are some values of OS tick rate I get with different CPU clock rates:

  • CPU: 4 MHz - Tick rate: 100 Hz
  • CPU: 8 MHz - Tick rate: 548 Hz
  • CPU: 12 MHz - Tick rate: 218 Hz
  • CPU: 16 MHz - Tick rate: 548 Hz
  • CPU: 48 MHz - Tick rate: 2,25 kHz

Also, when I configure the OS tick timer clock source as the internal ultra low power oscilator ULPOSC32k running at 32kHz, the tick rate is correct, independently of the CPU clock frequency (100Hz).

Moreover, when I select tickless mode (1 or 2), even with the configuration that works well in tick mode, with the CPU at 4MHz and the tick interrupt generated from the Systick timer, I have the same problem, the dalay lasts half of what it should.

In FreeRTOSConfig I have:

#define configUSE_PREEMPTION                    1
#define configUSE_TICKLESS_IDLE                 0
#define configUSE_IDLE_HOOK                     0
#define configUSE_TICK_HOOK                     1
#define configPRIO_BITS                         2
#define configCPU_CLOCK_HZ                      ( system_gclk_gen_get_hz(GCLK_GENERATOR_0) )
#define configTICK_RATE_HZ                      ( ( portTickType ) 100 )

The tick timer configuration is:

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_0;
    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);
}

where TIMER_RELOAD_VALUE_ONE_TICK comes from:

//! Frequency of timer
#define TIMER_HZ                            ( configCPU_CLOCK_HZ )

//! 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 )

I would appreciate very much any insight on this timer issue, which keeps me stuck. I have already checked two similar questions related to this:

STM32 SysTick counting twice as fast as it should

freertos tick factor 2 too fast on stm32f4xx

2
I'm voting to close this question as off-topic because : You have the debugger - what is stopping you from checking the timer o systick register values? Do some debugging yourself. it is easy to answer question if you put some effort.0___________
Yes, I completely agree. I have been using the debugger and checked the timer and frequency variables at the best of my ability, I already tried all the different combinations changing the CPU clock source and frequency, and the timer clock source. I also checked in tick and tickless mode. I have gone through all the registers I could find for several days and I cannot find the cause, probably I'm missing something obvious. Asking is my last resort after trying all I could think of. I would appreciate any advice to proceed with my efforts.Alvaro Muro
Are you sure your clock rate defines are correct for your hardware? Your processor appears capable of 48 MHz operation, probably using a PLL multiplier from the external clock.Chris Stratton
I think so, I'm using SYSTEM_CLOCK_SOURCE_OSC16M to clock the CPU through GLCK_0, and in the SAM L21 it allows 4, 8, 12 and 16 MHz modes. It is also possible to get 48 MHz with the DFLL or DPLL. I have tried with this CPU frequency too and the tick rate is 2,25 kHz. I have edited the question adding some results.Alvaro Muro

2 Answers

1
votes

The saml21 has 5 timer/counters TC0 - TC4. The count registers are 16bit. You can use TC0 and TC1(or TC2 and TC3) together to make it 32bit. TC4, the only timer in PDO, does not have another timer paired with it. It can't be used as a 32bit timer(though it will allow you to try).

Change TIMER_MAX_COUNT to 0xffff and tcconf.counter_size to TC_COUNTER_SIZE_16BIT and you will be able to use TC4 instead of TC2.

0
votes

Changing the Timer instance from TC4 to TC2 solves the issue.

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

  //! Timer/Counter instance to use as tick timer
  //#define TICK_TC TC4
  #define TICK_TC TC2

Now it generates a correct 100 Hz tick independently of the CPU clock frequency configured.

However, I 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).