X-Git-Url: https://git.friedersdorff.com/?a=blobdiff_plain;f=tmk_core%2Fcommon%2Fchibios%2Fsleep_led.c;h=4c35cfcbacf7d80d887b0d5ee174c1a205475c4e;hb=6bc7bab6a53a7fb78e0ab1d5989de3a6c9efce4f;hp=d9cdeba1e7ec3efae910e9c2b297701bcf9d7d8f;hpb=aef7a2973e223bbfc813c97b6244edc403051a55;p=max%2Ftmk_keyboard.git diff --git a/tmk_core/common/chibios/sleep_led.c b/tmk_core/common/chibios/sleep_led.c index d9cdeba1..4c35cfcb 100644 --- a/tmk_core/common/chibios/sleep_led.c +++ b/tmk_core/common/chibios/sleep_led.c @@ -4,11 +4,27 @@ #include "led.h" #include "sleep_led.h" -#if defined(KL2x) || defined(K20x) /* platform selection: familiar Kinetis chips */ -/* All right, we go the "software" way: LP timer, toggle LED in interrupt. +/* All right, we go the "software" way: timer, toggle LED in interrupt. * Based on hasu's code for AVRs. + * Use LP timer on Kinetises, TIM14 on STM32F0. */ +#if defined(KL2x) || defined(K20x) + +/* Use Low Power Timer (LPTMR) */ +#define TIMER_INTERRUPT_VECTOR KINETIS_LPTMR0_IRQ_VECTOR +#define RESET_COUNTER LPTMR0->CSR |= LPTMRx_CSR_TCF + +#elif defined(STM32F0XX) + +/* Use TIM14 manually */ +#define TIMER_INTERRUPT_VECTOR STM32_TIM14_HANDLER +#define RESET_COUNTER STM32_TIM14->SR &= ~STM32_TIM_SR_UIF + +#endif + +#if defined(KL2x) || defined(K20x) || defined(STM32F0XX) /* common parts for timers/interrupts */ + /* Breathing Sleep LED brighness(PWM On period) table * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle * @@ -22,8 +38,8 @@ static const uint8_t breathing_table[64] = { 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -/* LP Timer interrupt handler */ -OSAL_IRQ_HANDLER(KINETIS_LPTMR0_IRQ_VECTOR) { +/* interrupt handler */ +OSAL_IRQ_HANDLER(TIMER_INTERRUPT_VECTOR) { OSAL_IRQ_PROLOGUE(); /* Software PWM @@ -55,15 +71,20 @@ OSAL_IRQ_HANDLER(KINETIS_LPTMR0_IRQ_VECTOR) { } /* Reset the counter */ - LPTMR0->CSR |= LPTMRx_CSR_TCF; + RESET_COUNTER; OSAL_IRQ_EPILOGUE(); } +#endif /* common parts for known platforms */ + + +#if defined(KL2x) || defined(K20x) /* platform selection: familiar Kinetis chips */ + /* LPTMR clock options */ #define LPTMR_CLOCK_MCGIRCLK 0 /* 4MHz clock */ #define LPTMR_CLOCK_LPO 1 /* 1kHz clock */ -#define LPTMR_CLOCK_ERCLK32K 2 +#define LPTMR_CLOCK_ERCLK32K 2 /* external 32kHz crystal */ #define LPTMR_CLOCK_OSCERCLK 3 /* output from OSC */ /* Work around inconsistencies in Freescale naming */ @@ -78,7 +99,8 @@ void sleep_led_init(void) { /* Reset LPTMR settings */ LPTMR0->CSR = 0; /* Set the compare value */ - LPTMR0->CMR = 1; // trigger on counter value (i.e. every time) + LPTMR0->CMR = 0; // trigger on counter value (i.e. every time) + /* Set up clock source and prescaler */ /* Software PWM * ______ ______ __ @@ -90,28 +112,39 @@ void sleep_led_init(void) { * F periods/second[frequency] * R * F interrupts/second */ + /* === OPTION 1 === */ - // for 1kHz LPO + #if 0 + // 1kHz LPO // No prescaler => 1024 irqs/sec - // LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_LPO)|LPTMRx_PSR_PBYP; + // Note: this is too slow for a smooth breathe + LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_LPO)|LPTMRx_PSR_PBYP; + #endif /* OPTION 1 */ + /* === OPTION 2 === */ - // for nMHz IRC (n=4 on KL25Z, KL26Z and K20x; n=2 or 8 on KL27Z) + #if 1 + // nMHz IRC (n=4 on KL25Z, KL26Z and K20x; n=2 or 8 on KL27Z) MCG->C2 |= MCG_C2_IRCS; // fast (4MHz) internal ref clock - #if defined(KL27Z) // divide the 8MHz IRC by 2, to have the same MCGIRCLK speed as others + #if defined(KL27) // divide the 8MHz IRC by 2, to have the same MCGIRCLK speed as others MCG->MC |= MCG_MC_LIRC_DIV2_DIV2; - #endif /* KL27Z */ + #endif /* KL27 */ MCG->C1 |= MCG_C1_IRCLKEN; // enable internal ref clock // to work in stop mode, also MCG_C1_IREFSTEN - // Divide 4MHz by 2^N (N=5) => 62500 irqs/sec => + // Divide 4MHz by 2^N (N=6) => 62500 irqs/sec => // => approx F=61, R=256, duration = 4 - LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_MCGIRCLK)|LPTMRx_PSR_PRESCALE(5); + LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_MCGIRCLK)|LPTMRx_PSR_PRESCALE(6); + #endif /* OPTION 2 */ + /* === OPTION 3 === */ - // for OSC output (external crystal), usually 8MHz or 16MHz - // OSC0->CR |= OSC_CR_ERCLKEN; // enable ext ref clock + #if 0 + // OSC output (external crystal), usually 8MHz or 16MHz + OSC0->CR |= OSC_CR_ERCLKEN; // enable ext ref clock // to work in stop mode, also OSC_CR_EREFSTEN // Divide by 2^N - // LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_OSCERCLK)|LPTMRx_PSR_PRESCALE(7); + LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_OSCERCLK)|LPTMRx_PSR_PRESCALE(7); + #endif /* OPTION 3 */ /* === END OPTIONS === */ + /* Interrupt on TCF set (compare flag) */ nvicEnableVector(LPTMR0_IRQn, 2); // vector, priority LPTMR0->CSR |= LPTMRx_CSR_TIE; @@ -132,7 +165,48 @@ void sleep_led_toggle(void) { LPTMR0->CSR ^= LPTMRx_CSR_TEN; } -#else /* platform selection: not on familiar Kinetis chips */ +#elif defined(STM32F0XX) /* platform selection: STM32F0XX */ + +/* Initialise the timer */ +void sleep_led_init(void) { + /* enable clock */ + rccEnableTIM14(FALSE); /* low power enable = FALSE */ + rccResetTIM14(); + + /* prescale */ + /* Assuming 48MHz internal clock */ + /* getting cca 65484 irqs/sec */ + STM32_TIM14->PSC = 733; + + /* auto-reload */ + /* 0 => interrupt every time */ + STM32_TIM14->ARR = 3; + + /* enable counter update event interrupt */ + STM32_TIM14->DIER |= STM32_TIM_DIER_UIE; + + /* register interrupt vector */ + nvicEnableVector(STM32_TIM14_NUMBER, 2); /* vector, priority */ +} + +void sleep_led_enable(void) { + /* Enable the timer */ + STM32_TIM14->CR1 = STM32_TIM_CR1_CEN | STM32_TIM_CR1_URS; + /* URS => update event only on overflow; setting UG bit disabled */ +} + +void sleep_led_disable(void) { + /* Disable the timer */ + STM32_TIM14->CR1 = 0; +} + +void sleep_led_toggle(void) { + /* Toggle the timer */ + STM32_TIM14->CR1 ^= STM32_TIM_CR1_CEN; +} + + +#else /* platform selection: not on familiar chips */ void sleep_led_init(void) { }