Pull in ST7789

This commit is contained in:
brentru 2025-08-25 15:21:30 -04:00
parent 41598d93ee
commit 5c42673c03
5 changed files with 220 additions and 19 deletions

View file

@ -212,7 +212,7 @@ extra_scripts = pre:rename_usb_config.py
extends = common:esp32
board = adafruit_feather_esp32s2_tft
build_flags = -DARDUINO_ADAFRUIT_FEATHER_ESP32S2_TFT -DBOARD_HAS_PSRAM
board_build.partitions = tinyuf2-partitions-4MB.csv
board_build.partitions = tinyuf2-partitions-4MB-noota.csv
extra_scripts = pre:rename_usb_config.py
; Adafruit Feather ESP32-S2 Reverse TFT

View file

@ -43,6 +43,26 @@ public:
: _pin_dc(dc), _pin_rst(rst), _pin_cs(cs), _pin_sram_cs(sram_cs),
_pin_busy(busy) {}
/*!
@brief Constructor for the base display driver for SPI TFT displays.
@param cs
Chip Select pin for the display.
@param dc
Data/Command pin for the display.
@param mosi
MOSI pin for the display.
@param sck
SCK pin for the display.
@param rst
Optional Reset pin for the display.
@param miso
Optional MISO pin for the display.
*/
dispDrvBase(int8_t cs, int8_t dc, int8_t mosi, int8_t sck, int8_t rst = -1,
int8_t miso = -1)
: _pin_cs(cs), _pin_dc(dc), _pin_mosi(mosi), _pin_sck(sck), _pin_rst(rst),
_pin_miso(miso) {}
/*!
@brief Destructor for the base display driver.
This destructor is virtual to allow derived classes to clean up
@ -74,6 +94,9 @@ protected:
int16_t _pin_cs; ///< Chip Select pin
int16_t _pin_busy; ///< Optional Busy pin
int16_t _pin_sram_cs; ///< Optional EPD SRAM chip select pin
uint16_t _pin_mosi; ///< Optional MOSI pin for SPI TFT displays
uint16_t _pin_miso; ///< Optional MISO pin for SPI TFT displays
uint16_t _pin_sck; ///< Optional SCK pin for SPI TFT displays
uint8_t _text_sz = 1; ///< Text size for displaying a message
int16_t _height; ///< Height of the display
int16_t _width; ///< Width of the display

View file

@ -0,0 +1,138 @@
/*!
* @file src/components/display/drivers/dispDrvSt7789.h
*
* Driver for ST7789-based TFT displays.
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit and open-source hardware by purchasing
* products from Adafruit!
*
* Copyright (c) Brent Rubell 2025 for Adafruit Industries.
*
* BSD license, all text here must be included in any redistribution.
*
*/
#ifndef WS_DISP_DRV_ST7789
#define WS_DISP_DRV_ST7789
#include "dispDrvBase.h"
#include <Adafruit_ST7789.h>
/*!
@brief Driver for ST7789-based TFT displays.
*/
class dispDrvSt7789 : public dispDrvBase {
public:
/*!
@brief Constructor for the ST7789 display driver.
@param cs
Chip Select pin for the display.
@param dc
Data/Command pin for the display.
@param mosi
MOSI pin for the display.
@param sck
SCK pin for the display.
@param rst
Optional Reset pin for the display.
@param miso
Optional MISO pin for the display.
*/
dispDrvSt7789(int16_t cs, int16_t dc, int16_t mosi, int16_t sck,
int16_t rst = -1, int16_t miso = -1)
: dispDrvBase(cs, dc, mosi, sck, rst, miso), _display(nullptr) {}
~dispDrvSt7789() {
if (_display) {
delete _display;
_display = nullptr;
}
}
/*!
@brief Attempts to initialize the ST7789 TFT driver.
@return True if the display was initialized successfully, false otherwise.
*/
bool begin() override {
// Special configuration for Feather TFTs
#if defined(TFT_BACKLITE)
// turn on backlite
pinMode(TFT_BACKLITE, OUTPUT);
digitalWrite(TFT_BACKLITE, HIGH);
// turn on the TFT / I2C power supply
pinMode(TFT_I2C_POWER, OUTPUT);
digitalWrite(TFT_I2C_POWER, HIGH);
delay(10);
#endif
_display = new Adafruit_ST7789(_pin_cs, _pin_dc, _pin_rst);
if (!_display)
return false;
_display->init(_width, _height);
_display->setRotation(_rotation);
_display->fillScreen(ST77XX_BLACK);
_display->setTextColor(ST77XX_WHITE);
return true;
}
/*!
@brief Writes a message to the display.
@param message
The message to write to the display.
@note This method overrides the base class method to provide specific
functionality for the Think Ink Grayscale 4 EAAMGFGN driver.
*/
virtual void writeMessage(const char *message) override {
if (_display == nullptr)
return;
// Start with a fresh display buffer
_display->fillScreen(ST77XX_BLACK);
int16_t y_idx = 0;
_display->setCursor(0, y_idx);
// Calculate the line height based on the text size (NOTE: base height is
// 8px)
int16_t line_height = 8 * _text_sz;
uint16_t c_idx = 0;
size_t msg_size = strlen(message);
for (size_t i = 0; i < msg_size && c_idx < msg_size; i++) {
if (y_idx + line_height > _height)
break;
if (message[i] == '\\' && i + 1 < msg_size &&
(message[i + 1] == 'n' || message[i + 1] == 'r')) {
// Handle \r\n sequence as a single newline
if (message[i + 1] == 'r' && i + 3 < msg_size &&
message[i + 2] == '\\' && message[i + 3] == 'n') {
// Skip to the next line
if (y_idx + line_height > _height)
break;
y_idx += line_height;
_display->setCursor(0, y_idx);
i += 3;
} else if (message[i + 1] == 'n') {
// Skip to the next line
if (y_idx + line_height > _height)
break;
y_idx += line_height;
_display->setCursor(0, y_idx);
i++;
}
} else if (message[i] == 0xC2 && message[i + 1] == 0xB0) {
_display->write(char(248));
i++;
} else {
_display->print(message[i]);
}
}
}
private:
Adafruit_ST7789 *_display;
};
#endif // WS_DISP_DRV_ST7789

View file

@ -17,12 +17,12 @@
/*!
@brief Lambda function to create a dispDrvBase instance
*/
using FnCreateDispDrv =
using FnCreateDispDrvEpd =
std::function<dispDrvBase *(int16_t, int16_t, int16_t, int16_t, int16_t)>;
// Factory for creating a new display drivers
// NOTE: When you add a new display driver, make sure to add it to the factory!
static const std::map<std::string, FnCreateDispDrv> FactoryDrvDisp = {
static const std::map<std::string, FnCreateDispDrvEpd> FactoryDrvDispEpd = {
{"thinkink-gs4-eaamfgn",
[](int16_t dc, int16_t rst, int16_t cs, int16_t sram_cs,
int16_t busy) -> dispDrvBase * {
@ -35,7 +35,29 @@ static const std::map<std::string, FnCreateDispDrv> FactoryDrvDisp = {
}}};
/*!
@brief Creates a new display driver instance based on the driver name.
@brief Lambda function to create a dispDrvBase SPI TFT instance
*/
using FnCreateDispDrvTft = std::function<dispDrvBase *(
int16_t, int16_t, int16_t, int16_t, int16_t, int16_t)>;
// Factory for creating a new SPI TFT display driver
// NOTE: When you add a new SPI TFT display driver, make sure to add it to the
// factory!
static const std::map<std::string, FnCreateDispDrvTft> FactoryDrvDispTft = {
{"st7735",
[](int16_t cs, int16_t dc, int16_t mosi, int16_t sck, int16_t rst,
int16_t miso) -> dispDrvBase * {
return new dispDrvSt7789(cs, dc, mosi, sck, rst, miso);
}},
{"st7789",
[](int16_t cs, int16_t dc, int16_t mosi, int16_t sck, int16_t rst,
int16_t miso) -> dispDrvBase * {
return new dispDrvSt7789(cs, dc, mosi, sck, rst, miso);
}}};
/*!
@brief Creates a new E-Ink display driver instance based on the driver
name.
@param driver_name
The name of the display driver to create.
@param dc
@ -51,16 +73,32 @@ static const std::map<std::string, FnCreateDispDrv> FactoryDrvDisp = {
@return Pointer to the created display driver instance, or nullptr if the
driver name is not recognized.
*/
dispDrvBase *CreateDrvDisp(const char *driver_name, int16_t dc, int16_t rst,
int16_t cs, int16_t sram_cs = -1,
int16_t busy = -1) {
auto it = FactoryDrvDisp.find(driver_name);
if (it == FactoryDrvDisp.end())
dispDrvBase *CreateDrvDispEpd(const char *driver_name, int16_t dc, int16_t rst,
int16_t cs, int16_t sram_cs = -1,
int16_t busy = -1) {
auto it = FactoryDrvDispEpd.find(driver_name);
if (it == FactoryDrvDispEpd.end())
return nullptr;
return it->second(dc, rst, cs, sram_cs, busy);
}
/*!
@brief Creates a new SPI TFT display driver instance based on the driver
name.
@param driver_name
The name of the SPI TFT display driver to create.
*/
dispDrvBase *CreateDrvDispTft(const char *driver_name, int16_t cs, int16_t dc,
int16_t mosi, int16_t sck, int16_t rst = -1,
int16_t miso = -1) {
auto it = FactoryDrvDispTft.find(driver_name);
if (it == FactoryDrvDispTft.end())
return nullptr;
return it->second(cs, dc, mosi, sck, rst, miso);
}
/*!
@brief Constructs a new DisplayHardware object
@param name
@ -106,14 +144,13 @@ wippersnapper_display_v1_DisplayType DisplayHardware::getType() {
The pin string to parse.
@return The pin number, or -1 if the string is invalid.
*/
int16_t DisplayHardware::parsePin(const char* pinStr) {
if (!pinStr || strlen(pinStr) < 2 || pinStr[0] != 'D') {
return -1;
}
return atoi(pinStr + 1);
int16_t DisplayHardware::parsePin(const char *pinStr) {
if (!pinStr || strlen(pinStr) < 2 || pinStr[0] != 'D') {
return -1;
}
return atoi(pinStr + 1);
}
/*!
@brief Configures the EPD display with the provided configuration.
@param config
@ -179,7 +216,7 @@ bool DisplayHardware::beginEPD(
}
// Create display driver object using the factory function
_drvDisp = CreateDrvDisp(_name, dc, rst, cs, srcs, busy);
_drvDisp = CreateDrvDispEpd(_name, dc, rst, cs, srcs, busy);
if (!_drvDisp) {
WS_DEBUG_PRINTLN("[display] Failed to create display driver!");
return false; // Failed to create display driver
@ -210,7 +247,9 @@ bool DisplayHardware::beginEPD(
Pointer to the SPI configuration structure for TFT.
@return True if configuration was successful, False otherwise.
*/
bool DisplayHardware::beginTft(wippersnapper_display_v1_TftConfig *config, wippersnapper_display_v1_TftSpiConfig *spi_config) {
bool DisplayHardware::beginTft(
wippersnapper_display_v1_TftConfig *config,
wippersnapper_display_v1_TftSpiConfig *spi_config) {
// Validate pointers
if (config == nullptr || spi_config == nullptr) {
WS_DEBUG_PRINTLN("[display] EPD config or SPI config is null!");
@ -239,7 +278,7 @@ bool DisplayHardware::beginTft(wippersnapper_display_v1_TftConfig *config, wippe
miso = parsePin(spi_config->pin_miso);
}
return false;
return false;
}
/*!

View file

@ -16,6 +16,7 @@
#define WS_DISPLAY_HARDWARE_H
#include "Wippersnapper.h"
#include "drivers/dispDrvBase.h"
#include "drivers/dispDrvSt7789.h"
#include "drivers/dispDrvThinkInkGrayscale4Eaamfgn.h"
#include "drivers/dispDrvThinkInkGrayscale4T5.h"
#include <functional>
@ -51,7 +52,7 @@ public:
void writeMessage(const char *message);
private:
int16_t parsePin(const char* pinStr);
int16_t parsePin(const char *pinStr);
bool detect_ssd1680(uint8_t cs, uint8_t dc, uint8_t rst);
char _name[64]; ///< Identifies the hardware instance
wippersnapper_display_v1_DisplayType _type; ///< Display type