From 547fbe769c684745195a53baf9f62730ceea804d Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Tue, 13 Aug 2019 10:28:12 -0700 Subject: [PATCH] Enable PWM Support for Planck EZ Indicator Lights (#6473) * remove led layer code * enable PWM on STM32F303 * Unusable PWM code * Updated PWM Stuff? * PWM Semi-working * Both LEDs working at the same time * Update names * Add led level functions * Add LED levels and persistent settings * Revert change due to issues with timing related code * Review feedback and minor cleanup --- keyboards/planck/ez/ez.c | 167 ++++++++++++++++++++++++++++++++------- keyboards/planck/ez/ez.h | 21 +++++ quantum/stm32/halconf.h | 2 +- quantum/stm32/mcuconf.h | 4 +- 4 files changed, 164 insertions(+), 30 deletions(-) diff --git a/keyboards/planck/ez/ez.c b/keyboards/planck/ez/ez.c index e739b90b8c..8734042a42 100644 --- a/keyboards/planck/ez/ez.c +++ b/keyboards/planck/ez/ez.c @@ -14,6 +14,10 @@ * along with this program. If not, see . */ #include "ez.h" +#include "ch.h" +#include "hal.h" + keyboard_config_t keyboard_config; + #ifdef RGB_MATRIX_ENABLE const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { @@ -112,39 +116,148 @@ void suspend_power_down_kb(void) { } #endif -void matrix_init_kb(void) { - matrix_init_user(); +/* Left B9 Right B8 */ + +// See http://jared.geek.nz/2013/feb/linear-led-pwm +static uint16_t cie_lightness(uint16_t v) { + if (v <= 5243) // if below 8% of max + return v / 9; // same as dividing by 900% + else { + uint32_t y = (((uint32_t) v + 10486) << 8) / (10486 + 0xFFFFUL); // add 16% of max and compare + // to get a useful result with integer division, we shift left in the expression above + // and revert what we've done again after squaring. + y = y * y * y >> 8; + if (y > 0xFFFFUL) // prevent overflow + return 0xFFFFU; + else + return (uint16_t) y; + } +} + +static PWMConfig pwmCFG = { + 0xFFFF,/* PWM clock frequency */ + 256,/* initial PWM period (in ticks) 1S (1/10kHz=0.1mS 0.1ms*10000 ticks=1S) */ + NULL, + { + {PWM_OUTPUT_DISABLED, NULL}, /* channel 0 -> TIM1-CH1 = PA8 */ + {PWM_OUTPUT_DISABLED, NULL}, /* channel 1 -> TIM1-CH2 = PA9 */ + {PWM_OUTPUT_ACTIVE_HIGH, NULL}, + {PWM_OUTPUT_ACTIVE_HIGH, NULL} + }, + 0, /* HW dependent part.*/ + 0 +}; + +static uint32_t planck_ez_right_led_duty; +static uint32_t planck_ez_left_led_duty; + +void planck_ez_right_led_level(uint8_t level) { + planck_ez_right_led_duty = (uint32_t)(cie_lightness(0xFFFF * (uint32_t) level / 255)); + if (level == 0) { + // Turn backlight off + pwmDisableChannel(&PWMD4, 2); + } else { + // Turn backlight on + pwmEnableChannel(&PWMD4, 2, PWM_FRACTION_TO_WIDTH(&PWMD4,0xFFFF,planck_ez_right_led_duty)); + } +} - palSetPadMode(GPIOB, 8, PAL_MODE_OUTPUT_PUSHPULL); - palSetPadMode(GPIOB, 9, PAL_MODE_OUTPUT_PUSHPULL); - palClearPad(GPIOB, 8); - palClearPad(GPIOB, 9); +void planck_ez_right_led_on(void){ + pwmEnableChannel(&PWMD4, 2, PWM_FRACTION_TO_WIDTH(&PWMD4,0xFFFF,planck_ez_right_led_duty)); } -void matrix_scan_kb(void) { - matrix_scan_user(); +void planck_ez_right_led_off(void){ + pwmDisableChannel(&PWMD4, 2); } -uint32_t layer_state_set_kb(uint32_t state) { - - palClearPad(GPIOB, 8); - palClearPad(GPIOB, 9); - state = layer_state_set_user(state); - uint8_t layer = biton32(state); - switch (layer) { - case 3: - palSetPad(GPIOB, 9); - break; - case 4: - palSetPad(GPIOB, 8); - break; - case 6: - palSetPad(GPIOB, 9); - palSetPad(GPIOB, 8); - break; - default: - break; +void planck_ez_left_led_level(uint8_t level) { + planck_ez_left_led_duty = (uint32_t)(cie_lightness(0xFFFF * (uint32_t) level / 255)); + if (level == 0) { + // Turn backlight off + pwmDisableChannel(&PWMD4, 3); + } else { + // Turn backlight on + pwmEnableChannel(&PWMD4, 3, PWM_FRACTION_TO_WIDTH(&PWMD4,0xFFFF,planck_ez_left_led_duty)); + } +} + +void planck_ez_left_led_on(void){ + pwmEnableChannel(&PWMD4, 3, PWM_FRACTION_TO_WIDTH(&PWMD4,0xFFFF,planck_ez_left_led_duty)); +} + +void planck_ez_left_led_off(void){ + pwmDisableChannel(&PWMD4, 3); +} + + +void led_initialize_hardware(void) { + pwmStart(&PWMD4, &pwmCFG); + + // set up defaults + planck_ez_right_led_level((uint8_t)keyboard_config.led_level * 255 / 4 ); + palSetPadMode(GPIOB, 8, PAL_MODE_ALTERNATE(2)); + planck_ez_left_led_level((uint8_t)keyboard_config.led_level * 255 / 4 ); + palSetPadMode(GPIOB, 9, PAL_MODE_ALTERNATE(2)); + + + // turn LEDs off by default + planck_ez_left_led_off(); + planck_ez_right_led_off(); +} + +void keyboard_pre_init_kb(void) { + // read kb settings from eeprom + keyboard_config.raw = eeconfig_read_kb(); + + // initialize settings for front LEDs + led_initialize_hardware(); +} + +void eeconfig_init_kb(void) { // EEPROM is getting reset! + keyboard_config.raw = 0; + keyboard_config.led_level = 4; + eeconfig_update_kb(keyboard_config.raw); + eeconfig_init_user(); +} + +layer_state_t layer_state_set_kb(layer_state_t state) { + planck_ez_left_led_off(); + planck_ez_right_led_off(); + state = layer_state_set_user(state); + uint8_t layer = biton32(state); + switch (layer) { + case 3: + planck_ez_left_led_on(); + break; + case 4: + planck_ez_right_led_on(); + break; + case 6: + planck_ez_right_led_on(); + planck_ez_left_led_on(); + break; + default: + break; } return state; } + + +bool process_record_kb(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case LED_LEVEL: + if (record->event.pressed) { + keyboard_config.led_level++; + if (keyboard_config.led_level > 4) { + keyboard_config.led_level = 0; + } + planck_ez_right_led_level((uint8_t)keyboard_config.led_level * 255 / 4 ); + planck_ez_left_led_level((uint8_t)keyboard_config.led_level * 255 / 4 ); + eeconfig_update_kb(keyboard_config.raw); + layer_state_set_kb(layer_state); + } + break; + } + return true; +} diff --git a/keyboards/planck/ez/ez.h b/keyboards/planck/ez/ez.h index 55c4032422..e2ddaf3cec 100644 --- a/keyboards/planck/ez/ez.h +++ b/keyboards/planck/ez/ez.h @@ -50,3 +50,24 @@ LAYOUT_planck_1x2uC( \ #define KEYMAP LAYOUT_ortho_4x12 #define LAYOUT_planck_mit LAYOUT_planck_1x2uC #define LAYOUT_planck_grid LAYOUT_ortho_4x12 + +void planck_ez_right_led_on(void); +void planck_ez_right_led_off(void); +void planck_ez_right_led_level(uint8_t level); +void planck_ez_left_led_on(void); +void planck_ez_left_led_off(void); +void planck_ez_left_led_level(uint8_t level); + +enum planck_ez_keycodes { + LED_LEVEL = SAFE_RANGE, + EZ_SAFE_RANGE, +}; + +typedef union { + uint32_t raw; + struct { + uint8_t led_level :3; + }; +} keyboard_config_t; + +extern keyboard_config_t keyboard_config; diff --git a/quantum/stm32/halconf.h b/quantum/stm32/halconf.h index c3e0cbb728..a14ace02b4 100644 --- a/quantum/stm32/halconf.h +++ b/quantum/stm32/halconf.h @@ -111,7 +111,7 @@ * @brief Enables the PWM subsystem. */ #if !defined(HAL_USE_PWM) || defined(__DOXYGEN__) -#define HAL_USE_PWM FALSE +#define HAL_USE_PWM TRUE #endif /** diff --git a/quantum/stm32/mcuconf.h b/quantum/stm32/mcuconf.h index 36f8ca2252..32a73fb38e 100644 --- a/quantum/stm32/mcuconf.h +++ b/quantum/stm32/mcuconf.h @@ -183,9 +183,9 @@ */ #define STM32_PWM_USE_ADVANCED FALSE #define STM32_PWM_USE_TIM1 FALSE -#define STM32_PWM_USE_TIM2 TRUE +#define STM32_PWM_USE_TIM2 FALSE #define STM32_PWM_USE_TIM3 TRUE -#define STM32_PWM_USE_TIM4 FALSE +#define STM32_PWM_USE_TIM4 TRUE #define STM32_PWM_USE_TIM8 FALSE #define STM32_PWM_TIM1_IRQ_PRIORITY 7 #define STM32_PWM_TIM2_IRQ_PRIORITY 7