a074364c |
1 | #include <stdint.h> |
2 | #include <avr/io.h> |
3 | #include <avr/interrupt.h> |
4 | #include <avr/pgmspace.h> |
5 | #include "led.h" |
6 | #include "sleep_led.h" |
7 | |
8 | /* Software PWM |
9 | * ______ ______ __ |
10 | * | ON |___OFF___| ON |___OFF___| .... |
11 | * |<-------------->|<-------------->|<- .... |
12 | * PWM period PWM period |
13 | * |
14 | * 256 interrupts/period[resolution] |
15 | * 64 periods/second[frequency] |
16 | * 256*64 interrupts/second |
17 | * F_CPU/(256*64) clocks/interrupt |
18 | */ |
19 | #define SLEEP_LED_TIMER_TOP F_CPU/(256*64) |
20 | |
21 | void sleep_led_init(void) |
22 | { |
23 | /* Timer1 setup */ |
24 | /* CTC mode */ |
25 | TCCR1B |= _BV(WGM12); |
26 | /* Clock selelct: clk/1 */ |
27 | TCCR1B |= _BV(CS10); |
28 | /* Set TOP value */ |
29 | uint8_t sreg = SREG; |
30 | cli(); |
31 | OCR1AH = (SLEEP_LED_TIMER_TOP>>8)&0xff; |
32 | OCR1AL = SLEEP_LED_TIMER_TOP&0xff; |
33 | SREG = sreg; |
34 | } |
35 | |
36 | void sleep_led_enable(void) |
37 | { |
38 | /* Enable Compare Match Interrupt */ |
39 | TIMSK1 |= _BV(OCIE1A); |
40 | } |
41 | |
42 | void sleep_led_disable(void) |
43 | { |
44 | /* Disable Compare Match Interrupt */ |
45 | TIMSK1 &= ~_BV(OCIE1A); |
46 | } |
47 | |
5969d626 |
48 | |
49 | __attribute__ ((weak)) |
50 | void sleep_led_on(void) |
a074364c |
51 | { |
5969d626 |
52 | led_set(1<<USB_LED_CAPS_LOCK); |
53 | } |
54 | |
55 | __attribute__ ((weak)) |
56 | void sleep_led_off(void) |
57 | { |
58 | led_set(0); |
a074364c |
59 | } |
60 | |
61 | |
62 | /* Breathing Sleep LED brighness(PWM On period) table |
63 | * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle |
64 | * |
65 | * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63 |
66 | * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i } |
67 | */ |
68 | static const uint8_t breathing_table[64] PROGMEM = { |
69 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10, |
70 | 15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252, |
71 | 255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23, |
72 | 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
73 | }; |
74 | |
75 | ISR(TIMER1_COMPA_vect) |
76 | { |
77 | /* Software PWM |
78 | * timer:1111 1111 1111 1111 |
79 | * \_____/\/ \_______/____ count(0-255) |
80 | * \ \______________ duration of step(4) |
81 | * \__________________ index of step table(0-63) |
82 | */ |
83 | static union { |
84 | uint16_t row; |
85 | struct { |
86 | uint8_t count:8; |
87 | uint8_t duration:2; |
88 | uint8_t index:6; |
89 | } pwm; |
90 | } timer = { .row = 0 }; |
91 | |
92 | timer.row++; |
93 | |
94 | // LED on |
95 | if (timer.pwm.count == 0) { |
5969d626 |
96 | sleep_led_on(); |
a074364c |
97 | } |
98 | // LED off |
99 | if (timer.pwm.count == pgm_read_byte(&breathing_table[timer.pwm.index])) { |
5969d626 |
100 | sleep_led_off(); |
a074364c |
101 | } |
102 | } |