aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common_features.mk21
-rw-r--r--docs/feature_backlight.md131
-rw-r--r--quantum/backlight/backlight_avr.c10
-rw-r--r--quantum/backlight/backlight_soft.c66
-rw-r--r--quantum/quantum.c2
-rw-r--r--quantum/quantum.h4
6 files changed, 173 insertions, 61 deletions
diff --git a/common_features.mk b/common_features.mk
index 7bb9187bb..a1f95955a 100644
--- a/common_features.mk
+++ b/common_features.mk
@@ -234,7 +234,7 @@ ifeq ($(strip $(BACKLIGHT_CUSTOM_DRIVER)), yes)
234 BACKLIGHT_ENABLE = custom 234 BACKLIGHT_ENABLE = custom
235endif 235endif
236 236
237VALID_BACKLIGHT_TYPES := yes custom 237VALID_BACKLIGHT_TYPES := yes software custom
238 238
239BACKLIGHT_ENABLE ?= no 239BACKLIGHT_ENABLE ?= no
240ifneq ($(strip $(BACKLIGHT_ENABLE)), no) 240ifneq ($(strip $(BACKLIGHT_ENABLE)), no)
@@ -246,19 +246,22 @@ ifneq ($(strip $(BACKLIGHT_ENABLE)), no)
246 CIE1931_CURVE = yes 246 CIE1931_CURVE = yes
247 endif 247 endif
248 248
249
250 COMMON_VPATH += $(QUANTUM_DIR)/backlight 249 COMMON_VPATH += $(QUANTUM_DIR)/backlight
251 SRC += $(QUANTUM_DIR)/backlight/backlight.c 250 SRC += $(QUANTUM_DIR)/backlight/backlight.c
252 OPT_DEFS += -DBACKLIGHT_ENABLE 251 OPT_DEFS += -DBACKLIGHT_ENABLE
253 252
254 ifeq ($(strip $(BACKLIGHT_ENABLE)), custom) 253 ifeq ($(strip $(BACKLIGHT_ENABLE)), software)
255 OPT_DEFS += -DBACKLIGHT_CUSTOM_DRIVER 254 SRC += $(QUANTUM_DIR)/backlight/backlight_soft.c
256 endif
257
258 ifeq ($(PLATFORM),AVR)
259 SRC += $(QUANTUM_DIR)/backlight/backlight_avr.c
260 else 255 else
261 SRC += $(QUANTUM_DIR)/backlight/backlight_arm.c 256 ifeq ($(strip $(BACKLIGHT_ENABLE)), custom)
257 OPT_DEFS += -DBACKLIGHT_CUSTOM_DRIVER
258 endif
259
260 ifeq ($(PLATFORM),AVR)
261 SRC += $(QUANTUM_DIR)/backlight/backlight_avr.c
262 else
263 SRC += $(QUANTUM_DIR)/backlight/backlight_arm.c
264 endif
262 endif 265 endif
263endif 266endif
264 267
diff --git a/docs/feature_backlight.md b/docs/feature_backlight.md
index 6a2946fd6..71f375594 100644
--- a/docs/feature_backlight.md
+++ b/docs/feature_backlight.md
@@ -6,14 +6,16 @@ QMK is able to control the brightness of these LEDs by switching them on and off
6 6
7The 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. 7The 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.
8 8
9## Usage 9## Driver configuration
10 10
11Most 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: 11Most 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:
12 12
13```make 13```makefile
14BACKLIGHT_ENABLE = yes 14BACKLIGHT_ENABLE = software # Valid driver values are 'yes,software,no'
15``` 15```
16 16
17See below for help on individual drivers.
18
17## Keycodes 19## Keycodes
18Once enabled the following keycodes below can be used to change the backlight level. 20Once enabled the following keycodes below can be used to change the backlight level.
19 21
@@ -27,8 +29,54 @@ Once enabled the following keycodes below can be used to change the backlight le
27|`BL_DEC` |Decrease the backlight level | 29|`BL_DEC` |Decrease the backlight level |
28|`BL_BRTG`|Toggle backlight breathing | 30|`BL_BRTG`|Toggle backlight breathing |
29 31
32## Backlight Functions
33
34|Function |Description |
35|----------|-----------------------------------------------------------|
36|`backlight_toggle()` |Turn the backlight on or off |
37|`backlight_enable()` |Turn the backlight on |
38|`backlight_disable()` |Turn the backlight off |
39|`backlight_step()` |Cycle through backlight levels |
40|`backlight_increase()` |Increase the backlight level |
41|`backlight_decrease()` |Decrease the backlight level |
42|`backlight_level(x)` |Sets the backlight level to specified level |
43|`get_backlight_level()` |Return the current backlight level |
44|`is_backlight_enabled()`|Return whether the backlight is currently on |
45
46### Backlight Breathing Functions
47
48|Function |Description |
49|----------|---------------------------------------------------|
50|`breathing_toggle()` |Turn the backlight breathing on or off |
51|`breathing_enable()` |Turns on backlight breathing |
52|`breathing_disable()` |Turns off backlight breathing |
53
54## Common Driver Configuration
55
56To change the behavior of the backlighting, `#define` these in your `config.h`:
57
58|Define |Default |Description |
59|---------------------|-------------|--------------------------------------------------------------------------------------|
60|`BACKLIGHT_LEVELS` |`3` |The number of brightness levels (maximum 31 excluding off) |
61|`BACKLIGHT_CAPS_LOCK`|*Not defined*|Enable Caps Lock indicator using backlight (for keyboards without dedicated LED) |
62|`BACKLIGHT_BREATHING`|*Not defined*|Enable backlight breathing, if supported |
63|`BREATHING_PERIOD` |`6` |The length of one backlight "breath" in seconds |
64|`BACKLIGHT_ON_STATE` |`0` |The state of the backlight pin when the backlight is "on" - `1` for high, `0` for low |
65
66### Backlight On State
67
68Most 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*.
69Sometimes, 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.
70
71This functionality is configured at the keyboard level with the `BACKLIGHT_ON_STATE` define.
72
30## AVR driver 73## AVR driver
31 74
75On AVR boards, the default driver currently sniffs the configuration to pick the best scenario. To enable it, add this to your rules.mk:
76```makefile
77BACKLIGHT_ENABLE = yes
78```
79
32### Caveats 80### Caveats
33 81
34Hardware PWM is supported according to the following table: 82Hardware PWM is supported according to the following table:
@@ -63,22 +111,10 @@ When both timers are in use for Audio, the backlight PWM will not use a hardware
63 111
64To change the behavior of the backlighting, `#define` these in your `config.h`: 112To change the behavior of the backlighting, `#define` these in your `config.h`:
65 113
66|Define |Default |Description | 114|Define |Default |Description |
67|---------------------|-------------|-------------------------------------------------------------------------------------------------------------| 115|---------------------|-------------|--------------------------------------------------------------------------------------------------------------|
68|`BACKLIGHT_PIN` |`B7` |The pin that controls the LEDs. Unless you are designing your own keyboard, you shouldn't need to change this| 116|`BACKLIGHT_PIN` |`B7` |The pin that controls the LEDs. Unless you are designing your own keyboard, you shouldn't need to change this |
69|`BACKLIGHT_PINS` |*Not defined*|experimental: see below for more information | 117|`BACKLIGHT_PINS` |*Not defined*|experimental: see below for more information |
70|`BACKLIGHT_LEVELS` |`3` |The number of brightness levels (maximum 31 excluding off) |
71|`BACKLIGHT_CAPS_LOCK`|*Not defined*|Enable Caps Lock indicator using backlight (for keyboards without dedicated LED) |
72|`BACKLIGHT_BREATHING`|*Not defined*|Enable backlight breathing, if supported |
73|`BREATHING_PERIOD` |`6` |The length of one backlight "breath" in seconds |
74|`BACKLIGHT_ON_STATE` |`0` |The state of the backlight pin when the backlight is "on" - `1` for high, `0` for low |
75
76### Backlight On State
77
78Most 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*.
79Sometimes, 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.
80
81This functionality is configured at the keyboard level with the `BACKLIGHT_ON_STATE` define.
82 118
83### Multiple backlight pins 119### Multiple backlight pins
84 120
@@ -103,7 +139,7 @@ In this way `OCRxx` essentially controls the duty cycle of the LEDs, and thus th
103The 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. 139The 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.
104In 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. 140In 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.
105 141
106### Software PWM Implementation 142### Timer Assisted PWM Implementation
107 143
108When `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. 144When `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.
109When resetting to 0, the CPU will fire an OVF (overflow) interrupt that will turn the LEDs on, starting the duty cycle. 145When resetting to 0, the CPU will fire an OVF (overflow) interrupt that will turn the LEDs on, starting the duty cycle.
@@ -114,9 +150,14 @@ The breathing effect is the same as in the hardware PWM implementation.
114 150
115## ARM Driver 151## ARM Driver
116 152
153While still in its early stages, ARM backlight support aims to eventually have feature parity with AVR. To enable it, add this to your rules.mk:
154```makefile
155BACKLIGHT_ENABLE = yes
156```
157
117### Caveats 158### Caveats
118 159
119Currently only hardware PWM is supported, and does not provide automatic configuration. 160Currently only hardware PWM is supported, not timer assisted, and does not provide automatic configuration.
120 161
121?> STMF072 support is being investigated. 162?> STMF072 support is being investigated.
122 163
@@ -130,30 +171,32 @@ To change the behavior of the backlighting, `#define` these in your `config.h`:
130|`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| 171|`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|
131|`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| 172|`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|
132|`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| 173|`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|
133|`BACKLIGHT_LEVELS` |`3` |The number of brightness levels (maximum 31 excluding off) |
134|`BACKLIGHT_CAPS_LOCK` |*Not defined*|Enable Caps Lock indicator using backlight (for keyboards without dedicated LED) |
135|`BACKLIGHT_BREATHING` |*Not defined*|Enable backlight breathing, if supported |
136|`BREATHING_PERIOD` |`6` |The length of one backlight "breath" in seconds |
137 174
138## Backlight Functions 175## Software PWM Driver
139 176
140|Function |Description | 177Emulation of PWM 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:
141|----------|-----------------------------------------------------------| 178```makefile
142|`backlight_toggle()` |Turn the backlight on or off | 179BACKLIGHT_ENABLE = software
143|`backlight_enable()` |Turn the backlight on | 180```
144|`backlight_disable()` |Turn the backlight off |
145|`backlight_step()` |Cycle through backlight levels |
146|`backlight_increase()` |Increase the backlight level |
147|`backlight_decrease()` |Decrease the backlight level |
148|`backlight_level(x)` |Sets the backlight level, from 0 to |
149| |`BACKLIGHT_LEVELS` |
150|`get_backlight_level()` |Return the current backlight level |
151|`is_backlight_enabled()`|Return whether the backlight is currently on |
152 181
153### Backlight Breathing Functions 182### Software PWM Configuration
183
184To change the behavior of the backlighting, `#define` these in your `config.h`:
185
186|Define |Default |Description |
187|-----------------|-------------|-------------------------------------------------------------------------------------------------------------|
188|`BACKLIGHT_PIN` |`B7` |The pin that controls the LEDs. Unless you are designing your own keyboard, you shouldn't need to change this|
189|`BACKLIGHT_PINS` |*Not defined*|experimental: see below for more information |
154 190
155|Function |Description | 191### Multiple backlight pins
156|----------|----------------------------------------------------------| 192
157|`breathing_toggle()` |Turn the backlight breathing on or off | 193Most keyboards have only one backlight pin which control all backlight LEDs (especially if the backlight is connected to an hardware PWM pin).
158|`breathing_enable()` |Turns on backlight breathing | 194In 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.
159|`breathing_disable()` |Turns off backlight breathing | 195This 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.
196
197To activate multiple backlight pins, you need to add something like this to your user `config.h`:
198
199```c
200#undef BACKLIGHT_PIN
201#define BACKLIGHT_PINS { F5, B2 }
202```
diff --git a/quantum/backlight/backlight_avr.c b/quantum/backlight/backlight_avr.c
index 445698f47..648a37adf 100644
--- a/quantum/backlight/backlight_avr.c
+++ b/quantum/backlight/backlight_avr.c
@@ -159,7 +159,7 @@
159# define BACKLIGHT_ON_STATE 0 159# define BACKLIGHT_ON_STATE 0
160# endif 160# endif
161 161
162void backlight_on(uint8_t backlight_pin) { 162void backlight_on(pin_t backlight_pin) {
163# if BACKLIGHT_ON_STATE == 0 163# if BACKLIGHT_ON_STATE == 0
164 writePinLow(backlight_pin); 164 writePinLow(backlight_pin);
165# else 165# else
@@ -167,7 +167,7 @@ void backlight_on(uint8_t backlight_pin) {
167# endif 167# endif
168} 168}
169 169
170void backlight_off(uint8_t backlight_pin) { 170void backlight_off(pin_t backlight_pin) {
171# if BACKLIGHT_ON_STATE == 0 171# if BACKLIGHT_ON_STATE == 0
172 writePinHigh(backlight_pin); 172 writePinHigh(backlight_pin);
173# else 173# else
@@ -191,16 +191,16 @@ void backlight_off(uint8_t backlight_pin) {
191 191
192# define FOR_EACH_LED(x) \ 192# define FOR_EACH_LED(x) \
193 for (uint8_t i = 0; i < BACKLIGHT_LED_COUNT; i++) { \ 193 for (uint8_t i = 0; i < BACKLIGHT_LED_COUNT; i++) { \
194 uint8_t backlight_pin = backlight_pins[i]; \ 194 pin_t backlight_pin = backlight_pins[i]; \
195 { x } \ 195 { x } \
196 } 196 }
197 197
198static const uint8_t backlight_pins[BACKLIGHT_LED_COUNT] = BACKLIGHT_PIN_INIT; 198static const pin_t backlight_pins[BACKLIGHT_LED_COUNT] = BACKLIGHT_PIN_INIT;
199 199
200# else // full hardware PWM 200# else // full hardware PWM
201 201
202// we support only one backlight pin 202// we support only one backlight pin
203static const uint8_t backlight_pin = BACKLIGHT_PIN; 203static const pin_t backlight_pin = BACKLIGHT_PIN;
204# define FOR_EACH_LED(x) x 204# define FOR_EACH_LED(x) x
205 205
206# endif 206# endif
diff --git a/quantum/backlight/backlight_soft.c b/quantum/backlight/backlight_soft.c
new file mode 100644
index 000000000..a6aba7782
--- /dev/null
+++ b/quantum/backlight/backlight_soft.c
@@ -0,0 +1,66 @@
1#include "quantum.h"
2#include "backlight.h"
3
4#if !defined(BACKLIGHT_PIN) && !defined(BACKLIGHT_PINS)
5# error "Backlight pin/pins not defined. Please configure."
6#endif
7
8#ifdef BACKLIGHT_BREATHING
9# error "Backlight breathing is not available for software PWM. Please disable."
10#endif
11
12#ifndef BACKLIGHT_ON_STATE
13# define BACKLIGHT_ON_STATE 0
14#endif
15
16#ifdef BACKLIGHT_PINS
17# define BACKLIGHT_PIN_INIT BACKLIGHT_PINS
18#else
19# define BACKLIGHT_PIN_INIT \
20 { BACKLIGHT_PIN }
21#endif
22
23static const pin_t backlight_pins[] = BACKLIGHT_PIN_INIT;
24#define BACKLIGHT_LED_COUNT (sizeof(backlight_pins) / sizeof(pin_t))
25
26#define FOR_EACH_LED(x) \
27 for (uint8_t i = 0; i < BACKLIGHT_LED_COUNT; i++) { \
28 pin_t backlight_pin = backlight_pins[i]; \
29 { x } \
30 }
31
32void backlight_on(pin_t backlight_pin) {
33#if BACKLIGHT_ON_STATE == 0
34 writePinLow(backlight_pin);
35#else
36 writePinHigh(backlight_pin);
37#endif
38}
39
40void backlight_off(pin_t backlight_pin) {
41#if BACKLIGHT_ON_STATE == 0
42 writePinHigh(backlight_pin);
43#else
44 writePinLow(backlight_pin);
45#endif
46}
47
48void backlight_init_ports(void) {
49 // Setup backlight pin as output and output to on state.
50 FOR_EACH_LED(setPinOutput(backlight_pin); backlight_on(backlight_pin);)
51}
52
53void backlight_task(void) {
54 static uint8_t backlight_tick = 0;
55
56 if ((0xFFFF >> (get_backlight_level() * ((BACKLIGHT_LEVELS + 1) / 2))) & (1 << backlight_tick)) {
57 FOR_EACH_LED(backlight_on(backlight_pin);)
58 } else {
59 FOR_EACH_LED(backlight_off(backlight_pin);)
60 }
61 backlight_tick = (backlight_tick + 1) % 16;
62}
63
64void backlight_set(uint8_t level) {
65 // noop as backlight_task uses get_backlight_level()
66}
diff --git a/quantum/quantum.c b/quantum/quantum.c
index d689a9fbf..571dda4c5 100644
--- a/quantum/quantum.c
+++ b/quantum/quantum.c
@@ -981,7 +981,7 @@ void matrix_scan_quantum() {
981#if defined(BACKLIGHT_ENABLE) 981#if defined(BACKLIGHT_ENABLE)
982# if defined(LED_MATRIX_ENABLE) 982# if defined(LED_MATRIX_ENABLE)
983 led_matrix_task(); 983 led_matrix_task();
984# elif defined(BACKLIGHT_PIN) 984# elif defined(BACKLIGHT_PIN) || defined(BACKLIGHT_PINS)
985 backlight_task(); 985 backlight_task();
986# endif 986# endif
987#endif 987#endif
diff --git a/quantum/quantum.h b/quantum/quantum.h
index f5ac97379..01abe1c0a 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -257,8 +257,8 @@ void tap_code16(uint16_t code);
257void backlight_init_ports(void); 257void backlight_init_ports(void);
258void backlight_task(void); 258void backlight_task(void);
259void backlight_task_internal(void); 259void backlight_task_internal(void);
260void backlight_on(uint8_t backlight_pin); 260void backlight_on(pin_t backlight_pin);
261void backlight_off(uint8_t backlight_pin); 261void backlight_off(pin_t backlight_pin);
262 262
263# ifdef BACKLIGHT_BREATHING 263# ifdef BACKLIGHT_BREATHING
264void breathing_task(void); 264void breathing_task(void);