Skip to content

Commit 5c42673

Browse files
committed
Pull in ST7789
1 parent 41598d9 commit 5c42673

File tree

5 files changed

+220
-19
lines changed

5 files changed

+220
-19
lines changed

platformio.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ extra_scripts = pre:rename_usb_config.py
212212
extends = common:esp32
213213
board = adafruit_feather_esp32s2_tft
214214
build_flags = -DARDUINO_ADAFRUIT_FEATHER_ESP32S2_TFT -DBOARD_HAS_PSRAM
215-
board_build.partitions = tinyuf2-partitions-4MB.csv
215+
board_build.partitions = tinyuf2-partitions-4MB-noota.csv
216216
extra_scripts = pre:rename_usb_config.py
217217

218218
; Adafruit Feather ESP32-S2 Reverse TFT

src/components/display/drivers/dispDrvBase.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,26 @@ class dispDrvBase {
4343
: _pin_dc(dc), _pin_rst(rst), _pin_cs(cs), _pin_sram_cs(sram_cs),
4444
_pin_busy(busy) {}
4545

46+
/*!
47+
@brief Constructor for the base display driver for SPI TFT displays.
48+
@param cs
49+
Chip Select pin for the display.
50+
@param dc
51+
Data/Command pin for the display.
52+
@param mosi
53+
MOSI pin for the display.
54+
@param sck
55+
SCK pin for the display.
56+
@param rst
57+
Optional Reset pin for the display.
58+
@param miso
59+
Optional MISO pin for the display.
60+
*/
61+
dispDrvBase(int8_t cs, int8_t dc, int8_t mosi, int8_t sck, int8_t rst = -1,
62+
int8_t miso = -1)
63+
: _pin_cs(cs), _pin_dc(dc), _pin_mosi(mosi), _pin_sck(sck), _pin_rst(rst),
64+
_pin_miso(miso) {}
65+
4666
/*!
4767
@brief Destructor for the base display driver.
4868
This destructor is virtual to allow derived classes to clean up
@@ -74,6 +94,9 @@ class dispDrvBase {
7494
int16_t _pin_cs; ///< Chip Select pin
7595
int16_t _pin_busy; ///< Optional Busy pin
7696
int16_t _pin_sram_cs; ///< Optional EPD SRAM chip select pin
97+
uint16_t _pin_mosi; ///< Optional MOSI pin for SPI TFT displays
98+
uint16_t _pin_miso; ///< Optional MISO pin for SPI TFT displays
99+
uint16_t _pin_sck; ///< Optional SCK pin for SPI TFT displays
77100
uint8_t _text_sz = 1; ///< Text size for displaying a message
78101
int16_t _height; ///< Height of the display
79102
int16_t _width; ///< Width of the display
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/*!
2+
* @file src/components/display/drivers/dispDrvSt7789.h
3+
*
4+
* Driver for ST7789-based TFT displays.
5+
*
6+
* Adafruit invests time and resources providing this open source code,
7+
* please support Adafruit and open-source hardware by purchasing
8+
* products from Adafruit!
9+
*
10+
* Copyright (c) Brent Rubell 2025 for Adafruit Industries.
11+
*
12+
* BSD license, all text here must be included in any redistribution.
13+
*
14+
*/
15+
#ifndef WS_DISP_DRV_ST7789
16+
#define WS_DISP_DRV_ST7789
17+
18+
#include "dispDrvBase.h"
19+
#include <Adafruit_ST7789.h>
20+
21+
/*!
22+
@brief Driver for ST7789-based TFT displays.
23+
*/
24+
class dispDrvSt7789 : public dispDrvBase {
25+
public:
26+
/*!
27+
@brief Constructor for the ST7789 display driver.
28+
@param cs
29+
Chip Select pin for the display.
30+
@param dc
31+
Data/Command pin for the display.
32+
@param mosi
33+
MOSI pin for the display.
34+
@param sck
35+
SCK pin for the display.
36+
@param rst
37+
Optional Reset pin for the display.
38+
@param miso
39+
Optional MISO pin for the display.
40+
*/
41+
dispDrvSt7789(int16_t cs, int16_t dc, int16_t mosi, int16_t sck,
42+
int16_t rst = -1, int16_t miso = -1)
43+
: dispDrvBase(cs, dc, mosi, sck, rst, miso), _display(nullptr) {}
44+
45+
~dispDrvSt7789() {
46+
if (_display) {
47+
delete _display;
48+
_display = nullptr;
49+
}
50+
}
51+
52+
/*!
53+
@brief Attempts to initialize the ST7789 TFT driver.
54+
@return True if the display was initialized successfully, false otherwise.
55+
*/
56+
bool begin() override {
57+
58+
// Special configuration for Feather TFTs
59+
#if defined(TFT_BACKLITE)
60+
// turn on backlite
61+
pinMode(TFT_BACKLITE, OUTPUT);
62+
digitalWrite(TFT_BACKLITE, HIGH);
63+
64+
// turn on the TFT / I2C power supply
65+
pinMode(TFT_I2C_POWER, OUTPUT);
66+
digitalWrite(TFT_I2C_POWER, HIGH);
67+
delay(10);
68+
#endif
69+
70+
_display = new Adafruit_ST7789(_pin_cs, _pin_dc, _pin_rst);
71+
72+
if (!_display)
73+
return false;
74+
75+
_display->init(_width, _height);
76+
_display->setRotation(_rotation);
77+
_display->fillScreen(ST77XX_BLACK);
78+
_display->setTextColor(ST77XX_WHITE);
79+
return true;
80+
}
81+
82+
/*!
83+
@brief Writes a message to the display.
84+
@param message
85+
The message to write to the display.
86+
@note This method overrides the base class method to provide specific
87+
functionality for the Think Ink Grayscale 4 EAAMGFGN driver.
88+
*/
89+
virtual void writeMessage(const char *message) override {
90+
if (_display == nullptr)
91+
return;
92+
93+
// Start with a fresh display buffer
94+
_display->fillScreen(ST77XX_BLACK);
95+
int16_t y_idx = 0;
96+
_display->setCursor(0, y_idx);
97+
98+
// Calculate the line height based on the text size (NOTE: base height is
99+
// 8px)
100+
int16_t line_height = 8 * _text_sz;
101+
uint16_t c_idx = 0;
102+
size_t msg_size = strlen(message);
103+
for (size_t i = 0; i < msg_size && c_idx < msg_size; i++) {
104+
if (y_idx + line_height > _height)
105+
break;
106+
if (message[i] == '\\' && i + 1 < msg_size &&
107+
(message[i + 1] == 'n' || message[i + 1] == 'r')) {
108+
// Handle \r\n sequence as a single newline
109+
if (message[i + 1] == 'r' && i + 3 < msg_size &&
110+
message[i + 2] == '\\' && message[i + 3] == 'n') {
111+
// Skip to the next line
112+
if (y_idx + line_height > _height)
113+
break;
114+
y_idx += line_height;
115+
_display->setCursor(0, y_idx);
116+
i += 3;
117+
} else if (message[i + 1] == 'n') {
118+
// Skip to the next line
119+
if (y_idx + line_height > _height)
120+
break;
121+
y_idx += line_height;
122+
_display->setCursor(0, y_idx);
123+
i++;
124+
}
125+
} else if (message[i] == 0xC2 && message[i + 1] == 0xB0) {
126+
_display->write(char(248));
127+
i++;
128+
} else {
129+
_display->print(message[i]);
130+
}
131+
}
132+
}
133+
134+
private:
135+
Adafruit_ST7789 *_display;
136+
};
137+
138+
#endif // WS_DISP_DRV_ST7789

src/components/display/hardware.cpp

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@
1717
/*!
1818
@brief Lambda function to create a dispDrvBase instance
1919
*/
20-
using FnCreateDispDrv =
20+
using FnCreateDispDrvEpd =
2121
std::function<dispDrvBase *(int16_t, int16_t, int16_t, int16_t, int16_t)>;
2222

2323
// Factory for creating a new display drivers
2424
// NOTE: When you add a new display driver, make sure to add it to the factory!
25-
static const std::map<std::string, FnCreateDispDrv> FactoryDrvDisp = {
25+
static const std::map<std::string, FnCreateDispDrvEpd> FactoryDrvDispEpd = {
2626
{"thinkink-gs4-eaamfgn",
2727
[](int16_t dc, int16_t rst, int16_t cs, int16_t sram_cs,
2828
int16_t busy) -> dispDrvBase * {
@@ -35,7 +35,29 @@ static const std::map<std::string, FnCreateDispDrv> FactoryDrvDisp = {
3535
}}};
3636

3737
/*!
38-
@brief Creates a new display driver instance based on the driver name.
38+
@brief Lambda function to create a dispDrvBase SPI TFT instance
39+
*/
40+
using FnCreateDispDrvTft = std::function<dispDrvBase *(
41+
int16_t, int16_t, int16_t, int16_t, int16_t, int16_t)>;
42+
43+
// Factory for creating a new SPI TFT display driver
44+
// NOTE: When you add a new SPI TFT display driver, make sure to add it to the
45+
// factory!
46+
static const std::map<std::string, FnCreateDispDrvTft> FactoryDrvDispTft = {
47+
{"st7735",
48+
[](int16_t cs, int16_t dc, int16_t mosi, int16_t sck, int16_t rst,
49+
int16_t miso) -> dispDrvBase * {
50+
return new dispDrvSt7789(cs, dc, mosi, sck, rst, miso);
51+
}},
52+
{"st7789",
53+
[](int16_t cs, int16_t dc, int16_t mosi, int16_t sck, int16_t rst,
54+
int16_t miso) -> dispDrvBase * {
55+
return new dispDrvSt7789(cs, dc, mosi, sck, rst, miso);
56+
}}};
57+
58+
/*!
59+
@brief Creates a new E-Ink display driver instance based on the driver
60+
name.
3961
@param driver_name
4062
The name of the display driver to create.
4163
@param dc
@@ -51,16 +73,32 @@ static const std::map<std::string, FnCreateDispDrv> FactoryDrvDisp = {
5173
@return Pointer to the created display driver instance, or nullptr if the
5274
driver name is not recognized.
5375
*/
54-
dispDrvBase *CreateDrvDisp(const char *driver_name, int16_t dc, int16_t rst,
55-
int16_t cs, int16_t sram_cs = -1,
56-
int16_t busy = -1) {
57-
auto it = FactoryDrvDisp.find(driver_name);
58-
if (it == FactoryDrvDisp.end())
76+
dispDrvBase *CreateDrvDispEpd(const char *driver_name, int16_t dc, int16_t rst,
77+
int16_t cs, int16_t sram_cs = -1,
78+
int16_t busy = -1) {
79+
auto it = FactoryDrvDispEpd.find(driver_name);
80+
if (it == FactoryDrvDispEpd.end())
5981
return nullptr;
6082

6183
return it->second(dc, rst, cs, sram_cs, busy);
6284
}
6385

86+
/*!
87+
@brief Creates a new SPI TFT display driver instance based on the driver
88+
name.
89+
@param driver_name
90+
The name of the SPI TFT display driver to create.
91+
*/
92+
dispDrvBase *CreateDrvDispTft(const char *driver_name, int16_t cs, int16_t dc,
93+
int16_t mosi, int16_t sck, int16_t rst = -1,
94+
int16_t miso = -1) {
95+
auto it = FactoryDrvDispTft.find(driver_name);
96+
if (it == FactoryDrvDispTft.end())
97+
return nullptr;
98+
99+
return it->second(cs, dc, mosi, sck, rst, miso);
100+
}
101+
64102
/*!
65103
@brief Constructs a new DisplayHardware object
66104
@param name
@@ -106,14 +144,13 @@ wippersnapper_display_v1_DisplayType DisplayHardware::getType() {
106144
The pin string to parse.
107145
@return The pin number, or -1 if the string is invalid.
108146
*/
109-
int16_t DisplayHardware::parsePin(const char* pinStr) {
110-
if (!pinStr || strlen(pinStr) < 2 || pinStr[0] != 'D') {
111-
return -1;
112-
}
113-
return atoi(pinStr + 1);
147+
int16_t DisplayHardware::parsePin(const char *pinStr) {
148+
if (!pinStr || strlen(pinStr) < 2 || pinStr[0] != 'D') {
149+
return -1;
150+
}
151+
return atoi(pinStr + 1);
114152
}
115153

116-
117154
/*!
118155
@brief Configures the EPD display with the provided configuration.
119156
@param config
@@ -179,7 +216,7 @@ bool DisplayHardware::beginEPD(
179216
}
180217

181218
// Create display driver object using the factory function
182-
_drvDisp = CreateDrvDisp(_name, dc, rst, cs, srcs, busy);
219+
_drvDisp = CreateDrvDispEpd(_name, dc, rst, cs, srcs, busy);
183220
if (!_drvDisp) {
184221
WS_DEBUG_PRINTLN("[display] Failed to create display driver!");
185222
return false; // Failed to create display driver
@@ -210,7 +247,9 @@ bool DisplayHardware::beginEPD(
210247
Pointer to the SPI configuration structure for TFT.
211248
@return True if configuration was successful, False otherwise.
212249
*/
213-
bool DisplayHardware::beginTft(wippersnapper_display_v1_TftConfig *config, wippersnapper_display_v1_TftSpiConfig *spi_config) {
250+
bool DisplayHardware::beginTft(
251+
wippersnapper_display_v1_TftConfig *config,
252+
wippersnapper_display_v1_TftSpiConfig *spi_config) {
214253
// Validate pointers
215254
if (config == nullptr || spi_config == nullptr) {
216255
WS_DEBUG_PRINTLN("[display] EPD config or SPI config is null!");
@@ -239,7 +278,7 @@ bool DisplayHardware::beginTft(wippersnapper_display_v1_TftConfig *config, wippe
239278
miso = parsePin(spi_config->pin_miso);
240279
}
241280

242-
return false;
281+
return false;
243282
}
244283

245284
/*!

src/components/display/hardware.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#define WS_DISPLAY_HARDWARE_H
1717
#include "Wippersnapper.h"
1818
#include "drivers/dispDrvBase.h"
19+
#include "drivers/dispDrvSt7789.h"
1920
#include "drivers/dispDrvThinkInkGrayscale4Eaamfgn.h"
2021
#include "drivers/dispDrvThinkInkGrayscale4T5.h"
2122
#include <functional>
@@ -51,7 +52,7 @@ class DisplayHardware {
5152
void writeMessage(const char *message);
5253

5354
private:
54-
int16_t parsePin(const char* pinStr);
55+
int16_t parsePin(const char *pinStr);
5556
bool detect_ssd1680(uint8_t cs, uint8_t dc, uint8_t rst);
5657
char _name[64]; ///< Identifies the hardware instance
5758
wippersnapper_display_v1_DisplayType _type; ///< Display type

0 commit comments

Comments
 (0)