Files
MeshCore-Solo/variants/lilygo_techo_lite/KeyshieldBacklight.cpp
T
JakubandClaude Opus 5 05e57357d3 feat(boards): add M5Stack Cardputer ADV and LilyGO T-Echo Lite KeyShield
New M5Stack Cardputer ADV variant (ESP32-S3, ST7789 TFT, built-in TCA8418
QWERTY keyboard, PI4IOE5V6408 LoRa-cap IO-expander autodetect), and a
KeyShield accessory variant for the existing LilyGO T-Echo Lite (external
TCA8418 T9 keypad + AW21009 backlight driver). Both keyboards share one
ENV_USE_TCA8418 polling block in UITask.cpp::loop(), coexisting with the
unrelated CardKB support (different chip/address/flag).

Fixes carried in from the contributed T-Echo Lite code: swapped GPS RX/TX
pins, TX-LED hooks, TCXO voltage, missing GxEPD2_122_T61 panel include.
Fixed during integration: I2C bus was probed for an RTC before Wire.begin()
configured its pins on Cardputer ADV (silent RTC autodetect failure).

Added dedicated *_solo_dual release envs for both boards (auto-picked up by
the solo-firmware release workflow). Gave the T-Echo Lite KeyShield solo
build -Os/-Ofast-unflag like every other nRF52 solo build (was missing,
cut flash usage from 90.7% to 61.4%).

Ported the shared misc-fixed 6x9 font (full Latin/Greek/Cyrillic, opt-in via
OLED_MISC_FIXED_FONT) to ST7789Display for the Cardputer's on-screen
keyboard. ST7789Spi isn't Adafruit_GFX-based like the other single-font
drivers, and this panel's logical->physical scale is non-integer, so glyphs
are re-packed to XBM and blitted through the existing drawXbm(), which
already does correct fractional-scale boundary math, rather than
duplicating that logic.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 01:06:24 +02:00

66 lines
2.6 KiB
C++

// TechoKeyBacklight.cpp
// Self-contained AW21009(QNR) keyboard-backlight driver for the T-Echo Lite
// KeyShield. Provides a single free function consumed by the UITask Home-key hook:
//
// void techo_keyshield_backlight_toggle(); // on <-> off
//
// Raw-Wire register driver. The register sequence mirrors LilyGo's
// cpp_bus_driver Aw21009 implementation (reset / global-control / global-current
// / per-channel scaling / latch, then 12-bit per-channel brightness), so no
// dependency on that library is pulled in.
#ifdef LILYGO_TECHO_LITE_KEYSHIELD
#include <Arduino.h>
#include <Wire.h>
// ---- AW21009 (KeyShield backlight) -----------------------------------------
// I2C 0x20 on the shared Wire bus. Wire.begin() (TechoBoard::begin) and the
// shield 3V3 rail are already up before the UI loop runs, so this lazy-inits on
// first toggle.
#define AW21009_ADDR 0x20
#define AW21009_REG_GCR 0x20 // global control (auto-save / PWM / chip enable)
#define AW21009_REG_BRIGHT 0x21 // brightness start; per ch: LSB=0x21+ch*2, MSB+1
#define AW21009_REG_UPDATE 0x45 // write-to-latch register
#define AW21009_REG_SCALE 0x46 // per-channel current scaling start
#define AW21009_REG_GCCR 0x58 // global current control
#define AW21009_REG_RESET 0x70 // software reset
#define AW21009_CHANNELS 6
#define AW21009_ON_LEVEL 4095 // 0..4095; lower this to dim the backlight
static void aw_write(uint8_t reg, uint8_t val) {
Wire.beginTransmission(AW21009_ADDR);
Wire.write(reg);
Wire.write(val);
Wire.endTransmission();
}
static void aw_init() {
aw_write(AW21009_REG_RESET, 0x00); // software reset
delay(10);
aw_write(AW21009_REG_GCR, 0x87); // auto power save + 12-bit PWM + chip enable
aw_write(AW21009_REG_GCCR, 0xFF); // global current = max
for (uint8_t i = 0; i < AW21009_CHANNELS; i++)
aw_write(AW21009_REG_SCALE + i, 0xFF); // per-channel current = max
aw_write(AW21009_REG_UPDATE, 0x00); // latch
}
static void aw_set_brightness(uint16_t value) {
if (value > 4095) value = 4095;
for (uint8_t i = 0; i < AW21009_CHANNELS; i++) {
aw_write(AW21009_REG_BRIGHT + i * 2, (uint8_t)(value & 0xFF)); // LSB
aw_write(AW21009_REG_BRIGHT + i * 2 + 1, (uint8_t)((value >> 8) & 0x0F)); // MSB (12-bit)
}
aw_write(AW21009_REG_UPDATE, 0x00); // latch
}
void techo_keyshield_backlight_toggle() {
static bool inited = false;
static bool on = false;
if (!inited) { aw_init(); inited = true; }
on = !on;
aw_set_brightness(on ? AW21009_ON_LEVEL : 0);
}
#endif