buttons, power button pin 18, deep sleep implementation, dokumentaion, and decription. optimzed sd card and display init, remove bloink screens at start, added color screens for error notifications
This commit is contained in:
@@ -1,8 +1,22 @@
|
||||
/**
|
||||
* @file st7789.h
|
||||
* @brief ST7789 Display Driver for Waveshare ESP32-S3-Touch-LCD-2
|
||||
*
|
||||
* 2.0" TFT Display, 240x320 resolution
|
||||
* @brief ST7789 Display-Treiber für Waveshare ESP32-S3-Touch-LCD-2
|
||||
*
|
||||
* Dieser Treiber steuert das 2.0" TFT-Display (240×320 Pixel) über SPI.
|
||||
*
|
||||
* Hardware-Details:
|
||||
* - Controller: ST7789V2
|
||||
* - Auflösung: 320×240 Pixel (Landscape-Modus)
|
||||
* - Farbtiefe: 16-bit RGB565
|
||||
* - Interface: 4-Wire SPI
|
||||
* - Maximale SPI-Frequenz: 80 MHz
|
||||
* - DMA-Unterstützung für schnelle Framebuffer-Transfers
|
||||
*
|
||||
* Features:
|
||||
* - Hardware-Reset über GPIO
|
||||
* - PWM-Hintergrundbeleuchtung (0-100%)
|
||||
* - Optimierte Framebuffer-Funktion (preswapped)
|
||||
* - DMA-basierte SPI-Transfers für hohe Performance
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
@@ -15,53 +29,104 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialize ST7789 display
|
||||
* @return ESP_OK on success
|
||||
* @brief ST7789 Display initialisieren
|
||||
* @return ESP_OK bei Erfolg, Fehlercode sonst
|
||||
*
|
||||
* Diese Funktion:
|
||||
* - Initialisiert SPI-Bus (80 MHz)
|
||||
* - Führt Hardware-Reset durch
|
||||
* - Sendet Initialisierungs-Kommandos
|
||||
* - Konfiguriert Display-Orientierung (Landscape)
|
||||
* - Aktiviert Display
|
||||
*/
|
||||
esp_err_t st7789_init(void);
|
||||
|
||||
/**
|
||||
* @brief Set backlight brightness
|
||||
* @param brightness 0-100%
|
||||
* @brief Hintergrundbeleuchtung einstellen
|
||||
* @param brightness Helligkeit (0-100%)
|
||||
*
|
||||
* Verwendet LEDC PWM für stufenlose Helligkeitsregelung.
|
||||
* 0 = Aus, 100 = Maximale Helligkeit
|
||||
*/
|
||||
void st7789_set_backlight(uint8_t brightness);
|
||||
|
||||
/**
|
||||
* @brief Clear screen to color
|
||||
* @param color 16-bit RGB565 color
|
||||
* @brief Bildschirm mit Farbe füllen
|
||||
* @param color 16-bit RGB565 Farbe
|
||||
*
|
||||
* Füllt den gesamten Bildschirm (320×240) mit einer Vollfarbe.
|
||||
* Nützlich für Splash-Screens oder Hintergrund.
|
||||
*
|
||||
* RGB565 Format: RRRRR GGGGGG BBBBB
|
||||
* Beispiele:
|
||||
* 0xF800 = Rot, 0x07E0 = Grün, 0x001F = Blau
|
||||
* 0xFFFF = Weiß, 0x0000 = Schwarz
|
||||
*/
|
||||
void st7789_fill_screen(uint16_t color);
|
||||
|
||||
/**
|
||||
* @brief Draw pixel
|
||||
* @param x X coordinate
|
||||
* @param y Y coordinate
|
||||
* @param color 16-bit RGB565 color
|
||||
* @brief Einzelnes Pixel zeichnen
|
||||
* @param x X-Koordinate (0-319)
|
||||
* @param y Y-Koordinate (0-239)
|
||||
* @param color 16-bit RGB565 Farbe
|
||||
*
|
||||
* Langsame Funktion! Nur für einzelne Pixel verwenden.
|
||||
* Für größere Bereiche st7789_draw_buffer() nutzen.
|
||||
*/
|
||||
void st7789_draw_pixel(int16_t x, int16_t y, uint16_t color);
|
||||
|
||||
/**
|
||||
* @brief Draw buffer (framebuffer)
|
||||
* @param buffer Pointer to RGB565 framebuffer
|
||||
* @param x X start position
|
||||
* @param y Y start position
|
||||
* @param width Width of buffer
|
||||
* @param height Height of buffer
|
||||
* @brief Framebuffer zeichnen (mit Byte-Swap)
|
||||
* @param buffer Zeiger auf RGB565 Framebuffer
|
||||
* @param x X-Startposition
|
||||
* @param y Y-Startposition
|
||||
* @param width Breite des Buffers (Pixel)
|
||||
* @param height Höhe des Buffers (Pixel)
|
||||
*
|
||||
* Diese Funktion führt automatisches Byte-Swapping durch:
|
||||
* RGB565 → BGR565 (ST7789 erwartet BGR-Reihenfolge)
|
||||
*
|
||||
* HINWEIS: Allokiert temporären Buffer! Für Performance
|
||||
* besser st7789_draw_buffer_preswapped() verwenden.
|
||||
*/
|
||||
void st7789_draw_buffer(const uint16_t *buffer, int16_t x, int16_t y,
|
||||
int16_t width, int16_t height);
|
||||
|
||||
/**
|
||||
* @brief Draw buffer that is already byte-swapped (optimized, no allocation)
|
||||
* @param buffer Pointer to pre-swapped BGR565 framebuffer
|
||||
* @param x X start position
|
||||
* @param y Y start position
|
||||
* @param width Width of buffer
|
||||
* @param height Height of buffer
|
||||
* @brief Framebuffer zeichnen (OPTIMIERT, ohne Byte-Swap)
|
||||
* @param buffer Zeiger auf vor-geswapted BGR565 Framebuffer
|
||||
* @param x X-Startposition
|
||||
* @param y Y-Startposition
|
||||
* @param width Breite des Buffers (Pixel)
|
||||
* @param height Höhe des Buffers (Pixel)
|
||||
*
|
||||
* OPTIMIERTE VERSION! Kein Byte-Swapping, keine Buffer-Allokation.
|
||||
* Der Buffer MUSS bereits BGR565-formatiert sein!
|
||||
*
|
||||
* Verwendung:
|
||||
* uint16_t c_rgb = 0xF800; // Rot in RGB565
|
||||
* uint16_t c_bgr = (c_rgb >> 8) | (c_rgb << 8); // Swap zu BGR565
|
||||
* buffer[i] = c_bgr; // In Buffer schreiben
|
||||
*
|
||||
* Dies ist die schnellste Methode für GameBoy-Emulation!
|
||||
* Spart ~33% CPU-Zeit im Vergleich zu draw_buffer().
|
||||
*/
|
||||
void st7789_draw_buffer_preswapped(const uint16_t *buffer, int16_t x, int16_t y,
|
||||
int16_t width, int16_t height);
|
||||
|
||||
/**
|
||||
* @brief Display in Sleep-Modus versetzen (für Deep Sleep)
|
||||
*
|
||||
* Diese Funktion:
|
||||
* - Schaltet Hintergrundbeleuchtung aus
|
||||
* - Sendet DISPOFF Befehl (Display aus)
|
||||
* - Sendet SLPIN Befehl (Sleep In)
|
||||
*
|
||||
* WICHTIG: Diese Funktion MUSS aufgerufen werden bevor der ESP32
|
||||
* in Deep-Sleep geht! Sonst blinkt das Display mit zufälligen Farben.
|
||||
*/
|
||||
void st7789_sleep(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -124,13 +124,28 @@ static void st7789_backlight_init(void)
|
||||
esp_err_t st7789_init(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Initializing ST7789 display...");
|
||||
|
||||
|
||||
// WICHTIG: GPIO Hold deaktivieren falls wir aus Deep Sleep aufwachen
|
||||
// Sonst können die Pins nicht neu konfiguriert werden!
|
||||
gpio_hold_dis(LCD_PIN_CS);
|
||||
gpio_hold_dis(LCD_PIN_DC);
|
||||
gpio_hold_dis(LCD_PIN_BCKL);
|
||||
gpio_hold_dis(LCD_PIN_MOSI);
|
||||
gpio_hold_dis(LCD_PIN_SCLK);
|
||||
|
||||
// DC-Pin konfigurieren (immer vorhanden)
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.pin_bit_mask = (1ULL << LCD_PIN_DC) | (1ULL << LCD_PIN_RST);
|
||||
io_conf.pin_bit_mask = (1ULL << LCD_PIN_DC);
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
gpio_config(&io_conf);
|
||||
|
||||
// RST-Pin konfigurieren (falls vorhanden)
|
||||
if (LCD_PIN_RST >= 0) {
|
||||
io_conf.pin_bit_mask = (1ULL << LCD_PIN_RST);
|
||||
gpio_config(&io_conf);
|
||||
}
|
||||
|
||||
spi_bus_config_t buscfg = {
|
||||
.mosi_io_num = LCD_PIN_MOSI,
|
||||
@@ -138,7 +153,10 @@ esp_err_t st7789_init(void)
|
||||
.sclk_io_num = LCD_PIN_SCLK,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
.max_transfer_sz = LCD_WIDTH * LCD_HEIGHT * 2 + 8,
|
||||
// WICHTIG: Großer Buffer für Display UND SD-Karte (teilen sich den Bus!)
|
||||
// Display braucht: 320×240×2 = 153600 Bytes
|
||||
// SD-Karte braucht auch Platz für Transfers
|
||||
.max_transfer_sz = 4096 * 64, // 256 KB (genug für beide)
|
||||
.flags = SPICOMMON_BUSFLAG_MASTER,
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(LCD_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
@@ -154,11 +172,17 @@ esp_err_t st7789_init(void)
|
||||
|
||||
st7789_backlight_init();
|
||||
st7789_set_backlight(0);
|
||||
|
||||
gpio_set_level(LCD_PIN_RST, 0);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
gpio_set_level(LCD_PIN_RST, 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
// Hardware-Reset (falls RST-Pin vorhanden)
|
||||
if (LCD_PIN_RST >= 0) {
|
||||
gpio_set_level(LCD_PIN_RST, 0);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
gpio_set_level(LCD_PIN_RST, 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
} else {
|
||||
// Kein Hardware-Reset → Software-Reset reicht
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
}
|
||||
|
||||
st7789_send_cmd(ST7789_SWRESET);
|
||||
vTaskDelay(pdMS_TO_TICKS(150));
|
||||
@@ -302,3 +326,54 @@ void st7789_draw_buffer_preswapped(const uint16_t *buffer, int16_t x, int16_t y,
|
||||
offset += chunk_size;
|
||||
}
|
||||
}
|
||||
|
||||
void st7789_sleep(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Display in Sleep-Modus versetzen...");
|
||||
|
||||
// 1. ZUERST: Bildschirm schwarz füllen (entfernt letztes Frame)
|
||||
st7789_fill_screen(0x0000);
|
||||
|
||||
// 2. Hintergrundbeleuchtung über PWM ausschalten
|
||||
st7789_set_backlight(0);
|
||||
|
||||
// 3. LEDC (PWM) Kanal komplett stoppen!
|
||||
// Sonst läuft der PWM-Timer weiter und kann Glitches verursachen
|
||||
ledc_stop(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0); // 0 = LOW level
|
||||
|
||||
// 4. Display ausschalten (DISPOFF)
|
||||
st7789_send_cmd(ST7789_DISPOFF);
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
|
||||
// 5. Sleep-Modus aktivieren (SLPIN)
|
||||
// Im Sleep-Modus verbraucht das Display minimal Strom
|
||||
// und die Ausgänge sind in einem definierten Zustand (kein Blinken!)
|
||||
st7789_send_cmd(ST7789_SLPIN);
|
||||
vTaskDelay(pdMS_TO_TICKS(120)); // ST7789 braucht 120ms für Sleep-Eintritt
|
||||
|
||||
// 6. KRITISCH: SPI-Pins in definierten Zustand bringen!
|
||||
// Während Deep Sleep floaten die Pins sonst und verursachen
|
||||
// zufälliges Blinken auf dem Display.
|
||||
gpio_set_level(LCD_PIN_CS, 1); // CS HIGH = Display ignoriert SPI
|
||||
gpio_set_level(LCD_PIN_DC, 0); // DC auf definierten Pegel
|
||||
|
||||
// 7. Backlight-Pin manuell auf OUTPUT setzen und LOW
|
||||
// (überschreibt LEDC-Konfiguration)
|
||||
gpio_reset_pin(LCD_PIN_BCKL);
|
||||
gpio_set_direction(LCD_PIN_BCKL, GPIO_MODE_OUTPUT);
|
||||
gpio_set_level(LCD_PIN_BCKL, 0);
|
||||
|
||||
// 8. GPIO-Hold aktivieren für Deep Sleep
|
||||
// Dies hält die Pin-Zustände während Deep Sleep stabil
|
||||
gpio_hold_en(LCD_PIN_CS);
|
||||
gpio_hold_en(LCD_PIN_DC);
|
||||
gpio_hold_en(LCD_PIN_BCKL);
|
||||
|
||||
// Auch SPI-Pins auf definierte Pegel setzen und halten
|
||||
gpio_set_level(LCD_PIN_MOSI, 0);
|
||||
gpio_set_level(LCD_PIN_SCLK, 0);
|
||||
gpio_hold_en(LCD_PIN_MOSI);
|
||||
gpio_hold_en(LCD_PIN_SCLK);
|
||||
|
||||
ESP_LOGI(TAG, "Display schläft - GPIO Hold aktiviert");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user