From c4cb248eead0c403442cc018f2ebe3123fb2d395 Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Tue, 27 Sep 2011 21:04:35 +0200 Subject: src/common: use system clock prescaler to save power --- src/common/power.h | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'src/common/power.h') diff --git a/src/common/power.h b/src/common/power.h index 279a26e..ac1f03d 100644 --- a/src/common/power.h +++ b/src/common/power.h @@ -23,6 +23,8 @@ * Web: http://ni.fr.eu.org/ * Email: * }}} */ +#include +#include "io.h" /** Initialise power reduction. */ void @@ -33,4 +35,53 @@ power_init (void); void power_sleep (void); +/** Own version of clock_prescale_set which does not touch I bit. */ +static inline void __attribute__((__always_inline__)) +power_clock_prescale_set (uint8_t x) +{ + uint8_t tmp = _BV (CLKPCE); + __asm__ __volatile__ ( + "out %1, %0" "\n\t" + "out %1, %2" "\n\t" + : /* no outputs */ + : "d" (tmp), + "I" (_SFR_IO_ADDR (CLKPR)), + "d" (x) + : "r0"); +} + +#define CLOCK_COEF (1 << (AC_POWER_CLKPS_LOW - AC_POWER_CLKPS_INITIAL)) +/** Wait for a given duration, trying to reduce clock speed. */ +static inline void __attribute__((always_inline)) +power_delay_ms (double ms) +{ + double slow_ticks = (AC_FREQ / 1e3 / CLOCK_COEF) * ms; + if (slow_ticks > 3.0) + { + /* Can use slow clock, round down as some extra instructions will be + * executed using slow clock. */ + if (slow_ticks / 3.0 <= 256) + { + uint8_t loops = (uint8_t) (slow_ticks / 3.0); + power_clock_prescale_set (AC_POWER_CLKPS_LOW); + _delay_loop_1 (loops); + power_clock_prescale_set (AC_POWER_CLKPS_INITIAL); + } + else + { + uint16_t loops = (uint16_t) (slow_ticks / 4.0); + power_clock_prescale_set (AC_POWER_CLKPS_LOW); + _delay_loop_2 (loops); + power_clock_prescale_set (AC_POWER_CLKPS_INITIAL); + } + /* Do not support huge delay. */ + } + else + { + /* Here, the delay is small, use a short loop. */ + uint8_t loops = (uint8_t) (ms * AC_FREQ / 3e3); + _delay_loop_1 (loops); + } +} + #endif /* power_h */ -- cgit v1.2.3