From 87b11345a55d076966846d87b60d0f315b8bb984 Mon Sep 17 00:00:00 2001 From: Ryan Date: Thu, 6 Jul 2023 18:48:02 +1000 Subject: Get rid of `USB_LED_CAPS_LOCK` (#21436) --- platforms/avr/sleep_led.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'platforms/avr') diff --git a/platforms/avr/sleep_led.c b/platforms/avr/sleep_led.c index b05431633b..ad6253be93 100644 --- a/platforms/avr/sleep_led.c +++ b/platforms/avr/sleep_led.c @@ -109,16 +109,19 @@ ISR(TIMERx_COMPA_vect) { uint8_t duration : 2; uint8_t index : 6; } pwm; - } timer = {.row = 0}; + } timer = {.row = 0}; + static led_t led_state = {0}; timer.row++; // LED on if (timer.pwm.count == 0) { - led_set(1 << USB_LED_CAPS_LOCK); + led_state.caps_lock = true; + led_set(led_state.raw); } // LED off if (timer.pwm.count == pgm_read_byte(&breathing_table[timer.pwm.index])) { - led_set(0); + led_state.caps_lock = false; + led_set(led_state.raw); } } -- cgit v1.2.3 From cb2331713c84bb2b7f140f67b41037721f4958a1 Mon Sep 17 00:00:00 2001 From: Ryan Date: Sat, 8 Jul 2023 23:13:10 +1000 Subject: Relocate backlight drivers (#21444) --- builddefs/common_features.mk | 12 +- drivers/backlight/backlight_software.c | 54 +++ keyboards/4pplet/eagle_viper_rep/rev_a/config.h | 1 - keyboards/acheron/athena/alpha/alpha.c | 2 +- keyboards/acheron/athena/alpha/config.h | 1 - keyboards/acheron/athena/beta/config.h | 2 - keyboards/acheron/shark/alpha/config.h | 1 - keyboards/acheron/shark/beta/config.h | 1 - keyboards/checkerboards/nop60/config.h | 2 - keyboards/ebastler/e80_1800/config.h | 2 - keyboards/ebastler/isometria_75/rev1/config.h | 1 - keyboards/geonworks/frogmini/fms/config.h | 1 - keyboards/handwired/onekey/blackpill_f401/config.h | 1 - .../onekey/blackpill_f401_tinyuf2/config.h | 1 - keyboards/handwired/onekey/blackpill_f411/config.h | 1 - .../onekey/blackpill_f411_tinyuf2/config.h | 1 - keyboards/handwired/onekey/evb_wb32f3g71/config.h | 5 - keyboards/handwired/onekey/evb_wb32fq95/config.h | 5 - keyboards/handwired/onekey/nucleo_f446re/config.h | 5 - keyboards/handwired/onekey/nucleo_l432kc/config.h | 5 - keyboards/handwired/onekey/proton_c/config.h | 5 - keyboards/handwired/onekey/rp2040/config.h | 1 - keyboards/handwired/onekey/stm32f0_disco/config.h | 2 - keyboards/handwired/pill60/config.h | 19 - keyboards/linworks/fave104/config.h | 1 - keyboards/linworks/whale75/config.h | 1 - .../mechlovin/adelais/standard_led/arm/config.h | 1 - keyboards/mechlovin/hannah65/config.h | 21 - keyboards/mechlovin/hex4b/rev2/config.h | 20 - keyboards/mechlovin/hex6c/config.h | 1 - keyboards/mechlovin/infinity87/rev1/config.h | 1 - keyboards/mechlovin/infinity88/config.h | 1 - keyboards/mechlovin/mechlovin9/rev1/config.h | 21 - keyboards/mechlovin/tmkl/config.h | 3 - keyboards/mode/m75s/config.h | 1 - keyboards/smithrune/iron165r2/f411/config.h | 1 - platforms/avr/drivers/backlight_pwm.c | 463 ++++++++++++++++++++ platforms/chibios/drivers/backlight_pwm.c | 173 ++++++++ platforms/chibios/drivers/backlight_timer.c | 178 ++++++++ quantum/backlight/backlight.c | 1 - quantum/backlight/backlight_avr.c | 473 --------------------- quantum/backlight/backlight_chibios.c | 173 -------- quantum/backlight/backlight_driver_common.c | 3 +- quantum/backlight/backlight_software.c | 54 --- quantum/backlight/backlight_timer.c | 179 -------- 45 files changed, 877 insertions(+), 1024 deletions(-) create mode 100644 drivers/backlight/backlight_software.c delete mode 100644 keyboards/handwired/pill60/config.h delete mode 100644 keyboards/mechlovin/hannah65/config.h delete mode 100644 keyboards/mechlovin/hex4b/rev2/config.h delete mode 100644 keyboards/mechlovin/mechlovin9/rev1/config.h create mode 100644 platforms/avr/drivers/backlight_pwm.c create mode 100644 platforms/chibios/drivers/backlight_pwm.c create mode 100644 platforms/chibios/drivers/backlight_timer.c delete mode 100644 quantum/backlight/backlight_avr.c delete mode 100644 quantum/backlight/backlight_chibios.c delete mode 100644 quantum/backlight/backlight_software.c delete mode 100644 quantum/backlight/backlight_timer.c (limited to 'platforms/avr') diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk index e904d6beb9..5687201d61 100644 --- a/builddefs/common_features.mk +++ b/builddefs/common_features.mk @@ -565,18 +565,18 @@ ifeq ($(strip $(BACKLIGHT_ENABLE)), yes) endif COMMON_VPATH += $(QUANTUM_DIR)/backlight + COMMON_VPATH += $(DRIVER_PATH)/backlight SRC += $(QUANTUM_DIR)/backlight/backlight.c SRC += $(QUANTUM_DIR)/process_keycode/process_backlight.c OPT_DEFS += -DBACKLIGHT_ENABLE - ifeq ($(strip $(BACKLIGHT_DRIVER)), custom) - OPT_DEFS += -DBACKLIGHT_CUSTOM_DRIVER - else + ifneq ($(strip $(BACKLIGHT_DRIVER)), custom) SRC += $(QUANTUM_DIR)/backlight/backlight_driver_common.c - ifeq ($(strip $(BACKLIGHT_DRIVER)), pwm) - SRC += $(QUANTUM_DIR)/backlight/backlight_$(PLATFORM_KEY).c + + ifeq ($(strip $(BACKLIGHT_DRIVER)), software) + SRC += $(DRIVER_PATH)/backlight/backlight_software.c else - SRC += $(QUANTUM_DIR)/backlight/backlight_$(strip $(BACKLIGHT_DRIVER)).c + SRC += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/backlight_$(strip $(BACKLIGHT_DRIVER)).c endif endif endif diff --git a/drivers/backlight/backlight_software.c b/drivers/backlight/backlight_software.c new file mode 100644 index 0000000000..f2af3e918e --- /dev/null +++ b/drivers/backlight/backlight_software.c @@ -0,0 +1,54 @@ +#include "backlight.h" +#include "backlight_driver_common.h" +#include "util.h" + +#ifdef BACKLIGHT_BREATHING +# error "Backlight breathing is not available for software PWM. Please disable." +#endif + +static uint16_t s_duty_pattern = 0; + +// clang-format off + +/** \brief PWM duty patterns + * + * We scale the current backlight level to an index within this array. This allows + * backlight_task to focus on just switching LEDs on/off, and we can predict the duty pattern + */ +static const uint16_t backlight_duty_table[] = { + 0b0000000000000000, + 0b1000000000000000, + 0b1000000010000000, + 0b1000001000010000, + 0b1000100010001000, + 0b1001001001001000, + 0b1010101010101010, + 0b1110111011101110, + 0b1111111111111111, +}; +#define backlight_duty_table_size ARRAY_SIZE(backlight_duty_table) + +// clang-format on + +static uint8_t scale_backlight(uint8_t v) { + return v * (backlight_duty_table_size - 1) / BACKLIGHT_LEVELS; +} + +void backlight_init_ports(void) { + backlight_pins_init(); +} + +void backlight_set(uint8_t level) { + s_duty_pattern = backlight_duty_table[scale_backlight(level)]; +} + +void backlight_task(void) { + static uint8_t backlight_tick = 0; + + if (s_duty_pattern & ((uint16_t)1 << backlight_tick)) { + backlight_pins_on(); + } else { + backlight_pins_off(); + } + backlight_tick = (backlight_tick + 1) % 16; +} diff --git a/keyboards/4pplet/eagle_viper_rep/rev_a/config.h b/keyboards/4pplet/eagle_viper_rep/rev_a/config.h index ddd59434a4..1cc2d50f16 100644 --- a/keyboards/4pplet/eagle_viper_rep/rev_a/config.h +++ b/keyboards/4pplet/eagle_viper_rep/rev_a/config.h @@ -18,7 +18,6 @@ along with this program. If not, see . #define BACKLIGHT_PWM_DRIVER PWMD2 #define BACKLIGHT_PWM_CHANNEL 4 -#define BACKLIGHT_PAL_MODE 2 /* Underglow */ #define WS2812_SPI SPID1 diff --git a/keyboards/acheron/athena/alpha/alpha.c b/keyboards/acheron/athena/alpha/alpha.c index 5b5c45b7c7..9e4f82f7ad 100644 --- a/keyboards/acheron/athena/alpha/alpha.c +++ b/keyboards/acheron/athena/alpha/alpha.c @@ -23,7 +23,7 @@ void board_init(void) { void keyboard_post_init_kb(void){ // Defining the backlight pin (A6) as an floating (no pullup or pulldown resistor) opendrain output pin - palSetLineMode(BACKLIGHT_PIN, PAL_MODE_ALTERNATE(BACKLIGHT_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST | PAL_STM32_PUPDR_FLOATING); + palSetLineMode(BACKLIGHT_PIN, PAL_MODE_ALTERNATE(2) | PAL_STM32_OTYPE_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST | PAL_STM32_PUPDR_FLOATING); } void led_init_ports(void) { diff --git a/keyboards/acheron/athena/alpha/config.h b/keyboards/acheron/athena/alpha/config.h index 1bb03e3783..0466710e71 100644 --- a/keyboards/acheron/athena/alpha/config.h +++ b/keyboards/acheron/athena/alpha/config.h @@ -22,7 +22,6 @@ along with this program. If not, see . #define BACKLIGHT_PWM_DRIVER PWMD3 #define BACKLIGHT_PWM_CHANNEL 1 -#define BACKLIGHT_PAL_MODE 2 #define RGBLIGHT_EFFECT_BREATHING #define RGBLIGHT_EFFECT_RAINBOW_MOOD diff --git a/keyboards/acheron/athena/beta/config.h b/keyboards/acheron/athena/beta/config.h index 77985b2ae5..618cebef0c 100644 --- a/keyboards/acheron/athena/beta/config.h +++ b/keyboards/acheron/athena/beta/config.h @@ -21,8 +21,6 @@ along with this program. If not, see . #define LOCKING_RESYNC_ENABLE #define BACKLIGHT_PWM_DRIVER PWMD3 -#define BACKLIGHT_PWM_CHANNEL 3 -#define BACKLIGHT_PAL_MODE 2 #define RGBLIGHT_EFFECT_BREATHING #define RGBLIGHT_EFFECT_RAINBOW_MOOD diff --git a/keyboards/acheron/shark/alpha/config.h b/keyboards/acheron/shark/alpha/config.h index 91f51146f0..a34ea41cff 100644 --- a/keyboards/acheron/shark/alpha/config.h +++ b/keyboards/acheron/shark/alpha/config.h @@ -18,7 +18,6 @@ along with this program. If not, see . #pragma once #define BACKLIGHT_PWM_DRIVER PWMD3 -#define BACKLIGHT_PWM_CHANNEL 3 /* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */ #define LOCKING_SUPPORT_ENABLE diff --git a/keyboards/acheron/shark/beta/config.h b/keyboards/acheron/shark/beta/config.h index 25ad6b3bf0..d4616132e3 100644 --- a/keyboards/acheron/shark/beta/config.h +++ b/keyboards/acheron/shark/beta/config.h @@ -22,7 +22,6 @@ along with this program. If not, see . #define BACKLIGHT_PWM_DRIVER PWMD3 #define BACKLIGHT_PWM_CHANNEL 1 -#define BACKLIGHT_PAL_MODE 2 #define RGBLIGHT_EFFECT_BREATHING #define RGBLIGHT_EFFECT_RAINBOW_MOOD diff --git a/keyboards/checkerboards/nop60/config.h b/keyboards/checkerboards/nop60/config.h index cf5b1ff906..5cb854aebc 100644 --- a/keyboards/checkerboards/nop60/config.h +++ b/keyboards/checkerboards/nop60/config.h @@ -17,8 +17,6 @@ Copyright 2021 Nathan Spears #pragma once -#define BACKLIGHT_PWM_DRIVER PWMD3 - // ws2812 options #define RGBLIGHT_EFFECT_BREATHING #define RGBLIGHT_EFFECT_RAINBOW_MOOD diff --git a/keyboards/ebastler/e80_1800/config.h b/keyboards/ebastler/e80_1800/config.h index b0726f908a..baa7073176 100644 --- a/keyboards/ebastler/e80_1800/config.h +++ b/keyboards/ebastler/e80_1800/config.h @@ -16,8 +16,6 @@ #define BACKLIGHT_PWM_DRIVER PWMD1 #define BACKLIGHT_PWM_CHANNEL 2 -#define BACKLIGHT_PAL_MODE 2 - #ifdef OLED_ENABLE diff --git a/keyboards/ebastler/isometria_75/rev1/config.h b/keyboards/ebastler/isometria_75/rev1/config.h index 29a2ac527d..18f4f1f4d6 100644 --- a/keyboards/ebastler/isometria_75/rev1/config.h +++ b/keyboards/ebastler/isometria_75/rev1/config.h @@ -20,7 +20,6 @@ along with this program. If not, see . /* Backlight */ #define BACKLIGHT_PWM_DRIVER PWMD1 #define BACKLIGHT_PWM_CHANNEL 2 -#define BACKLIGHT_PAL_MODE 2 #define BACKLIGHT_PWM_OUTPUT_FREQUENCY 1000 // Increases backlight PWM freq if compiled with an unmerged PR. Does no harm without it. /* Underglow */ diff --git a/keyboards/geonworks/frogmini/fms/config.h b/keyboards/geonworks/frogmini/fms/config.h index 6576ee9efe..ddeaa2abff 100644 --- a/keyboards/geonworks/frogmini/fms/config.h +++ b/keyboards/geonworks/frogmini/fms/config.h @@ -18,7 +18,6 @@ along with this program. If not, see . #pragma once #define BACKLIGHT_PWM_DRIVER PWMD1 -#define BACKLIGHT_PWM_CHANNEL 3 #define BACKLIGHT_PAL_MODE 1 #define I2C_DRIVER I2CD1 diff --git a/keyboards/handwired/onekey/blackpill_f401/config.h b/keyboards/handwired/onekey/blackpill_f401/config.h index 6183ee9819..22143dfac5 100644 --- a/keyboards/handwired/onekey/blackpill_f401/config.h +++ b/keyboards/handwired/onekey/blackpill_f401/config.h @@ -19,7 +19,6 @@ #define BACKLIGHT_PWM_DRIVER PWMD5 #define BACKLIGHT_PWM_CHANNEL 1 -#define BACKLIGHT_PAL_MODE 2 #define ADC_PIN A0 diff --git a/keyboards/handwired/onekey/blackpill_f401_tinyuf2/config.h b/keyboards/handwired/onekey/blackpill_f401_tinyuf2/config.h index 6183ee9819..22143dfac5 100755 --- a/keyboards/handwired/onekey/blackpill_f401_tinyuf2/config.h +++ b/keyboards/handwired/onekey/blackpill_f401_tinyuf2/config.h @@ -19,7 +19,6 @@ #define BACKLIGHT_PWM_DRIVER PWMD5 #define BACKLIGHT_PWM_CHANNEL 1 -#define BACKLIGHT_PAL_MODE 2 #define ADC_PIN A0 diff --git a/keyboards/handwired/onekey/blackpill_f411/config.h b/keyboards/handwired/onekey/blackpill_f411/config.h index 6183ee9819..22143dfac5 100644 --- a/keyboards/handwired/onekey/blackpill_f411/config.h +++ b/keyboards/handwired/onekey/blackpill_f411/config.h @@ -19,7 +19,6 @@ #define BACKLIGHT_PWM_DRIVER PWMD5 #define BACKLIGHT_PWM_CHANNEL 1 -#define BACKLIGHT_PAL_MODE 2 #define ADC_PIN A0 diff --git a/keyboards/handwired/onekey/blackpill_f411_tinyuf2/config.h b/keyboards/handwired/onekey/blackpill_f411_tinyuf2/config.h index 6183ee9819..22143dfac5 100755 --- a/keyboards/handwired/onekey/blackpill_f411_tinyuf2/config.h +++ b/keyboards/handwired/onekey/blackpill_f411_tinyuf2/config.h @@ -19,7 +19,6 @@ #define BACKLIGHT_PWM_DRIVER PWMD5 #define BACKLIGHT_PWM_CHANNEL 1 -#define BACKLIGHT_PAL_MODE 2 #define ADC_PIN A0 diff --git a/keyboards/handwired/onekey/evb_wb32f3g71/config.h b/keyboards/handwired/onekey/evb_wb32f3g71/config.h index 4a65e9a72f..5f6f04f7b4 100644 --- a/keyboards/handwired/onekey/evb_wb32f3g71/config.h +++ b/keyboards/handwired/onekey/evb_wb32f3g71/config.h @@ -3,13 +3,8 @@ #pragma once - #define ADC_PIN A0 -#define BACKLIGHT_PWM_DRIVER PWMD4 -#define BACKLIGHT_PWM_CHANNEL 3 -#define BACKLIGHT_PAL_MODE 2 - #define APA102_NOPS (100 / (1000000000L / (CPU_CLOCK / 4))) #define SOLENOID_PIN B12 diff --git a/keyboards/handwired/onekey/evb_wb32fq95/config.h b/keyboards/handwired/onekey/evb_wb32fq95/config.h index 4a65e9a72f..5f6f04f7b4 100644 --- a/keyboards/handwired/onekey/evb_wb32fq95/config.h +++ b/keyboards/handwired/onekey/evb_wb32fq95/config.h @@ -3,13 +3,8 @@ #pragma once - #define ADC_PIN A0 -#define BACKLIGHT_PWM_DRIVER PWMD4 -#define BACKLIGHT_PWM_CHANNEL 3 -#define BACKLIGHT_PAL_MODE 2 - #define APA102_NOPS (100 / (1000000000L / (CPU_CLOCK / 4))) #define SOLENOID_PIN B12 diff --git a/keyboards/handwired/onekey/nucleo_f446re/config.h b/keyboards/handwired/onekey/nucleo_f446re/config.h index c6c04ed615..4401623e85 100644 --- a/keyboards/handwired/onekey/nucleo_f446re/config.h +++ b/keyboards/handwired/onekey/nucleo_f446re/config.h @@ -2,11 +2,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later #pragma once - -#define BACKLIGHT_PWM_DRIVER PWMD4 -#define BACKLIGHT_PWM_CHANNEL 3 -#define BACKLIGHT_PAL_MODE 2 - #define ADC_PIN A0 #define SOLENOID_PINS { B12, B13, B14, B15 } diff --git a/keyboards/handwired/onekey/nucleo_l432kc/config.h b/keyboards/handwired/onekey/nucleo_l432kc/config.h index d344a11094..03e017892c 100644 --- a/keyboards/handwired/onekey/nucleo_l432kc/config.h +++ b/keyboards/handwired/onekey/nucleo_l432kc/config.h @@ -2,9 +2,4 @@ // SPDX-License-Identifier: GPL-2.0-or-later #pragma once - -#define BACKLIGHT_PWM_DRIVER PWMD4 -#define BACKLIGHT_PWM_CHANNEL 3 -#define BACKLIGHT_PAL_MODE 2 - #define ADC_PIN A0 diff --git a/keyboards/handwired/onekey/proton_c/config.h b/keyboards/handwired/onekey/proton_c/config.h index 49376e474e..07ce929221 100644 --- a/keyboards/handwired/onekey/proton_c/config.h +++ b/keyboards/handwired/onekey/proton_c/config.h @@ -16,9 +16,4 @@ #pragma once - -#define BACKLIGHT_PWM_DRIVER PWMD4 -#define BACKLIGHT_PWM_CHANNEL 3 -#define BACKLIGHT_PAL_MODE 2 - #define ADC_PIN A0 diff --git a/keyboards/handwired/onekey/rp2040/config.h b/keyboards/handwired/onekey/rp2040/config.h index 5cbfb8dbff..0563ebfa5f 100644 --- a/keyboards/handwired/onekey/rp2040/config.h +++ b/keyboards/handwired/onekey/rp2040/config.h @@ -13,7 +13,6 @@ #define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED GP25 #define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT 500U -#define BACKLIGHT_PWM_DRIVER PWMD4 #define BACKLIGHT_PWM_CHANNEL RP2040_PWM_CHANNEL_B #define AUDIO_PIN GP16 diff --git a/keyboards/handwired/onekey/stm32f0_disco/config.h b/keyboards/handwired/onekey/stm32f0_disco/config.h index 806eb69df4..b8880f6581 100644 --- a/keyboards/handwired/onekey/stm32f0_disco/config.h +++ b/keyboards/handwired/onekey/stm32f0_disco/config.h @@ -16,9 +16,7 @@ #pragma once - #define BACKLIGHT_PWM_DRIVER PWMD3 -#define BACKLIGHT_PWM_CHANNEL 3 #define BACKLIGHT_PAL_MODE 0 #define ADC_PIN A0 diff --git a/keyboards/handwired/pill60/config.h b/keyboards/handwired/pill60/config.h deleted file mode 100644 index 399d0f2212..0000000000 --- a/keyboards/handwired/pill60/config.h +++ /dev/null @@ -1,19 +0,0 @@ - /* Copyright 2020 Imam Rafii - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#pragma once - -#define BACKLIGHT_PWM_DRIVER PWMD5 -#define BACKLIGHT_PWM_CHANNEL 1 diff --git a/keyboards/linworks/fave104/config.h b/keyboards/linworks/fave104/config.h index 73e72a129f..41c1a917f3 100644 --- a/keyboards/linworks/fave104/config.h +++ b/keyboards/linworks/fave104/config.h @@ -19,5 +19,4 @@ along with this program. If not, see . #define BACKLIGHT_PWM_DRIVER PWMD2 #define BACKLIGHT_PWM_CHANNEL 2 -#define BACKLIGHT_PAL_MODE 2 #define BACKLIGHT_PWM_OUTPUT_FREQUENCY 1000 // Increases backlight PWM freq if compiled with an unmerged PR. Does no harm without it. diff --git a/keyboards/linworks/whale75/config.h b/keyboards/linworks/whale75/config.h index d12d33bdfd..3aa16f3eb0 100644 --- a/keyboards/linworks/whale75/config.h +++ b/keyboards/linworks/whale75/config.h @@ -15,7 +15,6 @@ along with this program. If not, see . #pragma once #define BACKLIGHT_PWM_DRIVER PWMD1 -#define BACKLIGHT_PWM_CHANNEL 3 #define BACKLIGHT_PAL_MODE 6 #define BACKLIGHT_PWM_OUTPUT_FREQUENCY 1000 // Increases backlight PWM freq if compiled with an unmerged PR. Does no harm without it. diff --git a/keyboards/mechlovin/adelais/standard_led/arm/config.h b/keyboards/mechlovin/adelais/standard_led/arm/config.h index d7169c0443..68857621b7 100644 --- a/keyboards/mechlovin/adelais/standard_led/arm/config.h +++ b/keyboards/mechlovin/adelais/standard_led/arm/config.h @@ -18,7 +18,6 @@ along with this program. If not, see . #pragma once #define BACKLIGHT_PWM_DRIVER PWMD3 -#define BACKLIGHT_PWM_CHANNEL 3 #define RGBLIGHT_EFFECT_BREATHING #define RGBLIGHT_EFFECT_RAINBOW_MOOD diff --git a/keyboards/mechlovin/hannah65/config.h b/keyboards/mechlovin/hannah65/config.h deleted file mode 100644 index 1686c861fb..0000000000 --- a/keyboards/mechlovin/hannah65/config.h +++ /dev/null @@ -1,21 +0,0 @@ -/* -Copyright 2020 Team Mechlovin - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#pragma once - -#define BACKLIGHT_PWM_DRIVER PWMD4 -#define BACKLIGHT_PWM_CHANNEL 3 diff --git a/keyboards/mechlovin/hex4b/rev2/config.h b/keyboards/mechlovin/hex4b/rev2/config.h deleted file mode 100644 index 14dfffbed3..0000000000 --- a/keyboards/mechlovin/hex4b/rev2/config.h +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 2020 Team Mechlovin - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#pragma once - -#define BACKLIGHT_PWM_DRIVER PWMD4 diff --git a/keyboards/mechlovin/hex6c/config.h b/keyboards/mechlovin/hex6c/config.h index 48bf717581..4cfcaebcde 100644 --- a/keyboards/mechlovin/hex6c/config.h +++ b/keyboards/mechlovin/hex6c/config.h @@ -18,7 +18,6 @@ along with this program. If not, see . #pragma once #define BACKLIGHT_PWM_DRIVER PWMD3 -#define BACKLIGHT_PWM_CHANNEL 3 #define WEAR_LEVELING_BACKING_SIZE 4096 #define WEAR_LEVELING_LOGICAL_SIZE 2048 diff --git a/keyboards/mechlovin/infinity87/rev1/config.h b/keyboards/mechlovin/infinity87/rev1/config.h index 2265fff2d1..e21e5d019f 100644 --- a/keyboards/mechlovin/infinity87/rev1/config.h +++ b/keyboards/mechlovin/infinity87/rev1/config.h @@ -17,4 +17,3 @@ #pragma once #define BACKLIGHT_PWM_DRIVER PWMD3 -#define BACKLIGHT_PWM_CHANNEL 3 diff --git a/keyboards/mechlovin/infinity88/config.h b/keyboards/mechlovin/infinity88/config.h index 9f5eaf5d87..5d7b823cd4 100644 --- a/keyboards/mechlovin/infinity88/config.h +++ b/keyboards/mechlovin/infinity88/config.h @@ -18,7 +18,6 @@ along with this program. If not, see . #pragma once #define BACKLIGHT_PWM_DRIVER PWMD3 -#define BACKLIGHT_PWM_CHANNEL 3 /*== all animations enable ==*/#define RGBLIGHT_EFFECT_BREATHING #define RGBLIGHT_EFFECT_RAINBOW_MOOD diff --git a/keyboards/mechlovin/mechlovin9/rev1/config.h b/keyboards/mechlovin/mechlovin9/rev1/config.h deleted file mode 100644 index 3686536dfb..0000000000 --- a/keyboards/mechlovin/mechlovin9/rev1/config.h +++ /dev/null @@ -1,21 +0,0 @@ -/* -Copyright 2021 Mechlovin' Studio - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#pragma once - -#define BACKLIGHT_PWM_DRIVER PWMD3 -#define BACKLIGHT_PWM_CHANNEL 3 diff --git a/keyboards/mechlovin/tmkl/config.h b/keyboards/mechlovin/tmkl/config.h index e604c6bcfa..03e3beacd0 100644 --- a/keyboards/mechlovin/tmkl/config.h +++ b/keyboards/mechlovin/tmkl/config.h @@ -17,8 +17,5 @@ along with this program. If not, see . #pragma once -#define BACKLIGHT_PWM_DRIVER PWMD3 -#define BACKLIGHT_PWM_CHANNEL 3 - /* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */ #define LOCKING_SUPPORT_ENABLE diff --git a/keyboards/mode/m75s/config.h b/keyboards/mode/m75s/config.h index c17bf51b35..7fdb18d26a 100644 --- a/keyboards/mode/m75s/config.h +++ b/keyboards/mode/m75s/config.h @@ -20,7 +20,6 @@ along with this program. If not, see . #define BACKLIGHT_DEFAULT_LEVEL 20 #define BACKLIGHT_PWM_DRIVER PWMD3 #define BACKLIGHT_PWM_CHANNEL 1 -#define BACKLIGHT_PAL_MODE 2 #define WEAR_LEVELING_LOGICAL_SIZE 2048 #define WEAR_LEVELING_BACKING_SIZE 4096 diff --git a/keyboards/smithrune/iron165r2/f411/config.h b/keyboards/smithrune/iron165r2/f411/config.h index 5ce500d1e5..1cd8a5c150 100644 --- a/keyboards/smithrune/iron165r2/f411/config.h +++ b/keyboards/smithrune/iron165r2/f411/config.h @@ -19,7 +19,6 @@ along with this program. If not, see . #define BACKLIGHT_PWM_DRIVER PWMD3 #define BACKLIGHT_PWM_CHANNEL 1 -#define BACKLIGHT_PAL_MODE 2 #define RGBLIGHT_EFFECT_BREATHING #define RGBLIGHT_EFFECT_RAINBOW_MOOD diff --git a/platforms/avr/drivers/backlight_pwm.c b/platforms/avr/drivers/backlight_pwm.c new file mode 100644 index 0000000000..d234115641 --- /dev/null +++ b/platforms/avr/drivers/backlight_pwm.c @@ -0,0 +1,463 @@ +#include "backlight.h" +#include "backlight_driver_common.h" +#include "progmem.h" +#include +#include + +// Maximum duty cycle limit +#ifndef BACKLIGHT_LIMIT_VAL +# define BACKLIGHT_LIMIT_VAL 255 +#endif + +// This logic is a bit complex, we support 3 setups: +// +// 1. Hardware PWM when backlight is wired to a PWM pin. +// Depending on this pin, we use a different output compare unit. +// 2. Software PWM with hardware timers, but the used timer +// depends on the Audio setup (Audio wins over Backlight). +// 3. Full software PWM, driven by the matrix scan, if both timers are used by Audio. + +#if (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) && (BACKLIGHT_PIN == B5 || BACKLIGHT_PIN == B6 || BACKLIGHT_PIN == B7) +# define ICRx ICR1 +# define TCCRxA TCCR1A +# define TCCRxB TCCR1B +# define TIMERx_OVF_vect TIMER1_OVF_vect +# define TIMSKx TIMSK1 +# define TOIEx TOIE1 + +# if BACKLIGHT_PIN == B5 +# define COMxx0 COM1A0 +# define COMxx1 COM1A1 +# define OCRxx OCR1A +# elif BACKLIGHT_PIN == B6 +# define COMxx0 COM1B0 +# define COMxx1 COM1B1 +# define OCRxx OCR1B +# elif BACKLIGHT_PIN == B7 +# define COMxx0 COM1C0 +# define COMxx1 COM1C1 +# define OCRxx OCR1C +# endif +#elif (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) && (BACKLIGHT_PIN == C4 || BACKLIGHT_PIN == C5 || BACKLIGHT_PIN == C6) +# define ICRx ICR3 +# define TCCRxA TCCR3A +# define TCCRxB TCCR3B +# define TIMERx_OVF_vect TIMER3_OVF_vect +# define TIMSKx TIMSK3 +# define TOIEx TOIE3 + +# if BACKLIGHT_PIN == C4 +# if (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) +# error This MCU has no C4 pin! +# else +# define COMxx0 COM3C0 +# define COMxx1 COM3C1 +# define OCRxx OCR3C +# endif +# elif BACKLIGHT_PIN == C5 +# if (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) +# error This MCU has no C5 pin! +# else +# define COMxx0 COM3B0 +# define COMxx1 COM3B1 +# define OCRxx OCR3B +# endif +# elif BACKLIGHT_PIN == C6 +# define COMxx0 COM3A0 +# define COMxx1 COM3A1 +# define OCRxx OCR3A +# endif +#elif (defined(__AVR_AT90USB162__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__)) && (BACKLIGHT_PIN == B7 || BACKLIGHT_PIN == C5 || BACKLIGHT_PIN == C6) +# define ICRx ICR1 +# define TCCRxA TCCR1A +# define TCCRxB TCCR1B +# define TIMERx_OVF_vect TIMER1_OVF_vect +# define TIMSKx TIMSK1 +# define TOIEx TOIE1 + +# if BACKLIGHT_PIN == B7 +# define COMxx0 COM1C0 +# define COMxx1 COM1C1 +# define OCRxx OCR1C +# elif BACKLIGHT_PIN == C5 +# define COMxx0 COM1B0 +# define COMxx1 COM1B1 +# define OCRxx OCR1B +# elif BACKLIGHT_PIN == C6 +# define COMxx0 COM1A0 +# define COMxx1 COM1A1 +# define OCRxx OCR1A +# endif +#elif defined(__AVR_ATmega32A__) && (BACKLIGHT_PIN == D4 || BACKLIGHT_PIN == D5) +# define ICRx ICR1 +# define TCCRxA TCCR1A +# define TCCRxB TCCR1B +# define TIMERx_OVF_vect TIMER1_OVF_vect +# define TIMSKx TIMSK +# define TOIEx TOIE1 + +# if BACKLIGHT_PIN == D4 +# define COMxx0 COM1B0 +# define COMxx1 COM1B1 +# define OCRxx OCR1B +# elif BACKLIGHT_PIN == D5 +# define COMxx0 COM1A0 +# define COMxx1 COM1A1 +# define OCRxx OCR1A +# endif +#elif (defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)) && (BACKLIGHT_PIN == B1 || BACKLIGHT_PIN == B2) +# define ICRx ICR1 +# define TCCRxA TCCR1A +# define TCCRxB TCCR1B +# define TIMERx_OVF_vect TIMER1_OVF_vect +# define TIMSKx TIMSK1 +# define TOIEx TOIE1 + +# if BACKLIGHT_PIN == B1 +# define COMxx0 COM1A0 +# define COMxx1 COM1A1 +# define OCRxx OCR1A +# elif BACKLIGHT_PIN == B2 +# define COMxx0 COM1B0 +# define COMxx1 COM1B1 +# define OCRxx OCR1B +# endif +#elif (AUDIO_PIN != B5) && (AUDIO_PIN != B6) && (AUDIO_PIN != B7) && (AUDIO_PIN_ALT != B5) && (AUDIO_PIN_ALT != B6) && (AUDIO_PIN_ALT != B7) +// Timer 1 is not in use by Audio feature, Backlight can use it +# pragma message "Using hardware timer 1 with software PWM" +# define BACKLIGHT_PWM_TIMER +# define ICRx ICR1 +# define TCCRxA TCCR1A +# define TCCRxB TCCR1B +# define TIMERx_COMPA_vect TIMER1_COMPA_vect +# define TIMERx_OVF_vect TIMER1_OVF_vect +# if defined(__AVR_ATmega32A__) // This MCU has only one TIMSK register +# define TIMSKx TIMSK +# else +# define TIMSKx TIMSK1 +# endif +# define TOIEx TOIE1 + +# define OCIExA OCIE1A +# define OCRxx OCR1A +#elif (AUDIO_PIN != C4) && (AUDIO_PIN != C5) && (AUDIO_PIN != C6) +# pragma message "Using hardware timer 3 with software PWM" +// Timer 3 is not in use by Audio feature, Backlight can use it +# define BACKLIGHT_PWM_TIMER +# define ICRx ICR1 +# define TCCRxA TCCR3A +# define TCCRxB TCCR3B +# define TIMERx_COMPA_vect TIMER3_COMPA_vect +# define TIMERx_OVF_vect TIMER3_OVF_vect +# define TIMSKx TIMSK3 +# define TOIEx TOIE3 + +# define OCIExA OCIE3A +# define OCRxx OCR3A +#endif + +#ifndef BACKLIGHT_PWM_TIMER // pwm through software + +static inline void enable_pwm(void) { +# if BACKLIGHT_ON_STATE == 1 + TCCRxA |= _BV(COMxx1); +# else + TCCRxA |= _BV(COMxx1) | _BV(COMxx0); +# endif +} + +static inline void disable_pwm(void) { +# if BACKLIGHT_ON_STATE == 1 + TCCRxA &= ~(_BV(COMxx1)); +# else + TCCRxA &= ~(_BV(COMxx1) | _BV(COMxx0)); +# endif +} + +#endif + +#ifdef BACKLIGHT_PWM_TIMER + +// The idea of software PWM assisted by hardware timers is the following +// we use the hardware timer in fast PWM mode like for hardware PWM, but +// instead of letting the Output Match Comparator control the led pin +// (which is not possible since the backlight is not wired to PWM pins on the +// CPU), we do the LED on/off by oursleves. +// The timer is setup to count up to 0xFFFF, and we set the Output Compare +// register to the current 16bits backlight level (after CIE correction). +// This means the CPU will trigger a compare match interrupt when the counter +// reaches the backlight level, where we turn off the LEDs, +// but also an overflow interrupt when the counter rolls back to 0, +// in which we're going to turn on the LEDs. +// The LED will then be on for OCRxx/0xFFFF time, adjusted every 244Hz, +// or F_CPU/BACKLIGHT_CUSTOM_RESOLUTION if used. + +// Triggered when the counter reaches the OCRx value +ISR(TIMERx_COMPA_vect) { + backlight_pins_off(); +} + +// Triggered when the counter reaches the TOP value +// this one triggers at F_CPU/ICRx = 16MHz/65536 =~ 244 Hz +ISR(TIMERx_OVF_vect) { +# ifdef BACKLIGHT_BREATHING + if (is_breathing()) { + breathing_task(); + } +# endif + // for very small values of OCRxx (or backlight level) + // we can't guarantee this whole code won't execute + // at the same time as the compare match interrupt + // which means that we might turn on the leds while + // trying to turn them off, leading to flickering + // artifacts (especially while breathing, because breathing_task + // takes many computation cycles). + // so better not turn them on while the counter TOP is very low. + if (OCRxx > ICRx / 250 + 5) { + backlight_pins_on(); + } +} + +#endif + +#define TIMER_TOP 0xFFFFU + +// See http://jared.geek.nz/2013/feb/linear-led-pwm +static uint16_t cie_lightness(uint16_t v) { + if (v <= (uint32_t)ICRx / 12) // If the value is less than or equal to ~8% of max + { + return v / 9; // Same as dividing by 900% + } else { + // In the next two lines values are bit-shifted. This is to avoid loosing decimals in integer math. + uint32_t y = (((uint32_t)v + (uint32_t)ICRx / 6) << 5) / ((uint32_t)ICRx / 6 + ICRx); // If above 8%, add ~16% of max, and normalize with (max + ~16% max) + uint32_t out = (y * y * y * ICRx) >> 15; // Cube it and undo the bit-shifting. (which is now three times as much due to the cubing) + + if (out > ICRx) // Avoid overflows + { + out = ICRx; + } + return (uint16_t)out; + } +} + +// rescale the supplied backlight value to be in terms of the value limit // range for val is [0..ICRx]. PWM pin is high while the timer count is below val. +static uint32_t rescale_limit_val(uint32_t val) { + return (val * (BACKLIGHT_LIMIT_VAL + 1)) / 256; +} + +// range for val is [0..ICRx]. PWM pin is high while the timer count is below val. +static inline void set_pwm(uint16_t val) { + OCRxx = val; +} + +void backlight_set(uint8_t level) { + if (level > BACKLIGHT_LEVELS) level = BACKLIGHT_LEVELS; + + if (level == 0) { +#ifdef BACKLIGHT_PWM_TIMER + if (OCRxx) { + TIMSKx &= ~(_BV(OCIExA)); + TIMSKx &= ~(_BV(TOIEx)); + } +#else + // Turn off PWM control on backlight pin + disable_pwm(); +#endif + backlight_pins_off(); + } else { +#ifdef BACKLIGHT_PWM_TIMER + if (!OCRxx) { + TIMSKx |= _BV(OCIExA); + TIMSKx |= _BV(TOIEx); + } +#else + // Turn on PWM control of backlight pin + enable_pwm(); +#endif + } + // Set the brightness + set_pwm(cie_lightness(rescale_limit_val(ICRx * (uint32_t)level / BACKLIGHT_LEVELS))); +} + +void backlight_task(void) {} + +#ifdef BACKLIGHT_BREATHING + +# define BREATHING_NO_HALT 0 +# define BREATHING_HALT_OFF 1 +# define BREATHING_HALT_ON 2 +# define BREATHING_STEPS 128 + +static uint8_t breathing_halt = BREATHING_NO_HALT; +static uint16_t breathing_counter = 0; + +static uint8_t breath_scale_counter = 1; +/* Run the breathing loop at ~120Hz*/ +const uint8_t breathing_ISR_frequency = 120; +static uint16_t breathing_freq_scale_factor = 2; + +# ifdef BACKLIGHT_PWM_TIMER +static bool breathing = false; + +bool is_breathing(void) { + return breathing; +} + +# define breathing_interrupt_enable() \ + do { \ + breathing = true; \ + } while (0) +# define breathing_interrupt_disable() \ + do { \ + breathing = false; \ + } while (0) +# else + +bool is_breathing(void) { + return !!(TIMSKx & _BV(TOIEx)); +} + +# define breathing_interrupt_enable() \ + do { \ + TIMSKx |= _BV(TOIEx); \ + } while (0) +# define breathing_interrupt_disable() \ + do { \ + TIMSKx &= ~_BV(TOIEx); \ + } while (0) +# endif + +# define breathing_min() \ + do { \ + breathing_counter = 0; \ + } while (0) +# define breathing_max() \ + do { \ + breathing_counter = get_breathing_period() * breathing_ISR_frequency / 2; \ + } while (0) + +void breathing_enable(void) { + breathing_counter = 0; + breathing_halt = BREATHING_NO_HALT; + breathing_interrupt_enable(); +} + +void breathing_pulse(void) { + if (get_backlight_level() == 0) + breathing_min(); + else + breathing_max(); + breathing_halt = BREATHING_HALT_ON; + breathing_interrupt_enable(); +} + +void breathing_disable(void) { + breathing_interrupt_disable(); + // Restore backlight level + backlight_set(get_backlight_level()); +} + +void breathing_self_disable(void) { + if (get_backlight_level() == 0) + breathing_halt = BREATHING_HALT_OFF; + else + breathing_halt = BREATHING_HALT_ON; +} + +/* To generate breathing curve in python: + * from math import sin, pi; [int(sin(x/128.0*pi)**4*255) for x in range(128)] + */ +static const uint8_t breathing_table[BREATHING_STEPS] PROGMEM = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 17, 20, 24, 28, 32, 36, 41, 46, 51, 57, 63, 70, 76, 83, 91, 98, 106, 113, 121, 129, 138, 146, 154, 162, 170, 178, 185, 193, 200, 207, 213, 220, 225, 231, 235, 240, 244, 247, 250, 252, 253, 254, 255, 254, 253, 252, 250, 247, 244, 240, 235, 231, 225, 220, 213, 207, 200, 193, 185, 178, 170, 162, 154, 146, 138, 129, 121, 113, 106, 98, 91, 83, 76, 70, 63, 57, 51, 46, 41, 36, 32, 28, 24, 20, 17, 15, 12, 10, 8, 6, 5, 4, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +// Use this before the cie_lightness function. +static inline uint16_t scale_backlight(uint16_t v) { + return v / BACKLIGHT_LEVELS * get_backlight_level(); +} + +# ifdef BACKLIGHT_PWM_TIMER +void breathing_task(void) +# else +/* Assuming a 16MHz CPU clock and a timer that resets at 64k (ICR1), the following interrupt handler will run + * about 244 times per second. + * + * The following ISR runs at F_CPU/ISRx. With a 16MHz clock and default pwm resolution, that means 244Hz + */ +ISR(TIMERx_OVF_vect) +# endif +{ + + // Only run this ISR at ~120 Hz + if (breath_scale_counter++ == breathing_freq_scale_factor) { + breath_scale_counter = 1; + } else { + return; + } + uint16_t interval = (uint16_t)get_breathing_period() * breathing_ISR_frequency / BREATHING_STEPS; + // resetting after one period to prevent ugly reset at overflow. + breathing_counter = (breathing_counter + 1) % (get_breathing_period() * breathing_ISR_frequency); + uint8_t index = breathing_counter / interval; + // limit index to max step value + if (index >= BREATHING_STEPS) { + index = BREATHING_STEPS - 1; + } + + if (((breathing_halt == BREATHING_HALT_ON) && (index == BREATHING_STEPS / 2)) || ((breathing_halt == BREATHING_HALT_OFF) && (index == BREATHING_STEPS - 1))) { + breathing_interrupt_disable(); + } + + // Set PWM to a brightnessvalue scaled to the configured resolution + set_pwm(cie_lightness(rescale_limit_val(scale_backlight((uint32_t)pgm_read_byte(&breathing_table[index]) * ICRx / 255)))); +} + +#endif // BACKLIGHT_BREATHING + +void backlight_init_ports(void) { + // Setup backlight pin as output and output to on state. + backlight_pins_init(); + + // I could write a wall of text here to explain... but TL;DW + // Go read the ATmega32u4 datasheet. + // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on + +#ifdef BACKLIGHT_PWM_TIMER + // TimerX setup, Fast PWM mode count to TOP set in ICRx + TCCRxA = _BV(WGM11); // = 0b00000010; + // clock select clk/1 + TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001; +#else // hardware PWM + // Pin PB7 = OCR1C (Timer 1, Channel C) + // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0 + // (i.e. start high, go low when counter matches.) + // WGM Mode 14 (Fast PWM) = WGM13=1 WGM12=1 WGM11=1 WGM10=0 + // Clock Select = clk/1 (no prescaling) = CS12=0 CS11=0 CS10=1 + + /* + 14.8.3: + "In fast PWM mode, the compare units allow generation of PWM waveforms on the OCnx pins. Setting the COMnx1:0 bits to two will produce a non-inverted PWM [..]." + "In fast PWM mode the counter is incremented until the counter value matches either one of the fixed values 0x00FF, 0x01FF, or 0x03FF (WGMn3:0 = 5, 6, or 7), the value in ICRn (WGMn3:0 = 14), or the value in OCRnA (WGMn3:0 = 15)." + */ + TCCRxA = _BV(COMxx1) | _BV(WGM11); // = 0b00001010; + TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001; +#endif + +#ifdef BACKLIGHT_CUSTOM_RESOLUTION +# if (BACKLIGHT_CUSTOM_RESOLUTION > 0xFFFF || BACKLIGHT_CUSTOM_RESOLUTION < 1) +# error "This out of range of the timer capabilities" +# elif (BACKLIGHT_CUSTOM_RESOLUTION < 0xFF) +# warning "Resolution lower than 0xFF isn't recommended" +# endif +# ifdef BACKLIGHT_BREATHING + breathing_freq_scale_factor = F_CPU / BACKLIGHT_CUSTOM_RESOLUTION / 120; +# endif + ICRx = BACKLIGHT_CUSTOM_RESOLUTION; +#else + ICRx = TIMER_TOP; +#endif + + backlight_init(); +#ifdef BACKLIGHT_BREATHING + if (is_backlight_breathing()) { + breathing_enable(); + } +#endif +} diff --git a/platforms/chibios/drivers/backlight_pwm.c b/platforms/chibios/drivers/backlight_pwm.c new file mode 100644 index 0000000000..01e6f71307 --- /dev/null +++ b/platforms/chibios/drivers/backlight_pwm.c @@ -0,0 +1,173 @@ +#include "backlight.h" +#include "gpio.h" +#include "wait.h" +#include + +// Maximum duty cycle limit +#ifndef BACKLIGHT_LIMIT_VAL +# define BACKLIGHT_LIMIT_VAL 255 +#endif + +#ifndef BACKLIGHT_PAL_MODE +# if defined(USE_GPIOV1) +# define BACKLIGHT_PAL_MODE PAL_MODE_ALTERNATE_PUSHPULL +# else +// GPIOV2 && GPIOV3 +# define BACKLIGHT_PAL_MODE 2 +# endif +#endif + +// GENERIC +#ifndef BACKLIGHT_PWM_DRIVER +# define BACKLIGHT_PWM_DRIVER PWMD4 +#endif +#ifndef BACKLIGHT_PWM_CHANNEL +# define BACKLIGHT_PWM_CHANNEL 3 +#endif + +// Support for pins which are on TIM1_CH1N - requires STM32_PWM_USE_ADVANCED +#ifdef BACKLIGHT_PWM_COMPLEMENTARY_OUTPUT +# if BACKLIGHT_ON_STATE == 1 +# define PWM_OUTPUT_MODE PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW; +# else +# define PWM_OUTPUT_MODE PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH; +# endif +#else +# if BACKLIGHT_ON_STATE == 1 +# define PWM_OUTPUT_MODE PWM_OUTPUT_ACTIVE_HIGH; +# else +# define PWM_OUTPUT_MODE PWM_OUTPUT_ACTIVE_LOW; +# endif +#endif + +#ifndef BACKLIGHT_PWM_COUNTER_FREQUENCY +# define BACKLIGHT_PWM_COUNTER_FREQUENCY 0xFFFF +#endif + +#ifndef BACKLIGHT_PWM_PERIOD +# define BACKLIGHT_PWM_PERIOD 256 +#endif + +static PWMConfig pwmCFG = { + .frequency = BACKLIGHT_PWM_COUNTER_FREQUENCY, /* PWM clock frequency */ + .period = BACKLIGHT_PWM_PERIOD, /* PWM period in counter ticks. e.g. clock frequency is 10KHz, period is 256 ticks then t_period is 25.6ms */ +}; + +#ifdef BACKLIGHT_BREATHING +static virtual_timer_t breathing_vt; +#endif + +// 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 uint32_t rescale_limit_val(uint32_t val) { + // rescale the supplied backlight value to be in terms of the value limit + return (val * (BACKLIGHT_LIMIT_VAL + 1)) / 256; +} + +void backlight_init_ports(void) { +#ifdef USE_GPIOV1 + palSetPadMode(PAL_PORT(BACKLIGHT_PIN), PAL_PAD(BACKLIGHT_PIN), BACKLIGHT_PAL_MODE); +#else + palSetPadMode(PAL_PORT(BACKLIGHT_PIN), PAL_PAD(BACKLIGHT_PIN), PAL_MODE_ALTERNATE(BACKLIGHT_PAL_MODE)); +#endif + + pwmCFG.channels[BACKLIGHT_PWM_CHANNEL - 1].mode = PWM_OUTPUT_MODE; + pwmStart(&BACKLIGHT_PWM_DRIVER, &pwmCFG); + + backlight_set(get_backlight_level()); + +#ifdef BACKLIGHT_BREATHING + chVTObjectInit(&breathing_vt); + if (is_backlight_breathing()) { + breathing_enable(); + } +#endif +} + +void backlight_set(uint8_t level) { + if (level > BACKLIGHT_LEVELS) { + level = BACKLIGHT_LEVELS; + } + + if (level == 0) { + // Turn backlight off + pwmDisableChannel(&BACKLIGHT_PWM_DRIVER, BACKLIGHT_PWM_CHANNEL - 1); + } else { + // Turn backlight on + uint32_t duty = (uint32_t)(cie_lightness(rescale_limit_val(0xFFFF * (uint32_t)level / BACKLIGHT_LEVELS))); + pwmEnableChannel(&BACKLIGHT_PWM_DRIVER, BACKLIGHT_PWM_CHANNEL - 1, PWM_FRACTION_TO_WIDTH(&BACKLIGHT_PWM_DRIVER, 0xFFFF, duty)); + } +} + +void backlight_task(void) {} + +#ifdef BACKLIGHT_BREATHING + +# define BREATHING_STEPS 128 + +/* To generate breathing curve in python: + * from math import sin, pi; [int(sin(x/128.0*pi)**4*255) for x in range(128)] + */ +static const uint8_t breathing_table[BREATHING_STEPS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 17, 20, 24, 28, 32, 36, 41, 46, 51, 57, 63, 70, 76, 83, 91, 98, 106, 113, 121, 129, 138, 146, 154, 162, 170, 178, 185, 193, 200, 207, 213, 220, 225, 231, 235, 240, 244, 247, 250, 252, 253, 254, 255, 254, 253, 252, 250, 247, 244, 240, 235, 231, 225, 220, 213, 207, 200, 193, 185, 178, 170, 162, 154, 146, 138, 129, 121, 113, 106, 98, 91, 83, 76, 70, 63, 57, 51, 46, 41, 36, 32, 28, 24, 20, 17, 15, 12, 10, 8, 6, 5, 4, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +static void breathing_callback(virtual_timer_t *vtp, void *p); + +bool is_breathing(void) { + return chVTIsArmed(&breathing_vt); +} + +void breathing_enable(void) { + /* Update frequency is 256Hz -> 3906us intervals */ + chVTSetContinuous(&breathing_vt, TIME_US2I(3906), breathing_callback, NULL); +} + +void breathing_disable(void) { + chVTReset(&breathing_vt); + + // Restore backlight level + backlight_set(get_backlight_level()); +} + +// Use this before the cie_lightness function. +static inline uint16_t scale_backlight(uint16_t v) { + return v / BACKLIGHT_LEVELS * get_backlight_level(); +} + +static void breathing_callback(virtual_timer_t *vtp, void *p) { + uint8_t breathing_period = get_breathing_period(); + uint16_t interval = (uint16_t)breathing_period * 256 / BREATHING_STEPS; + + // resetting after one period to prevent ugly reset at overflow. + static uint16_t breathing_counter = 0; + breathing_counter = (breathing_counter + 1) % (breathing_period * 256); + uint8_t index = breathing_counter / interval % BREATHING_STEPS; + uint32_t duty = cie_lightness(rescale_limit_val(scale_backlight(breathing_table[index] * 256))); + + chSysLockFromISR(); + pwmEnableChannelI(&BACKLIGHT_PWM_DRIVER, BACKLIGHT_PWM_CHANNEL - 1, PWM_FRACTION_TO_WIDTH(&BACKLIGHT_PWM_DRIVER, 0xFFFF, duty)); + chSysUnlockFromISR(); +} + +// TODO: integrate generic pulse solution +void breathing_pulse(void) { + backlight_set(is_backlight_enabled() ? 0 : BACKLIGHT_LEVELS); + wait_ms(10); + backlight_set(is_backlight_enabled() ? get_backlight_level() : 0); +} + +#endif diff --git a/platforms/chibios/drivers/backlight_timer.c b/platforms/chibios/drivers/backlight_timer.c new file mode 100644 index 0000000000..0fabee93b1 --- /dev/null +++ b/platforms/chibios/drivers/backlight_timer.c @@ -0,0 +1,178 @@ +#include "backlight.h" +#include "backlight_driver_common.h" +#include "wait.h" + +#ifndef BACKLIGHT_GPT_DRIVER +# define BACKLIGHT_GPT_DRIVER GPTD15 +#endif + +// Platform specific implementations +static void backlight_timer_configure(bool enable); +static void backlight_timer_set_duty(uint16_t duty); +static uint16_t backlight_timer_get_duty(void); + +// 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; + } +} + +void backlight_init_ports(void) { + backlight_pins_init(); + + backlight_set(get_backlight_level()); + +#ifdef BACKLIGHT_BREATHING + if (is_backlight_breathing()) { + breathing_enable(); + } +#endif +} + +void backlight_set(uint8_t level) { + if (level > BACKLIGHT_LEVELS) level = BACKLIGHT_LEVELS; + + backlight_pins_off(); + + backlight_timer_set_duty(cie_lightness(0xFFFFU / BACKLIGHT_LEVELS * level)); + backlight_timer_configure(level != 0); +} + +static void backlight_timer_top(void) { +#ifdef BACKLIGHT_BREATHING + if (is_breathing()) { + breathing_task(); + } +#endif + + if (backlight_timer_get_duty() > 256) { + backlight_pins_on(); + } +} + +static void backlight_timer_cmp(void) { + backlight_pins_off(); +} + +void backlight_task(void) {} + +#ifdef BACKLIGHT_BREATHING +# define BREATHING_STEPS 128 + +static bool breathing = false; +static uint16_t breathing_counter = 0; + +/* To generate breathing curve in python: + * from math import sin, pi; [int(sin(x/128.0*pi)**4*255) for x in range(128)] + */ +static const uint8_t breathing_table[BREATHING_STEPS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 17, 20, 24, 28, 32, 36, 41, 46, 51, 57, 63, 70, 76, 83, 91, 98, 106, 113, 121, 129, 138, 146, 154, 162, 170, 178, 185, 193, 200, 207, 213, 220, 225, 231, 235, 240, 244, 247, 250, 252, 253, 254, 255, 254, 253, 252, 250, 247, 244, 240, 235, 231, 225, 220, 213, 207, 200, 193, 185, 178, 170, 162, 154, 146, 138, 129, 121, 113, 106, 98, 91, 83, 76, 70, 63, 57, 51, 46, 41, 36, 32, 28, 24, 20, 17, 15, 12, 10, 8, 6, 5, 4, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +// Use this before the cie_lightness function. +static inline uint16_t scale_backlight(uint16_t v) { + return v / BACKLIGHT_LEVELS * get_backlight_level(); +} + +void breathing_task(void) { + uint8_t breathing_period = get_breathing_period(); + uint16_t interval = (uint16_t)breathing_period * 256 / BREATHING_STEPS; + // resetting after one period to prevent ugly reset at overflow. + breathing_counter = (breathing_counter + 1) % (breathing_period * 256); + uint8_t index = breathing_counter / interval % BREATHING_STEPS; + + // printf("index:%u\n", index); + + backlight_timer_set_duty(cie_lightness(scale_backlight((uint16_t)breathing_table[index] * 256))); +} + +bool is_breathing(void) { + return breathing; +} + +void breathing_enable(void) { + breathing_counter = 0; + breathing = true; +} +void breathing_disable(void) { + breathing = false; +} + +void breathing_pulse(void) { + backlight_set(is_backlight_enabled() ? 0 : BACKLIGHT_LEVELS); + wait_ms(10); + backlight_set(is_backlight_enabled() ? get_backlight_level() : 0); +} +#endif + +#ifdef PROTOCOL_CHIBIOS +// On Platforms where timers fire every tick and have no capture/top events +// - fake event in the normal timer callback +uint16_t s_duty = 0; + +static void timerCallback(void) { + /* Software PWM + * timer:1111 1111 1111 1111 + * \______/| \_______/____ count(0-255) + * \ \______________ unused(1) + * \__________________ index of step table(0-127) + */ + + // this works for cca 65536 irqs/sec + static union { + uint16_t raw; + struct { + uint16_t count : 8; + uint8_t dummy : 1; + uint8_t index : 7; + } pwm; + } timer = {.raw = 0}; + + timer.raw++; + + if (timer.pwm.count == 0) { + // LED on + backlight_timer_top(); + } else if (timer.pwm.count == (s_duty / 256)) { + // LED off + backlight_timer_cmp(); + } +} + +static void backlight_timer_set_duty(uint16_t duty) { + s_duty = duty; +} +static uint16_t backlight_timer_get_duty(void) { + return s_duty; +} + +// ChibiOS - Map GPT timer onto Software PWM +static void gptTimerCallback(GPTDriver *gptp) { + (void)gptp; + timerCallback(); +} + +static void backlight_timer_configure(bool enable) { + static const GPTConfig gptcfg = {1000000, gptTimerCallback, 0, 0}; + + static bool s_init = false; + if (!s_init) { + gptStart(&BACKLIGHT_GPT_DRIVER, &gptcfg); + s_init = true; + } + + if (enable) { + gptStartContinuous(&BACKLIGHT_GPT_DRIVER, gptcfg.frequency / 0xFFFF); + } else { + gptStopTimer(&BACKLIGHT_GPT_DRIVER); + } +} +#endif diff --git a/quantum/backlight/backlight.c b/quantum/backlight/backlight.c index 52ec086bb0..9d9f944f5d 100644 --- a/quantum/backlight/backlight.c +++ b/quantum/backlight/backlight.c @@ -15,7 +15,6 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include "quantum.h" #include "backlight.h" #include "eeprom.h" #include "eeconfig.h" diff --git a/quantum/backlight/backlight_avr.c b/quantum/backlight/backlight_avr.c deleted file mode 100644 index 474e0a86f5..0000000000 --- a/quantum/backlight/backlight_avr.c +++ /dev/null @@ -1,473 +0,0 @@ -#include "quantum.h" -#include "backlight.h" -#include "backlight_driver_common.h" -#include "debug.h" - -// Maximum duty cycle limit -#ifndef BACKLIGHT_LIMIT_VAL -# define BACKLIGHT_LIMIT_VAL 255 -#endif - -// This logic is a bit complex, we support 3 setups: -// -// 1. Hardware PWM when backlight is wired to a PWM pin. -// Depending on this pin, we use a different output compare unit. -// 2. Software PWM with hardware timers, but the used timer -// depends on the Audio setup (Audio wins over Backlight). -// 3. Full software PWM, driven by the matrix scan, if both timers are used by Audio. - -#if (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) && (BACKLIGHT_PIN == B5 || BACKLIGHT_PIN == B6 || BACKLIGHT_PIN == B7) -# define HARDWARE_PWM -# define ICRx ICR1 -# define TCCRxA TCCR1A -# define TCCRxB TCCR1B -# define TIMERx_OVF_vect TIMER1_OVF_vect -# define TIMSKx TIMSK1 -# define TOIEx TOIE1 - -# if BACKLIGHT_PIN == B5 -# define COMxx0 COM1A0 -# define COMxx1 COM1A1 -# define OCRxx OCR1A -# elif BACKLIGHT_PIN == B6 -# define COMxx0 COM1B0 -# define COMxx1 COM1B1 -# define OCRxx OCR1B -# elif BACKLIGHT_PIN == B7 -# define COMxx0 COM1C0 -# define COMxx1 COM1C1 -# define OCRxx OCR1C -# endif -#elif (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) && (BACKLIGHT_PIN == C4 || BACKLIGHT_PIN == C5 || BACKLIGHT_PIN == C6) -# define HARDWARE_PWM -# define ICRx ICR3 -# define TCCRxA TCCR3A -# define TCCRxB TCCR3B -# define TIMERx_OVF_vect TIMER3_OVF_vect -# define TIMSKx TIMSK3 -# define TOIEx TOIE3 - -# if BACKLIGHT_PIN == C4 -# if (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) -# error This MCU has no C4 pin! -# else -# define COMxx0 COM3C0 -# define COMxx1 COM3C1 -# define OCRxx OCR3C -# endif -# elif BACKLIGHT_PIN == C5 -# if (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) -# error This MCU has no C5 pin! -# else -# define COMxx0 COM3B0 -# define COMxx1 COM3B1 -# define OCRxx OCR3B -# endif -# elif BACKLIGHT_PIN == C6 -# define COMxx0 COM3A0 -# define COMxx1 COM3A1 -# define OCRxx OCR3A -# endif -#elif (defined(__AVR_AT90USB162__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__)) && (BACKLIGHT_PIN == B7 || BACKLIGHT_PIN == C5 || BACKLIGHT_PIN == C6) -# define HARDWARE_PWM -# define ICRx ICR1 -# define TCCRxA TCCR1A -# define TCCRxB TCCR1B -# define TIMERx_OVF_vect TIMER1_OVF_vect -# define TIMSKx TIMSK1 -# define TOIEx TOIE1 - -# if BACKLIGHT_PIN == B7 -# define COMxx0 COM1C0 -# define COMxx1 COM1C1 -# define OCRxx OCR1C -# elif BACKLIGHT_PIN == C5 -# define COMxx0 COM1B0 -# define COMxx1 COM1B1 -# define OCRxx OCR1B -# elif BACKLIGHT_PIN == C6 -# define COMxx0 COM1A0 -# define COMxx1 COM1A1 -# define OCRxx OCR1A -# endif -#elif defined(__AVR_ATmega32A__) && (BACKLIGHT_PIN == D4 || BACKLIGHT_PIN == D5) -# define HARDWARE_PWM -# define ICRx ICR1 -# define TCCRxA TCCR1A -# define TCCRxB TCCR1B -# define TIMERx_OVF_vect TIMER1_OVF_vect -# define TIMSKx TIMSK -# define TOIEx TOIE1 - -# if BACKLIGHT_PIN == D4 -# define COMxx0 COM1B0 -# define COMxx1 COM1B1 -# define OCRxx OCR1B -# elif BACKLIGHT_PIN == D5 -# define COMxx0 COM1A0 -# define COMxx1 COM1A1 -# define OCRxx OCR1A -# endif -#elif (defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)) && (BACKLIGHT_PIN == B1 || BACKLIGHT_PIN == B2) -# define HARDWARE_PWM -# define ICRx ICR1 -# define TCCRxA TCCR1A -# define TCCRxB TCCR1B -# define TIMERx_OVF_vect TIMER1_OVF_vect -# define TIMSKx TIMSK1 -# define TOIEx TOIE1 - -# if BACKLIGHT_PIN == B1 -# define COMxx0 COM1A0 -# define COMxx1 COM1A1 -# define OCRxx OCR1A -# elif BACKLIGHT_PIN == B2 -# define COMxx0 COM1B0 -# define COMxx1 COM1B1 -# define OCRxx OCR1B -# endif -#elif (AUDIO_PIN != B5) && (AUDIO_PIN != B6) && (AUDIO_PIN != B7) && (AUDIO_PIN_ALT != B5) && (AUDIO_PIN_ALT != B6) && (AUDIO_PIN_ALT != B7) -// Timer 1 is not in use by Audio feature, Backlight can use it -# pragma message "Using hardware timer 1 with software PWM" -# define HARDWARE_PWM -# define BACKLIGHT_PWM_TIMER -# define ICRx ICR1 -# define TCCRxA TCCR1A -# define TCCRxB TCCR1B -# define TIMERx_COMPA_vect TIMER1_COMPA_vect -# define TIMERx_OVF_vect TIMER1_OVF_vect -# if defined(__AVR_ATmega32A__) // This MCU has only one TIMSK register -# define TIMSKx TIMSK -# else -# define TIMSKx TIMSK1 -# endif -# define TOIEx TOIE1 - -# define OCIExA OCIE1A -# define OCRxx OCR1A -#elif (AUDIO_PIN != C4) && (AUDIO_PIN != C5) && (AUDIO_PIN != C6) -# pragma message "Using hardware timer 3 with software PWM" -// Timer 3 is not in use by Audio feature, Backlight can use it -# define HARDWARE_PWM -# define BACKLIGHT_PWM_TIMER -# define ICRx ICR1 -# define TCCRxA TCCR3A -# define TCCRxB TCCR3B -# define TIMERx_COMPA_vect TIMER3_COMPA_vect -# define TIMERx_OVF_vect TIMER3_OVF_vect -# define TIMSKx TIMSK3 -# define TOIEx TOIE3 - -# define OCIExA OCIE3A -# define OCRxx OCR3A -#elif defined(BACKLIGHT_CUSTOM_DRIVER) -error("Please set 'BACKLIGHT_DRIVER = custom' within rules.mk") -#else -error("Please set 'BACKLIGHT_DRIVER = software' within rules.mk") -#endif - -#ifndef BACKLIGHT_PWM_TIMER // pwm through software - -static inline void enable_pwm(void) { -# if BACKLIGHT_ON_STATE == 1 - TCCRxA |= _BV(COMxx1); -# else - TCCRxA |= _BV(COMxx1) | _BV(COMxx0); -# endif -} - -static inline void disable_pwm(void) { -# if BACKLIGHT_ON_STATE == 1 - TCCRxA &= ~(_BV(COMxx1)); -# else - TCCRxA &= ~(_BV(COMxx1) | _BV(COMxx0)); -# endif -} - -#endif - -#ifdef BACKLIGHT_PWM_TIMER - -// The idea of software PWM assisted by hardware timers is the following -// we use the hardware timer in fast PWM mode like for hardware PWM, but -// instead of letting the Output Match Comparator control the led pin -// (which is not possible since the backlight is not wired to PWM pins on the -// CPU), we do the LED on/off by oursleves. -// The timer is setup to count up to 0xFFFF, and we set the Output Compare -// register to the current 16bits backlight level (after CIE correction). -// This means the CPU will trigger a compare match interrupt when the counter -// reaches the backlight level, where we turn off the LEDs, -// but also an overflow interrupt when the counter rolls back to 0, -// in which we're going to turn on the LEDs. -// The LED will then be on for OCRxx/0xFFFF time, adjusted every 244Hz, -// or F_CPU/BACKLIGHT_CUSTOM_RESOLUTION if used. - -// Triggered when the counter reaches the OCRx value -ISR(TIMERx_COMPA_vect) { - backlight_pins_off(); -} - -// Triggered when the counter reaches the TOP value -// this one triggers at F_CPU/ICRx = 16MHz/65536 =~ 244 Hz -ISR(TIMERx_OVF_vect) { -# ifdef BACKLIGHT_BREATHING - if (is_breathing()) { - breathing_task(); - } -# endif - // for very small values of OCRxx (or backlight level) - // we can't guarantee this whole code won't execute - // at the same time as the compare match interrupt - // which means that we might turn on the leds while - // trying to turn them off, leading to flickering - // artifacts (especially while breathing, because breathing_task - // takes many computation cycles). - // so better not turn them on while the counter TOP is very low. - if (OCRxx > ICRx / 250 + 5) { - backlight_pins_on(); - } -} - -#endif - -#define TIMER_TOP 0xFFFFU - -// See http://jared.geek.nz/2013/feb/linear-led-pwm -static uint16_t cie_lightness(uint16_t v) { - if (v <= (uint32_t)ICRx / 12) // If the value is less than or equal to ~8% of max - { - return v / 9; // Same as dividing by 900% - } else { - // In the next two lines values are bit-shifted. This is to avoid loosing decimals in integer math. - uint32_t y = (((uint32_t)v + (uint32_t)ICRx / 6) << 5) / ((uint32_t)ICRx / 6 + ICRx); // If above 8%, add ~16% of max, and normalize with (max + ~16% max) - uint32_t out = (y * y * y * ICRx) >> 15; // Cube it and undo the bit-shifting. (which is now three times as much due to the cubing) - - if (out > ICRx) // Avoid overflows - { - out = ICRx; - } - return (uint16_t)out; - } -} - -// rescale the supplied backlight value to be in terms of the value limit // range for val is [0..ICRx]. PWM pin is high while the timer count is below val. -static uint32_t rescale_limit_val(uint32_t val) { - return (val * (BACKLIGHT_LIMIT_VAL + 1)) / 256; -} - -// range for val is [0..ICRx]. PWM pin is high while the timer count is below val. -static inline void set_pwm(uint16_t val) { - OCRxx = val; -} - -void backlight_set(uint8_t level) { - if (level > BACKLIGHT_LEVELS) level = BACKLIGHT_LEVELS; - - if (level == 0) { -#ifdef BACKLIGHT_PWM_TIMER - if (OCRxx) { - TIMSKx &= ~(_BV(OCIExA)); - TIMSKx &= ~(_BV(TOIEx)); - } -#else - // Turn off PWM control on backlight pin - disable_pwm(); -#endif - backlight_pins_off(); - } else { -#ifdef BACKLIGHT_PWM_TIMER - if (!OCRxx) { - TIMSKx |= _BV(OCIExA); - TIMSKx |= _BV(TOIEx); - } -#else - // Turn on PWM control of backlight pin - enable_pwm(); -#endif - } - // Set the brightness - set_pwm(cie_lightness(rescale_limit_val(ICRx * (uint32_t)level / BACKLIGHT_LEVELS))); -} - -void backlight_task(void) {} - -#ifdef BACKLIGHT_BREATHING - -# define BREATHING_NO_HALT 0 -# define BREATHING_HALT_OFF 1 -# define BREATHING_HALT_ON 2 -# define BREATHING_STEPS 128 - -static uint8_t breathing_halt = BREATHING_NO_HALT; -static uint16_t breathing_counter = 0; - -static uint8_t breath_scale_counter = 1; -/* Run the breathing loop at ~120Hz*/ -const uint8_t breathing_ISR_frequency = 120; -static uint16_t breathing_freq_scale_factor = 2; - -# ifdef BACKLIGHT_PWM_TIMER -static bool breathing = false; - -bool is_breathing(void) { - return breathing; -} - -# define breathing_interrupt_enable() \ - do { \ - breathing = true; \ - } while (0) -# define breathing_interrupt_disable() \ - do { \ - breathing = false; \ - } while (0) -# else - -bool is_breathing(void) { - return !!(TIMSKx & _BV(TOIEx)); -} - -# define breathing_interrupt_enable() \ - do { \ - TIMSKx |= _BV(TOIEx); \ - } while (0) -# define breathing_interrupt_disable() \ - do { \ - TIMSKx &= ~_BV(TOIEx); \ - } while (0) -# endif - -# define breathing_min() \ - do { \ - breathing_counter = 0; \ - } while (0) -# define breathing_max() \ - do { \ - breathing_counter = get_breathing_period() * breathing_ISR_frequency / 2; \ - } while (0) - -void breathing_enable(void) { - breathing_counter = 0; - breathing_halt = BREATHING_NO_HALT; - breathing_interrupt_enable(); -} - -void breathing_pulse(void) { - if (get_backlight_level() == 0) - breathing_min(); - else - breathing_max(); - breathing_halt = BREATHING_HALT_ON; - breathing_interrupt_enable(); -} - -void breathing_disable(void) { - breathing_interrupt_disable(); - // Restore backlight level - backlight_set(get_backlight_level()); -} - -void breathing_self_disable(void) { - if (get_backlight_level() == 0) - breathing_halt = BREATHING_HALT_OFF; - else - breathing_halt = BREATHING_HALT_ON; -} - -/* To generate breathing curve in python: - * from math import sin, pi; [int(sin(x/128.0*pi)**4*255) for x in range(128)] - */ -static const uint8_t breathing_table[BREATHING_STEPS] PROGMEM = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 17, 20, 24, 28, 32, 36, 41, 46, 51, 57, 63, 70, 76, 83, 91, 98, 106, 113, 121, 129, 138, 146, 154, 162, 170, 178, 185, 193, 200, 207, 213, 220, 225, 231, 235, 240, 244, 247, 250, 252, 253, 254, 255, 254, 253, 252, 250, 247, 244, 240, 235, 231, 225, 220, 213, 207, 200, 193, 185, 178, 170, 162, 154, 146, 138, 129, 121, 113, 106, 98, 91, 83, 76, 70, 63, 57, 51, 46, 41, 36, 32, 28, 24, 20, 17, 15, 12, 10, 8, 6, 5, 4, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - -// Use this before the cie_lightness function. -static inline uint16_t scale_backlight(uint16_t v) { - return v / BACKLIGHT_LEVELS * get_backlight_level(); -} - -# ifdef BACKLIGHT_PWM_TIMER -void breathing_task(void) -# else -/* Assuming a 16MHz CPU clock and a timer that resets at 64k (ICR1), the following interrupt handler will run - * about 244 times per second. - * - * The following ISR runs at F_CPU/ISRx. With a 16MHz clock and default pwm resolution, that means 244Hz - */ -ISR(TIMERx_OVF_vect) -# endif -{ - - // Only run this ISR at ~120 Hz - if (breath_scale_counter++ == breathing_freq_scale_factor) { - breath_scale_counter = 1; - } else { - return; - } - uint16_t interval = (uint16_t)get_breathing_period() * breathing_ISR_frequency / BREATHING_STEPS; - // resetting after one period to prevent ugly reset at overflow. - breathing_counter = (breathing_counter + 1) % (get_breathing_period() * breathing_ISR_frequency); - uint8_t index = breathing_counter / interval; - // limit index to max step value - if (index >= BREATHING_STEPS) { - index = BREATHING_STEPS - 1; - } - - if (((breathing_halt == BREATHING_HALT_ON) && (index == BREATHING_STEPS / 2)) || ((breathing_halt == BREATHING_HALT_OFF) && (index == BREATHING_STEPS - 1))) { - breathing_interrupt_disable(); - } - - // Set PWM to a brightnessvalue scaled to the configured resolution - set_pwm(cie_lightness(rescale_limit_val(scale_backlight((uint32_t)pgm_read_byte(&breathing_table[index]) * ICRx / 255)))); -} - -#endif // BACKLIGHT_BREATHING - -void backlight_init_ports(void) { - // Setup backlight pin as output and output to on state. - backlight_pins_init(); - - // I could write a wall of text here to explain... but TL;DW - // Go read the ATmega32u4 datasheet. - // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on - -#ifdef BACKLIGHT_PWM_TIMER - // TimerX setup, Fast PWM mode count to TOP set in ICRx - TCCRxA = _BV(WGM11); // = 0b00000010; - // clock select clk/1 - TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001; -#else // hardware PWM - // Pin PB7 = OCR1C (Timer 1, Channel C) - // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0 - // (i.e. start high, go low when counter matches.) - // WGM Mode 14 (Fast PWM) = WGM13=1 WGM12=1 WGM11=1 WGM10=0 - // Clock Select = clk/1 (no prescaling) = CS12=0 CS11=0 CS10=1 - - /* - 14.8.3: - "In fast PWM mode, the compare units allow generation of PWM waveforms on the OCnx pins. Setting the COMnx1:0 bits to two will produce a non-inverted PWM [..]." - "In fast PWM mode the counter is incremented until the counter value matches either one of the fixed values 0x00FF, 0x01FF, or 0x03FF (WGMn3:0 = 5, 6, or 7), the value in ICRn (WGMn3:0 = 14), or the value in OCRnA (WGMn3:0 = 15)." - */ - TCCRxA = _BV(COMxx1) | _BV(WGM11); // = 0b00001010; - TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001; -#endif - -#ifdef BACKLIGHT_CUSTOM_RESOLUTION -# if (BACKLIGHT_CUSTOM_RESOLUTION > 0xFFFF || BACKLIGHT_CUSTOM_RESOLUTION < 1) -# error "This out of range of the timer capabilities" -# elif (BACKLIGHT_CUSTOM_RESOLUTION < 0xFF) -# warning "Resolution lower than 0xFF isn't recommended" -# endif -# ifdef BACKLIGHT_BREATHING - breathing_freq_scale_factor = F_CPU / BACKLIGHT_CUSTOM_RESOLUTION / 120; -# endif - ICRx = BACKLIGHT_CUSTOM_RESOLUTION; -#else - ICRx = TIMER_TOP; -#endif - - backlight_init(); -#ifdef BACKLIGHT_BREATHING - if (is_backlight_breathing()) { - breathing_enable(); - } -#endif -} diff --git a/quantum/backlight/backlight_chibios.c b/quantum/backlight/backlight_chibios.c deleted file mode 100644 index 30e95bd5c8..0000000000 --- a/quantum/backlight/backlight_chibios.c +++ /dev/null @@ -1,173 +0,0 @@ -#include "quantum.h" -#include "backlight.h" -#include -#include "debug.h" - -// Maximum duty cycle limit -#ifndef BACKLIGHT_LIMIT_VAL -# define BACKLIGHT_LIMIT_VAL 255 -#endif - -#ifndef BACKLIGHT_PAL_MODE -# if defined(USE_GPIOV1) -# define BACKLIGHT_PAL_MODE PAL_MODE_ALTERNATE_PUSHPULL -# else -// GPIOV2 && GPIOV3 -# define BACKLIGHT_PAL_MODE 5 -# endif -#endif - -// GENERIC -#ifndef BACKLIGHT_PWM_DRIVER -# define BACKLIGHT_PWM_DRIVER PWMD4 -#endif -#ifndef BACKLIGHT_PWM_CHANNEL -# define BACKLIGHT_PWM_CHANNEL 3 -#endif - -// Support for pins which are on TIM1_CH1N - requires STM32_PWM_USE_ADVANCED -#ifdef BACKLIGHT_PWM_COMPLEMENTARY_OUTPUT -# if BACKLIGHT_ON_STATE == 1 -# define PWM_OUTPUT_MODE PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW; -# else -# define PWM_OUTPUT_MODE PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH; -# endif -#else -# if BACKLIGHT_ON_STATE == 1 -# define PWM_OUTPUT_MODE PWM_OUTPUT_ACTIVE_HIGH; -# else -# define PWM_OUTPUT_MODE PWM_OUTPUT_ACTIVE_LOW; -# endif -#endif - -#ifndef BACKLIGHT_PWM_COUNTER_FREQUENCY -# define BACKLIGHT_PWM_COUNTER_FREQUENCY 0xFFFF -#endif - -#ifndef BACKLIGHT_PWM_PERIOD -# define BACKLIGHT_PWM_PERIOD 256 -#endif - -static PWMConfig pwmCFG = { - .frequency = BACKLIGHT_PWM_COUNTER_FREQUENCY, /* PWM clock frequency */ - .period = BACKLIGHT_PWM_PERIOD, /* PWM period in counter ticks. e.g. clock frequency is 10KHz, period is 256 ticks then t_period is 25.6ms */ -}; - -#ifdef BACKLIGHT_BREATHING -static virtual_timer_t breathing_vt; -#endif - -// 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 uint32_t rescale_limit_val(uint32_t val) { - // rescale the supplied backlight value to be in terms of the value limit - return (val * (BACKLIGHT_LIMIT_VAL + 1)) / 256; -} - -void backlight_init_ports(void) { -#ifdef USE_GPIOV1 - palSetPadMode(PAL_PORT(BACKLIGHT_PIN), PAL_PAD(BACKLIGHT_PIN), BACKLIGHT_PAL_MODE); -#else - palSetPadMode(PAL_PORT(BACKLIGHT_PIN), PAL_PAD(BACKLIGHT_PIN), PAL_MODE_ALTERNATE(BACKLIGHT_PAL_MODE)); -#endif - - pwmCFG.channels[BACKLIGHT_PWM_CHANNEL - 1].mode = PWM_OUTPUT_MODE; - pwmStart(&BACKLIGHT_PWM_DRIVER, &pwmCFG); - - backlight_set(get_backlight_level()); - -#ifdef BACKLIGHT_BREATHING - chVTObjectInit(&breathing_vt); - if (is_backlight_breathing()) { - breathing_enable(); - } -#endif -} - -void backlight_set(uint8_t level) { - if (level > BACKLIGHT_LEVELS) { - level = BACKLIGHT_LEVELS; - } - - if (level == 0) { - // Turn backlight off - pwmDisableChannel(&BACKLIGHT_PWM_DRIVER, BACKLIGHT_PWM_CHANNEL - 1); - } else { - // Turn backlight on - uint32_t duty = (uint32_t)(cie_lightness(rescale_limit_val(0xFFFF * (uint32_t)level / BACKLIGHT_LEVELS))); - pwmEnableChannel(&BACKLIGHT_PWM_DRIVER, BACKLIGHT_PWM_CHANNEL - 1, PWM_FRACTION_TO_WIDTH(&BACKLIGHT_PWM_DRIVER, 0xFFFF, duty)); - } -} - -void backlight_task(void) {} - -#ifdef BACKLIGHT_BREATHING - -# define BREATHING_STEPS 128 - -/* To generate breathing curve in python: - * from math import sin, pi; [int(sin(x/128.0*pi)**4*255) for x in range(128)] - */ -static const uint8_t breathing_table[BREATHING_STEPS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 17, 20, 24, 28, 32, 36, 41, 46, 51, 57, 63, 70, 76, 83, 91, 98, 106, 113, 121, 129, 138, 146, 154, 162, 170, 178, 185, 193, 200, 207, 213, 220, 225, 231, 235, 240, 244, 247, 250, 252, 253, 254, 255, 254, 253, 252, 250, 247, 244, 240, 235, 231, 225, 220, 213, 207, 200, 193, 185, 178, 170, 162, 154, 146, 138, 129, 121, 113, 106, 98, 91, 83, 76, 70, 63, 57, 51, 46, 41, 36, 32, 28, 24, 20, 17, 15, 12, 10, 8, 6, 5, 4, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - -static void breathing_callback(virtual_timer_t *vtp, void *p); - -bool is_breathing(void) { - return chVTIsArmed(&breathing_vt); -} - -void breathing_enable(void) { - /* Update frequency is 256Hz -> 3906us intervals */ - chVTSetContinuous(&breathing_vt, TIME_US2I(3906), breathing_callback, NULL); -} - -void breathing_disable(void) { - chVTReset(&breathing_vt); - - // Restore backlight level - backlight_set(get_backlight_level()); -} - -// Use this before the cie_lightness function. -static inline uint16_t scale_backlight(uint16_t v) { - return v / BACKLIGHT_LEVELS * get_backlight_level(); -} - -static void breathing_callback(virtual_timer_t *vtp, void *p) { - uint8_t breathing_period = get_breathing_period(); - uint16_t interval = (uint16_t)breathing_period * 256 / BREATHING_STEPS; - - // resetting after one period to prevent ugly reset at overflow. - static uint16_t breathing_counter = 0; - breathing_counter = (breathing_counter + 1) % (breathing_period * 256); - uint8_t index = breathing_counter / interval % BREATHING_STEPS; - uint32_t duty = cie_lightness(rescale_limit_val(scale_backlight(breathing_table[index] * 256))); - - chSysLockFromISR(); - pwmEnableChannelI(&BACKLIGHT_PWM_DRIVER, BACKLIGHT_PWM_CHANNEL - 1, PWM_FRACTION_TO_WIDTH(&BACKLIGHT_PWM_DRIVER, 0xFFFF, duty)); - chSysUnlockFromISR(); -} - -// TODO: integrate generic pulse solution -void breathing_pulse(void) { - backlight_set(is_backlight_enabled() ? 0 : BACKLIGHT_LEVELS); - wait_ms(10); - backlight_set(is_backlight_enabled() ? get_backlight_level() : 0); -} - -#endif diff --git a/quantum/backlight/backlight_driver_common.c b/quantum/backlight/backlight_driver_common.c index 1eb8969084..8c3fe461d7 100644 --- a/quantum/backlight/backlight_driver_common.c +++ b/quantum/backlight/backlight_driver_common.c @@ -1,6 +1,7 @@ -#include "quantum.h" #include "backlight.h" #include "backlight_driver_common.h" +#include "gpio.h" +#include "util.h" #if !defined(BACKLIGHT_PIN) && !defined(BACKLIGHT_PINS) # error "Backlight pin/pins not defined. Please configure." diff --git a/quantum/backlight/backlight_software.c b/quantum/backlight/backlight_software.c deleted file mode 100644 index 27ccbd2c9f..0000000000 --- a/quantum/backlight/backlight_software.c +++ /dev/null @@ -1,54 +0,0 @@ -#include "quantum.h" -#include "backlight.h" -#include "backlight_driver_common.h" - -#ifdef BACKLIGHT_BREATHING -# error "Backlight breathing is not available for software PWM. Please disable." -#endif - -static uint16_t s_duty_pattern = 0; - -// clang-format off - -/** \brief PWM duty patterns - * - * We scale the current backlight level to an index within this array. This allows - * backlight_task to focus on just switching LEDs on/off, and we can predict the duty pattern - */ -static const uint16_t backlight_duty_table[] = { - 0b0000000000000000, - 0b1000000000000000, - 0b1000000010000000, - 0b1000001000010000, - 0b1000100010001000, - 0b1001001001001000, - 0b1010101010101010, - 0b1110111011101110, - 0b1111111111111111, -}; -#define backlight_duty_table_size ARRAY_SIZE(backlight_duty_table) - -// clang-format on - -static uint8_t scale_backlight(uint8_t v) { - return v * (backlight_duty_table_size - 1) / BACKLIGHT_LEVELS; -} - -void backlight_init_ports(void) { - backlight_pins_init(); -} - -void backlight_set(uint8_t level) { - s_duty_pattern = backlight_duty_table[scale_backlight(level)]; -} - -void backlight_task(void) { - static uint8_t backlight_tick = 0; - - if (s_duty_pattern & ((uint16_t)1 << backlight_tick)) { - backlight_pins_on(); - } else { - backlight_pins_off(); - } - backlight_tick = (backlight_tick + 1) % 16; -} diff --git a/quantum/backlight/backlight_timer.c b/quantum/backlight/backlight_timer.c deleted file mode 100644 index 82fb6a6a83..0000000000 --- a/quantum/backlight/backlight_timer.c +++ /dev/null @@ -1,179 +0,0 @@ -#include "quantum.h" -#include "backlight.h" -#include "backlight_driver_common.h" -#include "debug.h" - -#ifndef BACKLIGHT_GPT_DRIVER -# define BACKLIGHT_GPT_DRIVER GPTD15 -#endif - -// Platform specific implementations -static void backlight_timer_configure(bool enable); -static void backlight_timer_set_duty(uint16_t duty); -static uint16_t backlight_timer_get_duty(void); - -// 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; - } -} - -void backlight_init_ports(void) { - backlight_pins_init(); - - backlight_set(get_backlight_level()); - -#ifdef BACKLIGHT_BREATHING - if (is_backlight_breathing()) { - breathing_enable(); - } -#endif -} - -void backlight_set(uint8_t level) { - if (level > BACKLIGHT_LEVELS) level = BACKLIGHT_LEVELS; - - backlight_pins_off(); - - backlight_timer_set_duty(cie_lightness(0xFFFFU / BACKLIGHT_LEVELS * level)); - backlight_timer_configure(level != 0); -} - -static void backlight_timer_top(void) { -#ifdef BACKLIGHT_BREATHING - if (is_breathing()) { - breathing_task(); - } -#endif - - if (backlight_timer_get_duty() > 256) { - backlight_pins_on(); - } -} - -static void backlight_timer_cmp(void) { - backlight_pins_off(); -} - -void backlight_task(void) {} - -#ifdef BACKLIGHT_BREATHING -# define BREATHING_STEPS 128 - -static bool breathing = false; -static uint16_t breathing_counter = 0; - -/* To generate breathing curve in python: - * from math import sin, pi; [int(sin(x/128.0*pi)**4*255) for x in range(128)] - */ -static const uint8_t breathing_table[BREATHING_STEPS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 17, 20, 24, 28, 32, 36, 41, 46, 51, 57, 63, 70, 76, 83, 91, 98, 106, 113, 121, 129, 138, 146, 154, 162, 170, 178, 185, 193, 200, 207, 213, 220, 225, 231, 235, 240, 244, 247, 250, 252, 253, 254, 255, 254, 253, 252, 250, 247, 244, 240, 235, 231, 225, 220, 213, 207, 200, 193, 185, 178, 170, 162, 154, 146, 138, 129, 121, 113, 106, 98, 91, 83, 76, 70, 63, 57, 51, 46, 41, 36, 32, 28, 24, 20, 17, 15, 12, 10, 8, 6, 5, 4, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - -// Use this before the cie_lightness function. -static inline uint16_t scale_backlight(uint16_t v) { - return v / BACKLIGHT_LEVELS * get_backlight_level(); -} - -void breathing_task(void) { - uint8_t breathing_period = get_breathing_period(); - uint16_t interval = (uint16_t)breathing_period * 256 / BREATHING_STEPS; - // resetting after one period to prevent ugly reset at overflow. - breathing_counter = (breathing_counter + 1) % (breathing_period * 256); - uint8_t index = breathing_counter / interval % BREATHING_STEPS; - - // printf("index:%u\n", index); - - backlight_timer_set_duty(cie_lightness(scale_backlight((uint16_t)breathing_table[index] * 256))); -} - -bool is_breathing(void) { - return breathing; -} - -void breathing_enable(void) { - breathing_counter = 0; - breathing = true; -} -void breathing_disable(void) { - breathing = false; -} - -void breathing_pulse(void) { - backlight_set(is_backlight_enabled() ? 0 : BACKLIGHT_LEVELS); - wait_ms(10); - backlight_set(is_backlight_enabled() ? get_backlight_level() : 0); -} -#endif - -#ifdef PROTOCOL_CHIBIOS -// On Platforms where timers fire every tick and have no capture/top events -// - fake event in the normal timer callback -uint16_t s_duty = 0; - -static void timerCallback(void) { - /* Software PWM - * timer:1111 1111 1111 1111 - * \______/| \_______/____ count(0-255) - * \ \______________ unused(1) - * \__________________ index of step table(0-127) - */ - - // this works for cca 65536 irqs/sec - static union { - uint16_t raw; - struct { - uint16_t count : 8; - uint8_t dummy : 1; - uint8_t index : 7; - } pwm; - } timer = {.raw = 0}; - - timer.raw++; - - if (timer.pwm.count == 0) { - // LED on - backlight_timer_top(); - } else if (timer.pwm.count == (s_duty / 256)) { - // LED off - backlight_timer_cmp(); - } -} - -static void backlight_timer_set_duty(uint16_t duty) { - s_duty = duty; -} -static uint16_t backlight_timer_get_duty(void) { - return s_duty; -} - -// ChibiOS - Map GPT timer onto Software PWM -static void gptTimerCallback(GPTDriver *gptp) { - (void)gptp; - timerCallback(); -} - -static void backlight_timer_configure(bool enable) { - static const GPTConfig gptcfg = {1000000, gptTimerCallback, 0, 0}; - - static bool s_init = false; - if (!s_init) { - gptStart(&BACKLIGHT_GPT_DRIVER, &gptcfg); - s_init = true; - } - - if (enable) { - gptStartContinuous(&BACKLIGHT_GPT_DRIVER, gptcfg.frequency / 0xFFFF); - } else { - gptStopTimer(&BACKLIGHT_GPT_DRIVER); - } -} -#endif -- cgit v1.2.3 From b9e5895184c6d36b46ba723d6d71e27249e70c20 Mon Sep 17 00:00:00 2001 From: Ryan Date: Sat, 15 Jul 2023 17:27:32 +1000 Subject: Eliminate `TMK_COMMON_*` in makefiles (#21517) --- builddefs/build_full_test.mk | 3 +- builddefs/build_keyboard.mk | 3 -- .../capsunlocked/cu75/keymaps/default/rules.mk | 26 -------------- keyboards/capsunlocked/cu75/keymaps/iso/rules.mk | 26 -------------- keyboards/capsunlocked/cu75/post_rules.mk | 23 +++++++++++++ keyboards/lfkeyboards/lfk78/post_rules.mk | 6 ++-- keyboards/lfkeyboards/lfkpad/post_rules.mk | 4 +-- keyboards/lfkeyboards/mini1800/reva/post_rules.mk | 4 +-- keyboards/lfkeyboards/mini1800/revc/post_rules.mk | 4 +-- .../lfkeyboards/smk65/keymaps/default/rules.mk | 9 ----- keyboards/lfkeyboards/smk65/keymaps/iso/rules.mk | 9 ----- keyboards/lfkeyboards/smk65/post_rules.mk | 7 ++++ keyboards/woodkeys/meira/post_rules.mk | 9 +++++ keyboards/woodkeys/meira/rules.mk | 9 ----- platforms/avr/printf.mk | 4 +-- platforms/common.mk | 2 +- tmk_core/protocol.mk | 40 +++++++++++----------- 17 files changed, 72 insertions(+), 116 deletions(-) create mode 100644 keyboards/capsunlocked/cu75/post_rules.mk create mode 100644 keyboards/lfkeyboards/smk65/post_rules.mk create mode 100644 keyboards/woodkeys/meira/post_rules.mk (limited to 'platforms/avr') diff --git a/builddefs/build_full_test.mk b/builddefs/build_full_test.mk index 964ba773d4..85ee0898ec 100644 --- a/builddefs/build_full_test.mk +++ b/builddefs/build_full_test.mk @@ -17,7 +17,6 @@ $(TEST)_INC := \ tests/test_common/common_config.h $(TEST)_SRC := \ - $(TMK_COMMON_SRC) \ $(QUANTUM_SRC) \ $(SRC) \ $(QUANTUM_PATH)/keymap_introspection.c \ @@ -31,7 +30,7 @@ $(TEST)_SRC := \ tests/test_common/test_logger.cpp \ $(patsubst $(ROOTDIR)/%,%,$(wildcard $(TEST_PATH)/*.cpp)) -$(TEST)_DEFS := $(TMK_COMMON_DEFS) $(OPT_DEFS) "-DKEYMAP_C=\"keymap.c\"" +$(TEST)_DEFS := $(OPT_DEFS) "-DKEYMAP_C=\"keymap.c\"" $(TEST)_CONFIG := $(TEST_PATH)/config.h diff --git a/builddefs/build_keyboard.mk b/builddefs/build_keyboard.mk index 72c990abbb..e93ab97cc1 100644 --- a/builddefs/build_keyboard.mk +++ b/builddefs/build_keyboard.mk @@ -431,9 +431,6 @@ include $(PLATFORM_PATH)/common.mk SRC += $(patsubst %.c,%.clib,$(LIB_SRC)) SRC += $(patsubst %.c,%.clib,$(QUANTUM_LIB_SRC)) -SRC += $(TMK_COMMON_SRC) -OPT_DEFS += $(TMK_COMMON_DEFS) -EXTRALDFLAGS += $(TMK_COMMON_LDFLAGS) -include $(PLATFORM_PATH)/$(PLATFORM_KEY)/bootloader.mk include $(PLATFORM_PATH)/$(PLATFORM_KEY)/platform.mk diff --git a/keyboards/capsunlocked/cu75/keymaps/default/rules.mk b/keyboards/capsunlocked/cu75/keymaps/default/rules.mk index bbd4c8c9fd..aefb10a8b1 100644 --- a/keyboards/capsunlocked/cu75/keymaps/default/rules.mk +++ b/keyboards/capsunlocked/cu75/keymaps/default/rules.mk @@ -12,29 +12,3 @@ SLEEP_LED_ENABLE = yes ISSI_ENABLE = yes # If the I2C pullup resistors aren't install this must be disabled WATCHDOG_ENABLE = no # Resets keyboard if matrix_scan isn't run every 250ms - - -ifeq ($(strip $(ISSI_ENABLE)), yes) - TMK_COMMON_DEFS += -DISSI_ENABLE -endif - -ifeq ($(strip $(WATCHDOG_ENABLE)), yes) - TMK_COMMON_DEFS += -DWATCHDOG_ENABLE -endif - - -# # Set the LFK78 hardware version. This is defined in rules.mk, but can be overidden here if desired -# # -# # RevB - first public release, uses atmega32u4, has audio, ISSI matrix split between RGB and backlight -# # RevC/D - at90usb1286, no audio, ISSI device 0 is backlight, 4 is RGB -# # -# # Set to B, C or D -# LFK_REV = D - -# ifeq ($(LFK_REV), B) -# MCU = atmega32u4 -# else -# MCU = at90usb1286 -# endif -# OPT_DEFS += -DLFK_REV_$(LFK_REV) -# OPT_DEFS += -DUSB_PRODUCT=\"LFK_Rev$(LFK_REV)\" diff --git a/keyboards/capsunlocked/cu75/keymaps/iso/rules.mk b/keyboards/capsunlocked/cu75/keymaps/iso/rules.mk index be27fed69c..26239f265e 100644 --- a/keyboards/capsunlocked/cu75/keymaps/iso/rules.mk +++ b/keyboards/capsunlocked/cu75/keymaps/iso/rules.mk @@ -12,29 +12,3 @@ SLEEP_LED_ENABLE = yes ISSI_ENABLE = no # If the I2C pullup resistors aren't install this must be disabled WATCHDOG_ENABLE = yes # Resets keyboard if matrix_scan isn't run every 250ms - - -ifeq ($(strip $(ISSI_ENABLE)), yes) - TMK_COMMON_DEFS += -DISSI_ENABLE -endif - -ifeq ($(strip $(WATCHDOG_ENABLE)), yes) - TMK_COMMON_DEFS += -DWATCHDOG_ENABLE -endif - - -# # Set the LFK78 hardware version. This is defined in rules.mk, but can be overidden here if desired -# # -# # RevB - first public release, uses atmega32u4, has audio, ISSI matrix split between RGB and backlight -# # RevC/D - at90usb1286, no audio, ISSI device 0 is backlight, 4 is RGB -# # -# # Set to B, C or D -# LFK_REV = D - -# ifeq ($(LFK_REV), B) -# MCU = atmega32u4 -# else -# MCU = at90usb1286 -# endif -# OPT_DEFS += -DLFK_REV_$(LFK_REV) -# OPT_DEFS += -DUSB_PRODUCT=\"LFK_Rev$(LFK_REV)\" diff --git a/keyboards/capsunlocked/cu75/post_rules.mk b/keyboards/capsunlocked/cu75/post_rules.mk new file mode 100644 index 0000000000..a5d9746664 --- /dev/null +++ b/keyboards/capsunlocked/cu75/post_rules.mk @@ -0,0 +1,23 @@ +ifeq ($(strip $(ISSI_ENABLE)), yes) + OPT_DEFS += -DISSI_ENABLE +endif + +ifeq ($(strip $(WATCHDOG_ENABLE)), yes) + OPT_DEFS += -DWATCHDOG_ENABLE +endif + +# # Set the LFK78 hardware version. This is defined in rules.mk, but can be overidden here if desired +# # +# # RevB - first public release, uses atmega32u4, has audio, ISSI matrix split between RGB and backlight +# # RevC/D - at90usb1286, no audio, ISSI device 0 is backlight, 4 is RGB +# # +# # Set to B, C or D +# LFK_REV = D + +# ifeq ($(LFK_REV), B) +# MCU = atmega32u4 +# else +# MCU = at90usb1286 +# endif +# OPT_DEFS += -DLFK_REV_$(LFK_REV) +# OPT_DEFS += -DUSB_PRODUCT=\"LFK_Rev$(LFK_REV)\" diff --git a/keyboards/lfkeyboards/lfk78/post_rules.mk b/keyboards/lfkeyboards/lfk78/post_rules.mk index 03f975b9df..817a085f5e 100644 --- a/keyboards/lfkeyboards/lfk78/post_rules.mk +++ b/keyboards/lfkeyboards/lfk78/post_rules.mk @@ -2,13 +2,13 @@ SRC += TWIlib.c issi.c lighting.c ifeq ($(strip $(ISSI_ENABLE)), yes) - TMK_COMMON_DEFS += -DISSI_ENABLE + OPT_DEFS += -DISSI_ENABLE endif ifeq ($(strip $(WATCHDOG_ENABLE)), yes) - TMK_COMMON_DEFS += -DWATCHDOG_ENABLE + OPT_DEFS += -DWATCHDOG_ENABLE endif ifeq ($(strip $(CAPSLOCK_LED)), yes) - TMK_COMMON_DEFS += -DCAPSLOCK_LED + OPT_DEFS += -DCAPSLOCK_LED endif diff --git a/keyboards/lfkeyboards/lfkpad/post_rules.mk b/keyboards/lfkeyboards/lfkpad/post_rules.mk index ad997587b2..044d9754f1 100644 --- a/keyboards/lfkeyboards/lfkpad/post_rules.mk +++ b/keyboards/lfkeyboards/lfkpad/post_rules.mk @@ -1,7 +1,7 @@ ifeq ($(strip $(ISSI_ENABLE)), yes) - TMK_COMMON_DEFS += -DISSI_ENABLE + OPT_DEFS += -DISSI_ENABLE endif ifeq ($(strip $(WATCHDOG_ENABLE)), yes) - TMK_COMMON_DEFS += -DWATCHDOG_ENABLE + OPT_DEFS += -DWATCHDOG_ENABLE endif diff --git a/keyboards/lfkeyboards/mini1800/reva/post_rules.mk b/keyboards/lfkeyboards/mini1800/reva/post_rules.mk index ad997587b2..044d9754f1 100644 --- a/keyboards/lfkeyboards/mini1800/reva/post_rules.mk +++ b/keyboards/lfkeyboards/mini1800/reva/post_rules.mk @@ -1,7 +1,7 @@ ifeq ($(strip $(ISSI_ENABLE)), yes) - TMK_COMMON_DEFS += -DISSI_ENABLE + OPT_DEFS += -DISSI_ENABLE endif ifeq ($(strip $(WATCHDOG_ENABLE)), yes) - TMK_COMMON_DEFS += -DWATCHDOG_ENABLE + OPT_DEFS += -DWATCHDOG_ENABLE endif diff --git a/keyboards/lfkeyboards/mini1800/revc/post_rules.mk b/keyboards/lfkeyboards/mini1800/revc/post_rules.mk index ad997587b2..044d9754f1 100644 --- a/keyboards/lfkeyboards/mini1800/revc/post_rules.mk +++ b/keyboards/lfkeyboards/mini1800/revc/post_rules.mk @@ -1,7 +1,7 @@ ifeq ($(strip $(ISSI_ENABLE)), yes) - TMK_COMMON_DEFS += -DISSI_ENABLE + OPT_DEFS += -DISSI_ENABLE endif ifeq ($(strip $(WATCHDOG_ENABLE)), yes) - TMK_COMMON_DEFS += -DWATCHDOG_ENABLE + OPT_DEFS += -DWATCHDOG_ENABLE endif diff --git a/keyboards/lfkeyboards/smk65/keymaps/default/rules.mk b/keyboards/lfkeyboards/smk65/keymaps/default/rules.mk index 0cc9a7b76b..1f0147bd38 100644 --- a/keyboards/lfkeyboards/smk65/keymaps/default/rules.mk +++ b/keyboards/lfkeyboards/smk65/keymaps/default/rules.mk @@ -6,12 +6,3 @@ RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow ISSI_ENABLE = no # If the I2C pullup resistors aren't install this must be disabled WATCHDOG_ENABLE = no # Resets keyboard if matrix_scan isn't run every 250ms - - -ifeq ($(strip $(ISSI_ENABLE)), yes) - TMK_COMMON_DEFS += -DISSI_ENABLE -endif - -ifeq ($(strip $(WATCHDOG_ENABLE)), yes) - TMK_COMMON_DEFS += -DWATCHDOG_ENABLE -endif diff --git a/keyboards/lfkeyboards/smk65/keymaps/iso/rules.mk b/keyboards/lfkeyboards/smk65/keymaps/iso/rules.mk index 0cc9a7b76b..1f0147bd38 100644 --- a/keyboards/lfkeyboards/smk65/keymaps/iso/rules.mk +++ b/keyboards/lfkeyboards/smk65/keymaps/iso/rules.mk @@ -6,12 +6,3 @@ RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow ISSI_ENABLE = no # If the I2C pullup resistors aren't install this must be disabled WATCHDOG_ENABLE = no # Resets keyboard if matrix_scan isn't run every 250ms - - -ifeq ($(strip $(ISSI_ENABLE)), yes) - TMK_COMMON_DEFS += -DISSI_ENABLE -endif - -ifeq ($(strip $(WATCHDOG_ENABLE)), yes) - TMK_COMMON_DEFS += -DWATCHDOG_ENABLE -endif diff --git a/keyboards/lfkeyboards/smk65/post_rules.mk b/keyboards/lfkeyboards/smk65/post_rules.mk new file mode 100644 index 0000000000..044d9754f1 --- /dev/null +++ b/keyboards/lfkeyboards/smk65/post_rules.mk @@ -0,0 +1,7 @@ +ifeq ($(strip $(ISSI_ENABLE)), yes) + OPT_DEFS += -DISSI_ENABLE +endif + +ifeq ($(strip $(WATCHDOG_ENABLE)), yes) + OPT_DEFS += -DWATCHDOG_ENABLE +endif diff --git a/keyboards/woodkeys/meira/post_rules.mk b/keyboards/woodkeys/meira/post_rules.mk new file mode 100644 index 0000000000..5d85581c6e --- /dev/null +++ b/keyboards/woodkeys/meira/post_rules.mk @@ -0,0 +1,9 @@ +SRC += matrix.c TWIlib.c issi.c lighting.c + +#ifeq ($(strip $(ISSI_ENABLE)), yes) +# OPT_DEFS += -DISSI_ENABLE +#endif + +#ifeq ($(strip $(WATCHDOG_ENABLE)), yes) +# OPT_DEFS += -DWATCHDOG_ENABLE +#endif diff --git a/keyboards/woodkeys/meira/rules.mk b/keyboards/woodkeys/meira/rules.mk index 20802b3179..63586244c0 100644 --- a/keyboards/woodkeys/meira/rules.mk +++ b/keyboards/woodkeys/meira/rules.mk @@ -14,13 +14,4 @@ AUDIO_ENABLE = no # Audio output CUSTOM_MATRIX = yes -#ifeq ($(strip $(ISSI_ENABLE)), yes) -# TMK_COMMON_DEFS += -DISSI_ENABLE -#endif - -#ifeq ($(strip $(WATCHDOG_ENABLE)), yes) -# TMK_COMMON_DEFS += -DWATCHDOG_ENABLE -#endif -SRC += matrix.c TWIlib.c issi.c lighting.c - DEFAULT_FOLDER = woodkeys/meira/promicro diff --git a/platforms/avr/printf.mk b/platforms/avr/printf.mk index 060ad88c57..c6490169d8 100644 --- a/platforms/avr/printf.mk +++ b/platforms/avr/printf.mk @@ -1,2 +1,2 @@ -TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/xprintf.S -TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/printf.c +SRC += $(PLATFORM_COMMON_DIR)/xprintf.S +SRC += $(PLATFORM_COMMON_DIR)/printf.c diff --git a/platforms/common.mk b/platforms/common.mk index da0697e3b0..bbbe71ea12 100644 --- a/platforms/common.mk +++ b/platforms/common.mk @@ -1,6 +1,6 @@ PLATFORM_COMMON_DIR = $(PLATFORM_PATH)/$(PLATFORM_KEY) -TMK_COMMON_SRC += \ +SRC += \ $(PLATFORM_PATH)/suspend.c \ $(PLATFORM_PATH)/synchronization_util.c \ $(PLATFORM_PATH)/timer.c \ diff --git a/tmk_core/protocol.mk b/tmk_core/protocol.mk index 2ae7aa9abe..d159dacc55 100644 --- a/tmk_core/protocol.mk +++ b/tmk_core/protocol.mk @@ -1,4 +1,4 @@ -TMK_COMMON_SRC += \ +SRC += \ $(PROTOCOL_DIR)/host.c \ $(PROTOCOL_DIR)/report.c \ $(PROTOCOL_DIR)/usb_device_state.c \ @@ -7,7 +7,7 @@ TMK_COMMON_SRC += \ SHARED_EP_ENABLE = no MOUSE_SHARED_EP ?= yes ifeq ($(strip $(KEYBOARD_SHARED_EP)), yes) - TMK_COMMON_DEFS += -DKEYBOARD_SHARED_EP + OPT_DEFS += -DKEYBOARD_SHARED_EP SHARED_EP_ENABLE = yes # With the current usb_descriptor.c code, # you can't share kbd without sharing mouse; @@ -18,31 +18,31 @@ endif ifeq ($(strip $(MOUSE_ENABLE)), yes) OPT_DEFS += -DMOUSE_ENABLE ifeq ($(strip $(MOUSE_SHARED_EP)), yes) - TMK_COMMON_DEFS += -DMOUSE_SHARED_EP + OPT_DEFS += -DMOUSE_SHARED_EP SHARED_EP_ENABLE = yes endif endif ifeq ($(strip $(EXTRAKEY_ENABLE)), yes) - TMK_COMMON_DEFS += -DEXTRAKEY_ENABLE + OPT_DEFS += -DEXTRAKEY_ENABLE SHARED_EP_ENABLE = yes endif ifeq ($(strip $(PROGRAMMABLE_BUTTON_ENABLE)), yes) - TMK_COMMON_DEFS += -DPROGRAMMABLE_BUTTON_ENABLE + OPT_DEFS += -DPROGRAMMABLE_BUTTON_ENABLE SHARED_EP_ENABLE = yes endif ifeq ($(strip $(RAW_ENABLE)), yes) - TMK_COMMON_DEFS += -DRAW_ENABLE + OPT_DEFS += -DRAW_ENABLE endif ifeq ($(strip $(CONSOLE_ENABLE)), yes) - TMK_COMMON_DEFS += -DCONSOLE_ENABLE + OPT_DEFS += -DCONSOLE_ENABLE else # TODO: decouple this so other print backends can exist - TMK_COMMON_DEFS += -DNO_PRINT - TMK_COMMON_DEFS += -DNO_DEBUG + OPT_DEFS += -DNO_PRINT + OPT_DEFS += -DNO_DEBUG endif ifeq ($(strip $(NKRO_ENABLE)), yes) @@ -51,51 +51,51 @@ ifeq ($(strip $(NKRO_ENABLE)), yes) else ifeq ($(strip $(BLUETOOTH_ENABLE)), yes) $(info NKRO is not currently supported with Bluetooth, and has been disabled.) else - TMK_COMMON_DEFS += -DNKRO_ENABLE + OPT_DEFS += -DNKRO_ENABLE SHARED_EP_ENABLE = yes endif endif ifeq ($(strip $(RING_BUFFERED_6KRO_REPORT_ENABLE)), yes) - TMK_COMMON_DEFS += -DRING_BUFFERED_6KRO_REPORT_ENABLE + OPT_DEFS += -DRING_BUFFERED_6KRO_REPORT_ENABLE endif ifeq ($(strip $(NO_SUSPEND_POWER_DOWN)), yes) - TMK_COMMON_DEFS += -DNO_SUSPEND_POWER_DOWN + OPT_DEFS += -DNO_SUSPEND_POWER_DOWN endif ifeq ($(strip $(NO_USB_STARTUP_CHECK)), yes) - TMK_COMMON_DEFS += -DNO_USB_STARTUP_CHECK + OPT_DEFS += -DNO_USB_STARTUP_CHECK endif ifeq ($(strip $(JOYSTICK_SHARED_EP)), yes) - TMK_COMMON_DEFS += -DJOYSTICK_SHARED_EP + OPT_DEFS += -DJOYSTICK_SHARED_EP SHARED_EP_ENABLE = yes endif ifeq ($(strip $(JOYSTICK_ENABLE)), yes) - TMK_COMMON_DEFS += -DJOYSTICK_ENABLE + OPT_DEFS += -DJOYSTICK_ENABLE ifeq ($(strip $(SHARED_EP_ENABLE)), yes) - TMK_COMMON_DEFS += -DJOYSTICK_SHARED_EP + OPT_DEFS += -DJOYSTICK_SHARED_EP SHARED_EP_ENABLE = yes endif endif ifeq ($(strip $(DIGITIZER_SHARED_EP)), yes) - TMK_COMMON_DEFS += -DDIGITIZER_SHARED_EP + OPT_DEFS += -DDIGITIZER_SHARED_EP SHARED_EP_ENABLE = yes endif ifeq ($(strip $(DIGITIZER_ENABLE)), yes) - TMK_COMMON_DEFS += -DDIGITIZER_ENABLE + OPT_DEFS += -DDIGITIZER_ENABLE ifeq ($(strip $(SHARED_EP_ENABLE)), yes) - TMK_COMMON_DEFS += -DDIGITIZER_SHARED_EP + OPT_DEFS += -DDIGITIZER_SHARED_EP SHARED_EP_ENABLE = yes endif endif ifeq ($(strip $(SHARED_EP_ENABLE)), yes) - TMK_COMMON_DEFS += -DSHARED_EP_ENABLE + OPT_DEFS += -DSHARED_EP_ENABLE endif ifeq ($(strip $(USB_HID_ENABLE)), yes) -- cgit v1.2.3 From da2d2f947d5c30aebea17f414fb22ad50fe5410b Mon Sep 17 00:00:00 2001 From: Ryan Date: Sun, 16 Jul 2023 23:42:56 +1000 Subject: quantum: remove direct `quantum.h` includes (#21507) --- keyboards/boardsource/lulu/lulu.c | 2 +- keyboards/input_club/k_type/k_type-rgbdriver.c | 3 +- .../input_club/k_type/keymaps/default/keymap.c | 3 ++ keyboards/system76/launch_1/rgb_matrix_kb.inc | 1 + keyboards/system76/system76_ec.c | 6 ++++ platforms/avr/drivers/audio_pwm_hardware.c | 8 ++--- platforms/chibios/drivers/audio_dac_additive.c | 5 +-- platforms/chibios/drivers/audio_dac_basic.c | 3 +- platforms/chibios/drivers/audio_pwm_hardware.c | 3 +- platforms/chibios/drivers/audio_pwm_software.c | 3 +- quantum/audio/audio.c | 3 ++ quantum/audio/audio.h | 9 ++--- quantum/audio/muse.c | 2 ++ quantum/audio/muse.h | 3 +- quantum/audio/voices.c | 2 ++ quantum/bootmagic/bootmagic_lite.c | 7 +++- quantum/dynamic_keymap.c | 12 ++++--- quantum/encoder.c | 5 +++ quantum/encoder.h | 4 ++- quantum/encoder/tests/encoder_tests_split_role.cpp | 1 + quantum/keyboard.c | 34 +++++++++++++++++-- quantum/keyboard.h | 2 ++ quantum/keymap_common.c | 7 +++- quantum/led_matrix/led_matrix.c | 5 +++ quantum/led_matrix/led_matrix.h | 2 +- quantum/matrix.c | 3 +- quantum/matrix_common.c | 2 +- quantum/midi/qmk_midi.c | 1 + .../pointing_device/pointing_device_auto_mouse.c | 3 ++ .../pointing_device/pointing_device_auto_mouse.h | 11 +++--- quantum/process_keycode/process_audio.c | 4 +-- quantum/process_keycode/process_audio.h | 3 -- quantum/process_keycode/process_clicky.c | 4 ++- quantum/process_keycode/process_key_override.c | 4 +++ quantum/repeat_key.c | 1 + quantum/repeat_key.h | 5 ++- quantum/rgb_matrix/rgb_matrix.c | 5 +++ quantum/rgb_matrix/rgb_matrix.h | 2 +- quantum/rgb_matrix/rgb_matrix_drivers.c | 1 + quantum/split_common/split_util.c | 2 +- quantum/split_common/split_util.h | 1 - quantum/split_common/transactions.c | 39 +++++++++++++++++++++- quantum/split_common/transactions.h | 4 +-- quantum/split_common/transport.h | 4 +-- quantum/unicode/unicode.c | 2 ++ quantum/unicode/unicode.h | 3 +- quantum/via.c | 26 +++++++++++++-- quantum/via.h | 1 + tmk_core/protocol/arm_atsam/main_arm_atsam.c | 1 + tmk_core/protocol/arm_atsam/md_rgb_matrix.c | 1 + tmk_core/protocol/arm_atsam/spi_master.h | 2 ++ 51 files changed, 208 insertions(+), 62 deletions(-) (limited to 'platforms/avr') diff --git a/keyboards/boardsource/lulu/lulu.c b/keyboards/boardsource/lulu/lulu.c index be6d565a32..8d011268c4 100644 --- a/keyboards/boardsource/lulu/lulu.c +++ b/keyboards/boardsource/lulu/lulu.c @@ -1,6 +1,6 @@ // Copyright 2022 Cole Smith // SPDX-License-Identifier: GPL-2.0-or-later -#include "encoder.h" +#include "quantum.h" #ifdef ENCODER_ENABLE bool encoder_update_kb(uint8_t index, bool clockwise) { diff --git a/keyboards/input_club/k_type/k_type-rgbdriver.c b/keyboards/input_club/k_type/k_type-rgbdriver.c index e663c224c4..6529f98201 100644 --- a/keyboards/input_club/k_type/k_type-rgbdriver.c +++ b/keyboards/input_club/k_type/k_type-rgbdriver.c @@ -19,8 +19,7 @@ #include "rgb_matrix.h" #include "i2c_master.h" #include "is31fl3733-dual.h" - - +#include "gpio.h" static void init(void) { i2c_init(&I2CD1, I2C1_SCL_PIN, I2C1_SDA_PIN); diff --git a/keyboards/input_club/k_type/keymaps/default/keymap.c b/keyboards/input_club/k_type/keymaps/default/keymap.c index 790bd93290..452791b13a 100644 --- a/keyboards/input_club/k_type/keymaps/default/keymap.c +++ b/keyboards/input_club/k_type/keymaps/default/keymap.c @@ -1,3 +1,6 @@ +// Copyright 2023 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + #include QMK_KEYBOARD_H const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { diff --git a/keyboards/system76/launch_1/rgb_matrix_kb.inc b/keyboards/system76/launch_1/rgb_matrix_kb.inc index 02de10ed50..f29183dde0 100644 --- a/keyboards/system76/launch_1/rgb_matrix_kb.inc +++ b/keyboards/system76/launch_1/rgb_matrix_kb.inc @@ -22,6 +22,7 @@ RGB_MATRIX_EFFECT(unlocked) #ifdef RGB_MATRIX_CUSTOM_EFFECT_IMPLS #include "dynamic_keymap.h" +#include "action_layer.h" static bool active_keys_initialized = false; static uint8_t active_keys_table[RGB_MATRIX_LED_COUNT] = {0}; diff --git a/keyboards/system76/system76_ec.c b/keyboards/system76/system76_ec.c index 6301659072..1b7955e19b 100644 --- a/keyboards/system76/system76_ec.c +++ b/keyboards/system76/system76_ec.c @@ -22,6 +22,12 @@ #include "raw_hid.h" #include "rgb_matrix.h" #include "version.h" +#include "keyboard.h" +#include "eeprom.h" +#include "matrix.h" +#include "action_layer.h" +#include "bootloader.h" +#include "wait.h" enum Command { CMD_PROBE = 1, // Probe for System76 EC protocol diff --git a/platforms/avr/drivers/audio_pwm_hardware.c b/platforms/avr/drivers/audio_pwm_hardware.c index 2fc448ea58..6799cf2fdd 100644 --- a/platforms/avr/drivers/audio_pwm_hardware.c +++ b/platforms/avr/drivers/audio_pwm_hardware.c @@ -15,13 +15,9 @@ * along with this program. If not, see . */ -#if defined(__AVR__) -# include -# include -# include -#endif - #include "audio.h" +#include "gpio.h" +#include extern bool playing_note; extern bool playing_melody; diff --git a/platforms/chibios/drivers/audio_dac_additive.c b/platforms/chibios/drivers/audio_dac_additive.c index d29147ca3b..9a5fe4c336 100644 --- a/platforms/chibios/drivers/audio_dac_additive.c +++ b/platforms/chibios/drivers/audio_dac_additive.c @@ -16,8 +16,9 @@ */ #include "audio.h" -#include -#include +#include "gpio.h" +#include +#include "util.h" // Need to disable GCC's "tautological-compare" warning for this file, as it causes issues when running `KEEP_INTERMEDIATES=yes`. Corresponding pop at the end of the file. #pragma GCC diagnostic push diff --git a/platforms/chibios/drivers/audio_dac_basic.c b/platforms/chibios/drivers/audio_dac_basic.c index 4ea23a2158..9a3f3fea1f 100644 --- a/platforms/chibios/drivers/audio_dac_basic.c +++ b/platforms/chibios/drivers/audio_dac_basic.c @@ -16,8 +16,7 @@ */ #include "audio.h" -#include "ch.h" -#include "hal.h" +#include "gpio.h" // Need to disable GCC's "tautological-compare" warning for this file, as it causes issues when running `KEEP_INTERMEDIATES=yes`. Corresponding pop at the end of the file. #pragma GCC diagnostic push diff --git a/platforms/chibios/drivers/audio_pwm_hardware.c b/platforms/chibios/drivers/audio_pwm_hardware.c index 54dac46605..40d891326f 100644 --- a/platforms/chibios/drivers/audio_pwm_hardware.c +++ b/platforms/chibios/drivers/audio_pwm_hardware.c @@ -12,8 +12,7 @@ // function. #include "audio.h" -#include "ch.h" -#include "hal.h" +#include "gpio.h" #if !defined(AUDIO_PIN) # error "Audio feature enabled, but no pin selected - see docs/feature_audio under the ARM PWM settings" diff --git a/platforms/chibios/drivers/audio_pwm_software.c b/platforms/chibios/drivers/audio_pwm_software.c index e01f86ea52..663a9eca16 100644 --- a/platforms/chibios/drivers/audio_pwm_software.c +++ b/platforms/chibios/drivers/audio_pwm_software.c @@ -25,8 +25,7 @@ this driver uses the chibios-PWM system to produce a square-wave on any given ou */ #include "audio.h" -#include "ch.h" -#include "hal.h" +#include "gpio.h" #if !defined(AUDIO_PIN) # error "Audio feature enabled, but no pin selected - see docs/feature_audio under the ARM PWM settings" diff --git a/quantum/audio/audio.c b/quantum/audio/audio.c index 0300483a93..b9b21066cb 100644 --- a/quantum/audio/audio.c +++ b/quantum/audio/audio.c @@ -583,3 +583,6 @@ uint16_t audio_duration_to_ms(uint16_t duration_bpm) { uint16_t audio_ms_to_duration(uint16_t duration_ms) { return ((uint32_t)duration_ms * 2 * note_tempo) / 1875; } + +__attribute__((weak)) void audio_on_user(void) {} +__attribute__((weak)) void audio_off_user(void) {} diff --git a/quantum/audio/audio.h b/quantum/audio/audio.h index 75016a1100..a4a908b43c 100644 --- a/quantum/audio/audio.h +++ b/quantum/audio/audio.h @@ -21,12 +21,6 @@ #include "musical_notes.h" #include "song_list.h" #include "voices.h" -#include "quantum.h" -#include - -#if defined(__AVR__) -# include -#endif #if defined(AUDIO_DRIVER_PWM) # include "audio_pwm.h" @@ -280,3 +274,6 @@ bool audio_update_state(void); #define increase_tempo(t) audio_increase_tempo(t) #define decrease_tempo(t) audio_decrease_tempo(t) // vibrato functions are not used in any keyboards + +void audio_on_user(void); +void audio_off_user(void); diff --git a/quantum/audio/muse.c b/quantum/audio/muse.c index 01b95671fd..4c23cd7348 100644 --- a/quantum/audio/muse.c +++ b/quantum/audio/muse.c @@ -1,5 +1,7 @@ #include "muse.h" +#include + enum { MUSE_OFF, MUSE_ON, MUSE_C_1_2, MUSE_C1, MUSE_C2, MUSE_C4, MUSE_C8, MUSE_C3, MUSE_C6, MUSE_B1, MUSE_B2, MUSE_B3, MUSE_B4, MUSE_B5, MUSE_B6, MUSE_B7, MUSE_B8, MUSE_B9, MUSE_B10, MUSE_B11, MUSE_B12, MUSE_B13, MUSE_B14, MUSE_B15, MUSE_B16, MUSE_B17, MUSE_B18, MUSE_B19, MUSE_B20, MUSE_B21, MUSE_B22, MUSE_B23, MUSE_B24, MUSE_B25, MUSE_B26, MUSE_B27, MUSE_B28, MUSE_B29, MUSE_B30, MUSE_B31 }; bool number_of_ones_to_bool[16] = {1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1}; diff --git a/quantum/audio/muse.h b/quantum/audio/muse.h index ad2f96e43a..7b289cac6c 100644 --- a/quantum/audio/muse.h +++ b/quantum/audio/muse.h @@ -1,6 +1,5 @@ #pragma once -#include "quantum.h" -#include "process_audio.h" +#include uint8_t muse_clock_pulse(void); diff --git a/quantum/audio/voices.c b/quantum/audio/voices.c index 01f257f4d4..4f511c93ba 100644 --- a/quantum/audio/voices.c +++ b/quantum/audio/voices.c @@ -16,7 +16,9 @@ */ #include "voices.h" #include "audio.h" +#include "timer.h" #include +#include uint8_t note_timbre = TIMBRE_DEFAULT; bool glissando = false; diff --git a/quantum/bootmagic/bootmagic_lite.c b/quantum/bootmagic/bootmagic_lite.c index f63c71fc6b..efce6bfd12 100644 --- a/quantum/bootmagic/bootmagic_lite.c +++ b/quantum/bootmagic/bootmagic_lite.c @@ -13,7 +13,12 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include "quantum.h" +#include "bootmagic.h" +#include "matrix.h" +#include "keyboard.h" +#include "wait.h" +#include "eeconfig.h" +#include "bootloader.h" /** \brief Reset eeprom * diff --git a/quantum/dynamic_keymap.c b/quantum/dynamic_keymap.c index 2030c82a1b..4c95128337 100644 --- a/quantum/dynamic_keymap.c +++ b/quantum/dynamic_keymap.c @@ -14,14 +14,16 @@ * along with this program. If not, see . */ -#include "keymap_introspection.h" // to get keymaps[][][] -#include "eeprom.h" -#include "progmem.h" // to read default from flash -#include "quantum.h" // for send_string() #include "dynamic_keymap.h" +#include "keymap_introspection.h" +#include "action.h" +#include "eeprom.h" +#include "progmem.h" +#include "send_string.h" +#include "keycodes.h" #ifdef VIA_ENABLE -# include "via.h" // for VIA_EEPROM_CONFIG_END +# include "via.h" # define DYNAMIC_KEYMAP_EEPROM_START (VIA_EEPROM_CONFIG_END) #else # define DYNAMIC_KEYMAP_EEPROM_START (EECONFIG_SIZE) diff --git a/quantum/encoder.c b/quantum/encoder.c index 1046fe6cc3..7ab194ed52 100644 --- a/quantum/encoder.c +++ b/quantum/encoder.c @@ -16,6 +16,11 @@ */ #include "encoder.h" +#include "keyboard.h" +#include "action.h" +#include "keycodes.h" +#include "wait.h" + #ifdef SPLIT_KEYBOARD # include "split_util.h" #endif diff --git a/quantum/encoder.h b/quantum/encoder.h index 7644853b30..1cbac98cb5 100644 --- a/quantum/encoder.h +++ b/quantum/encoder.h @@ -17,7 +17,9 @@ #pragma once -#include "quantum.h" +#include +#include +#include "gpio.h" #include "util.h" void encoder_init(void); diff --git a/quantum/encoder/tests/encoder_tests_split_role.cpp b/quantum/encoder/tests/encoder_tests_split_role.cpp index 02264067f4..0ab7bfc2a7 100644 --- a/quantum/encoder/tests/encoder_tests_split_role.cpp +++ b/quantum/encoder/tests/encoder_tests_split_role.cpp @@ -22,6 +22,7 @@ extern "C" { #include "encoder.h" +#include "keyboard.h" #include "encoder/tests/mock_split.h" } diff --git a/quantum/keyboard.c b/quantum/keyboard.c index 5115709748..c2ca15d52d 100644 --- a/quantum/keyboard.c +++ b/quantum/keyboard.c @@ -16,8 +16,8 @@ along with this program. If not, see . */ #include -#include "quantum.h" #include "keyboard.h" +#include "keycode_config.h" #include "matrix.h" #include "keymap_introspection.h" #include "magic.h" @@ -33,6 +33,12 @@ along with this program. If not, see . #include "sendchar.h" #include "eeconfig.h" #include "action_layer.h" +#ifdef AUDIO_ENABLE +# include "audio.h" +#endif +#if defined(AUDIO_ENABLE) || (defined(MIDI_ENABLE) && defined(MIDI_BASIC)) +# include "process_music.h" +#endif #ifdef BACKLIGHT_ENABLE # include "backlight.h" #endif @@ -54,9 +60,27 @@ along with this program. If not, see . #ifdef ENCODER_ENABLE # include "encoder.h" #endif +#ifdef HAPTIC_ENABLE +# include "haptic.h" +#endif +#ifdef AUTO_SHIFT_ENABLE +# include "process_auto_shift.h" +#endif +#ifdef COMBO_ENABLE +# include "process_combo.h" +#endif +#ifdef TAP_DANCE_ENABLE +# include "process_tap_dance.h" +#endif #ifdef STENO_ENABLE # include "process_steno.h" #endif +#ifdef KEY_OVERRIDE_ENABLE +# include "process_key_override.h" +#endif +#ifdef SECURE_ENABLE +# include "secure.h" +#endif #ifdef POINTING_DEVICE_ENABLE # include "pointing_device.h" #endif @@ -64,7 +88,7 @@ along with this program. If not, see . # include "process_midi.h" #endif #ifdef JOYSTICK_ENABLE -# include "process_joystick.h" +# include "joystick.h" #endif #ifdef HD44780_ENABLE # include "hd44780.h" @@ -108,6 +132,12 @@ along with this program. If not, see . #ifdef LEADER_ENABLE # include "leader.h" #endif +#ifdef UNICODE_COMMON_ENABLE +# include "unicode.h" +#endif +#ifdef WPM_ENABLE +# include "wpm.h" +#endif static uint32_t last_input_modification_time = 0; uint32_t last_input_activity_time(void) { diff --git a/quantum/keyboard.h b/quantum/keyboard.h index bf1890d10b..5ea57815a7 100644 --- a/quantum/keyboard.h +++ b/quantum/keyboard.h @@ -20,6 +20,8 @@ along with this program. If not, see . #include #include +#include "timer.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/quantum/keymap_common.c b/quantum/keymap_common.c index 0492e6fd1c..9a67fad278 100644 --- a/quantum/keymap_common.c +++ b/quantum/keymap_common.c @@ -22,7 +22,12 @@ along with this program. If not, see . #include "action_layer.h" #include "action.h" #include "debug.h" -#include "quantum.h" +#include "keycode_config.h" +#include "quantum_keycodes.h" + +#ifdef ENCODER_MAP_ENABLE +# include "encoder.h" +#endif #ifdef BACKLIGHT_ENABLE # include "backlight.h" diff --git a/quantum/led_matrix/led_matrix.c b/quantum/led_matrix/led_matrix.c index 4b692d1904..1676a60aa3 100644 --- a/quantum/led_matrix/led_matrix.c +++ b/quantum/led_matrix/led_matrix.c @@ -20,8 +20,13 @@ #include "led_matrix.h" #include "progmem.h" #include "eeprom.h" +#include "eeconfig.h" +#include "keyboard.h" +#include "sync_timer.h" +#include "debug.h" #include #include +#include #include "led_tables.h" #include diff --git a/quantum/led_matrix/led_matrix.h b/quantum/led_matrix/led_matrix.h index 9091f6890b..c2533ca49c 100644 --- a/quantum/led_matrix/led_matrix.h +++ b/quantum/led_matrix/led_matrix.h @@ -23,7 +23,7 @@ #include #include #include "led_matrix_types.h" -#include "quantum.h" +#include "keyboard.h" #ifdef IS31FL3731 # include "is31fl3731-simple.h" diff --git a/quantum/matrix.c b/quantum/matrix.c index 97d41caedd..f087a215d4 100644 --- a/quantum/matrix.c +++ b/quantum/matrix.c @@ -20,7 +20,8 @@ along with this program. If not, see . #include "util.h" #include "matrix.h" #include "debounce.h" -#include "quantum.h" +#include "atomic_util.h" + #ifdef SPLIT_KEYBOARD # include "split_common/split_util.h" # include "split_common/transactions.h" diff --git a/quantum/matrix_common.c b/quantum/matrix_common.c index 3173351888..d02c527caa 100644 --- a/quantum/matrix_common.c +++ b/quantum/matrix_common.c @@ -1,9 +1,9 @@ -#include "quantum.h" #include "matrix.h" #include "debounce.h" #include "wait.h" #include "print.h" #include "debug.h" + #ifdef SPLIT_KEYBOARD # include "split_common/split_util.h" # include "split_common/transactions.h" diff --git a/quantum/midi/qmk_midi.c b/quantum/midi/qmk_midi.c index 688259784c..43ebd72937 100644 --- a/quantum/midi/qmk_midi.c +++ b/quantum/midi/qmk_midi.c @@ -7,6 +7,7 @@ #ifdef AUDIO_ENABLE # include "audio.h" +# include #endif /******************************************************************************* diff --git a/quantum/pointing_device/pointing_device_auto_mouse.c b/quantum/pointing_device/pointing_device_auto_mouse.c index b008d18db5..fc3106e37e 100644 --- a/quantum/pointing_device/pointing_device_auto_mouse.c +++ b/quantum/pointing_device/pointing_device_auto_mouse.c @@ -18,6 +18,9 @@ #ifdef POINTING_DEVICE_AUTO_MOUSE_ENABLE # include "pointing_device_auto_mouse.h" +# include "debug.h" +# include "action_util.h" +# include "quantum_keycodes.h" /* local data structure for tracking auto mouse */ static auto_mouse_context_t auto_mouse_context = { diff --git a/quantum/pointing_device/pointing_device_auto_mouse.h b/quantum/pointing_device/pointing_device_auto_mouse.h index 7db63bc6b8..1343855e00 100644 --- a/quantum/pointing_device/pointing_device_auto_mouse.h +++ b/quantum/pointing_device/pointing_device_auto_mouse.h @@ -16,11 +16,14 @@ #pragma once -#include - -#include "quantum.h" +#include +#include #include "pointing_device.h" -#include "print.h" +#include "keycodes.h" +#include "action.h" +#include "report.h" +#include "action_layer.h" +#include "action_tapping.h" /* check settings and set defaults */ #ifndef POINTING_DEVICE_AUTO_MOUSE_ENABLE diff --git a/quantum/process_keycode/process_audio.c b/quantum/process_keycode/process_audio.c index c189dd02b7..ef2f52c9f1 100644 --- a/quantum/process_keycode/process_audio.c +++ b/quantum/process_keycode/process_audio.c @@ -1,5 +1,6 @@ #include "audio.h" #include "process_audio.h" +#include #ifndef VOICE_CHANGE_SONG # define VOICE_CHANGE_SONG SONG(VOICE_CHANGE_SOUND) @@ -61,6 +62,3 @@ void process_audio_noteoff(uint8_t note) { void process_audio_all_notes_off(void) { stop_all_notes(); } - -__attribute__((weak)) void audio_on_user(void) {} -__attribute__((weak)) void audio_off_user(void) {} diff --git a/quantum/process_keycode/process_audio.h b/quantum/process_keycode/process_audio.h index c80136f2c2..69e201e447 100644 --- a/quantum/process_keycode/process_audio.h +++ b/quantum/process_keycode/process_audio.h @@ -10,6 +10,3 @@ bool process_audio(uint16_t keycode, keyrecord_t *record); void process_audio_noteon(uint8_t note); void process_audio_noteoff(uint8_t note); void process_audio_all_notes_off(void); - -void audio_on_user(void); -void audio_off_user(void); diff --git a/quantum/process_keycode/process_clicky.c b/quantum/process_keycode/process_clicky.c index b662a3f2f4..0ee58282e6 100644 --- a/quantum/process_keycode/process_clicky.c +++ b/quantum/process_keycode/process_clicky.c @@ -1,5 +1,7 @@ -#include "audio.h" #include "process_clicky.h" +#include "audio.h" +#include "eeconfig.h" +#include #ifdef AUDIO_CLICKY diff --git a/quantum/process_keycode/process_key_override.c b/quantum/process_keycode/process_key_override.c index 6ce1e4d925..264e2562b8 100644 --- a/quantum/process_keycode/process_key_override.c +++ b/quantum/process_keycode/process_key_override.c @@ -19,6 +19,10 @@ #include "report.h" #include "timer.h" #include "debug.h" +#include "wait.h" +#include "action_util.h" +#include "quantum.h" +#include "quantum_keycodes.h" #ifndef KEY_OVERRIDE_REPEAT_DELAY # define KEY_OVERRIDE_REPEAT_DELAY 500 diff --git a/quantum/repeat_key.c b/quantum/repeat_key.c index 0689c6d454..4567428723 100644 --- a/quantum/repeat_key.c +++ b/quantum/repeat_key.c @@ -13,6 +13,7 @@ // limitations under the License. #include "repeat_key.h" +#include "quantum_keycodes.h" // Variables saving the state of the last key press. static keyrecord_t last_record = {0}; diff --git a/quantum/repeat_key.h b/quantum/repeat_key.h index 06e8364529..8084be24ad 100644 --- a/quantum/repeat_key.h +++ b/quantum/repeat_key.h @@ -14,7 +14,10 @@ #pragma once -#include "quantum.h" +#include +#include +#include "action.h" +#include "keyboard.h" uint16_t get_last_keycode(void); /**< Keycode of the last key. */ uint8_t get_last_mods(void); /**< Mods active with the last key. */ diff --git a/quantum/rgb_matrix/rgb_matrix.c b/quantum/rgb_matrix/rgb_matrix.c index 1680389793..96be615162 100644 --- a/quantum/rgb_matrix/rgb_matrix.c +++ b/quantum/rgb_matrix/rgb_matrix.c @@ -19,8 +19,13 @@ #include "rgb_matrix.h" #include "progmem.h" #include "eeprom.h" +#include "eeconfig.h" +#include "keyboard.h" +#include "sync_timer.h" +#include "debug.h" #include #include +#include #include diff --git a/quantum/rgb_matrix/rgb_matrix.h b/quantum/rgb_matrix/rgb_matrix.h index 83851d8995..38040fb0cc 100644 --- a/quantum/rgb_matrix/rgb_matrix.h +++ b/quantum/rgb_matrix/rgb_matrix.h @@ -22,7 +22,7 @@ #include #include "rgb_matrix_types.h" #include "color.h" -#include "quantum.h" +#include "keyboard.h" #ifdef IS31FL3731 # include "is31fl3731.h" diff --git a/quantum/rgb_matrix/rgb_matrix_drivers.c b/quantum/rgb_matrix/rgb_matrix_drivers.c index 6de20ac8a5..7bd274ee99 100644 --- a/quantum/rgb_matrix/rgb_matrix_drivers.c +++ b/quantum/rgb_matrix/rgb_matrix_drivers.c @@ -15,6 +15,7 @@ */ #include "rgb_matrix.h" +#include "util.h" /* Each driver needs to define the struct * const rgb_matrix_driver_t rgb_matrix_driver; diff --git a/quantum/split_common/split_util.c b/quantum/split_common/split_util.c index a431383454..87838c3195 100644 --- a/quantum/split_common/split_util.c +++ b/quantum/split_common/split_util.c @@ -18,8 +18,8 @@ #include "keyboard.h" #include "timer.h" #include "transport.h" -#include "quantum.h" #include "wait.h" +#include "debug.h" #include "usb_util.h" #ifdef EE_HANDS diff --git a/quantum/split_common/split_util.h b/quantum/split_common/split_util.h index 5c9a260a14..ab42c85e9f 100644 --- a/quantum/split_common/split_util.h +++ b/quantum/split_common/split_util.h @@ -2,7 +2,6 @@ #include #include -#include #include "matrix.h" diff --git a/quantum/split_common/transactions.c b/quantum/split_common/transactions.c index 8cd018a6ec..2b9423cd63 100644 --- a/quantum/split_common/transactions.c +++ b/quantum/split_common/transactions.c @@ -20,13 +20,50 @@ #include "crc.h" #include "debug.h" #include "matrix.h" -#include "quantum.h" +#include "host.h" +#include "action_util.h" +#include "sync_timer.h" +#include "wait.h" #include "transactions.h" #include "transport.h" #include "transaction_id_define.h" #include "split_util.h" #include "synchronization_util.h" +#ifdef BACKLIGHT_ENABLE +# include "backlight.h" +#endif +#ifdef RGBLIGHT_ENABLE +# include "rgblight.h" +#endif +#ifdef LED_MATRIX_ENABLE +# include "led_matrix.h" +#endif +#ifdef RGB_MATRIX_ENABLE +# include "rgb_matrix.h" +#endif +#ifdef OLED_ENABLE +# include "oled_driver.h" +#endif +#ifdef ST7565_ENABLE +# include "st7565.h" +#endif +#ifdef ENCODER_ENABLE +# include "encoder.h" +#endif +#ifdef HAPTIC_ENABLE +# include "haptic.h" +#endif +#ifdef POINTING_DEVICE_ENABLE +# include "pointing_device.h" +#endif +#ifdef OS_DETECTION_ENABLE +# include "os_detection.h" +#endif +#ifdef WPM_ENABLE +# include "wpm.h" +#endif + #define SYNC_TIMER_OFFSET 2 #ifndef FORCED_SYNC_THROTTLE_MS diff --git a/quantum/split_common/transactions.h b/quantum/split_common/transactions.h index e38ec79ce9..af3e68a15f 100644 --- a/quantum/split_common/transactions.h +++ b/quantum/split_common/transactions.h @@ -16,8 +16,8 @@ #pragma once -#include "stdint.h" -#include "stdbool.h" +#include +#include #include "matrix.h" #include "transaction_id_define.h" diff --git a/quantum/split_common/transport.h b/quantum/split_common/transport.h index a3d6f1dfe9..2e2b918d45 100644 --- a/quantum/split_common/transport.h +++ b/quantum/split_common/transport.h @@ -16,8 +16,8 @@ #pragma once -#include "stdint.h" -#include "stdbool.h" +#include +#include #include "progmem.h" #include "action_layer.h" diff --git a/quantum/unicode/unicode.c b/quantum/unicode/unicode.c index 35cb62e700..f92ba51984 100644 --- a/quantum/unicode/unicode.c +++ b/quantum/unicode/unicode.c @@ -25,6 +25,8 @@ #include "wait.h" #include "send_string.h" #include "utf8.h" +#include "debug.h" +#include "quantum.h" #if defined(AUDIO_ENABLE) # include "audio.h" diff --git a/quantum/unicode/unicode.h b/quantum/unicode/unicode.h index 06505d87c0..ccf475d57c 100644 --- a/quantum/unicode/unicode.h +++ b/quantum/unicode/unicode.h @@ -17,8 +17,7 @@ #pragma once #include - -#include "quantum.h" +#include "quantum_keycodes.h" typedef union { uint8_t raw; diff --git a/quantum/via.c b/quantum/via.c index f4293dacd4..2acd7aa90c 100644 --- a/quantum/via.c +++ b/quantum/via.c @@ -22,19 +22,41 @@ # error "DYNAMIC_KEYMAP_ENABLE is not enabled" #endif -#include "quantum.h" - #include "via.h" #include "raw_hid.h" #include "dynamic_keymap.h" #include "eeprom.h" +#include "eeconfig.h" +#include "matrix.h" +#include "timer.h" +#include "wait.h" #include "version.h" // for QMK_BUILDDATE used in EEPROM magic +#if defined(AUDIO_ENABLE) +# include "audio.h" +#endif + +#if defined(BACKLIGHT_ENABLE) +# include "backlight.h" +#endif + +#if defined(RGBLIGHT_ENABLE) +# include "rgblight.h" +#endif + #if (defined(RGB_MATRIX_ENABLE) || defined(LED_MATRIX_ENABLE)) # include #endif +#if defined(RGB_MATRIX_ENABLE) +# include "rgb_matrix.h" +#endif + +#if defined(LED_MATRIX_ENABLE) +# include "led_matrix.h" +#endif + // Can be called in an overriding via_init_kb() to test if keyboard level code usage of // EEPROM is invalid and use/save defaults. bool via_eeprom_is_valid(void) { diff --git a/quantum/via.h b/quantum/via.h index 6c8465b81e..01d4c48b37 100644 --- a/quantum/via.h +++ b/quantum/via.h @@ -17,6 +17,7 @@ #pragma once #include "eeconfig.h" // for EECONFIG_SIZE +#include "action.h" // Keyboard level code can change where VIA stores the magic. // The magic is the build date YYMMDD encoded as BCD in 3 bytes, diff --git a/tmk_core/protocol/arm_atsam/main_arm_atsam.c b/tmk_core/protocol/arm_atsam/main_arm_atsam.c index 5bed9e0cf4..30817c17b6 100644 --- a/tmk_core/protocol/arm_atsam/main_arm_atsam.c +++ b/tmk_core/protocol/arm_atsam/main_arm_atsam.c @@ -21,6 +21,7 @@ along with this program. If not, see . #include "report.h" #include "host.h" #include "host_driver.h" +#include "suspend.h" #include "keycode_config.h" #include diff --git a/tmk_core/protocol/arm_atsam/md_rgb_matrix.c b/tmk_core/protocol/arm_atsam/md_rgb_matrix.c index 6069d1e609..0f316b256c 100644 --- a/tmk_core/protocol/arm_atsam/md_rgb_matrix.c +++ b/tmk_core/protocol/arm_atsam/md_rgb_matrix.c @@ -24,6 +24,7 @@ along with this program. If not, see . # include "led.h" # include "rgb_matrix.h" # include "eeprom.h" +# include "host.h" # include # include diff --git a/tmk_core/protocol/arm_atsam/spi_master.h b/tmk_core/protocol/arm_atsam/spi_master.h index 26c55128be..80678a5707 100644 --- a/tmk_core/protocol/arm_atsam/spi_master.h +++ b/tmk_core/protocol/arm_atsam/spi_master.h @@ -16,7 +16,9 @@ #pragma once +#include #include +#include "gpio.h" typedef int16_t spi_status_t; -- cgit v1.2.3 From 4137685f8eb3ecde7ba0158a78cd9c411ee05606 Mon Sep 17 00:00:00 2001 From: Ryan Date: Fri, 21 Jul 2023 09:27:55 +1000 Subject: backlight: split AVR PWM and timer drivers (#21540) --- docs/feature_backlight.md | 346 +++++++++++++-------- keyboards/40percentclub/4pack/info.json | 1 + keyboards/40percentclub/sixpack/info.json | 1 + keyboards/8pack/info.json | 1 + keyboards/ai03/equinox/rev0/info.json | 1 + keyboards/amjkeyboard/amj66/info.json | 1 + keyboards/anavi/macropad8/info.json | 1 + keyboards/bear_face/info.json | 1 + keyboards/cablecardesigns/cypher/rev6/info.json | 1 + keyboards/cest73/tkm/info.json | 1 + keyboards/checkerboards/nop60/info.json | 1 + keyboards/checkerboards/quark_plus/info.json | 1 + keyboards/checkerboards/snop60/info.json | 1 + keyboards/efreet/info.json | 1 + keyboards/gray_studio/cod67/info.json | 1 + keyboards/handwired/bdn9_ble/info.json | 1 + keyboards/kc60se/info.json | 1 + keyboards/keebio/iris/rev1/info.json | 1 + keyboards/kopibeng/xt65/info.json | 1 + keyboards/kprepublic/cospad/info.json | 1 + keyboards/ktec/daisy/info.json | 1 + keyboards/ktec/staryu/info.json | 1 + keyboards/maple_computing/christmas_tree/info.json | 1 + keyboards/maple_computing/ivy/rev1/info.json | 1 + keyboards/maple_computing/jnao/info.json | 1 + keyboards/melgeek/mj6xy/rev3/info.json | 1 - keyboards/mntre/config.h | 2 +- keyboards/mt/mt40/info.json | 1 + keyboards/nopunin10did/jabberwocky/v2/info.json | 4 +- keyboards/org60/info.json | 1 + keyboards/playkbtw/ca66/info.json | 1 + keyboards/sandwich/keeb68/info.json | 1 + keyboards/tkc/osav2/info.json | 1 + keyboards/v60_type_r/info.json | 1 + keyboards/viktus/osav2/info.json | 1 + keyboards/westfoxtrot/cypher/rev5/info.json | 1 + keyboards/xiudi/xd60/rev2/info.json | 1 + keyboards/xiudi/xd60/rev3/info.json | 1 + keyboards/xiudi/xd68/info.json | 1 + keyboards/xiudi/xd84pro/info.json | 1 + keyboards/xiudi/xd87/info.json | 1 + platforms/avr/drivers/backlight_pwm.c | 200 ++---------- platforms/avr/drivers/backlight_timer.c | 267 ++++++++++++++++ 43 files changed, 555 insertions(+), 302 deletions(-) create mode 100644 platforms/avr/drivers/backlight_timer.c (limited to 'platforms/avr') diff --git a/docs/feature_backlight.md b/docs/feature_backlight.md index 24057c608f..d032c33f18 100644 --- a/docs/feature_backlight.md +++ b/docs/feature_backlight.md @@ -1,12 +1,12 @@ # Backlighting :id=backlighting -Many keyboards support backlit keys by way of individual LEDs placed through or underneath the keyswitches. This feature is distinct from both the [RGB underglow](feature_rgblight.md) and [RGB matrix](feature_rgb_matrix.md) features as it usually allows for only a single colour per switch, though you can obviously install multiple different single coloured LEDs on a keyboard. +Many keyboards support backlit keys by way of individual LEDs placed through or underneath the keyswitches. This feature is distinct from both the [RGB Underglow](feature_rgblight.md) and [RGB Matrix](feature_rgb_matrix.md) features as it usually allows for only a single colour per switch, though you can obviously install multiple different single coloured LEDs on a keyboard. QMK is able to control the brightness of these LEDs by switching them on and off rapidly in a certain ratio, a technique known as *Pulse Width Modulation*, or PWM. By altering the duty cycle of the PWM signal, it creates the illusion of dimming. -The MCU can only supply so much current to its GPIO pins. Instead of powering the backlight directly from the MCU, the backlight pin is connected to a transistor or MOSFET that switches the power to the LEDs. +## Usage :id=usage -Most keyboards have backlighting enabled by default if they support it, but if it is not working for you, check that your `rules.mk` includes the following: +Most keyboards have backlighting enabled by default if they support it, but if it is not working for you (or you have added support), check that your `rules.mk` includes the following: ```make BACKLIGHT_ENABLE = yes @@ -14,57 +14,23 @@ BACKLIGHT_ENABLE = yes ## Keycodes :id=keycodes -Once enabled, the following keycodes below can be used to change the backlight level. +|Key |Aliases |Description | +|-------------------------------|---------|-----------------------------------| +|`QK_BACKLIGHT_TOGGLE` |`BL_TOGG`|Turn the backlight on or off | +|`QK_BACKLIGHT_STEP` |`BL_STEP`|Cycle through backlight levels | +|`QK_BACKLIGHT_ON` |`BL_ON` |Set the backlight to max brightness| +|`QK_BACKLIGHT_OFF` |`BL_OFF` |Turn the backlight off | +|`QK_BACKLIGHT_UP` |`BL_UP` |Increase the backlight level | +|`QK_BACKLIGHT_DOWN` |`BL_DOWN`|Decrease the backlight level | +|`QK_BACKLIGHT_TOGGLE_BREATHING`|`BL_BRTG`|Toggle backlight breathing | -| Key | Aliases | Description | -|---------------------------------|-----------|-------------------------------------| -| `QK_BACKLIGHT_TOGGLE` | `BL_TOGG` | Turn the backlight on or off | -| `QK_BACKLIGHT_STEP` | `BL_STEP` | Cycle through backlight levels | -| `QK_BACKLIGHT_ON` | `BL_ON` | Set the backlight to max brightness | -| `QK_BACKLIGHT_OFF` | `BL_OFF` | Turn the backlight off | -| `QK_BACKLIGHT_UP` | `BL_UP` | Increase the backlight level | -| `QK_BACKLIGHT_DOWN` | `BL_DOWN` | Decrease the backlight level | -| `QK_BACKLIGHT_TOGGLE_BREATHING` | `BL_BRTG` | Toggle backlight breathing | +## Basic Configuration :id=basic-configuration -## Functions :id=functions - -These functions can be used to change the backlighting in custom code: - -|Function |Description | -|------------------------|--------------------------------------------| -|`backlight_toggle()` |Turn the backlight on or off | -|`backlight_enable()` |Turn the backlight on | -|`backlight_disable()` |Turn the backlight off | -|`backlight_step()` |Cycle through backlight levels | -|`backlight_increase()` |Increase the backlight level | -|`backlight_decrease()` |Decrease the backlight level | -|`backlight_level(x)` |Sets the backlight level to specified level | -|`get_backlight_level()` |Return the current backlight level | -|`is_backlight_enabled()`|Return whether the backlight is currently on| - -If backlight breathing is enabled (see below), the following functions are also available: - -|Function |Description | -|---------------------|--------------------------------------| -|`breathing_toggle()` |Turn the backlight breathing on or off| -|`breathing_enable()` |Turns on backlight breathing | -|`breathing_disable()`|Turns off backlight breathing | - -## Configuration :id=configuration - -To select which driver to use, configure your `rules.mk` with the following: - -```make -BACKLIGHT_DRIVER = software -``` - -Valid driver values are `pwm`, `software`, `custom` or `no`. See below for help on individual drivers. - -To configure the backlighting, `#define` these in your `config.h`: +Add the following to your `config.h`: |Define |Default |Description | |-----------------------------|------------------|-----------------------------------------------------------------------------------------------------------------| -|`BACKLIGHT_PIN` |*Not defined* |The pin that controls the LED(s) | +|`BACKLIGHT_PIN` |*Not defined* |The pin that controls the LEDs | |`BACKLIGHT_LEVELS` |`3` |The number of brightness levels (maximum 31 excluding off) | |`BACKLIGHT_CAPS_LOCK` |*Not defined* |Enable Caps Lock indicator using backlight (for keyboards without dedicated LED) | |`BACKLIGHT_BREATHING` |*Not defined* |Enable backlight breathing, if supported | @@ -76,24 +42,88 @@ To configure the backlighting, `#define` these in your `config.h`: Unless you are designing your own keyboard, you generally should not need to change the `BACKLIGHT_PIN` or `BACKLIGHT_ON_STATE`. -### Backlight On State :id=backlight-on-state +### "On" State :id=on-state Most backlight circuits are driven by an N-channel MOSFET or NPN transistor. This means that to turn the transistor *on* and light the LEDs, you must drive the backlight pin, connected to the gate or base, *high*. Sometimes, however, a P-channel MOSFET, or a PNP transistor is used. In this case, when the transistor is on, the pin is driven *low* instead. -This functionality is configured at the keyboard level with the `BACKLIGHT_ON_STATE` define. +To configure the "on" state of the backlight circuit, add the following to your `config.h`: + +```c +#define BACKLIGHT_ON_STATE 0 +``` + +### Multiple Backlight Pins :id=multiple-backlight-pins + +Most keyboards have only one backlight pin which controls all backlight LEDs (especially if the backlight is connected to a hardware PWM pin). +The `timer` and `software` drivers allow you to define multiple backlight pins, which will be turned on and off at the same time during the PWM duty cycle. + +This feature allows to set, for instance, the Caps Lock LED's (or any other controllable LED) brightness at the same level as the other LEDs of the backlight. This is useful if you have mapped Control in place of Caps Lock and you need the Caps Lock LED to be part of the backlight instead of being activated when Caps Lock is on, as it is usually wired to a separate pin from the backlight. + +To configure multiple backlight pins, add something like this to your `config.h`, instead of `BACKLIGHT_PIN`: + +```c +#define BACKLIGHT_PINS { F5, B2 } +``` + +## Driver Configuration :id=driver-configuration + +Backlight driver selection is configured in `rules.mk`. Valid drivers are `pwm` (default), `timer`, `software`, or `custom`. See below for information on individual drivers. -### AVR Driver :id=avr-driver +### PWM Driver :id=pwm-driver -The `pwm` driver is configured by default, however the equivalent setting within `rules.mk` would be: +This is the default backlight driver, which leverages the hardware PWM output capability of the microcontroller. ```make BACKLIGHT_DRIVER = pwm ``` -#### Caveats :id=avr-caveats +### Timer Driver :id=timer-driver + +This driver is similar to the PWM driver, but instead of directly configuring the pin to output a PWM signal, an interrupt handler is attached to the timer to turn the pin on and off as appropriate. + +```make +BACKLIGHT_DRIVER = timer +``` + +### Software Driver :id=software-driver + +In this mode, PWM is "emulated" while running other keyboard tasks. It offers maximum hardware compatibility without extra platform configuration. However, breathing is not supported, and the backlight can flicker when the keyboard is busy. + +```make +BACKLIGHT_DRIVER = software +``` + +### Custom Driver :id=custom-driver + +If none of the above drivers apply to your board (for example, you are using a separate IC to control the backlight), you can implement a custom backlight driver using a simple API. + +```make +BACKLIGHT_DRIVER = custom +``` + +```c +void backlight_init_ports(void) { + // Optional - runs on startup + // Usually you want to configure pins here +} +void backlight_set(uint8_t level) { + // Optional - runs on level change + // Usually you want to respond to the new value +} + +void backlight_task(void) { + // Optional - runs periodically + // Note that this is called in the main keyboard loop, + // so long running actions here can cause performance issues +} +``` + +## AVR Configuration :id=avr-configuration + +### PWM Driver :id=avr-pwm-driver -On AVR boards, QMK automatically decides which driver to use according to the following table: +The following table describes the supported pins for the PWM driver. Only cells marked with a timer number are capable of hardware PWM output; any others must use the `timer` driver. |Backlight Pin|AT90USB64/128|AT90USB162|ATmega16/32U4|ATmega16/32U2|ATmega32A|ATmega328/P| |-------------|-------------|----------|-------------|-------------|---------|-----------| @@ -108,113 +138,169 @@ On AVR boards, QMK automatically decides which driver to use according to the fo |`D4` | | | | |Timer 1 | | |`D5` | | | | |Timer 1 | | -All other pins will use timer-assisted software PWM: +### Timer Driver :id=avr-timer-driver -|Audio Pin|Audio Timer|Software PWM Timer| -|---------|-----------|------------------| -|`C4` |Timer 3 |Timer 1 | -|`C5` |Timer 3 |Timer 1 | -|`C6` |Timer 3 |Timer 1 | -|`B5` |Timer 1 |Timer 3 | -|`B6` |Timer 1 |Timer 3 | -|`B7` |Timer 1 |Timer 3 | +Any GPIO pin can be used with this driver. The following table describes the supported timers: -When both timers are in use for Audio, the backlight PWM cannot use a hardware timer, and will instead be triggered during the matrix scan. In this case, breathing is not supported, and the backlight might flicker, because the PWM computation may not be called with enough timing precision. +|AT90USB64/128|AT90USB162|ATmega16/32U4|ATmega16/32U2|ATmega32A|ATmega328/P| +|-------------|----------|-------------|-------------|---------|-----------| +|Timers 1 & 3 |Timer 1 |Timers 1 & 3 |Timer 1 |Timer 1 |Timer 1 | -#### Hardware PWM Implementation :id=hardware-pwm-implementation +The following `#define`s apply only to the `timer` driver: -When using the supported pins for backlighting, QMK will use a hardware timer configured to output a PWM signal. This timer will count up to `ICRx` (by default `0xFFFF`) before resetting to 0. -The desired brightness is calculated and stored in the `OCRxx` register. When the counter reaches this value, the backlight pin will go low, and is pulled high again when the counter resets. -In this way `OCRxx` essentially controls the duty cycle of the LEDs, and thus the brightness, where `0x0000` is completely off and `0xFFFF` is completely on. +|Define |Default|Description | +|-----------------------|-------|----------------| +|`BACKLIGHT_PWM_TIMER` |`1` |The timer to use| -The breathing effect is achieved by registering an interrupt handler for `TIMER1_OVF_vect` that is called whenever the counter resets, roughly 244 times per second. -In this handler, the value of an incrementing counter is mapped onto a precomputed brightness curve. To turn off breathing, the interrupt handler is simply disabled, and the brightness reset to the level stored in EEPROM. +Note that the choice of timer may conflict with the [Audio](feature_audio.md) feature. -#### Timer Assisted PWM Implementation :id=timer-assisted-implementation +## ChibiOS/ARM Configuration :id=arm-configuration -When `BACKLIGHT_PIN` is not set to a hardware backlight pin, QMK will use a hardware timer configured to trigger software interrupts. This time will count up to `ICRx` (by default `0xFFFF`) before resetting to 0. -When resetting to 0, the CPU will fire an OVF (overflow) interrupt that will turn the LEDs on, starting the duty cycle. -The desired brightness is calculated and stored in the `OCRxx` register. When the counter reaches this value, the CPU will fire a Compare Output match interrupt, which will turn the LEDs off. -In this way `OCRxx` essentially controls the duty cycle of the LEDs, and thus the brightness, where `0x0000` is completely off and `0xFFFF` is completely on. +### PWM Driver :id=arm-pwm-driver -The breathing effect is the same as in the hardware PWM implementation. +Depending on the ChibiOS board configuration, you may need to enable PWM at the keyboard level. For STM32, this would look like: -### ARM Driver :id=arm-configuration +`halconf.h`: +```c +#define HAL_USE_PWM TRUE +``` +`mcuconf.h`: +```c +#undef STM32_PWM_USE_TIM4 +#define STM32_PWM_USE_TIM4 TRUE +``` -While still in its early stages, ARM backlight support aims to eventually have feature parity with AVR. The `pwm` driver is configured by default, however the equivalent setting within `rules.mk` would be: +The following `#define`s apply only to the `pwm` driver: -```make -BACKLIGHT_DRIVER = pwm +|Define |Default |Description | +|-----------------------|--------|-----------------------------------| +|`BACKLIGHT_PWM_DRIVER` |`PWMD4` |The PWM driver to use | +|`BACKLIGHT_PWM_CHANNEL`|`3` |The PWM channel to use | +|`BACKLIGHT_PAL_MODE` |`2` |The pin alternative function to use| + +Refer to the ST datasheet for your particular MCU to determine these values. For example, these defaults are set up for pin `B8` on a Proton-C (STM32F303) using `TIM4_CH3` on AF2. Unless you are designing your own keyboard, you generally should not need to change them. + +### Timer Driver :id=arm-timer-driver + +Depending on the ChibiOS board configuration, you may need to enable general-purpose timers at the keyboard level. For STM32, this would look like: + +`halconf.h`: +```c +#define HAL_USE_GPT TRUE +``` +`mcuconf.h`: +```c +#undef STM32_GPT_USE_TIM15 +#define STM32_GPT_USE_TIM15 TRUE ``` -#### ChibiOS Configuration :id=arm-configuration +The following `#define`s apply only to the `timer` driver: -The following `#define`s apply only to ARM-based keyboards: +|Define |Default |Description | +|----------------------|--------|----------------| +|`BACKLIGHT_GPT_DRIVER`|`GPTD15`|The timer to use| -|Define |Default|Description | -|-----------------------|-------|-----------------------------------| -|`BACKLIGHT_PWM_DRIVER` |`PWMD4`|The PWM driver to use | -|`BACKLIGHT_PWM_CHANNEL`|`3` |The PWM channel to use | -|`BACKLIGHT_PAL_MODE` |`2` |The pin alternative function to use| +## Example Schematic -See the ST datasheet for your particular MCU to determine these values. Unless you are designing your own keyboard, you generally should not need to change them. +Since the MCU can only supply so much current to its GPIO pins, instead of powering the backlight directly from the MCU, the backlight pin is connected to a transistor or MOSFET that switches the power to the LEDs. -#### Caveats :id=arm-caveats +In this typical example, the backlight LEDs are all connected in parallel towards an N-channel MOSFET. Its gate pin is wired to one of the microcontroller's GPIO pins through a 470Ω resistor to avoid ringing. +A pulldown resistor is also placed between the gate pin and ground to keep it at a defined state when it is not otherwise being driven by the MCU. +The values of these resistors are not critical - see [this Electronics StackExchange question](https://electronics.stackexchange.com/q/68748) for more information. -Currently only hardware PWM is supported, not timer assisted, and does not provide automatic configuration. +![Backlight example circuit](https://i.imgur.com/BmAvoUC.png) -### Software PWM Driver :id=software-pwm-driver +## API :id=api -In this mode, PWM is "emulated" while running other keyboard tasks. It offers maximum hardware compatibility without extra platform configuration. The tradeoff is the backlight might jitter when the keyboard is busy. To enable, add this to your `rules.mk`: +### `void backlight_toggle(void)` :id=api-backlight-toggle -```make -BACKLIGHT_DRIVER = software -``` +Toggle the backlight on or off. -#### Multiple Backlight Pins :id=multiple-backlight-pins +--- -Most keyboards have only one backlight pin which controls all backlight LEDs (especially if the backlight is connected to a hardware PWM pin). -In software PWM, it is possible to define multiple backlight pins, which will be turned on and off at the same time during the PWM duty cycle. +### `void backlight_enable(void)` :id=api-backlight-enable -This feature allows to set, for instance, the Caps Lock LED's (or any other controllable LED) brightness at the same level as the other LEDs of the backlight. This is useful if you have mapped Control in place of Caps Lock and you need the Caps Lock LED to be part of the backlight instead of being activated when Caps Lock is on, as it is usually wired to a separate pin from the backlight. +Turn the backlight on. -To activate multiple backlight pins, add something like this to your `config.h`, instead of `BACKLIGHT_PIN`: +--- -```c -#define BACKLIGHT_PINS { F5, B2 } -``` +### `void backlight_disable(void)` :id=api-backlight-disable -### Custom Driver :id=custom-driver +Turn the backlight off. -If none of the above drivers apply to your board (for example, you are using a separate IC to control the backlight), you can implement a custom backlight driver using this simple API provided by QMK. To enable, add this to your `rules.mk`: +--- -```make -BACKLIGHT_DRIVER = custom -``` +### `void backlight_step(void)` :id=api-backlight-step -Then implement any of these hooks: +Cycle through backlight levels. -```c -void backlight_init_ports(void) { - // Optional - runs on startup - // Usually you want to configure pins here -} -void backlight_set(uint8_t level) { - // Optional - runs on level change - // Usually you want to respond to the new value -} +--- -void backlight_task(void) { - // Optional - runs periodically - // Note that this is called in the main keyboard loop, - // so long running actions here can cause performance issues -} -``` +### `void backlight_increase(void)` :id=api-backlight-increase -## Example Schematic +Increase the backlight level. -In this typical example, the backlight LEDs are all connected in parallel towards an N-channel MOSFET. Its gate pin is wired to one of the microcontroller's GPIO pins through a 470Ω resistor to avoid ringing. -A pulldown resistor is also placed between the gate pin and ground to keep it at a defined state when it is not otherwise being driven by the MCU. -The values of these resistors are not critical - see [this Electronics StackExchange question](https://electronics.stackexchange.com/q/68748) for more information. +--- -![Backlight example circuit](https://i.imgur.com/BmAvoUC.png) +### `void backlight_decrease(void)` :id=api-backlight-decrease + +Decrease the backlight level. + +--- + +### `void backlight_level(uint8_t level)` :id=api-backlight-level + +Set the backlight level. + +#### Arguments :id=api-backlight-level-arguments + + - `uint8_t level` + The level to set, from 0 to `BACKLIGHT_LEVELS`. + +--- + +### `uint8_t get_backlight_level(void)` :id=api-get-backlight-level + +Get the current backlight level. + +#### Return Value :id=api-get-backlight-level-return + +The current backlight level, from 0 to `BACKLIGHT_LEVELS`. + +--- + +### `bool is_backlight_enabled(void)` :id=api-is-backlight-enabled + +Get the current backlight state. + +#### Return Value :id=api-is-backlight-enabled-return + +`true` if the backlight is enabled. + +--- + +### `void backlight_toggle_breathing(void)` :id=api-backlight-toggle-breathing + +Toggle backlight breathing on or off. + +--- + +### `void backlight_enable_breathing(void)` :id=api-backlight-enable-breathing + +Turn backlight breathing on. + +--- + +### `void backlight_disable_breathing(void)` :id=api-backlight-disable-breathing + +Turn backlight breathing off. + +--- + +### `bool is_backlight_breathing(void)` :id=api-is-backlight-breathing + +Get the current backlight breathing state. + +#### Return Value :id=api-is-backlight-breathing-return + +`true` if backlight breathing is enabled. diff --git a/keyboards/40percentclub/4pack/info.json b/keyboards/40percentclub/4pack/info.json index 9709807612..31d4559883 100644 --- a/keyboards/40percentclub/4pack/info.json +++ b/keyboards/40percentclub/4pack/info.json @@ -9,6 +9,7 @@ "device_version": "0.0.1" }, "backlight": { + "driver": "timer", "pins": ["F6", "F7"] }, "processor": "atmega32u4", diff --git a/keyboards/40percentclub/sixpack/info.json b/keyboards/40percentclub/sixpack/info.json index 3483c7d4df..cd4864fbd1 100644 --- a/keyboards/40percentclub/sixpack/info.json +++ b/keyboards/40percentclub/sixpack/info.json @@ -9,6 +9,7 @@ "device_version": "10.0.1" }, "backlight": { + "driver": "timer", "pins": ["F4", "F5"], "levels": 6, "breathing": true diff --git a/keyboards/8pack/info.json b/keyboards/8pack/info.json index fffac7d426..b572bdd0e9 100644 --- a/keyboards/8pack/info.json +++ b/keyboards/8pack/info.json @@ -8,6 +8,7 @@ "pid": "0x2171" }, "backlight": { + "driver": "timer", "pins": ["D1", "D0", "D4", "C6", "D7", "E6", "B4", "B5"], "levels": 8 }, diff --git a/keyboards/ai03/equinox/rev0/info.json b/keyboards/ai03/equinox/rev0/info.json index f5dd365564..396f50c376 100644 --- a/keyboards/ai03/equinox/rev0/info.json +++ b/keyboards/ai03/equinox/rev0/info.json @@ -5,6 +5,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "D1", "levels": 5, "breathing": true diff --git a/keyboards/amjkeyboard/amj66/info.json b/keyboards/amjkeyboard/amj66/info.json index a28b91d7c6..07a170a3f6 100644 --- a/keyboards/amjkeyboard/amj66/info.json +++ b/keyboards/amjkeyboard/amj66/info.json @@ -14,6 +14,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "D4", "breathing": true }, diff --git a/keyboards/anavi/macropad8/info.json b/keyboards/anavi/macropad8/info.json index b21f12b7d7..2ff901c0d5 100644 --- a/keyboards/anavi/macropad8/info.json +++ b/keyboards/anavi/macropad8/info.json @@ -9,6 +9,7 @@ "device_version": "0.0.1" }, "backlight": { + "driver": "timer", "pin": "D7", "breathing": true }, diff --git a/keyboards/bear_face/info.json b/keyboards/bear_face/info.json index 0c3e614803..e0df316093 100644 --- a/keyboards/bear_face/info.json +++ b/keyboards/bear_face/info.json @@ -15,6 +15,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "F7" }, "processor": "atmega32u4", diff --git a/keyboards/cablecardesigns/cypher/rev6/info.json b/keyboards/cablecardesigns/cypher/rev6/info.json index 9722db7a63..5bd725322e 100644 --- a/keyboards/cablecardesigns/cypher/rev6/info.json +++ b/keyboards/cablecardesigns/cypher/rev6/info.json @@ -14,6 +14,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "D0", "levels": 5, "breathing": true diff --git a/keyboards/cest73/tkm/info.json b/keyboards/cest73/tkm/info.json index 028e028159..6447189b93 100644 --- a/keyboards/cest73/tkm/info.json +++ b/keyboards/cest73/tkm/info.json @@ -15,6 +15,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "E6" }, "indicators": { diff --git a/keyboards/checkerboards/nop60/info.json b/keyboards/checkerboards/nop60/info.json index 8b164a9982..7dff63e711 100644 --- a/keyboards/checkerboards/nop60/info.json +++ b/keyboards/checkerboards/nop60/info.json @@ -14,6 +14,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "D1", "levels": 6, "breathing": true diff --git a/keyboards/checkerboards/quark_plus/info.json b/keyboards/checkerboards/quark_plus/info.json index 3b8803ce71..bbe63a750b 100644 --- a/keyboards/checkerboards/quark_plus/info.json +++ b/keyboards/checkerboards/quark_plus/info.json @@ -31,6 +31,7 @@ ] }, "backlight": { + "driver": "timer", "pin": "C4", "levels": 6, "breathing": true diff --git a/keyboards/checkerboards/snop60/info.json b/keyboards/checkerboards/snop60/info.json index 00194c0184..fe9f30e289 100644 --- a/keyboards/checkerboards/snop60/info.json +++ b/keyboards/checkerboards/snop60/info.json @@ -19,6 +19,7 @@ ] }, "backlight": { + "driver": "timer", "pin": "D1", "levels": 6, "breathing": true diff --git a/keyboards/efreet/info.json b/keyboards/efreet/info.json index ea2a48be25..b7749ed341 100644 --- a/keyboards/efreet/info.json +++ b/keyboards/efreet/info.json @@ -14,6 +14,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "D0", "breathing": true }, diff --git a/keyboards/gray_studio/cod67/info.json b/keyboards/gray_studio/cod67/info.json index 91b6668581..fa47399232 100644 --- a/keyboards/gray_studio/cod67/info.json +++ b/keyboards/gray_studio/cod67/info.json @@ -23,6 +23,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "D4", "on_state": 0 }, diff --git a/keyboards/handwired/bdn9_ble/info.json b/keyboards/handwired/bdn9_ble/info.json index eb6e57abde..bb8258c7cf 100644 --- a/keyboards/handwired/bdn9_ble/info.json +++ b/keyboards/handwired/bdn9_ble/info.json @@ -9,6 +9,7 @@ "device_version": "1.0.0" }, "backlight": { + "driver": "timer", "pin": "F6", "levels": 5 }, diff --git a/keyboards/kc60se/info.json b/keyboards/kc60se/info.json index afca676446..ff9fa35165 100644 --- a/keyboards/kc60se/info.json +++ b/keyboards/kc60se/info.json @@ -14,6 +14,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "F5", "levels": 6 }, diff --git a/keyboards/keebio/iris/rev1/info.json b/keyboards/keebio/iris/rev1/info.json index a389e7ae09..fef671c457 100644 --- a/keyboards/keebio/iris/rev1/info.json +++ b/keyboards/keebio/iris/rev1/info.json @@ -10,6 +10,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "D2", "levels": 5 }, diff --git a/keyboards/kopibeng/xt65/info.json b/keyboards/kopibeng/xt65/info.json index 650e0e05b2..17e61aaf4d 100644 --- a/keyboards/kopibeng/xt65/info.json +++ b/keyboards/kopibeng/xt65/info.json @@ -14,6 +14,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "B1", "levels": 5 }, diff --git a/keyboards/kprepublic/cospad/info.json b/keyboards/kprepublic/cospad/info.json index 90b9dab4a1..82b6abec6c 100644 --- a/keyboards/kprepublic/cospad/info.json +++ b/keyboards/kprepublic/cospad/info.json @@ -14,6 +14,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "F7", "on_state": 0 }, diff --git a/keyboards/ktec/daisy/info.json b/keyboards/ktec/daisy/info.json index aa9a45477a..b11e946096 100644 --- a/keyboards/ktec/daisy/info.json +++ b/keyboards/ktec/daisy/info.json @@ -14,6 +14,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "D0", "levels": 6 }, diff --git a/keyboards/ktec/staryu/info.json b/keyboards/ktec/staryu/info.json index da277a0ae0..2235bafbb3 100644 --- a/keyboards/ktec/staryu/info.json +++ b/keyboards/ktec/staryu/info.json @@ -9,6 +9,7 @@ "device_version": "2.0.5" }, "backlight": { + "driver": "timer", "pins": ["C2", "C7", "D5", "D6", "B0"], "levels": 10 }, diff --git a/keyboards/maple_computing/christmas_tree/info.json b/keyboards/maple_computing/christmas_tree/info.json index 0a19667957..e675f2f932 100644 --- a/keyboards/maple_computing/christmas_tree/info.json +++ b/keyboards/maple_computing/christmas_tree/info.json @@ -13,6 +13,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "D2" }, "processor": "atmega32u4", diff --git a/keyboards/maple_computing/ivy/rev1/info.json b/keyboards/maple_computing/ivy/rev1/info.json index 3b971cb673..de89abee75 100644 --- a/keyboards/maple_computing/ivy/rev1/info.json +++ b/keyboards/maple_computing/ivy/rev1/info.json @@ -14,6 +14,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "D2" }, "processor": "atmega32u4", diff --git a/keyboards/maple_computing/jnao/info.json b/keyboards/maple_computing/jnao/info.json index f1e753017f..73ddf107ec 100644 --- a/keyboards/maple_computing/jnao/info.json +++ b/keyboards/maple_computing/jnao/info.json @@ -14,6 +14,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "D0" }, "processor": "atmega32u4", diff --git a/keyboards/melgeek/mj6xy/rev3/info.json b/keyboards/melgeek/mj6xy/rev3/info.json index 3b5c7375a4..74e77035ca 100644 --- a/keyboards/melgeek/mj6xy/rev3/info.json +++ b/keyboards/melgeek/mj6xy/rev3/info.json @@ -5,7 +5,6 @@ }, "diode_direction": "COL2ROW", "backlight": { - "driver": "software", "pin": "B7", "levels": 10 }, diff --git a/keyboards/mntre/config.h b/keyboards/mntre/config.h index 55a7a8457e..c12ca23672 100644 --- a/keyboards/mntre/config.h +++ b/keyboards/mntre/config.h @@ -3,7 +3,7 @@ #pragma once -#define BACKLIGHT_CUSTOM_RESOLUTION 0x400 +#define BACKLIGHT_RESOLUTION 0x400 /* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */ #define LOCKING_SUPPORT_ENABLE diff --git a/keyboards/mt/mt40/info.json b/keyboards/mt/mt40/info.json index f53e9f60d4..7b4a0cac64 100644 --- a/keyboards/mt/mt40/info.json +++ b/keyboards/mt/mt40/info.json @@ -14,6 +14,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "D2" }, "rgblight": { diff --git a/keyboards/nopunin10did/jabberwocky/v2/info.json b/keyboards/nopunin10did/jabberwocky/v2/info.json index 71d6d94542..64848c0552 100644 --- a/keyboards/nopunin10did/jabberwocky/v2/info.json +++ b/keyboards/nopunin10did/jabberwocky/v2/info.json @@ -14,8 +14,8 @@ }, "diode_direction": "COL2ROW", "backlight": { - "driver": "software", - "pins": ["D6"], + "driver": "timer", + "pin": "D6", "levels": 6 }, "indicators": { diff --git a/keyboards/org60/info.json b/keyboards/org60/info.json index bc922012f0..c1de3084ed 100644 --- a/keyboards/org60/info.json +++ b/keyboards/org60/info.json @@ -14,6 +14,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "F5", "levels": 6 }, diff --git a/keyboards/playkbtw/ca66/info.json b/keyboards/playkbtw/ca66/info.json index 3f9538f31c..60b17cfb46 100644 --- a/keyboards/playkbtw/ca66/info.json +++ b/keyboards/playkbtw/ca66/info.json @@ -14,6 +14,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "F0" }, "rgblight": { diff --git a/keyboards/sandwich/keeb68/info.json b/keyboards/sandwich/keeb68/info.json index ec09badedf..df8b91a338 100644 --- a/keyboards/sandwich/keeb68/info.json +++ b/keyboards/sandwich/keeb68/info.json @@ -14,6 +14,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "C7", "levels": 5, "breathing": true diff --git a/keyboards/tkc/osav2/info.json b/keyboards/tkc/osav2/info.json index 7a59bb65db..c882c073ac 100644 --- a/keyboards/tkc/osav2/info.json +++ b/keyboards/tkc/osav2/info.json @@ -21,6 +21,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "D6", "breathing": true }, diff --git a/keyboards/v60_type_r/info.json b/keyboards/v60_type_r/info.json index 8a2b7827ce..760a4f7356 100644 --- a/keyboards/v60_type_r/info.json +++ b/keyboards/v60_type_r/info.json @@ -14,6 +14,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "F7", "on_state": 0 }, diff --git a/keyboards/viktus/osav2/info.json b/keyboards/viktus/osav2/info.json index eba02a4137..b528bac281 100644 --- a/keyboards/viktus/osav2/info.json +++ b/keyboards/viktus/osav2/info.json @@ -44,6 +44,7 @@ "pin": "D4" }, "backlight": { + "driver": "timer", "levels": 6, "max_brightness": 191, "pin": "D6" diff --git a/keyboards/westfoxtrot/cypher/rev5/info.json b/keyboards/westfoxtrot/cypher/rev5/info.json index c7e62632e2..6cb14f3b0e 100644 --- a/keyboards/westfoxtrot/cypher/rev5/info.json +++ b/keyboards/westfoxtrot/cypher/rev5/info.json @@ -12,6 +12,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "D0", "levels": 5, "breathing": true diff --git a/keyboards/xiudi/xd60/rev2/info.json b/keyboards/xiudi/xd60/rev2/info.json index 2fae5080c3..a253f14b24 100644 --- a/keyboards/xiudi/xd60/rev2/info.json +++ b/keyboards/xiudi/xd60/rev2/info.json @@ -9,6 +9,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "F5", "levels": 6, "on_state": 0 diff --git a/keyboards/xiudi/xd60/rev3/info.json b/keyboards/xiudi/xd60/rev3/info.json index c77b145607..6cc83bef59 100644 --- a/keyboards/xiudi/xd60/rev3/info.json +++ b/keyboards/xiudi/xd60/rev3/info.json @@ -9,6 +9,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "F5", "levels": 6, "on_state": 0 diff --git a/keyboards/xiudi/xd68/info.json b/keyboards/xiudi/xd68/info.json index 27f40e6ee8..5332e1243f 100644 --- a/keyboards/xiudi/xd68/info.json +++ b/keyboards/xiudi/xd68/info.json @@ -14,6 +14,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "F5", "levels": 6, "breathing": true, diff --git a/keyboards/xiudi/xd84pro/info.json b/keyboards/xiudi/xd84pro/info.json index 1df9eccb0f..697d267741 100644 --- a/keyboards/xiudi/xd84pro/info.json +++ b/keyboards/xiudi/xd84pro/info.json @@ -14,6 +14,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "F5", "levels": 10, "on_state": 0 diff --git a/keyboards/xiudi/xd87/info.json b/keyboards/xiudi/xd87/info.json index 4226947c25..74495b0f9f 100644 --- a/keyboards/xiudi/xd87/info.json +++ b/keyboards/xiudi/xd87/info.json @@ -14,6 +14,7 @@ }, "diode_direction": "COL2ROW", "backlight": { + "driver": "timer", "pin": "D0", "on_state": 0 }, diff --git a/platforms/avr/drivers/backlight_pwm.c b/platforms/avr/drivers/backlight_pwm.c index d234115641..74d25753a4 100644 --- a/platforms/avr/drivers/backlight_pwm.c +++ b/platforms/avr/drivers/backlight_pwm.c @@ -1,5 +1,5 @@ #include "backlight.h" -#include "backlight_driver_common.h" +#include "gpio.h" #include "progmem.h" #include #include @@ -9,14 +9,6 @@ # define BACKLIGHT_LIMIT_VAL 255 #endif -// This logic is a bit complex, we support 3 setups: -// -// 1. Hardware PWM when backlight is wired to a PWM pin. -// Depending on this pin, we use a different output compare unit. -// 2. Software PWM with hardware timers, but the used timer -// depends on the Audio setup (Audio wins over Backlight). -// 3. Full software PWM, driven by the matrix scan, if both timers are used by Audio. - #if (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) && (BACKLIGHT_PIN == B5 || BACKLIGHT_PIN == B6 || BACKLIGHT_PIN == B7) # define ICRx ICR1 # define TCCRxA TCCR1A @@ -122,106 +114,34 @@ # define COMxx1 COM1B1 # define OCRxx OCR1B # endif -#elif (AUDIO_PIN != B5) && (AUDIO_PIN != B6) && (AUDIO_PIN != B7) && (AUDIO_PIN_ALT != B5) && (AUDIO_PIN_ALT != B6) && (AUDIO_PIN_ALT != B7) -// Timer 1 is not in use by Audio feature, Backlight can use it -# pragma message "Using hardware timer 1 with software PWM" -# define BACKLIGHT_PWM_TIMER -# define ICRx ICR1 -# define TCCRxA TCCR1A -# define TCCRxB TCCR1B -# define TIMERx_COMPA_vect TIMER1_COMPA_vect -# define TIMERx_OVF_vect TIMER1_OVF_vect -# if defined(__AVR_ATmega32A__) // This MCU has only one TIMSK register -# define TIMSKx TIMSK -# else -# define TIMSKx TIMSK1 -# endif -# define TOIEx TOIE1 +#endif -# define OCIExA OCIE1A -# define OCRxx OCR1A -#elif (AUDIO_PIN != C4) && (AUDIO_PIN != C5) && (AUDIO_PIN != C6) -# pragma message "Using hardware timer 3 with software PWM" -// Timer 3 is not in use by Audio feature, Backlight can use it -# define BACKLIGHT_PWM_TIMER -# define ICRx ICR1 -# define TCCRxA TCCR3A -# define TCCRxB TCCR3B -# define TIMERx_COMPA_vect TIMER3_COMPA_vect -# define TIMERx_OVF_vect TIMER3_OVF_vect -# define TIMSKx TIMSK3 -# define TOIEx TOIE3 +#ifndef BACKLIGHT_RESOLUTION +# define BACKLIGHT_RESOLUTION 0xFFFFU +#endif -# define OCIExA OCIE3A -# define OCRxx OCR3A +#if (BACKLIGHT_RESOLUTION > 0xFFFF || BACKLIGHT_RESOLUTION < 0x00FF) +# error "Backlight resolution must be between 0x00FF and 0xFFFF" #endif -#ifndef BACKLIGHT_PWM_TIMER // pwm through software +#define BREATHING_SCALE_FACTOR F_CPU / BACKLIGHT_RESOLUTION / 120 static inline void enable_pwm(void) { -# if BACKLIGHT_ON_STATE == 1 +#if BACKLIGHT_ON_STATE == 1 TCCRxA |= _BV(COMxx1); -# else +#else TCCRxA |= _BV(COMxx1) | _BV(COMxx0); -# endif +#endif } static inline void disable_pwm(void) { -# if BACKLIGHT_ON_STATE == 1 +#if BACKLIGHT_ON_STATE == 1 TCCRxA &= ~(_BV(COMxx1)); -# else +#else TCCRxA &= ~(_BV(COMxx1) | _BV(COMxx0)); -# endif -} - #endif - -#ifdef BACKLIGHT_PWM_TIMER - -// The idea of software PWM assisted by hardware timers is the following -// we use the hardware timer in fast PWM mode like for hardware PWM, but -// instead of letting the Output Match Comparator control the led pin -// (which is not possible since the backlight is not wired to PWM pins on the -// CPU), we do the LED on/off by oursleves. -// The timer is setup to count up to 0xFFFF, and we set the Output Compare -// register to the current 16bits backlight level (after CIE correction). -// This means the CPU will trigger a compare match interrupt when the counter -// reaches the backlight level, where we turn off the LEDs, -// but also an overflow interrupt when the counter rolls back to 0, -// in which we're going to turn on the LEDs. -// The LED will then be on for OCRxx/0xFFFF time, adjusted every 244Hz, -// or F_CPU/BACKLIGHT_CUSTOM_RESOLUTION if used. - -// Triggered when the counter reaches the OCRx value -ISR(TIMERx_COMPA_vect) { - backlight_pins_off(); } -// Triggered when the counter reaches the TOP value -// this one triggers at F_CPU/ICRx = 16MHz/65536 =~ 244 Hz -ISR(TIMERx_OVF_vect) { -# ifdef BACKLIGHT_BREATHING - if (is_breathing()) { - breathing_task(); - } -# endif - // for very small values of OCRxx (or backlight level) - // we can't guarantee this whole code won't execute - // at the same time as the compare match interrupt - // which means that we might turn on the leds while - // trying to turn them off, leading to flickering - // artifacts (especially while breathing, because breathing_task - // takes many computation cycles). - // so better not turn them on while the counter TOP is very low. - if (OCRxx > ICRx / 250 + 5) { - backlight_pins_on(); - } -} - -#endif - -#define TIMER_TOP 0xFFFFU - // See http://jared.geek.nz/2013/feb/linear-led-pwm static uint16_t cie_lightness(uint16_t v) { if (v <= (uint32_t)ICRx / 12) // If the value is less than or equal to ~8% of max @@ -254,26 +174,11 @@ void backlight_set(uint8_t level) { if (level > BACKLIGHT_LEVELS) level = BACKLIGHT_LEVELS; if (level == 0) { -#ifdef BACKLIGHT_PWM_TIMER - if (OCRxx) { - TIMSKx &= ~(_BV(OCIExA)); - TIMSKx &= ~(_BV(TOIEx)); - } -#else // Turn off PWM control on backlight pin disable_pwm(); -#endif - backlight_pins_off(); } else { -#ifdef BACKLIGHT_PWM_TIMER - if (!OCRxx) { - TIMSKx |= _BV(OCIExA); - TIMSKx |= _BV(TOIEx); - } -#else // Turn on PWM control of backlight pin enable_pwm(); -#endif } // Set the brightness set_pwm(cie_lightness(rescale_limit_val(ICRx * (uint32_t)level / BACKLIGHT_LEVELS))); @@ -282,7 +187,6 @@ void backlight_set(uint8_t level) { void backlight_task(void) {} #ifdef BACKLIGHT_BREATHING - # define BREATHING_NO_HALT 0 # define BREATHING_HALT_OFF 1 # define BREATHING_HALT_ON 2 @@ -293,39 +197,20 @@ static uint16_t breathing_counter = 0; static uint8_t breath_scale_counter = 1; /* Run the breathing loop at ~120Hz*/ -const uint8_t breathing_ISR_frequency = 120; -static uint16_t breathing_freq_scale_factor = 2; - -# ifdef BACKLIGHT_PWM_TIMER -static bool breathing = false; - -bool is_breathing(void) { - return breathing; -} - -# define breathing_interrupt_enable() \ - do { \ - breathing = true; \ - } while (0) -# define breathing_interrupt_disable() \ - do { \ - breathing = false; \ - } while (0) -# else +const uint8_t breathing_ISR_frequency = 120; bool is_breathing(void) { return !!(TIMSKx & _BV(TOIEx)); } -# define breathing_interrupt_enable() \ - do { \ - TIMSKx |= _BV(TOIEx); \ - } while (0) -# define breathing_interrupt_disable() \ - do { \ - TIMSKx &= ~_BV(TOIEx); \ - } while (0) -# endif +# define breathing_interrupt_enable() \ + do { \ + TIMSKx |= _BV(TOIEx); \ + } while (0) +# define breathing_interrupt_disable() \ + do { \ + TIMSKx &= ~_BV(TOIEx); \ + } while (0) # define breathing_min() \ do { \ @@ -374,20 +259,14 @@ static inline uint16_t scale_backlight(uint16_t v) { return v / BACKLIGHT_LEVELS * get_backlight_level(); } -# ifdef BACKLIGHT_PWM_TIMER -void breathing_task(void) -# else /* Assuming a 16MHz CPU clock and a timer that resets at 64k (ICR1), the following interrupt handler will run * about 244 times per second. * * The following ISR runs at F_CPU/ISRx. With a 16MHz clock and default pwm resolution, that means 244Hz */ -ISR(TIMERx_OVF_vect) -# endif -{ - +ISR(TIMERx_OVF_vect) { // Only run this ISR at ~120 Hz - if (breath_scale_counter++ == breathing_freq_scale_factor) { + if (breath_scale_counter++ == BREATHING_SCALE_FACTOR) { breath_scale_counter = 1; } else { return; @@ -412,19 +291,17 @@ ISR(TIMERx_OVF_vect) #endif // BACKLIGHT_BREATHING void backlight_init_ports(void) { - // Setup backlight pin as output and output to on state. - backlight_pins_init(); + setPinOutput(BACKLIGHT_PIN); +#if BACKLIGHT_ON_STATE == 1 + writePinLow(BACKLIGHT_PIN); +#else + writePinHigh(BACKLIGHT_PIN); +#endif // I could write a wall of text here to explain... but TL;DW // Go read the ATmega32u4 datasheet. // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on -#ifdef BACKLIGHT_PWM_TIMER - // TimerX setup, Fast PWM mode count to TOP set in ICRx - TCCRxA = _BV(WGM11); // = 0b00000010; - // clock select clk/1 - TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001; -#else // hardware PWM // Pin PB7 = OCR1C (Timer 1, Channel C) // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0 // (i.e. start high, go low when counter matches.) @@ -438,23 +315,10 @@ void backlight_init_ports(void) { */ TCCRxA = _BV(COMxx1) | _BV(WGM11); // = 0b00001010; TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001; -#endif - -#ifdef BACKLIGHT_CUSTOM_RESOLUTION -# if (BACKLIGHT_CUSTOM_RESOLUTION > 0xFFFF || BACKLIGHT_CUSTOM_RESOLUTION < 1) -# error "This out of range of the timer capabilities" -# elif (BACKLIGHT_CUSTOM_RESOLUTION < 0xFF) -# warning "Resolution lower than 0xFF isn't recommended" -# endif -# ifdef BACKLIGHT_BREATHING - breathing_freq_scale_factor = F_CPU / BACKLIGHT_CUSTOM_RESOLUTION / 120; -# endif - ICRx = BACKLIGHT_CUSTOM_RESOLUTION; -#else - ICRx = TIMER_TOP; -#endif + ICRx = BACKLIGHT_RESOLUTION; backlight_init(); + #ifdef BACKLIGHT_BREATHING if (is_backlight_breathing()) { breathing_enable(); diff --git a/platforms/avr/drivers/backlight_timer.c b/platforms/avr/drivers/backlight_timer.c new file mode 100644 index 0000000000..e1f4286557 --- /dev/null +++ b/platforms/avr/drivers/backlight_timer.c @@ -0,0 +1,267 @@ +#include "backlight.h" +#include "backlight_driver_common.h" +#include "progmem.h" +#include +#include + +// Maximum duty cycle limit +#ifndef BACKLIGHT_LIMIT_VAL +# define BACKLIGHT_LIMIT_VAL 255 +#endif + +#ifndef BACKLIGHT_PWM_TIMER +# define BACKLIGHT_PWM_TIMER 1 +#endif + +#if BACKLIGHT_PWM_TIMER == 1 +# define ICRx ICR1 +# define TCCRxA TCCR1A +# define TCCRxB TCCR1B +# define TIMERx_COMPA_vect TIMER1_COMPA_vect +# define TIMERx_OVF_vect TIMER1_OVF_vect +# if defined(__AVR_ATmega32A__) // This MCU has only one TIMSK register +# define TIMSKx TIMSK +# else +# define TIMSKx TIMSK1 +# endif +# define TOIEx TOIE1 + +# define OCIExA OCIE1A +# define OCRxx OCR1A +#elif BACKLIGHT_PWM_TIMER == 3 +# define ICRx ICR1 +# define TCCRxA TCCR3A +# define TCCRxB TCCR3B +# define TIMERx_COMPA_vect TIMER3_COMPA_vect +# define TIMERx_OVF_vect TIMER3_OVF_vect +# define TIMSKx TIMSK3 +# define TOIEx TOIE3 + +# define OCIExA OCIE3A +# define OCRxx OCR3A +#else +# error Invalid backlight PWM timer! +#endif + +#ifndef BACKLIGHT_RESOLUTION +# define BACKLIGHT_RESOLUTION 0xFFFFU +#endif + +#if (BACKLIGHT_RESOLUTION > 0xFFFF || BACKLIGHT_RESOLUTION < 0x00FF) +# error "Backlight resolution must be between 0x00FF and 0xFFFF" +#endif + +#define BREATHING_SCALE_FACTOR F_CPU / BACKLIGHT_RESOLUTION / 120 + +// The idea of software PWM assisted by hardware timers is the following +// we use the hardware timer in fast PWM mode like for hardware PWM, but +// instead of letting the Output Match Comparator control the led pin +// (which is not possible since the backlight is not wired to PWM pins on the +// CPU), we do the LED on/off by oursleves. +// The timer is setup to count up to 0xFFFF, and we set the Output Compare +// register to the current 16bits backlight level (after CIE correction). +// This means the CPU will trigger a compare match interrupt when the counter +// reaches the backlight level, where we turn off the LEDs, +// but also an overflow interrupt when the counter rolls back to 0, +// in which we're going to turn on the LEDs. +// The LED will then be on for OCRxx/0xFFFF time, adjusted every 244Hz, +// or F_CPU/BACKLIGHT_RESOLUTION if used. + +// Triggered when the counter reaches the OCRx value +ISR(TIMERx_COMPA_vect) { + backlight_pins_off(); +} + +// Triggered when the counter reaches the TOP value +// this one triggers at F_CPU/ICRx = 16MHz/65536 =~ 244 Hz +ISR(TIMERx_OVF_vect) { +#ifdef BACKLIGHT_BREATHING + if (is_breathing()) { + breathing_task(); + } +#endif + // for very small values of OCRxx (or backlight level) + // we can't guarantee this whole code won't execute + // at the same time as the compare match interrupt + // which means that we might turn on the leds while + // trying to turn them off, leading to flickering + // artifacts (especially while breathing, because breathing_task + // takes many computation cycles). + // so better not turn them on while the counter TOP is very low. + if (OCRxx > ICRx / 250 + 5) { + backlight_pins_on(); + } +} + +// See http://jared.geek.nz/2013/feb/linear-led-pwm +static uint16_t cie_lightness(uint16_t v) { + if (v <= (uint32_t)ICRx / 12) // If the value is less than or equal to ~8% of max + { + return v / 9; // Same as dividing by 900% + } else { + // In the next two lines values are bit-shifted. This is to avoid loosing decimals in integer math. + uint32_t y = (((uint32_t)v + (uint32_t)ICRx / 6) << 5) / ((uint32_t)ICRx / 6 + ICRx); // If above 8%, add ~16% of max, and normalize with (max + ~16% max) + uint32_t out = (y * y * y * ICRx) >> 15; // Cube it and undo the bit-shifting. (which is now three times as much due to the cubing) + + if (out > ICRx) // Avoid overflows + { + out = ICRx; + } + return (uint16_t)out; + } +} + +// rescale the supplied backlight value to be in terms of the value limit // range for val is [0..ICRx]. PWM pin is high while the timer count is below val. +static uint32_t rescale_limit_val(uint32_t val) { + return (val * (BACKLIGHT_LIMIT_VAL + 1)) / 256; +} + +// range for val is [0..ICRx]. PWM pin is high while the timer count is below val. +static inline void set_pwm(uint16_t val) { + OCRxx = val; +} + +void backlight_set(uint8_t level) { + if (level > BACKLIGHT_LEVELS) level = BACKLIGHT_LEVELS; + + if (level == 0) { + if (OCRxx) { + TIMSKx &= ~(_BV(OCIExA)); + TIMSKx &= ~(_BV(TOIEx)); + } + backlight_pins_off(); + } else { + if (!OCRxx) { + TIMSKx |= _BV(OCIExA); + TIMSKx |= _BV(TOIEx); + } + } + // Set the brightness + set_pwm(cie_lightness(rescale_limit_val(ICRx * (uint32_t)level / BACKLIGHT_LEVELS))); +} + +void backlight_task(void) {} + +#ifdef BACKLIGHT_BREATHING +# define BREATHING_NO_HALT 0 +# define BREATHING_HALT_OFF 1 +# define BREATHING_HALT_ON 2 +# define BREATHING_STEPS 128 + +static uint8_t breathing_halt = BREATHING_NO_HALT; +static uint16_t breathing_counter = 0; + +static uint8_t breath_scale_counter = 1; +/* Run the breathing loop at ~120Hz*/ +const uint8_t breathing_ISR_frequency = 120; + +static bool breathing = false; + +bool is_breathing(void) { + return breathing; +} + +# define breathing_interrupt_enable() \ + do { \ + breathing = true; \ + } while (0) +# define breathing_interrupt_disable() \ + do { \ + breathing = false; \ + } while (0) + +# define breathing_min() \ + do { \ + breathing_counter = 0; \ + } while (0) +# define breathing_max() \ + do { \ + breathing_counter = get_breathing_period() * breathing_ISR_frequency / 2; \ + } while (0) + +void breathing_enable(void) { + breathing_counter = 0; + breathing_halt = BREATHING_NO_HALT; + breathing_interrupt_enable(); +} + +void breathing_pulse(void) { + if (get_backlight_level() == 0) + breathing_min(); + else + breathing_max(); + breathing_halt = BREATHING_HALT_ON; + breathing_interrupt_enable(); +} + +void breathing_disable(void) { + breathing_interrupt_disable(); + // Restore backlight level + backlight_set(get_backlight_level()); +} + +void breathing_self_disable(void) { + if (get_backlight_level() == 0) + breathing_halt = BREATHING_HALT_OFF; + else + breathing_halt = BREATHING_HALT_ON; +} + +/* To generate breathing curve in python: + * from math import sin, pi; [int(sin(x/128.0*pi)**4*255) for x in range(128)] + */ +static const uint8_t breathing_table[BREATHING_STEPS] PROGMEM = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 17, 20, 24, 28, 32, 36, 41, 46, 51, 57, 63, 70, 76, 83, 91, 98, 106, 113, 121, 129, 138, 146, 154, 162, 170, 178, 185, 193, 200, 207, 213, 220, 225, 231, 235, 240, 244, 247, 250, 252, 253, 254, 255, 254, 253, 252, 250, 247, 244, 240, 235, 231, 225, 220, 213, 207, 200, 193, 185, 178, 170, 162, 154, 146, 138, 129, 121, 113, 106, 98, 91, 83, 76, 70, 63, 57, 51, 46, 41, 36, 32, 28, 24, 20, 17, 15, 12, 10, 8, 6, 5, 4, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +// Use this before the cie_lightness function. +static inline uint16_t scale_backlight(uint16_t v) { + return v / BACKLIGHT_LEVELS * get_backlight_level(); +} + +void breathing_task(void) { + // Only run this ISR at ~120 Hz + if (breath_scale_counter++ == BREATHING_SCALE_FACTOR) { + breath_scale_counter = 1; + } else { + return; + } + uint16_t interval = (uint16_t)get_breathing_period() * breathing_ISR_frequency / BREATHING_STEPS; + // resetting after one period to prevent ugly reset at overflow. + breathing_counter = (breathing_counter + 1) % (get_breathing_period() * breathing_ISR_frequency); + uint8_t index = breathing_counter / interval; + // limit index to max step value + if (index >= BREATHING_STEPS) { + index = BREATHING_STEPS - 1; + } + + if (((breathing_halt == BREATHING_HALT_ON) && (index == BREATHING_STEPS / 2)) || ((breathing_halt == BREATHING_HALT_OFF) && (index == BREATHING_STEPS - 1))) { + breathing_interrupt_disable(); + } + + // Set PWM to a brightnessvalue scaled to the configured resolution + set_pwm(cie_lightness(rescale_limit_val(scale_backlight((uint32_t)pgm_read_byte(&breathing_table[index]) * ICRx / 255)))); +} + +#endif // BACKLIGHT_BREATHING + +void backlight_init_ports(void) { + // Setup backlight pin as output and output to on state. + backlight_pins_init(); + + // I could write a wall of text here to explain... but TL;DW + // Go read the ATmega32u4 datasheet. + // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on + + // TimerX setup, Fast PWM mode count to TOP set in ICRx + TCCRxA = _BV(WGM11); // = 0b00000010; + // clock select clk/1 + TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001; + ICRx = BACKLIGHT_RESOLUTION; + + backlight_init(); + +#ifdef BACKLIGHT_BREATHING + if (is_backlight_breathing()) { + breathing_enable(); + } +#endif +} -- cgit v1.2.3