diff options
Diffstat (limited to 'common/sleep_led.c')
| -rw-r--r-- | common/sleep_led.c | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/common/sleep_led.c b/common/sleep_led.c new file mode 100644 index 000000000..edf68c352 --- /dev/null +++ b/common/sleep_led.c | |||
| @@ -0,0 +1,84 @@ | |||
| 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 | |||
| 48 | |||
| 49 | /* Breathing Sleep LED brighness(PWM On period) table | ||
| 50 | * (32[steps] * 8[duration]) / 64[PWM periods/s] = 4 second breath cycle | ||
| 51 | */ | ||
| 52 | static const uint8_t breathing_table[32] PROGMEM = { | ||
| 53 | 0, 0, 0, 2, 9, 21, 37, 56, 78, 127, 151, 175, 197, 216, 232, 244, | ||
| 54 | 254, 244, 216, 197, 175, 151, 127, 78, 56, 37, 21, 9, 2, 0, 0, 0 | ||
| 55 | }; | ||
| 56 | |||
| 57 | ISR(TIMER1_COMPA_vect) | ||
| 58 | { | ||
| 59 | /* Software PWM | ||
| 60 | * timer:1111 1111 1111 1111 | ||
| 61 | * \----/\-/ \-------/+--- count(0-255) | ||
| 62 | * | +--------------- duration of step(8) | ||
| 63 | * +-------------------- index of step table(0-31) | ||
| 64 | */ | ||
| 65 | static union { | ||
| 66 | uint16_t row; | ||
| 67 | struct { | ||
| 68 | uint8_t count:8; | ||
| 69 | uint8_t duration:3; | ||
| 70 | uint8_t index:5; | ||
| 71 | } pwm; | ||
| 72 | } timer = { .row = 0 }; | ||
| 73 | |||
| 74 | timer.row++; | ||
| 75 | |||
| 76 | // LED on | ||
| 77 | if (timer.pwm.count == 0) { | ||
| 78 | led_set(1<<USB_LED_CAPS_LOCK); | ||
| 79 | } | ||
| 80 | // LED off | ||
| 81 | if (timer.pwm.count == pgm_read_byte(&breathing_table[timer.pwm.index])) { | ||
| 82 | led_set(0); | ||
| 83 | } | ||
| 84 | } | ||
