rgb-led-string: Christmas tree mod after real-world testing
[tinyboard.git] / projects / step-up / pwm.c
1 #include <avr/io.h>
2 #include <avr/interrupt.h>
3 #include <avr/power.h>
4 #include <util/delay.h>
5 #include <util/atomic.h>
6
7 #include "lights.h"
8
9 /*
10  * Single PWM channel on OC1B (pin PB4 of Tiny45).
11  * Counts from 0 to 0xFF, without OCR1C compare.
12  */
13
14 volatile unsigned char pwm_enabled;
15
16 static void inline enable_pll()
17 {
18         /* Async clock */
19         PLLCSR = _BV(PLLE) | _BV(LSM);
20
21         /* Synchronize to the phase lock */
22         _delay_us(100);
23         while ((PLLCSR & _BV(PLOCK)) == 0)
24                 ;
25         PLLCSR |= _BV(PCKE);
26 }
27
28 void init_pwm()
29 {
30         pwm_enabled = 0;
31         power_timer1_enable();
32
33         TCCR1 = _BV(CTC1) | _BV(CS11);  // pll_clk/2
34         GTCCR = _BV(COM1B1) | _BV(PWM1B);
35
36         OCR1C = PWM_MAX;
37         OCR1B = 0;              // initial stride is 0
38
39         DDRB &= ~(_BV( PB4 ));
40         PORTB &= ~_BV(PB4); // set to zero
41 }
42
43 void susp_pwm()
44 {
45         DDRB &= ~(_BV( PB4 ));
46         PORTB &= ~(_BV( PB4 ));
47         TCCR1 = 0;
48         TIMSK = 0;
49         TIFR = 0;
50
51         PLLCSR &= ~(_BV(PLLE) | _BV(PCKE));
52 }
53
54 void pwm_off()
55 {
56         OCR1B = 0;
57         DDRB &= ~_BV(PB4);
58
59         PLLCSR &= ~(_BV(PLLE) | _BV(PCKE));
60         power_timer1_disable();
61         pwm_enabled = 0;
62 }
63
64 void pwm_set(uint8_t stride)
65 {
66         OCR1B = stride;
67
68         if (!pwm_enabled) {
69                 power_timer1_enable();
70                 enable_pll();
71                 DDRB |= _BV(PB4);
72                 pwm_enabled = 1;
73         }
74 }