Skip to content


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 and RGB Matrix 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.


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 includes the following:



QK_BACKLIGHT_TOGGLEBL_TOGGTurn the backlight on or off
QK_BACKLIGHT_STEPBL_STEPCycle through backlight levels
QK_BACKLIGHT_ONBL_ONSet the backlight to max brightness
QK_BACKLIGHT_OFFBL_OFFTurn the backlight off
QK_BACKLIGHT_UPBL_UPIncrease the backlight level
QK_BACKLIGHT_DOWNBL_DOWNDecrease the backlight level

Basic Configuration

Add the following to your config.h:

BACKLIGHT_PINNot definedThe pin that controls the LEDs
BACKLIGHT_LEVELS3The number of brightness levels (maximum 31 excluding off)
BACKLIGHT_CAPS_LOCKNot definedEnable Caps Lock indicator using backlight (for keyboards without dedicated LED)
BACKLIGHT_BREATHINGNot definedEnable backlight breathing, if supported
BREATHING_PERIOD6The length of one backlight "breath" in seconds
BACKLIGHT_ON_STATE1The state of the backlight pin when the backlight is "on" - 1 for high, 0 for low
BACKLIGHT_LIMIT_VAL255The maximum duty cycle of the backlight -- 255 allows for full brightness, any lower will decrease the maximum.
BACKLIGHT_DEFAULT_ONtrueEnable backlight upon clearing the EEPROM
BACKLIGHT_DEFAULT_BREATHINGfalseWhether to enable backlight breathing upon clearing the EEPROM
BACKLIGHT_DEFAULT_LEVELBACKLIGHT_LEVELSThe default backlight level to use upon clearing the EEPROM

Unless you are designing your own keyboard, you generally should not need to change the BACKLIGHT_PIN or BACKLIGHT_ON_STATE.

"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.

To configure the "on" state of the backlight circuit, add the following to your config.h:


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:

#define BACKLIGHT_PINS { F5, B2 }

Driver Configuration

Backlight driver selection is configured in Valid drivers are pwm (default), timer, software, or custom. See below for information on individual drivers.

PWM Driver

This is the default backlight driver, which leverages the hardware PWM output capability of the microcontroller.


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.


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.


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.

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

PWM Driver

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 PinAT90USB64/128AT90USB162ATmega16/32U4ATmega16/32U2ATmega32AATmega328/P
B1Timer 1
B2Timer 1
B5Timer 1Timer 1
B6Timer 1Timer 1
B7Timer 1Timer 1Timer 1Timer 1
C4Timer 3
C5Timer 3Timer 1Timer 1
C6Timer 3Timer 1Timer 3Timer 1
D4Timer 1
D5Timer 1

Timer Driver

Any GPIO pin can be used with this driver. The following table describes the supported timers:

Timers 1 & 3Timer 1Timers 1 & 3Timer 1Timer 1Timer 1

The following #defines apply only to the timer driver:

BACKLIGHT_PWM_TIMER1The timer to use

Note that the choice of timer may conflict with the Audio feature.

ChibiOS/ARM Configuration

PWM Driver

Depending on the ChibiOS board configuration, you may need to enable PWM at the keyboard level. For STM32, this would look like:




#undef STM32_PWM_USE_TIM4

The following #defines apply only to the pwm driver:

BACKLIGHT_PAL_MODE2The pin alternative function to use
BACKLIGHT_PWM_PERIODNot definedThe PWM period in counter ticks - Default is platform dependent

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

Depending on the ChibiOS board configuration, you may need to enable general-purpose timers at the keyboard level. For STM32, this would look like:




#undef STM32_GPT_USE_TIM15
#define STM32_GPT_USE_TIM15 TRUE

The following #defines apply only to the timer driver:


Example Schematic

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.

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 for more information.

Backlight example circuit


void backlight_toggle(void)

Toggle the backlight on or off.

void backlight_enable(void)

Turn the backlight on.

void backlight_disable(void)

Turn the backlight off.

void backlight_step(void)

Cycle through backlight levels.

void backlight_increase(void)

Increase the backlight level.

void backlight_decrease(void)

Decrease the backlight level.

void backlight_level(uint8_t level)

Set the backlight level.


  • uint8_t level
    The level to set, from 0 to BACKLIGHT_LEVELS.

uint8_t get_backlight_level(void)

Get the current backlight level.

Return Value

The current backlight level, from 0 to BACKLIGHT_LEVELS.

bool is_backlight_enabled(void)

Get the current backlight state.

Return Value

true if the backlight is enabled.

void backlight_toggle_breathing(void)

Toggle backlight breathing on or off.

void backlight_enable_breathing(void)

Turn backlight breathing on.

void backlight_disable_breathing(void)

Turn backlight breathing off.

bool is_backlight_breathing(void)

Get the current backlight breathing state.

Return Value

true if backlight breathing is enabled.