/** * * @brief Initialize the tickless idle feature * * This routine initializes the tickless idle feature by calculating the * necessary hardware-specific parameters. * * Note that the maximum number of ticks that can elapse during a "tickless idle" * is limited by <default_load_value>. The larger the value (the lower the * tick frequency), the fewer elapsed ticks during a "tickless idle". * Conversely, the smaller the value (the higher the tick frequency), the * more elapsed ticks during a "tickless idle". * * @return N/A */ static void sysTickTicklessIdleInit(void) { /* enable counter, disable interrupt and set clock src to system clock */ u32_t ctrl = SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_CLKSOURCE_Msk; volatile u32_t dummy; /* used to help determine the 'skew time' */ /* store the default reload value (which has already been set) */ default_load_value = sysTickReloadGet(); /* calculate the max number of ticks with this 24-bit H/W counter */ max_system_ticks = 0x00ffffff / default_load_value; /* determine the associated load value */ max_load_value = max_system_ticks * default_load_value; /* * Calculate the skew from switching the timer in and out of idle mode. * The following sequence is emulated: * 1. Stop the timer. * 2. Read the current counter value. * 3. Calculate the new/remaining counter reload value. * 4. Load the new counter value. * 5. Set the timer mode to periodic/one-shot. * 6. Start the timer. * * The timer must be running for this to work, so enable the * systick counter without generating interrupts, using the processor *clock. * Note that the reload value has already been set by the caller. */ SysTick->CTRL |= ctrl; __ISB(); timer_idle_skew = sysTickCurrentGet(); /* start of skew time */ SysTick->CTRL |= ctrl; /* normally sysTickStop() */ dummy = sysTickCurrentGet(); /* emulate sysTickReloadSet() */ /* emulate calculation of the new counter reload value */ if ((dummy == 1) || (dummy == default_load_value)) { dummy = max_system_ticks - 1; dummy += max_load_value - default_load_value; } else { dummy = dummy - 1; dummy += dummy * default_load_value; } /* _sysTickStart() without interrupts */ SysTick->CTRL |= ctrl; timer_mode = TIMER_MODE_PERIODIC; /* skew time calculation for down counter (assumes no rollover) */ timer_idle_skew -= sysTickCurrentGet(); /* restore the previous sysTick state */ sysTickStop(); sysTickReloadSet(default_load_value); #ifdef CONFIG_TICKLESS_KERNEL idle_original_ticks = 0; #endif }
/** * * @brief Initialize the tickless idle feature * * This routine initializes the tickless idle feature by calculating the * necessary hardware-specific parameters. * * Note that the maximum number of ticks that can elapse during a "tickless idle" * is limited by <default_load_value>. The larger the value (the lower the * tick frequency), the fewer elapsed ticks during a "tickless idle". * Conversely, the smaller the value (the higher the tick frequency), the * more elapsed ticks during a "tickless idle". * * @return N/A */ static void sysTickTicklessIdleInit(void) { /* enable counter, disable interrupt and set clock src to system clock */ union __stcsr stcsr = {.bit = {1, 0, 1, 0, 0, 0} }; volatile uint32_t dummy; /* used to help determine the 'skew time' */ /* store the default reload value (which has already been set) */ default_load_value = sysTickReloadGet(); /* calculate the max number of ticks with this 24-bit H/W counter */ max_system_ticks = 0x00ffffff / default_load_value; /* determine the associated load value */ max_load_value = max_system_ticks * default_load_value; /* * Calculate the skew from switching the timer in and out of idle mode. * The following sequence is emulated: * 1. Stop the timer. * 2. Read the current counter value. * 3. Calculate the new/remaining counter reload value. * 4. Load the new counter value. * 5. Set the timer mode to periodic/one-shot. * 6. Start the timer. * * The timer must be running for this to work, so enable the * systick counter without generating interrupts, using the processor *clock. * Note that the reload value has already been set by the caller. */ __scs.systick.stcsr.val |= stcsr.val; __asm__(" isb"); /* ensure the timer is started before reading */ timer_idle_skew = sysTickCurrentGet(); /* start of skew time */ __scs.systick.stcsr.val |= stcsr.val; /* normally sysTickStop() */ dummy = sysTickCurrentGet(); /* emulate sysTickReloadSet() */ /* emulate calculation of the new counter reload value */ if ((dummy == 1) || (dummy == default_load_value)) { dummy = max_system_ticks - 1; dummy += max_load_value - default_load_value; } else { dummy = dummy - 1; dummy += dummy * default_load_value; } /* _sysTickStart() without interrupts */ __scs.systick.stcsr.val |= stcsr.val; timer_mode = TIMER_MODE_PERIODIC; /* skew time calculation for down counter (assumes no rollover) */ timer_idle_skew -= sysTickCurrentGet(); /* restore the previous sysTick state */ sysTickStop(); sysTickReloadSet(default_load_value); }