Skip to content

Commit

Permalink
ARM - Initial backlight support (qmk#6487)
Browse files Browse the repository at this point in the history
* Move AVR backlight to own file, add borrowed ARM implementation

* Tiny fix for backlight custom logic

* Remove duplicate board from rebase

* Fix f303 onekey example

* clang-format

* clang-format

* Remove backlight keymap debug

* Initial pass of ARM backlight docs

* Initial pass of ARM backlight docs - resolve todos

* fix rules validation logic

* Add f072 warning

* Add f072 warning

* tidy up breathing in backlight keymap

* tidy up breathing in backlight keymap

* add missing break to backlight keymap
  • Loading branch information
zvecr authored Oct 5, 2019
1 parent 60b2a9a commit 38aefaf
Show file tree
Hide file tree
Showing 17 changed files with 860 additions and 529 deletions.
23 changes: 21 additions & 2 deletions common_features.mk
Original file line number Diff line number Diff line change
Expand Up @@ -229,13 +229,32 @@ ifeq ($(strip $(LCD_ENABLE)), yes)
CIE1931_CURVE = yes
endif

ifeq ($(strip $(BACKLIGHT_ENABLE)), yes)
# backward compat
ifeq ($(strip $(BACKLIGHT_CUSTOM_DRIVER)), yes)
BACKLIGHT_ENABLE = custom
endif

VALID_BACKLIGHT_TYPES := yes custom

BACKLIGHT_ENABLE ?= no
ifneq ($(strip $(BACKLIGHT_ENABLE)), no)
ifeq ($(filter $(BACKLIGHT_ENABLE),$(VALID_BACKLIGHT_TYPES)),)
$(error BACKLIGHT_ENABLE="$(BACKLIGHT_ENABLE)" is not a valid backlight type)
endif

ifeq ($(strip $(VISUALIZER_ENABLE)), yes)
CIE1931_CURVE = yes
endif
ifeq ($(strip $(BACKLIGHT_CUSTOM_DRIVER)), yes)

ifeq ($(strip $(BACKLIGHT_ENABLE)), custom)
OPT_DEFS += -DBACKLIGHT_CUSTOM_DRIVER
endif

ifeq ($(PLATFORM),AVR)
SRC += $(QUANTUM_DIR)/backlight/backlight_avr.c
else
SRC += $(QUANTUM_DIR)/backlight/backlight_arm.c
endif
endif

ifeq ($(strip $(CIE1931_CURVE)), yes)
Expand Down
50 changes: 37 additions & 13 deletions docs/feature_backlight.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Backlighting

Many keyboards support backlit keys by way of individual LEDs placed through or underneath the keyswitches. 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.
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.

Expand All @@ -12,9 +14,8 @@ Most keyboards have backlighting enabled by default if they support it, but if i
BACKLIGHT_ENABLE = yes
```

You should then be able to use the keycodes below to change the backlight level.

## Keycodes
Once enabled the following keycodes below can be used to change the backlight level.

|Key |Description |
|---------|------------------------------------------|
Expand All @@ -26,9 +27,9 @@ You should then be able to use the keycodes below to change the backlight level.
|`BL_DEC` |Decrease the backlight level |
|`BL_BRTG`|Toggle backlight breathing |

## Caveats
## AVR driver

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 use multiple different coloured LEDs on a keyboard.
### Caveats

Hardware PWM is supported according to the following table:

Expand Down Expand Up @@ -58,9 +59,9 @@ All other pins will use software PWM. If the [Audio](feature_audio.md) feature i

When both timers are in use for Audio, the backlight PWM will not use a hardware timer, but 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.

## Configuration
### AVR Configuration

To change the behaviour of the backlighting, `#define` these in your `config.h`:
To change the behavior of the backlighting, `#define` these in your `config.h`:

|Define |Default |Description |
|---------------------|-------------|-------------------------------------------------------------------------------------------------------------|
Expand All @@ -72,28 +73,28 @@ To change the behaviour of the backlighting, `#define` these in your `config.h`:
|`BREATHING_PERIOD` |`6` |The length of one backlight "breath" in seconds |
|`BACKLIGHT_ON_STATE` |`0` |The state of the backlight pin when the backlight is "on" - `1` for high, `0` for low |

## Backlight On State
### Backlight 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.

## Multiple backlight pins
### Multiple backlight pins

Most keyboards have only one backlight pin which control all backlight LEDs (especially if the backlight is connected to an hardware PWM pin).
In software PWM, it is possible to define multiple backlight pins. All those pins 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 (or any other controllable LED) brightness at the same level as the other LEDs of the backlight. This is useful if you have mapped LCTRL 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.

To activate multiple backlight pins, you need to add something like this to your user `config.h`:

~~~c
```c
#define BACKLIGHT_LED_COUNT 2
#undef BACKLIGHT_PIN
#define BACKLIGHT_PINS { F5, B2 }
~~~
```
## Hardware PWM Implementation
### Hardware PWM Implementation
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.
Expand All @@ -102,7 +103,7 @@ In this way `OCRxx` essentially controls the duty cycle of the LEDs, and thus th
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.
## Software PWM Implementation
### Software PWM Implementation
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.
Expand All @@ -111,6 +112,29 @@ In this way `OCRxx` essentially controls the duty cycle of the LEDs, and thus th
The breathing effect is the same as in the hardware PWM implementation.
## ARM Driver
### Caveats
Currently only hardware PWM is supported, and does not provide automatic configuration.
?> STMF072 support is being investigated.
### ARM Configuration
To change the behavior of the backlighting, `#define` these in your `config.h`:
|Define |Default |Description |
|------------------------|-------------|-------------------------------------------------------------------------------------------------------------|
|`BACKLIGHT_PIN` |`B7` |The pin that controls the LEDs. Unless you are designing your own keyboard, you shouldn't need to change this|
|`BACKLIGHT_PWM_DRIVER` |`PWMD4` |The PWM driver to use, see ST datasheets for pin to PWM timer mapping. Unless you are designing your own keyboard, you shouldn't need to change this|
|`BACKLIGHT_PWM_CHANNEL` |`3` |The PWM channel to use, see ST datasheets for pin to PWM channel mapping. Unless you are designing your own keyboard, you shouldn't need to change this|
|`BACKLIGHT_PAL_MODE` |`2` |The pin alternative function to use, see ST datasheets for pin AF mapping. Unless you are designing your own keyboard, you shouldn't need to change this|
|`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 |
|`BREATHING_PERIOD` |`6` |The length of one backlight "breath" in seconds |
## Backlight Functions
|Function |Description |
Expand Down
4 changes: 4 additions & 0 deletions keyboards/handwired/onekey/bluepill/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@
#define MATRIX_COL_PINS { B0 }
#define MATRIX_ROW_PINS { A7 }
#define UNUSED_PINS

#define BACKLIGHT_PIN A0
#define BACKLIGHT_PWM_DRIVER PWMD2
#define BACKLIGHT_PWM_CHANNEL 1
2 changes: 1 addition & 1 deletion keyboards/handwired/onekey/bluepill/halconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@
* @brief Enables the SPI subsystem.
*/
#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__)
#define HAL_USE_SPI TRUE
#define HAL_USE_SPI FALSE
#endif

/**
Expand Down
6 changes: 3 additions & 3 deletions keyboards/handwired/onekey/bluepill/mcuconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@
* PWM driver system settings.
*/
#define STM32_PWM_USE_ADVANCED FALSE
#define STM32_PWM_USE_TIM1 TRUE
#define STM32_PWM_USE_TIM2 FALSE
#define STM32_PWM_USE_TIM1 FALSE
#define STM32_PWM_USE_TIM2 TRUE
#define STM32_PWM_USE_TIM3 FALSE
#define STM32_PWM_USE_TIM4 FALSE
#define STM32_PWM_USE_TIM5 FALSE
Expand Down Expand Up @@ -168,7 +168,7 @@
* SPI driver system settings.
*/
#define STM32_SPI_USE_SPI1 FALSE
#define STM32_SPI_USE_SPI2 TRUE
#define STM32_SPI_USE_SPI2 FALSE
#define STM32_SPI_USE_SPI3 FALSE
#define STM32_SPI_SPI1_DMA_PRIORITY 1
#define STM32_SPI_SPI2_DMA_PRIORITY 1
Expand Down
6 changes: 5 additions & 1 deletion keyboards/handwired/onekey/bluepill/rules.mk
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
# GENERIC STM32F103C8T6 board - stm32duino bootloader
BOARD = GENERIC_STM32_F103

OPT_DEFS = -DCORTEX_VTOR_INIT=0x2000
MCU_LDSCRIPT = STM32F103x8_stm32duino_bootloader
BOARD = GENERIC_STM32_F103

DFU_ARGS = -d 1eaf:0003 -a2 -R
DFU_SUFFIX_ARGS ?= -v 1eaf -p 0003

# OPT_DEFS =
# MCU_LDSCRIPT = STM32F103x8
Expand Down
2 changes: 2 additions & 0 deletions keyboards/handwired/onekey/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
/* Set 0 if debouncing isn't needed */
#define DEBOUNCE 5

#define TAPPING_TERM 500

/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */
#define LOCKING_SUPPORT_ENABLE
/* Locking resynchronize hack */
Expand Down
3 changes: 3 additions & 0 deletions keyboards/handwired/onekey/keymaps/backlight/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#define BACKLIGHT_BREATHING
40 changes: 40 additions & 0 deletions keyboards/handwired/onekey/keymaps/backlight/keymap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include QMK_KEYBOARD_H

//Tap Dance Declarations
enum {
TD_BL = 0
};

void dance_cln_finished (qk_tap_dance_state_t *state, void *user_data) {
// noop
}

void dance_cln_reset (qk_tap_dance_state_t *state, void *user_data) {
switch (state->count) {
case 1:
// single tap - step through backlight
backlight_step();
break;
#ifdef BACKLIGHT_BREATHING
case 2:
// double tap - toggle breathing
breathing_toggle();
break;
case 3:
//tripple tap - do some pulse stuff
breathing_pulse();
break;
#endif
default:
// more - nothing
break;
}
}

qk_tap_dance_action_t tap_dance_actions[] = {
[TD_BL] = ACTION_TAP_DANCE_FN_ADVANCED (NULL, dance_cln_finished, dance_cln_reset)
};

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
LAYOUT( TD(TD_BL) )
};
2 changes: 2 additions & 0 deletions keyboards/handwired/onekey/keymaps/backlight/rules.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
BACKLIGHT_ENABLE = yes
TAP_DANCE_ENABLE = yes
5 changes: 5 additions & 0 deletions keyboards/handwired/onekey/proton_c/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,8 @@
#define MATRIX_COL_PINS { A3 }
#define MATRIX_ROW_PINS { A2 }
#define UNUSED_PINS

#define BACKLIGHT_PIN B8
#define BACKLIGHT_PWM_DRIVER PWMD4
#define BACKLIGHT_PWM_CHANNEL 3
#define BACKLIGHT_PAL_MODE 2
5 changes: 5 additions & 0 deletions keyboards/handwired/onekey/stm32f0_disco/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,8 @@
#define MATRIX_COL_PINS { B4 }
#define MATRIX_ROW_PINS { B5 }
#define UNUSED_PINS

#define BACKLIGHT_PIN C8
#define BACKLIGHT_PWM_DRIVER PWMD3
#define BACKLIGHT_PWM_CHANNEL 3
#define BACKLIGHT_PAL_MODE 0
1 change: 1 addition & 0 deletions quantum/backlight/backlight.c
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// TODO: Add common code here, for example cie_lightness implementation
Loading

0 comments on commit 38aefaf

Please sign in to comment.