From f6ee533f417fd98a3af65fbb80bdfd00cbbee96b Mon Sep 17 00:00:00 2001 From: mverch67 Date: Sun, 1 Jun 2025 00:46:35 +0200 Subject: [PATCH] initial draft --- boards/t-deck-pro.json | 43 ++++++++++ src/configuration.h | 5 ++ src/detect/ScanI2C.h | 5 ++ src/detect/ScanI2CTwoWire.cpp | 21 ++++- src/graphics/EInkDisplay2.cpp | 2 +- src/input/TCA8418Keyboard.cpp | 76 +++++++++++++++- src/main.cpp | 13 +++ .../extra_variants/t_deck_pro/variant.cpp | 46 ++++++++++ variants/t-deck-pro/pins_arduino.h | 19 ++++ variants/t-deck-pro/platformio.ini | 24 ++++++ variants/t-deck-pro/variant.h | 86 +++++++++++++++++++ 11 files changed, 335 insertions(+), 5 deletions(-) create mode 100644 boards/t-deck-pro.json create mode 100644 src/platform/extra_variants/t_deck_pro/variant.cpp create mode 100644 variants/t-deck-pro/pins_arduino.h create mode 100644 variants/t-deck-pro/platformio.ini create mode 100644 variants/t-deck-pro/variant.h diff --git a/boards/t-deck-pro.json b/boards/t-deck-pro.json new file mode 100644 index 000000000..2f4bd594a --- /dev/null +++ b/boards/t-deck-pro.json @@ -0,0 +1,43 @@ +{ + "build": { + "arduino": { + "ldscript": "esp32s3_out.ld", + "memory_type": "qio_qspi", + "partitions": "default_16MB.csv" + }, + "core": "esp32", + "extra_flags": [ + "-DBOARD_HAS_PSRAM", + "-DARDUINO_USB_CDC_ON_BOOT=1", + "-DARDUINO_USB_MODE=1", + "-DARDUINO_RUNNING_CORE=1", + "-DARDUINO_EVENT_RUNNING_CORE=1" + ], + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "hwids": [["0x303A", "0x1001"]], + "mcu": "esp32s3", + "variant": "esp32s3" + }, + "connectivity": ["wifi", "bluetooth", "lora"], + "debug": { + "default_tool": "esp-builtin", + "onboard_tools": ["esp-builtin"], + "openocd_target": "esp32s3.cfg" + }, + "frameworks": ["arduino", "espidf"], + "name": "LilyGo T-Deck Pro S3 (16M Flash 8M QSPI PSRAM )", + "upload": { + "flash_size": "16MB", + "maximum_ram_size": 327680, + "maximum_size": 16777216, + "require_upload_port": true, + "speed": 921600 + }, + "monitor": { + "speed": 115200 + }, + "url": "https://lilygo.cc/products/t-deck-pro", + "vendor": "LilyGo" +} diff --git a/src/configuration.h b/src/configuration.h index 32d99295e..c5519a54b 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -158,6 +158,9 @@ along with this program. If not, see . #define LTR390UV_ADDR 0x53 #define XPOWERS_AXP192_AXP2101_ADDRESS 0x34 // same adress as TCA8418 #define PCT2075_ADDR 0x37 +#define BQ27220_ADDR 0x55 // same address as TDECK_KB +#define BQ25896_ADDR 0x6B +#define LTR553ALS_ADDR 0x23 // ----------------------------------------------------------------------------- // ACCELEROMETER @@ -171,6 +174,7 @@ along with this program. If not, see . #define BMX160_ADDR 0x69 #define ICM20948_ADDR 0x69 #define ICM20948_ADDR_ALT 0x68 +#define BHI260AP_ADDR 0x28 // ----------------------------------------------------------------------------- // LED @@ -192,6 +196,7 @@ along with this program. If not, see . // Touchscreen // ----------------------------------------------------------------------------- #define FT6336U_ADDR 0x48 +#define CST328_ADDR 0x1A // ----------------------------------------------------------------------------- // BIAS-T Generator diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 72184db69..3cabc6341 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -72,6 +72,11 @@ class ScanI2C LTR390UV, TCA8418KB, PCT2075, + CST328, + BQ25896, + BQ27220, + LTR553ALS, + BHI260AP } DeviceType; // typedef uint8_t DeviceAddress; diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index e2ba78a92..60a429ec7 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -206,7 +206,17 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) } break; - SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard", (uint8_t)addr.address); + case TDECK_KB_ADDR: + // Do we have the T-Deck keyboard or the T-Deck Pro battery sensor? + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x40), 2); // MACData + if (registerValue != 0) { + logFoundDevice("BQ27220", (uint8_t)addr.address); + type = BQ27220; + } else { + logFoundDevice("TDECKKB", (uint8_t)addr.address); + type = TDECKKB; + } + break; SCAN_SIMPLE_CASE(BBQ10_KB_ADDR, BBQ10KB, "BB Q10", (uint8_t)addr.address); SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "ST7567", (uint8_t)addr.address); @@ -396,6 +406,12 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) logFoundDevice("BQ24295", (uint8_t)addr.address); break; } + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x14), 1); // get ID + if ((registerValue & 0b00000011) == 0b00000010) { + type = BQ25896; + logFoundDevice("BQ25896", (uint8_t)addr.address); + break; + } registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0F), 1); // get ID if (registerValue == 0x6A) { type = LSM6DS3; @@ -435,6 +451,9 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) SCAN_SIMPLE_CASE(DFROBOT_RAIN_ADDR, DFROBOT_RAIN, "DFRobot Rain Gauge", (uint8_t)addr.address); SCAN_SIMPLE_CASE(LTR390UV_ADDR, LTR390UV, "LTR390UV", (uint8_t)addr.address); SCAN_SIMPLE_CASE(PCT2075_ADDR, PCT2075, "PCT2075", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(CST328_ADDR, CST328, "CST328", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(LTR553ALS_ADDR, LTR553ALS, "LTR553ALS", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(BHI260AP_ADDR, BHI260AP, "BHI260AP", (uint8_t)addr.address); #ifdef HAS_TPS65233 SCAN_SIMPLE_CASE(TPS65233_ADDR, TPS65233, "TPS65233", (uint8_t)addr.address); #endif diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp index 5a2749482..260df2a8d 100644 --- a/src/graphics/EInkDisplay2.cpp +++ b/src/graphics/EInkDisplay2.cpp @@ -203,7 +203,7 @@ bool EInkDisplay::connect() adafruitDisplay->setRotation(0); adafruitDisplay->setPartialWindow(0, 0, EINK_WIDTH, EINK_HEIGHT); } -#elif defined(M5_COREINK) +#elif defined(M5_COREINK) || defined(T_DECK_PRO) auto lowLevel = new EINK_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY); adafruitDisplay = new GxEPD2_BW(*lowLevel); adafruitDisplay->init(115200, true, 40, false, SPI, SPISettings(4000000, MSBFIRST, SPI_MODE0)); diff --git a/src/input/TCA8418Keyboard.cpp b/src/input/TCA8418Keyboard.cpp index 21cd7b2d5..86263a1b5 100644 --- a/src/input/TCA8418Keyboard.cpp +++ b/src/input/TCA8418Keyboard.cpp @@ -103,10 +103,70 @@ enum { _TCA8418_COL9 // Pin ID for column 9 }; +#if defined(T_DECK_PRO) +#define _TCA8418_COLS 10 +#define _TCA8418_ROWS 4 +#define _TCA8418_NUM_KEYS 35 + +#define _TCA8418_LONG_PRESS_THRESHOLD 2000 +#define _TCA8418_MULTI_TAP_THRESHOLD 1500 + +// Num chars per key, Modulus for rotating through characters +uint8_t TCA8418TapMod[_TCA8418_NUM_KEYS] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}; + +// https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes +unsigned char TCA8418TapMap[_TCA8418_NUM_KEYS][3] = {{'p', 'P', '@'}, + {'o', 'O', '+'}, + {'i', 'I', '-'}, + {'u', 'U', '_'}, + {'y', 'Y', ')'}, + {'t', 'T', '('}, + {'r', 'R', '3'}, + {'e', 'E', '2'}, + {'w', 'W', '1'}, + {'q', 'Q', '#'}, + {_TCA8418_BSP, 0x00, 0x00}, + {'l', 'L', '"'}, + {'k', 'K', '\''}, + {'j', 'J', ';'}, + {'h', 'H', ':'}, + {'g', 'G', '/'}, + {'f', 'F', '6'}, + {'d', 'D', '5'}, + {'s', 'S', '4'}, + {'a', 'A', '*'}, + {0x0d, 0x00, 0x00}, + {'$', 0x00, 0x00}, + {'m', 'M', '.'}, + {'n', 'N', ','}, + {'b', 'B', '!'}, + {'v', 'V', '?'}, + {'c', 'C', '9'}, + {'x', 'X', '8'}, + {'z', 'Z', '7'}, + {0xa4, 0x00, 0x00}, + {0xa1, 0x00, 0x00}, + {0x00, 0x00, 0x00}, + {0x20, 0x00, 0x00}, + {0x00, 0x00, '0'}, + {0xa0, 0x00, 0x00}}; + +unsigned char TCA8418LongPressMap[_TCA8418_NUM_KEYS] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, _TCA8418_ESC, // p,o,i,u,y,t,r,e,w,q + 0x00, 0x00, 0x00, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // bsp,l,k,j,h,g,f,d,s,a + 0x00, 0x00, 0xb7, 0xb6, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, // ent,$,m,n,b,v,c,x,z,alt + 0x00, 0x00, 0x00, 0x00, 0x00 // rShift,sym,space,mic,lShift +}; + +#else #define _TCA8418_COLS 3 #define _TCA8418_ROWS 4 #define _TCA8418_NUM_KEYS 12 +#define _TCA8418_LONG_PRESS_THRESHOLD 2000 +#define _TCA8418_MULTI_TAP_THRESHOLD 750 + uint8_t TCA8418TapMod[_TCA8418_NUM_KEYS] = {13, 7, 7, 7, 7, 7, 9, 7, 9, 2, 2, 2}; // Num chars per key, Modulus for rotating through characters @@ -139,9 +199,7 @@ unsigned char TCA8418LongPressMap[_TCA8418_NUM_KEYS] = { _TCA8418_NONE, // 0 _TCA8418_NONE, // # }; - -#define _TCA8418_LONG_PRESS_THRESHOLD 2000 -#define _TCA8418_MULTI_TAP_THRESHOLD 750 +#endif TCA8418Keyboard::TCA8418Keyboard() : m_wire(nullptr), m_addr(0), readCallback(nullptr), writeCallback(nullptr) { @@ -182,10 +240,14 @@ void TCA8418Keyboard::reset() // set default all GIO pins to INPUT writeRegister(_TCA8418_REG_GPIO_DIR_1, 0x00); writeRegister(_TCA8418_REG_GPIO_DIR_2, 0x00); +#ifndef T_DECK_PRO // Set COL9 as GPIO output writeRegister(_TCA8418_REG_GPIO_DIR_3, 0x02); // Switch off keyboard backlight (COL9 = LOW) writeRegister(_TCA8418_REG_GPIO_DAT_OUT_3, 0x00); +#else + writeRegister(_TCA8418_REG_GPIO_DIR_3, 0x00); +#endif // add all pins to key events writeRegister(_TCA8418_REG_GPI_EM_1, 0xFF); @@ -516,11 +578,19 @@ void TCA8418Keyboard::disableDebounce() void TCA8418Keyboard::setBacklight(bool on) { +#ifdef T_DECK_PRO + if (on) { + digitalWrite(KB_BL_PIN, HIGH); + } else { + digitalWrite(KB_BL_PIN, LOW); + } +#else if (on) { digitalWrite(_TCA8418_COL9, HIGH); } else { digitalWrite(_TCA8418_COL9, LOW); } +#endif } uint8_t TCA8418Keyboard::readRegister(uint8_t reg) const diff --git a/src/main.cpp b/src/main.cpp index 2d49b2fbe..9fe9acd0a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -363,6 +363,19 @@ void setup() pinMode(TFT_CS, OUTPUT); digitalWrite(TFT_CS, HIGH); delay(100); +#elif defined(T_DECK_PRO) + pinMode(LORA_EN, OUTPUT); + digitalWrite(LORA_EN, HIGH); + // pinMode(BOARD_1V8_EN, OUTPUT); + // digitalWrite(BOARD_1V8_EN, HIGH); + // pinMode(BOARD_6609_EN, OUTPUT); + // digitalWrite(BOARD_6609_EN, HIGH); + pinMode(LORA_CS, OUTPUT); + digitalWrite(LORA_CS, HIGH); + pinMode(SDCARD_CS, OUTPUT); + digitalWrite(SDCARD_CS, HIGH); + pinMode(PIN_EINK_CS, OUTPUT); + digitalWrite(PIN_EINK_CS, HIGH); #endif concurrency::hasBeenSetup = true; diff --git a/src/platform/extra_variants/t_deck_pro/variant.cpp b/src/platform/extra_variants/t_deck_pro/variant.cpp new file mode 100644 index 000000000..abf9a6e40 --- /dev/null +++ b/src/platform/extra_variants/t_deck_pro/variant.cpp @@ -0,0 +1,46 @@ +#include "configuration.h" + +#ifdef T_DECK_PRO + +#include "input/TouchScreenImpl1.h" +#include +#include + +CSE_CST328 tsPanel = CSE_CST328(EINK_WIDTH, EINK_HEIGHT, &Wire, CST328_PIN_RST, CST328_PIN_INT); + +volatile bool intReceived = false; + +void touchISR() +{ + // Detach the interrupt to prevent multiple interrupts + detachInterrupt(digitalPinToInterrupt(CST328_PIN_INT)); + intReceived = true; +} + +bool readTouch(int16_t *x, int16_t *y) +{ + if (1 /* intReceived */) { + intReceived = false; + // Reattach the interrupt for the next touch + // attachInterrupt (digitalPinToInterrupt(CST328_PIN_INT), touchISR, FALLING); + + // Read the touch point + // if (tsPanel.isTouched(0)) { + if (tsPanel.getTouches()) { + *x = tsPanel.getPoint(0).x; + *y = tsPanel.getPoint(0).y; + return true; + } + } + return false; +} + +// T-Deck Pro specific init +void lateInitVariant() +{ + tsPanel.begin(); + // attachInterrupt (digitalPinToInterrupt(CST328_PIN_INT), touchISR, FALLING); + touchScreenImpl1 = new TouchScreenImpl1(EINK_WIDTH, EINK_HEIGHT, readTouch); + touchScreenImpl1->init(); +} +#endif \ No newline at end of file diff --git a/variants/t-deck-pro/pins_arduino.h b/variants/t-deck-pro/pins_arduino.h new file mode 100644 index 000000000..af0ba80b3 --- /dev/null +++ b/variants/t-deck-pro/pins_arduino.h @@ -0,0 +1,19 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +#define USB_VID 0x303a +#define USB_PID 0x1001 + +// used for keyboard, touch controller, beam sensor, and gyroscope +static const uint8_t SDA = 13; +static const uint8_t SCL = 14; + +// Default SPI will be mapped to Radio +static const uint8_t SS = 3; +static const uint8_t MOSI = 33; +static const uint8_t MISO = 47; +static const uint8_t SCK = 36; + +#endif /* Pins_Arduino_h */ diff --git a/variants/t-deck-pro/platformio.ini b/variants/t-deck-pro/platformio.ini new file mode 100644 index 000000000..8c0f54748 --- /dev/null +++ b/variants/t-deck-pro/platformio.ini @@ -0,0 +1,24 @@ +[env:t-deck-pro] +extends = esp32s3_base +board = t-deck-pro +board_check = true +upload_protocol = esptool + +build_flags = + ${esp32_base.build_flags} -I variants/t-deck-pro + -D T_DECK_PRO + -D PRIVATE_HW ; TODO: remove me + -D GPS_POWER_TOGGLE + -D USE_EINK + -D EINK_DISPLAY_MODEL=GxEPD2_310_GDEQ031T10 + -D EINK_WIDTH=240 + -D EINK_HEIGHT=320 + ;-D USE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk + -D EINK_LIMIT_FASTREFRESH=10 ; How many consecutive fast-refreshes are permitted + -D EINK_LIMIT_GHOSTING_PX=2000 ; (Optional) How much image ghosting is tolerated + +lib_deps = + ${esp32s3_base.lib_deps} + https://github.com/ZinggJM/GxEPD2/archive/refs/tags/1.6.4.zip + https://github.com/CIRCUITSTATE/CSE_Touch/archive/b44f23b6f870b848f1fbe453c190879bc6cfaafa.zip + https://github.com/CIRCUITSTATE/CSE_CST328/archive/refs/tags/v0.0.4.zip diff --git a/variants/t-deck-pro/variant.h b/variants/t-deck-pro/variant.h new file mode 100644 index 000000000..730c0533b --- /dev/null +++ b/variants/t-deck-pro/variant.h @@ -0,0 +1,86 @@ +// Display (E-Ink) +#define PIN_EINK_CS 34 +#define PIN_EINK_BUSY 37 +#define PIN_EINK_DC 35 +#define PIN_EINK_RES -1 +#define PIN_EINK_SCLK 36 +#define PIN_EINK_MOSI 47 + +#define I2C_SDA SDA +#define I2C_SCL SCL + +// CST328 touch screen (implementation in src/platform/extra_variants/t_deck_pro/variant.cpp) +#define CST328_PIN_INT 12 +#define CST328_PIN_RST 45 + +#define USE_POWERSAVE +#define SLEEP_TIME 120 + +// GNNS +#define PIN_GPS_EN 15 +#define GPS_EN_ACTIVE 1 +#define GPS_RX_PIN 44 +#define GPS_TX_PIN 43 +#define PIN_GPS_PPS 1 + +#define BUTTON_PIN 0 + +// Have SPI interface SD card slot +#define HAS_SDCARD +#define SDCARD_USE_SPI1 +#define SPI_MOSI (33) +#define SPI_SCK (36) +#define SPI_MISO (47) +#define SPI_CS (48) +#define SDCARD_CS SPI_CS +#define SD_SPI_FREQUENCY 75000000U + +// T-Deck Pro PMU + +// TCA8418 keyboard +#define KB_BL_PIN 42 +#define CANNED_MESSAGE_MODULE_ENABLE 1 + +// microphone PCM5102A +#define PCM5102A_SCK 47 +#define PCM5102A_DIN 17 +#define PCM5102A_LRCK 18 + +// LTR_553ALS light sensor +#define HAS_LTR553ALS + +// gyroscope BHI260AP +#define BOARD_1V8_EN 38 +#define HAS_BHI260AP + +// battery quality sensor BQ25896 +#define HAS_BQ25896 + +// battery quality sensor BQ27220 +#define HAS_BQ27220 + +// LoRa +#define USE_SX1262 +#define USE_SX1268 + +#define LORA_EN 46 // LoRa enable pin +#define LORA_SCK 36 +#define LORA_MISO 47 +#define LORA_MOSI 33 +#define LORA_CS 3 + +#define LORA_DIO0 -1 // a No connect on the SX1262 module +#define LORA_RESET 4 +#define LORA_DIO1 5 // SX1262 IRQ +#define LORA_DIO2 6 // SX1262 BUSY +#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled + +#define SX126X_CS LORA_CS // FIXME - we really should define LORA_CS instead +#define SX126X_DIO1 LORA_DIO1 +#define SX126X_BUSY LORA_DIO2 +#define SX126X_RESET LORA_RESET +// Not really an E22 but TTGO seems to be trying to clone that +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 2.4 +// Internally the TTGO module hooks the SX1262-DIO2 in to control the TX/RX switch (which is the default for the sx1262interface +// code)