diff --git a/src/configuration.h b/src/configuration.h index cddc7ba7a..2efcf73a2 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -230,6 +230,8 @@ along with this program. If not, see . // Touchscreen // ----------------------------------------------------------------------------- #define FT6336U_ADDR 0x48 +#define CST226SE_ADDR 0x1A +#define CST226SE_ADDR_ALT 0x5A // ----------------------------------------------------------------------------- // RAK12035VB Soil Monitor (using RAK12023 up to 3 RAK12035 monitors can be connected) diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index dd290db98..a46fb6476 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -75,6 +75,7 @@ class ScanI2C TCA8418KB, PCT2075, BMM150, + CST226SE, } DeviceType; // typedef uint8_t DeviceAddress; diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 9e9441123..e3bfcc9a6 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -449,13 +449,18 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) SCAN_SIMPLE_CASE(PCT2075_ADDR, PCT2075, "PCT2075", (uint8_t)addr.address); SCAN_SIMPLE_CASE(SCD4X_ADDR, SCD4X, "SCD4X", (uint8_t)addr.address); SCAN_SIMPLE_CASE(BMM150_ADDR, BMM150, "BMM150", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(CST226SE_ADDR, CST226SE, "CST226SE", (uint8_t)addr.address); #ifdef HAS_TPS65233 SCAN_SIMPLE_CASE(TPS65233_ADDR, TPS65233, "TPS65233", (uint8_t)addr.address); #endif case MLX90614_ADDR_DEF: - registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0e), 1); - if (registerValue == 0x5a) { + // Do we have the MLX90614 or the MPR121KB or the CST226SE + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x06), 1); + if (registerValue == 0xAB) { + type = CST226SE; + logFoundDevice("CST226SE", (uint8_t)addr.address); + } else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0e), 1) == 0x5a) { type = MLX90614; logFoundDevice("MLX90614", (uint8_t)addr.address); } else { diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 87d394d69..aa0c352b9 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -281,7 +281,7 @@ static int8_t prevFrame = -1; // Combined dynamic node list frame cycling through LastHeard, HopSignal, and Distance modes // Uses a single frame and changes data every few seconds (E-Ink variant is separate) -#if defined(ESP_PLATFORM) && defined(USE_ST7789) +#if defined(ESP_PLATFORM) && (defined(USE_ST7789) || defined(USE_ST7796)) SPIClass SPI1(HSPI); #endif @@ -313,7 +313,18 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O #else dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT); #endif +#elif defined(USE_ST7796) +#ifdef ESP_PLATFORM + dispdev = new ST7796Spi(&SPI1, ST7796_RESET, ST7796_RS, ST7796_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT, ST7796_SDA, + ST7796_MISO, ST7796_SCK, TFT_SPI_FREQUENCY); +#else + dispdev = new ST7796Spi(&SPI1, ST7796_RESET, ST7796_RS, ST7796_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT); +#endif +#if defined(USE_ST7789) static_cast(dispdev)->setRGB(TFT_MESH); +#elif defined(USE_ST7796) + static_cast(dispdev)->setRGB(TFT_MESH); +#endif #elif defined(USE_SSD1306) dispdev = new SSD1306Wire(address.address, -1, -1, geometry, (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); @@ -410,6 +421,15 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver) pinMode(VTFT_LEDA, OUTPUT); digitalWrite(VTFT_LEDA, TFT_BACKLIGHT_ON); #endif +#endif +#ifdef USE_ST7796 + ui->init(); +#ifdef ESP_PLATFORM + analogWrite(VTFT_LEDA, BRIGHTNESS_DEFAULT); +#else + pinMode(VTFT_LEDA, OUTPUT); + digitalWrite(VTFT_LEDA, TFT_BACKLIGHT_ON); +#endif #endif enabled = true; setInterval(0); // Draw ASAP @@ -442,6 +462,21 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver) nrf_gpio_cfg_default(ST7789_NSS); #endif #endif +#ifdef USE_ST7796 + SPI1.end(); +#if defined(ARCH_ESP32) + pinMode(VTFT_LEDA, OUTPUT); + digitalWrite(VTFT_LEDA, LOW); + pinMode(ST7796_RESET, ANALOG); + pinMode(ST7796_RS, ANALOG); + pinMode(ST7796_NSS, ANALOG); +#else + nrf_gpio_cfg_default(VTFT_LEDA); + nrf_gpio_cfg_default(ST7796_RESET); + nrf_gpio_cfg_default(ST7796_RS); + nrf_gpio_cfg_default(ST7796_NSS); +#endif +#endif #ifdef T_WATCH_S3 PMU->disablePowerOutput(XPOWERS_ALDO2); @@ -484,6 +519,10 @@ void Screen::setup() // Apply custom RGB color (e.g. Heltec T114/T190) static_cast(dispdev)->setRGB(TFT_MESH); #endif +#if defined(USE_ST7796) && defined(TFT_MESH) + // Custom text color, if defined in variant.h + static_cast(dispdev)->setRGB(TFT_MESH); +#endif // === Initialize display and UI system === ui->init(); @@ -547,6 +586,8 @@ void Screen::setup() static_cast(dispdev)->flipScreenVertically(); #elif defined(USE_ST7789) static_cast(dispdev)->flipScreenVertically(); +#elif defined(USE_ST7796) + static_cast(dispdev)->mirrorScreen(); #else dispdev->flipScreenVertically(); #endif @@ -579,7 +620,7 @@ void Screen::setup() touchScreenImpl1->init(); } } -#elif HAS_TOUCHSCREEN +#elif HAS_TOUCHSCREEN && !HAS_CST226SE touchScreenImpl1 = new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast(dispdev)->getTouch); touchScreenImpl1->init(); diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 265900131..4eb0c07d4 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -81,6 +81,8 @@ class Screen #include #elif defined(USE_ST7789) #include +#elif defined(USE_ST7796) +#include #else // the SH1106/SSD1306 variant is auto-detected #include diff --git a/src/graphics/ScreenFonts.h b/src/graphics/ScreenFonts.h index 3373a47a7..a91efdba1 100644 --- a/src/graphics/ScreenFonts.h +++ b/src/graphics/ScreenFonts.h @@ -65,7 +65,7 @@ #endif #if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \ - defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS)) && \ + defined(ST7789_CS) || defined(USE_ST7789) || defined(USE_ST7796) || defined(HX8357_CS) || defined(ILI9488_CS)) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) // The screen is bigger so use bigger fonts #define FONT_SMALL FONT_MEDIUM_LOCAL // Height: 19 diff --git a/src/graphics/draw/DebugRenderer.cpp b/src/graphics/draw/DebugRenderer.cpp index 5420d1b4b..bbb808e69 100644 --- a/src/graphics/draw/DebugRenderer.cpp +++ b/src/graphics/draw/DebugRenderer.cpp @@ -94,7 +94,8 @@ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16 if (!Throttle::isWithinTimespanMs(storeForwardModule->lastHeartbeat, (storeForwardModule->heartbeatInterval * 1200))) { // no heartbeat, overlap a bit #if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \ - defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || ARCH_PORTDUINO) && \ + defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(USE_ST7796) || \ + ARCH_PORTDUINO) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8, imgQuestionL1); @@ -106,7 +107,7 @@ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16 #endif } else { #if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \ - defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS)) && \ + defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(USE_ST7796)) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 16, 8, imgSFL1); @@ -121,7 +122,8 @@ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16 } else { // TODO: Raspberry Pi supports more than just the one screen size #if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \ - defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || ARCH_PORTDUINO) && \ + defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(USE_ST7796) || \ + ARCH_PORTDUINO) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8, imgInfoL1); diff --git a/src/graphics/draw/UIRenderer.cpp b/src/graphics/draw/UIRenderer.cpp index 71d92616f..704e75260 100644 --- a/src/graphics/draw/UIRenderer.cpp +++ b/src/graphics/draw/UIRenderer.cpp @@ -194,7 +194,7 @@ void UIRenderer::drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const mes } #if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \ - defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS)) && \ + defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(USE_ST7796)) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) if (isHighResolution) { diff --git a/src/graphics/images.h b/src/graphics/images.h index beef3a1b2..711e0093d 100644 --- a/src/graphics/images.h +++ b/src/graphics/images.h @@ -27,7 +27,8 @@ const uint8_t bluetoothConnectedIcon[36] PROGMEM = {0xfe, 0x01, 0xff, 0x03, 0x03 0xfe, 0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0x3f, 0xe0, 0x1f}; #if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \ - defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS) || ARCH_PORTDUINO) && \ + defined(ST7789_CS) || defined(USE_ST7789) || defined(USE_ST7796) || defined(HX8357_CS) || defined(ILI9488_CS) || \ + ARCH_PORTDUINO) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) const uint8_t imgQuestionL1[] PROGMEM = {0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff}; const uint8_t imgQuestionL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f}; diff --git a/src/main.cpp b/src/main.cpp index 2e2adfd46..824439589 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -817,7 +817,7 @@ void setup() if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { #if defined(ST7701_CS) || defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || \ - defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) + defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(USE_ST7796) screen = new graphics::Screen(screen_found, screen_model, screen_geometry); #elif defined(ARCH_PORTDUINO) if ((screen_found.port != ScanI2C::I2CPort::NO_I2C || settingsMap[displayPanel]) && @@ -1074,7 +1074,7 @@ void setup() // Don't call screen setup until after nodedb is setup (because we need // the current region name) #if defined(ST7701_CS) || defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || \ - defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) + defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(USE_ST7796) if (screen) screen->setup(); #elif defined(ARCH_PORTDUINO) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 3c19971e6..38cb98ece 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -671,7 +671,7 @@ void NodeDB::installDefaultConfig(bool preserveKey = false) config.bluetooth.fixed_pin = defaultBLEPin; #if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7789_CS) || \ - defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) + defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(USE_ST7796) bool hasScreen = true; #ifdef HELTEC_MESH_NODE_T114 uint32_t st7789_id = get_st7789_id(ST7789_NSS, ST7789_SCK, ST7789_SDA, ST7789_RS, ST7789_RESET); diff --git a/src/platform/extra_variants/tbeam_displayshield/variant.cpp b/src/platform/extra_variants/tbeam_displayshield/variant.cpp new file mode 100644 index 000000000..ebfb9b87b --- /dev/null +++ b/src/platform/extra_variants/tbeam_displayshield/variant.cpp @@ -0,0 +1,43 @@ +#include "configuration.h" + +#ifdef HAS_CST226SE + +#include "TouchDrvCSTXXX.hpp" +#include "input/TouchScreenImpl1.h" +#include + +TouchDrvCSTXXX tsPanel; +static constexpr uint8_t PossibleAddresses[2] = {CST226SE_ADDR, CST226SE_ADDR_ALT}; +uint8_t i2cAddress = 0; + +bool readTouch(int16_t *x, int16_t *y) +{ + int16_t x_array[1], y_array[1]; + uint8_t touched = tsPanel.getPoint(x_array, y_array, 1); + if (touched > 0) { + *y = x_array[0]; + *x = (TFT_WIDTH - y_array[0]); + // Check bounds + if (*x < 0 || *x >= TFT_WIDTH || *y < 0 || *y >= TFT_HEIGHT) { + return false; + } + return true; // Valid touch detected + } + return false; // No valid touch data +} + +void lateInitVariant() +{ + tsPanel.setTouchDrvModel(TouchDrv_CST226); + for (uint8_t addr : PossibleAddresses) { + if (tsPanel.begin(Wire, addr, I2C_SDA, I2C_SCL)) { + i2cAddress = addr; + LOG_DEBUG("CST226SE init OK at address 0x%02X", addr); + touchScreenImpl1 = new TouchScreenImpl1(TFT_WIDTH, TFT_HEIGHT, readTouch); + touchScreenImpl1->init(); + return; + } + } + LOG_ERROR("CST226SE init failed at all known addresses"); +} +#endif diff --git a/variants/esp32/tbeam/platformio.ini b/variants/esp32/tbeam/platformio.ini index 084a981da..e9fbdb611 100644 --- a/variants/esp32/tbeam/platformio.ini +++ b/variants/esp32/tbeam/platformio.ini @@ -3,13 +3,23 @@ extends = esp32_base board = ttgo-t-beam board_check = true -lib_deps = - ${esp32_base.lib_deps} -build_flags = - ${esp32_base.build_flags} +lib_deps = ${esp32_base.lib_deps} +build_flags = ${esp32_base.build_flags} -D TBEAM_V10 -I variants/esp32/tbeam - -DGPS_POWER_TOGGLE ; comment this line to disable double press function on the user button to turn off gps entirely. - -DBOARD_HAS_PSRAM + -D GPS_POWER_TOGGLE ; comment this line to disable double press function on the user button to turn off gps entirely. + -D BOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue upload_speed = 921600 + +[env:tbeam-displayshield] +extends = env:tbeam + +build_flags = + ${env:tbeam.build_flags} + -D USE_ST7796 + +lib_deps = + ${env:tbeam.lib_deps} + https://github.com/meshtastic/st7796/archive/refs/tags/1.0.5.zip ; display addon + lewisxhe/SensorLib@0.3.1 ; touchscreen addon \ No newline at end of file diff --git a/variants/esp32/tbeam/variant.h b/variants/esp32/tbeam/variant.h index 5b521a2de..2d144a888 100644 --- a/variants/esp32/tbeam/variant.h +++ b/variants/esp32/tbeam/variant.h @@ -42,4 +42,35 @@ #define GPS_UBLOX #define GPS_RX_PIN 34 #define GPS_TX_PIN 12 -// #define GPS_DEBUG \ No newline at end of file +// #define GPS_DEBUG + +// Used when the display shield is chosen +#ifdef USE_ST7796 + +#undef EXT_NOTIFY_OUT +#undef LED_STATE_ON +#undef LED_PIN + +#define HAS_CST226SE 1 +#define HAS_TOUCHSCREEN 1 +// #define TOUCH_IRQ 35 // broken in this version of the lib 0.3.1 +#ifndef TOUCH_IRQ +#define TOUCH_IRQ -1 +#endif +#define CANNED_MESSAGE_MODULE_ENABLE 1 +#define USE_VIRTUAL_KEYBOARD 1 + +#define ST7796_NSS 25 +#define ST7796_RS 13 // DC +#define ST7796_SDA 14 // MOSI +#define ST7796_SCK 15 +#define ST7796_RESET 2 +#define ST7796_MISO -1 +#define ST7796_BUSY -1 +#define VTFT_LEDA 4 +#define TFT_SPI_FREQUENCY 60000000 +#define TFT_HEIGHT 222 +#define TFT_WIDTH 480 +#define BRIGHTNESS_DEFAULT 100 // Medium Low Brightness +#define SCREEN_TRANSITION_FRAMERATE 5 // fps +#endif \ No newline at end of file