Esempio n. 1
0
u32_t _get_elapsed_program_time(void)
{
	if (idle_original_ticks == 0) {
		return 0;
	}

	return idle_original_ticks - (sysTickCurrentGet() / default_load_value);
}
Esempio n. 2
0
u32_t _get_remaining_program_time(void)
{
	if (idle_original_ticks == 0) {
		return 0;
	}

	return (u32_t)ceiling_fraction((u32_t)sysTickCurrentGet(),
						default_load_value);
}
Esempio n. 3
0
/**
 *
 * @brief Place the system timer into idle state
 *
 * Re-program the timer to enter into the idle state for the given number of
 * ticks. It is set to a "one shot" mode where it will fire in the number of
 * ticks supplied or the maximum number of ticks that can be programmed into
 * hardware. A value of -1 will result in the maximum number of ticks.
 *
 * @return N/A
 */
void _timer_idle_enter(s32_t ticks /* system ticks */
				)
{
#ifdef CONFIG_TICKLESS_KERNEL
	if (ticks != K_FOREVER) {
		/* Need to reprogram only if current program is smaller */
		if (ticks > idle_original_ticks) {
			_set_time(ticks);
		}
	} else {
		sysTickStop();
		idle_original_ticks = 0;
	}
	idle_mode = IDLE_TICKLESS;
#else
	sysTickStop();

	/*
	 * We're being asked to have the timer fire in "ticks" from now. To
	 * maintain accuracy we must account for the remaining time left in the
	 * timer. So we read the count out of it and add it to the requested
	 * time out
	 */
	idle_original_count = sysTickCurrentGet() - timer_idle_skew;

	if ((ticks == -1) || (ticks > max_system_ticks)) {
		/*
		 * We've been asked to fire the timer so far in the future that
		 * the required count value would not fit in the 24-bit reload
		 * register.
		 * Instead, we program for the maximum programmable interval
		 * minus one system tick to prevent overflow when the left over
		 * count read earlier is added.
		 */
		idle_original_count += max_load_value - default_load_value;
		idle_original_ticks = max_system_ticks - 1;
	} else {
		/*
		 * leave one tick of buffer to have to time react when coming
		 * back
		 */
		idle_original_ticks = ticks - 1;
		idle_original_count += idle_original_ticks * default_load_value;
	}

	/*
	 * Set timer to virtual "one shot" mode - sysTick does not have multiple
	 * modes, so the reload value is simply changed.
	 */
	timer_mode = TIMER_MODE_ONE_SHOT;
	idle_mode = IDLE_TICKLESS;
	sysTickReloadSet(idle_original_count);
	sysTickStart();
#endif
}
Esempio n. 4
0
/**
 *
 * @brief Handling of tickless idle when interrupted
 *
 * The routine, called by _sys_power_save_idle_exit, is responsible for taking
 * the timer out of idle mode and generating an interrupt at the next
 * tick interval.  It is expected that interrupts have been disabled.
 *
 * Note that in this routine, _sys_idle_elapsed_ticks must be zero because the
 * ticker has done its work and consumed all the ticks. This has to be true
 * otherwise idle mode wouldn't have been entered in the first place.
 *
 * @return N/A
 */
void _timer_idle_exit(void)
{
#ifdef CONFIG_TICKLESS_KERNEL
	if (idle_mode == IDLE_TICKLESS) {
		idle_mode = IDLE_NOT_TICKLESS;
		if (!idle_original_ticks && _sys_clock_always_on) {
			_sys_clock_tick_count = _get_elapsed_clock_time();
			timer_overflow = 0;
			sysTickReloadSet(max_load_value);
			sysTickStart();
			sys_tick_reload();
		}
	}
#else
	u32_t count; /* timer's current count register value */

	if (timer_mode == TIMER_MODE_PERIODIC) {
		/*
		 * The timer interrupt handler is handling a completed tickless
		 * idle or this has been called by mistake; there's nothing to
		 * do here.
		 */
		return;
	}

	sysTickStop();

	/* timer is in idle mode, adjust the ticks expired */

	count = sysTickCurrentGet();

	if ((count == 0) || (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk)) {
		/*
		 * The timer expired and/or wrapped around. Re-set the timer to
		 * its default value and mode.
		 */
		sysTickReloadSet(default_load_value);
		timer_mode = TIMER_MODE_PERIODIC;

		/*
		 * Announce elapsed ticks to the kernel. Note we are guaranteed
		 * that the timer ISR will execute before the tick event is
		 * serviced, so _sys_idle_elapsed_ticks is adjusted to account
		 * for it.
		 */
		_sys_idle_elapsed_ticks = idle_original_ticks - 1;
		_sys_clock_tick_announce();
	} else {
		u32_t elapsed;   /* elapsed "counter time" */
		u32_t remaining; /* remaining "counter time" */

		elapsed = idle_original_count - count;

		remaining = elapsed % default_load_value;

		/* ensure that the timer will interrupt at the next tick */

		if (remaining == 0) {
			/*
			 * Idle was interrupted on a tick boundary. Re-set the
			 * timer to its default value and mode.
			 */
			sysTickReloadSet(default_load_value);
			timer_mode = TIMER_MODE_PERIODIC;
		} else if (count > remaining) {
			/*
			 * There is less time remaining to the next tick
			 * boundary than time left for idle. Leave in "one
			 * shot" mode.
			 */
			sysTickReloadSet(remaining);
		}

		_sys_idle_elapsed_ticks = elapsed / default_load_value;

		if (_sys_idle_elapsed_ticks) {
			_sys_clock_tick_announce();
		}
	}

	idle_mode = IDLE_NOT_TICKLESS;
	sysTickStart();
#endif
}
Esempio n. 5
0
/**
 *
 * @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
}
Esempio n. 6
0
/**
 *
 * @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);
}
Esempio n. 7
0
/**
 *
 * @brief Handling of tickless idle when interrupted
 *
 * The routine, called by _sys_power_save_idle_exit, is responsible for taking
 * the timer out of idle mode and generating an interrupt at the next
 * tick interval.  It is expected that interrupts have been disabled.
 *
 * Note that in this routine, _sys_idle_elapsed_ticks must be zero because the
 * ticker has done its work and consumed all the ticks. This has to be true
 * otherwise idle mode wouldn't have been entered in the first place.
 *
 * @return N/A
 */
void _timer_idle_exit(void)
{
	uint32_t count; /* timer's current count register value */

	if (timer_mode == TIMER_MODE_PERIODIC) {
		/*
		 * The timer interrupt handler is handling a completed tickless
		 * idle
		 * or this has been called by mistake; there's nothing to do
		 * here.
		 */
		return;
	}

	sysTickStop();

	/* timer is in idle mode, adjust the ticks expired */

	count = sysTickCurrentGet();

	if ((count == 0) || (__scs.systick.stcsr.bit.countflag)) {
		/*
		 * The timer expired and/or wrapped around. Re-set the timer to
		 * its default value and mode.
		 */
		sysTickReloadSet(default_load_value);
		timer_mode = TIMER_MODE_PERIODIC;

		/*
		 * Announce elapsed ticks to the microkernel. Note we are
		 * guaranteed
		 * that the timer ISR will execute before the tick event is
		 * serviced,
		 * so _sys_idle_elapsed_ticks is adjusted to account for it.
		 */
		_sys_idle_elapsed_ticks = idle_original_ticks - 1;
		_sys_clock_tick_announce();
	} else {
		uint32_t elapsed;   /* elapsed "counter time" */
		uint32_t remaining; /* remaining "counter time" */

		elapsed = idle_original_count - count;

		remaining = elapsed % default_load_value;

		/* ensure that the timer will interrupt at the next tick */

		if (remaining == 0) {
			/*
			 * Idle was interrupted on a tick boundary. Re-set the
			 * timer to
			 * its default value and mode.
			 */
			sysTickReloadSet(default_load_value);
			timer_mode = TIMER_MODE_PERIODIC;
		} else if (count > remaining) {
			/*
			 * There is less time remaining to the next tick
			 * boundary than
			 * time left for idle. Leave in "one shot" mode.
			 */
			sysTickReloadSet(remaining);
		}

		_sys_idle_elapsed_ticks = elapsed / default_load_value;

		if (_sys_idle_elapsed_ticks) {
			_sys_clock_tick_announce();
		}
	}

	idle_mode = IDLE_NOT_TICKLESS;
	sysTickStart();
}