From be889015f7792d8a15367d0ac471cb66b2f5d6cb Mon Sep 17 00:00:00 2001 From: Gareth Coleman Date: Wed, 3 Apr 2024 20:17:13 +0100 Subject: [PATCH 1/2] New device unPhone using HX8357D LCD and XPT2046 touchscreen --- src/graphics/Screen.cpp | 15 ++-- src/graphics/ScreenFonts.h | 2 +- src/graphics/TFTDisplay.cpp | 113 +++++++++++++++++++++++++++++- src/graphics/images.h | 5 +- src/main.cpp | 18 ++++- src/platform/esp32/architecture.h | 4 +- variants/unphone/platformio.ini | 16 +++++ variants/unphone/variant.h | 61 ++++++++++++++++ 8 files changed, 218 insertions(+), 16 deletions(-) create mode 100644 variants/unphone/platformio.ini create mode 100644 variants/unphone/variant.h diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 2087b8daf8..8510562c40 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -528,7 +528,7 @@ static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const NodeStat { char usersString[20]; snprintf(usersString, sizeof(usersString), "%d/%d", nodeStatus->getNumOnline(), nodeStatus->getNumTotal()); -#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \ +#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS) || defined(HX8357_CS)) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) display->drawFastImage(x, y + 3, 8, 8, imgUser); #else @@ -955,7 +955,7 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O #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); -#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(RAK14014) +#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(RAK14014) || defined(HX8357_CS) dispdev = new TFTDisplay(address.address, -1, -1, geometry, (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); #elif defined(USE_EINK) && !defined(USE_EINK_DYNAMICDISPLAY) @@ -1101,7 +1101,7 @@ void Screen::setup() // Standard behaviour is to FLIP the screen (needed on T-Beam). If this config item is set, unflip it, and thereby logically // flip it. If you have a headache now, you're welcome. if (!config.display.flip_screen) { -#if defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(RAK14014) +#if defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(RAK14014) || defined(HX8357_CS) static_cast(dispdev)->flipScreenVertically(); #else dispdev->flipScreenVertically(); @@ -1686,7 +1686,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 #ifdef ARCH_ESP32 if (millis() - storeForwardModule->lastHeartbeat > (storeForwardModule->heartbeatInterval * 1200)) { // no heartbeat, overlap a bit -#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \ +#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS) || defined(HX8357_CS)) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8, imgQuestionL1); @@ -1697,7 +1697,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 imgQuestion); #endif } else { -#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \ +#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS) || defined(HX8357_CS)) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 16, 8, imgSFL1); @@ -1711,7 +1711,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 #endif } else { // TODO: Raspberry Pi supports more than just the one screen size -#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS) || ARCH_PORTDUINO) && \ +#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS) || defined(HX8357_CS) || \ + ARCH_PORTDUINO) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8, imgInfoL1); @@ -1974,4 +1975,4 @@ int Screen::handleInputEvent(const InputEvent *event) } // namespace graphics #else graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {} -#endif // HAS_SCREEN \ No newline at end of file +#endif // HAS_SCREEN diff --git a/src/graphics/ScreenFonts.h b/src/graphics/ScreenFonts.h index d858add2ce..4b34563f70 100644 --- a/src/graphics/ScreenFonts.h +++ b/src/graphics/ScreenFonts.h @@ -8,7 +8,7 @@ #include "graphics/fonts/OLEDDisplayFontsUA.h" #endif -#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \ +#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS) || defined(HX8357_CS)) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) // The screen is bigger so use bigger fonts #define FONT_SMALL ArialMT_Plain_16 // Height: 19 diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp index 79f521fbbd..c1f482b840 100644 --- a/src/graphics/TFTDisplay.cpp +++ b/src/graphics/TFTDisplay.cpp @@ -402,9 +402,95 @@ class LGFX : public lgfx::LGFX_Device }; static LGFX *tft = nullptr; + +#elif defined(HX8357_CS) +#include // Graphics and font library for HX8357 driver chip + +class LGFX : public lgfx::LGFX_Device +{ + lgfx::Panel_HX8357D _panel_instance; + lgfx::Bus_SPI _bus_instance; + #if defined(USE_XPT2046) + lgfx::ITouch *_touch_instance; + // lgfx::Touch_XPT2046 _touch_instance; + #endif + + public: + LGFX(void) + { + // Panel_HX8357D + { + // configure SPI + auto cfg = _bus_instance.config(); + + cfg.spi_host = HX8357_SPI_HOST; + cfg.spi_mode = 0; + cfg.freq_write = SPI_FREQUENCY; // SPI clock for transmission (up to 80MHz, rounded to the value obtained by dividing + // 80MHz by an integer) + cfg.freq_read = SPI_READ_FREQUENCY; // SPI clock when receiving + cfg.spi_3wire = false; // Set to true if reception is done on the MOSI pin + cfg.use_lock = true; // Set to true to use transaction locking + cfg.dma_channel = SPI_DMA_CH_AUTO; // SPI_DMA_CH_AUTO; // Set DMA channel to use (0=not use DMA / 1=1ch / 2=ch / + // SPI_DMA_CH_AUTO=auto setting) + cfg.pin_sclk = HX8357_SCK; // Set SPI SCLK pin number + cfg.pin_mosi = HX8357_MOSI; // Set SPI MOSI pin number + cfg.pin_miso = HX8357_MISO; // Set SPI MISO pin number (-1 = disable) + cfg.pin_dc = HX8357_RS; // Set SPI DC pin number (-1 = disable) + + _bus_instance.config(cfg); // applies the set value to the bus. + _panel_instance.setBus(&_bus_instance); // set the bus on the panel. + } + { + // Set the display panel control. + auto cfg = _panel_instance.config(); // Gets a structure for display panel settings. + + cfg.pin_cs = HX8357_CS; // Pin number where CS is connected (-1 = disable) + cfg.pin_rst = HX8357_RESET; // Pin number where RST is connected (-1 = disable) + cfg.pin_busy = HX8357_BUSY; // Pin number where BUSY is connected (-1 = disable) + + cfg.panel_width = TFT_WIDTH; // actual displayable width + cfg.panel_height = TFT_HEIGHT; // actual displayable height + cfg.offset_x = TFT_OFFSET_X; // Panel offset amount in X direction + cfg.offset_y = TFT_OFFSET_Y; // Panel offset amount in Y direction + cfg.offset_rotation = TFT_OFFSET_ROTATION; // Rotation direction value offset 0~7 (4~7 is upside down) + cfg.dummy_read_pixel = 8; // Number of bits for dummy read before pixel readout + cfg.dummy_read_bits = 1; // Number of bits for dummy read before non-pixel data read + cfg.readable = true; // Set to true if data can be read + cfg.invert = TFT_INVERT; // Set to true if the light/darkness of the panel is reversed + cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped + cfg.dlen_16bit = false; + cfg.bus_shared = true; // If the bus is shared with the SD card, set to true (bus control with drawJpgFile etc.) + + _panel_instance.config(cfg); + } + #if defined(USE_XPT2046) + { + // Configure settings for touch control. + _touch_instance = new lgfx::Touch_XPT2046; + auto touch_cfg = _touch_instance->config(); + + touch_cfg.pin_cs = TOUCH_CS; + touch_cfg.x_min = 0; + touch_cfg.x_max = TFT_HEIGHT - 1; + touch_cfg.y_min = 0; + touch_cfg.y_max = TFT_WIDTH - 1; + touch_cfg.pin_int = -1; + touch_cfg.bus_shared = true; + touch_cfg.offset_rotation = 1; + + _touch_instance->config(touch_cfg); + //_panel_instance->setTouch(_touch_instance); + } + #endif + setPanel(&_panel_instance); + } +}; + +static LGFX *tft = nullptr; + #endif -#if defined(ST7735_CS) || defined(ST7789_CS) || defined(ILI9341_DRIVER) || defined(RAK14014) || \ +#if defined(ST7735_CS) || defined(ST7789_CS) || defined(ILI9341_DRIVER) || defined(RAK14014) || defined(HX8357_CS) || \ (ARCH_PORTDUINO && HAS_SCREEN != 0) #include "SPILock.h" #include "TFTDisplay.h" @@ -487,7 +573,13 @@ void TFTDisplay::sendCommand(uint8_t com) #ifdef VTFT_CTRL digitalWrite(VTFT_CTRL, LOW); #endif - +#ifdef UNPHONE + Wire.beginTransmission(0x26); + Wire.write(0x02); + Wire.write(0x04); // Backlight on + Wire.write(0x22); // G&B LEDs off + Wire.endTransmission(); +#endif #ifdef RAK14014 #elif !defined(M5STACK) tft->setBrightness(172); @@ -514,6 +606,13 @@ void TFTDisplay::sendCommand(uint8_t com) #ifdef VTFT_CTRL digitalWrite(VTFT_CTRL, HIGH); #endif +#ifdef UNPHONE + Wire.beginTransmission(0x26); + Wire.write(0x02); + Wire.write(0x00); // Backlight off + Wire.write(0x22); // G&B LEDs off + Wire.endTransmission(); +#endif #ifdef RAK14014 #elif !defined(M5STACK) tft->setBrightness(0); @@ -585,6 +684,14 @@ bool TFTDisplay::connect() pinMode(ST7735_BL_V05, OUTPUT); digitalWrite(ST7735_BL_V05, TFT_BACKLIGHT_ON); #endif +#ifdef UNPHONE + Wire.beginTransmission(0x26); + Wire.write(0x02); + Wire.write(0x04); // Backlight on + Wire.write(0x22); // G&B LEDs off + Wire.endTransmission(); + LOG_INFO("Power to TFT Backlight\n"); +#endif tft->init(); @@ -606,4 +713,4 @@ bool TFTDisplay::connect() return true; } -#endif \ No newline at end of file +#endif diff --git a/src/graphics/images.h b/src/graphics/images.h index 207fc3a86c..5c6fb42753 100644 --- a/src/graphics/images.h +++ b/src/graphics/images.h @@ -14,7 +14,8 @@ const uint8_t imgUser[] PROGMEM = {0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3 const uint8_t imgPositionEmpty[] PROGMEM = {0x20, 0x30, 0x28, 0x24, 0x42, 0xFF}; const uint8_t imgPositionSolid[] PROGMEM = {0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF}; -#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS) || ARCH_PORTDUINO) && \ +#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS) || defined(HX8357_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}; @@ -30,4 +31,4 @@ const uint8_t imgQuestion[] PROGMEM = {0xbf, 0x41, 0xc0, 0x8b, 0xdb, 0x70, 0xa1, const uint8_t imgSF[] PROGMEM = {0xd2, 0xb7, 0xad, 0xbb, 0x92, 0x01, 0xfd, 0xfd, 0x15, 0x85, 0xf5}; #endif -#include "img/icon.xbm" \ No newline at end of file +#include "img/icon.xbm" diff --git a/src/main.cpp b/src/main.cpp index 0c45e903a3..e93acf0ffc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -589,6 +589,20 @@ void setup() if (config.display.oled != meshtastic_Config_DisplayConfig_OledType_OLED_AUTO) screen_model = config.display.oled; +#ifdef UNPHONE + // initialise IO expander with pinmodes + Wire.beginTransmission(0x26); + Wire.write(0x06); + Wire.write(0x7A); + Wire.write(0xDD); + Wire.endTransmission(); + Wire.beginTransmission(0x26); + Wire.write(0x02); + Wire.write(0x04); // Backlight on + Wire.write(0x22); // G&B LEDs off + Wire.endTransmission(); +#endif + #if defined(USE_SH1107) screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1107; // set dimension of 128x128 display_geometry = GEOMETRY_128_128; @@ -686,7 +700,7 @@ void setup() // Don't call screen setup until after nodedb is setup (because we need // the current region name) -#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) +#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(HX8357_CS) screen->setup(); #elif defined(ARCH_PORTDUINO) if (screen_found.port != ScanI2C::I2CPort::NO_I2C || settingsMap[displayPanel]) { @@ -986,4 +1000,4 @@ void loop() mainDelay.delay(delayMsec); } // if (didWake) LOG_DEBUG("wake!\n"); -} \ No newline at end of file +} diff --git a/src/platform/esp32/architecture.h b/src/platform/esp32/architecture.h index 703bcefc98..6855265ac6 100644 --- a/src/platform/esp32/architecture.h +++ b/src/platform/esp32/architecture.h @@ -135,6 +135,8 @@ #define HW_VENDOR meshtastic_HardwareModel_CHATTER_2 #elif defined(STATION_G2) #define HW_VENDOR meshtastic_HardwareModel_STATION_G2 +#elif defined(UNPHONE) +#define HW_VENDOR meshtastic_HardwareModel_UNPHONE #endif // ----------------------------------------------------------------------------- @@ -157,4 +159,4 @@ #define LORA_CS 18 #endif -#define SERIAL0_RX_GPIO 3 // Always GPIO3 on ESP32 // FIXME: may be different on ESP32-S3, etc. \ No newline at end of file +#define SERIAL0_RX_GPIO 3 // Always GPIO3 on ESP32 // FIXME: may be different on ESP32-S3, etc. diff --git a/variants/unphone/platformio.ini b/variants/unphone/platformio.ini new file mode 100644 index 0000000000..9a4a638070 --- /dev/null +++ b/variants/unphone/platformio.ini @@ -0,0 +1,16 @@ +[env:unphone] +;build_type = debug ; to make it possible to step through our jtag debugger +extends = esp32s3_base +board_level = extra +board = unphone9 +upload_speed = 921600 +monitor_speed = 115200 +monitor_filters = esp32_exception_decoder + +build_flags = ${esp32_base.build_flags} + -D UNPHONE + -D BOARD_HAS_PSRAM + -I variants/unphone + +lib_deps = ${esp32s3_base.lib_deps} + lovyan03/LovyanGFX@^1.1.8 \ No newline at end of file diff --git a/variants/unphone/variant.h b/variants/unphone/variant.h new file mode 100644 index 0000000000..3032156f49 --- /dev/null +++ b/variants/unphone/variant.h @@ -0,0 +1,61 @@ +#define SPI_SCK 39 +#define SPI_MOSI 40 +#define SPI_MISO 41 + +// We use the RFM95W LoRa module +#define USE_RF95 +#define LORA_SCK SPI_SCK +#define LORA_MOSI SPI_MOSI +#define LORA_MISO SPI_MISO +#define LORA_CS 44 +#define LORA_DIO0 10 // AKA LORA_IRQ +#define LORA_RESET 42 +#define LORA_DIO1 11 +#define LORA_DIO2 RADIOLIB_NC // Not really used + +// HX8357 TFT LCD +#define HX8357_CS 48 +#define HX8357_RS 47 // AKA DC +#define HX8357_RESET 46 +#define HX8357_SCK SPI_SCK +#define HX8357_MOSI SPI_MOSI +#define HX8357_MISO SPI_MISO +#define HX8357_BUSY -1 +#define HX8357_SPI_HOST SPI2_HOST +#define SPI_FREQUENCY 40000000 +#define SPI_READ_FREQUENCY 16000000 +#define TFT_HEIGHT 480 +#define TFT_WIDTH 320 +#define TFT_OFFSET_X 0 +#define TFT_OFFSET_Y 0 +#define TFT_OFFSET_ROTATION 6 // the unPhone's screen is wired unusually, 0 is typical value here +#define TFT_INVERT false +#define SCREEN_ROTATE true +#define SCREEN_TRANSITION_FRAMERATE 5 + +#define HAS_TOUCHSCREEN 1 +#define USE_XPT2046 1 +#define TOUCH_CS 38 + +#define HAS_GPS 0 // the unphone doesn't have a gps module +#undef GPS_RX_PIN +#undef GPS_TX_PIN + +#define HAS_SDCARD 1 +#define SDCARD_CS 43 + +#define LED_PIN 13 // the red part of the RGB LED +#define LED_INVERTED 1 + +#define BUTTON_PIN 21 // Button 3 - square - top button in landscape mode +#define BUTTON_NEED_PULLUP // we do need a helping hand up + +#define I2C_SDA 3 // I2C pins for this board +#define I2C_SCL 4 + +// ratio of voltage divider = 3.20 (R1=100k, R2=220k) +// #define ADC_MULTIPLIER 3.2 + +// #define BATTERY_PIN 13 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage +// #define ADC_CHANNEL ADC2_GPIO13_CHANNEL +// #define BAT_MEASURE_ADC_UNIT 2 \ No newline at end of file From 4cdfae71cfe2a47b6265adb6bc2041384dcc6114 Mon Sep 17 00:00:00 2001 From: Gareth Coleman Date: Wed, 3 Apr 2024 20:34:31 +0100 Subject: [PATCH 2/2] first attempt at getting trunk to do linting --- src/graphics/TFTDisplay.cpp | 10 +++++----- variants/unphone/variant.h | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp index c1f482b840..8de415185a 100644 --- a/src/graphics/TFTDisplay.cpp +++ b/src/graphics/TFTDisplay.cpp @@ -410,10 +410,10 @@ class LGFX : public lgfx::LGFX_Device { lgfx::Panel_HX8357D _panel_instance; lgfx::Bus_SPI _bus_instance; - #if defined(USE_XPT2046) +#if defined(USE_XPT2046) lgfx::ITouch *_touch_instance; - // lgfx::Touch_XPT2046 _touch_instance; - #endif +// lgfx::Touch_XPT2046 _touch_instance; +#endif public: LGFX(void) @@ -463,7 +463,7 @@ class LGFX : public lgfx::LGFX_Device _panel_instance.config(cfg); } - #if defined(USE_XPT2046) +#if defined(USE_XPT2046) { // Configure settings for touch control. _touch_instance = new lgfx::Touch_XPT2046; @@ -481,7 +481,7 @@ class LGFX : public lgfx::LGFX_Device _touch_instance->config(touch_cfg); //_panel_instance->setTouch(_touch_instance); } - #endif +#endif setPanel(&_panel_instance); } }; diff --git a/variants/unphone/variant.h b/variants/unphone/variant.h index 3032156f49..dff03b8d5b 100644 --- a/variants/unphone/variant.h +++ b/variants/unphone/variant.h @@ -28,7 +28,7 @@ #define TFT_WIDTH 320 #define TFT_OFFSET_X 0 #define TFT_OFFSET_Y 0 -#define TFT_OFFSET_ROTATION 6 // the unPhone's screen is wired unusually, 0 is typical value here +#define TFT_OFFSET_ROTATION 6 // the unPhone's screen is wired unusually, 0 is typical value here #define TFT_INVERT false #define SCREEN_ROTATE true #define SCREEN_TRANSITION_FRAMERATE 5 @@ -37,20 +37,20 @@ #define USE_XPT2046 1 #define TOUCH_CS 38 -#define HAS_GPS 0 // the unphone doesn't have a gps module +#define HAS_GPS 0 // the unphone doesn't have a gps module #undef GPS_RX_PIN #undef GPS_TX_PIN #define HAS_SDCARD 1 #define SDCARD_CS 43 -#define LED_PIN 13 // the red part of the RGB LED +#define LED_PIN 13 // the red part of the RGB LED #define LED_INVERTED 1 -#define BUTTON_PIN 21 // Button 3 - square - top button in landscape mode +#define BUTTON_PIN 21 // Button 3 - square - top button in landscape mode #define BUTTON_NEED_PULLUP // we do need a helping hand up -#define I2C_SDA 3 // I2C pins for this board +#define I2C_SDA 3 // I2C pins for this board #define I2C_SCL 4 // ratio of voltage divider = 3.20 (R1=100k, R2=220k)