#include <avr/io.h>
#include <avr/interrupt.h>
+#include <avr/power.h>
#include <util/delay.h>
#include <util/atomic.h>
#error PWM_TOP too high
#endif
+volatile unsigned char channels_running;
+
static uint16_t pwm[N_PWMLEDS];
static volatile unsigned char step;
+static unsigned char pll_enabled;
static void enable_pll()
{
while ((PLLCSR & _BV(PLOCK)) == 0)
;
PLLCSR |= _BV(PCKE);
+
+ pll_enabled = 1;
}
void init_pwm()
int i;
step = 0;
+ channels_running = 0;
+ pll_enabled = 0;
for (i = 0; i < N_PWMLEDS; i++)
pwm[i] = 0;
- enable_pll();
-
// PWM channel D is inverted, ...
TCCR1C = _BV(COM1D1) | _BV(COM1D0) | _BV(PWM1D);
// PWM channels A and B are not
{
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
pwm[n] = 0;
+ channels_running &= ~(1 << n);
switch (n) {
case 0: DDRB &= ~_BV(PB1); break;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
pwm[n] = stride;
+ channels_running |= (1 << n);
+
+ if (!pll_enabled) {
+ power_timer1_enable();
+ enable_pll();
+ }
pwm_update_hw(n);
pwm_update_hw(i);
}
+void pwm_disable_if_not_needed()
+{
+ if (channels_running)
+ return;
+
+ pll_enabled = 0;
+ DDRB &= ~(_BV(PB1) | _BV(PB3) | _BV(PB5));
+ PLLCSR &= ~(_BV(PLLE) | _BV(PCKE));
+
+ power_timer1_disable();
+}
+