- C++ 100%
| .github/workflows | ||
| src | ||
| .gitignore | ||
| .pre-commit-config.yaml | ||
| LICENSE | ||
| platformio.ini | ||
| README.md | ||
LILYGO T-Deck Keyboard Firmware
This is advanced firmware for the keyboard on a LILYGO T-Deck keyboard, which uses a separate ESP32-C3 for its MCU.
Features
- Keypress Buffer - Up to 64 key events are stored for the host to retrieve.
- Raw/Cooked Mode - Receive decoded keys ("G" for shift-G, "+" for sym-O) like the original firmware, or optionally switch to receiving raw key press/release events.
- I2C Commands - Host commands can change the keyboard mode and keyboard backlight level.
- Log Output - Debug information is printed to the UART.
Flashing
Flashing requires a USB-to-TTL adapter (aka UART adapter, or FTDI if you're old), and PlatformIO: https://docs.platformio.org/en/latest/core/installation/methods/installer-script.html
The pins being connected to are slightly undersized from a standard debug header. The preferred method of connecting is using probes/test clips. However, male headers removed from the housing will work too, just ensure they don't touch each other. The LILYGO T-Deck includes a 6-pin header that can be soldered to the board, but that may be unnecessarily risky.
It is also necessary to short the boot and reset pins to ground in order to get the keyboard ready for flashing.
The pins, on the right edge of the back of the logic board, from top (grove plug) to bottom (USB-C port) are:
- TX
- RX
- boot
- reset
- ground
- Vcc
The safest method is to leave Vcc (power) disconnected. Connect TX/RX/ground to your USB UART adapter, and connect boot & reset to grounded buttons. Power the T-Deck via USB-C independently. Pressing the reset button (grounding it for a moment) will reboot the keyboard firmware and show you a boot message. If you press the reset button while holding (grounding) the boot button, it boots into ROM mode, ready to upload new firmware.
Boot into ROM mode as described above, quit any serial terminal apps (minicom, tio, ...), and use PlatformIO to flash the new firmware:
pio run -t upload
You can now launch your favorite serial terminal app, even if it's not tio. Press (ground) the reset button again, and you should see the new boot message:
t-deck keyboard robey-2.0 20250402
i2c addr=$55
I2C Commands
Any read (from any register) will return the next byte in the keyboard buffer. If the buffer is empty, it returns the zero byte (0x00).
The following write commands are supported:
| Register | Description | Data Byte |
|---|---|---|
| 0x01 | Set backlight level | 0x00 (off) - 0xff (brightest) |
| 0x02 | Set "normal" (alt-B) backlight level | 0x00 (off) - 0xff (brightest) |
| 0x73 | Set mode | 0x00=cooked, 0x01=modifiers, 0x02=raw |
Modes
Switching modes is a new feature at register 0x73. To make it easy to detect this keyboard firmware, it will respond to any mode change with the special byte 0xf3, to indicate it understood. If you receive that byte, you are talking to this firmware. If you don't, you aren't. :)
The keyboard boots into "cooked" (or default) mode: mode 0. This behaves just like the original firmware that shipped with the T-Deck. Key combinations are decoded in the firmware, and keyboard events are the translated ASCII code. For example, pressing the "mic" button while holding down "sym" will send 0x30 (ASCII "0") for the 0 key.
Mode 0 also supports one "hotkey": Alt-B toggles the keyboard backlight between "off" and "normal". The "normal" backlight level is 0x7f at boot, and can be changed with write command 0x02 above.
Mode 1 is just like mode 0, except Alt-B does not toggle the backlight, sym and shift keys are not processed, and there are new events to represent a change in which modifier keys are pressed. These events have the high bit (0x80) set, and use the low 5 bits to indicate which modifiers are currently pressed (so: 0x80 - 0x9f):
| Bit | Key |
|---|---|
| 0 | sym |
| 1 | alt |
| 2 | mic |
| 3 | left shift |
| 4 | right shift |
For example, if sym and left shift are down, the keyboard will send event 0x89. Once no modifiers are pressed, it will send event 0x80.
All other keys send the un-shifted un-symbol'd ASCII code for their key, even if a modifier is pressed.
Mode 2 sends only raw key press/release events using a bit encoding:
| Bit | Meaning |
|---|---|
| 7 | 1=Pressed, 0=Released |
| 5-3 | Column (1 - 5) |
| 2-0 | Row (0 - 6) |
For example, if the key in row 3, column 4 is pressed, it will send 0xa3. When it's released, it sends 0x23.
The row/column grid follows no rhyme or reason except the underlying hardware:
| Row 0 | 1 | 2 | 3 | 4 | 5 | 6 | |
|---|---|---|---|---|---|---|---|
| Col 1 | Q | W | sym | A | alt | space | mic |
| 2 | E | S | D | P | X | Z | l-shift |
| 3 | R | G | T | r-shift | V | C | F |
| 4 | U | H | Y | enter | B | N | J |
| 5 | O | L | I | backspace | $ | M | K |
Credits
This firmware is heavily based on the original firmware code provided by Koby Hale of Lilygo, and an alternate version modified by Robert Grizzell:
- https://github.com/Xinyuan-LilyGO/T-Deck/blob/master/examples/Keyboard_ESP32C3/Keyboard_ESP32C3.ino
- https://github.com/rgrizzell/lilygo-t-deck-keyboard
This code is licensed under the MIT license, just like the original.