]>
Commit | Line | Data |
---|---|---|
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 | } |