qmk_firmware/docs/feature_encoders.md
Balz Guenat 32215d5bff
Rework encoders to enable asymmetric split keyboards (#12090)
Co-authored-by: Balz Guenat <balz.guenat@siemens.com>
Co-authored-by: Nick Brassel <nick@tzarc.org>
2021-11-20 09:06:08 -08:00

3.6 KiB
Raw Blame History

Encoders

Basic encoders are supported by adding this to your rules.mk:

ENCODER_ENABLE = yes

and this to your config.h:

#define ENCODERS_PAD_A { B12 }
#define ENCODERS_PAD_B { B13 }

Each PAD_A/B variable defines an array so multiple encoders can be defined, e.g.:

#define ENCODERS_PAD_A { encoder1a, encoder2a }
#define ENCODERS_PAD_B { encoder1b, encoder2b }

If your encoder's clockwise directions are incorrect, you can swap the A & B pad definitions. They can also be flipped with a define:

#define ENCODER_DIRECTION_FLIP

Additionally, the resolution, which defines how many pulses the encoder registers between each detent, can be defined with:

#define ENCODER_RESOLUTION 4

It can also be defined per-encoder, by instead defining:

#define ENCODER_RESOLUTIONS { 4, 2 }

For 4× encoders you also can assign default position if encoder skips pulses when it changes direction. For example, if your encoder send high level on both pins by default, define this:

#define ENCODER_DEFAULT_POS 0x3

Split Keyboards

The above is enough for split keyboards that are symmetrical, i.e. the halves have the same number of encoders and they are on the same pins. If the halves are not symmetrical, you can define the pinout (and optionally, resolutions) of the right half separately. The left half will use the definitions above.

#define ENCODERS_PAD_A_RIGHT { encoder1a, encoder2a }
#define ENCODERS_PAD_B_RIGHT { encoder1b, encoder2b }
#define ENCODER_RESOLUTIONS_RIGHT { 2, 4 }

If only the right half has encoders, you must still define an empty array for the left pads (and resolutions, if you define ENCODER_RESOLUTIONS_RIGHT).

#define ENCODERS_PAD_A {  }
#define ENCODERS_PAD_B {  }
#define ENCODER_RESOLUTIONS {  }
#define ENCODERS_PAD_A_RIGHT { encoder1a, encoder2a }
#define ENCODERS_PAD_B_RIGHT { encoder1b, encoder2b }
#define ENCODER_RESOLUTIONS_RIGHT { 2, 4 }

Callbacks

The callback functions can be inserted into your <keyboard>.c:

bool encoder_update_kb(uint8_t index, bool clockwise) {
    return encoder_update_user(index, clockwise);
}

or keymap.c:

bool encoder_update_user(uint8_t index, bool clockwise) {
    if (index == 0) { /* First encoder */
        if (clockwise) {
            tap_code(KC_PGDN);
        } else {
            tap_code(KC_PGUP);
        }
    } else if (index == 1) { /* Second encoder */
        if (clockwise) {
            tap_code(KC_DOWN);
        } else {
            tap_code(KC_UP);
        }
    }
    return false;
}

!> If you return true, this will allow the keyboard level code to run, as well. Returning false will override the keyboard level code. Depending on how the keyboard level function is set up.

Hardware

The A an B lines of the encoders should be wired directly to the MCU, and the C/common lines should be wired to ground.

Multiple Encoders

Multiple encoders may share pins so long as each encoder has a distinct pair of pins.

For example you can support two encoders using only 3 pins like this

#define ENCODERS_PAD_A { B1, B1 }
#define ENCODERS_PAD_B { B2, B3 }

You could even support three encoders using only three pins (one per encoder) however in this configuration, rotating two encoders which share pins simultaneously will often generate incorrect output. For example:

#define ENCODERS_PAD_A { B1, B1, B2 }
#define ENCODERS_PAD_B { B2, B3, B3 }

Here rotating Encoder 0 B1 B2 and Encoder 1 B1 B3 could be interpreted as rotating Encoder 2 B2 B3 or B3 B2 depending on the timing. This may still be a useful configuration depending on your use case