diff options
| author | Joel Challis <git@zvecr.com> | 2021-11-19 18:41:02 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-11-19 10:41:02 -0800 |
| commit | 2728603fe6d73e805a539d337fd01051c46ca806 (patch) | |
| tree | 5c83ffc7efa112da870bd5d8502a9d91d4792f35 /platforms/avr/sleep_led.c | |
| parent | 43b9e23bae12916d5161f03700c9bfe46737324b (diff) | |
| download | qmk_firmware-2728603fe6d73e805a539d337fd01051c46ca806.tar.gz qmk_firmware-2728603fe6d73e805a539d337fd01051c46ca806.zip | |
Move tmk_core/common/<plat> (#13918)
Diffstat (limited to 'platforms/avr/sleep_led.c')
| -rw-r--r-- | platforms/avr/sleep_led.c | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/platforms/avr/sleep_led.c b/platforms/avr/sleep_led.c new file mode 100644 index 000000000..9a3b52abe --- /dev/null +++ b/platforms/avr/sleep_led.c | |||
| @@ -0,0 +1,124 @@ | |||
| 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 | #ifndef SLEEP_LED_TIMER | ||
| 9 | # define SLEEP_LED_TIMER 1 | ||
| 10 | #endif | ||
| 11 | |||
| 12 | #if SLEEP_LED_TIMER == 1 | ||
| 13 | # define TCCRxB TCCR1B | ||
| 14 | # define TIMERx_COMPA_vect TIMER1_COMPA_vect | ||
| 15 | # if defined(__AVR_ATmega32A__) // This MCU has only one TIMSK register | ||
| 16 | # define TIMSKx TIMSK | ||
| 17 | # else | ||
| 18 | # define TIMSKx TIMSK1 | ||
| 19 | # endif | ||
| 20 | # define OCIExA OCIE1A | ||
| 21 | # define OCRxx OCR1A | ||
| 22 | #elif SLEEP_LED_TIMER == 3 | ||
| 23 | # define TCCRxB TCCR3B | ||
| 24 | # define TIMERx_COMPA_vect TIMER3_COMPA_vect | ||
| 25 | # define TIMSKx TIMSK3 | ||
| 26 | # define OCIExA OCIE3A | ||
| 27 | # define OCRxx OCR3A | ||
| 28 | #else | ||
| 29 | error("Invalid SLEEP_LED_TIMER config") | ||
| 30 | #endif | ||
| 31 | |||
| 32 | /* Software PWM | ||
| 33 | * ______ ______ __ | ||
| 34 | * | ON |___OFF___| ON |___OFF___| .... | ||
| 35 | * |<-------------->|<-------------->|<- .... | ||
| 36 | * PWM period PWM period | ||
| 37 | * | ||
| 38 | * 256 interrupts/period[resolution] | ||
| 39 | * 64 periods/second[frequency] | ||
| 40 | * 256*64 interrupts/second | ||
| 41 | * F_CPU/(256*64) clocks/interrupt | ||
| 42 | */ | ||
| 43 | #define SLEEP_LED_TIMER_TOP F_CPU / (256 * 64) | ||
| 44 | |||
| 45 | /** \brief Sleep LED initialization | ||
| 46 | * | ||
| 47 | * FIXME: needs doc | ||
| 48 | */ | ||
| 49 | void sleep_led_init(void) { | ||
| 50 | /* Timer1 setup */ | ||
| 51 | /* CTC mode */ | ||
| 52 | TCCRxB |= _BV(WGM12); | ||
| 53 | /* Clock selelct: clk/1 */ | ||
| 54 | TCCRxB |= _BV(CS10); | ||
| 55 | /* Set TOP value */ | ||
| 56 | uint8_t sreg = SREG; | ||
| 57 | cli(); | ||
| 58 | OCRxx = SLEEP_LED_TIMER_TOP; | ||
| 59 | SREG = sreg; | ||
| 60 | } | ||
| 61 | |||
| 62 | /** \brief Sleep LED enable | ||
| 63 | * | ||
| 64 | * FIXME: needs doc | ||
| 65 | */ | ||
| 66 | void sleep_led_enable(void) { | ||
| 67 | /* Enable Compare Match Interrupt */ | ||
| 68 | TIMSKx |= _BV(OCIExA); | ||
| 69 | } | ||
| 70 | |||
| 71 | /** \brief Sleep LED disable | ||
| 72 | * | ||
| 73 | * FIXME: needs doc | ||
| 74 | */ | ||
| 75 | void sleep_led_disable(void) { | ||
| 76 | /* Disable Compare Match Interrupt */ | ||
| 77 | TIMSKx &= ~_BV(OCIExA); | ||
| 78 | } | ||
| 79 | |||
| 80 | /** \brief Sleep LED toggle | ||
| 81 | * | ||
| 82 | * FIXME: needs doc | ||
| 83 | */ | ||
| 84 | void sleep_led_toggle(void) { | ||
| 85 | /* Disable Compare Match Interrupt */ | ||
| 86 | TIMSKx ^= _BV(OCIExA); | ||
| 87 | } | ||
| 88 | |||
| 89 | /** \brief Breathing Sleep LED brighness(PWM On period) table | ||
| 90 | * | ||
| 91 | * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle | ||
| 92 | * | ||
| 93 | * https://www.wolframalpha.com/input/?i=sin%28x%2F64*pi%29**8+*+255%2C+x%3D0+to+63 | ||
| 94 | * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i } | ||
| 95 | */ | ||
| 96 | static const uint8_t breathing_table[64] PROGMEM = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10, 15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252, 255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23, 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 97 | |||
| 98 | ISR(TIMERx_COMPA_vect) { | ||
| 99 | /* Software PWM | ||
| 100 | * timer:1111 1111 1111 1111 | ||
| 101 | * \_____/\/ \_______/____ count(0-255) | ||
| 102 | * \ \______________ duration of step(4) | ||
| 103 | * \__________________ index of step table(0-63) | ||
| 104 | */ | ||
| 105 | static union { | ||
| 106 | uint16_t row; | ||
| 107 | struct { | ||
| 108 | uint8_t count : 8; | ||
| 109 | uint8_t duration : 2; | ||
| 110 | uint8_t index : 6; | ||
| 111 | } pwm; | ||
| 112 | } timer = {.row = 0}; | ||
| 113 | |||
| 114 | timer.row++; | ||
| 115 | |||
| 116 | // LED on | ||
| 117 | if (timer.pwm.count == 0) { | ||
| 118 | led_set(1 << USB_LED_CAPS_LOCK); | ||
| 119 | } | ||
| 120 | // LED off | ||
| 121 | if (timer.pwm.count == pgm_read_byte(&breathing_table[timer.pwm.index])) { | ||
| 122 | led_set(0); | ||
| 123 | } | ||
| 124 | } | ||
