mirror of
https://github.com/skoelle/wt32sc01-dashboard.git
synced 2026-09-17 17:30:25 +00:00
Phase 0/1: display_setup (LovyanGFX + LVGL) and LVGL theme
- include/theme.h: replace M5Stack-based RGB565 constants with LVGL
lv_color_hex helpers; same dark-mode palette + tile accent colors,
portrait SCREEN_W=320 / SCREEN_H=480
- src/display/display_setup.{h,cpp}: custom LGfx device class with
Panel_ST7796 + Bus_Parallel8 (esp32s3) + Light_PWM + Touch_FT5x06
(FT6336U is FT5x06 family), setRotation(1) for portrait 320x480
- LVGL display driver with two PSRAM partial draw buffers (320x80)
- LVGL pointer indev wired to LovyanGFX touch readback
- display_loop() drives lv_tick_inc + lv_timer_handler
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
#include <lvgl.h>
|
||||
|
||||
// Dark-mode theme constants and tile accent colors for the WT32-SC01 Plus
|
||||
// dashboard. Replaces the former M5Stack-specific theme.h; the same RGB565
|
||||
// values are kept as 16-bit literals so they can be reused both for LVGL
|
||||
// (via lv_color_hex) and for direct LovyanGFX drawing if needed.
|
||||
namespace Theme {
|
||||
|
||||
// Logical portrait resolution after rotation (320 wide x 480 tall).
|
||||
constexpr int SCREEN_W = 320;
|
||||
constexpr int SCREEN_H = 480;
|
||||
|
||||
// Base palette (RGB565 kept for reference; LVGL uses the hex forms below).
|
||||
// BG 0x0000 pure black
|
||||
// BG_CARD 0x1082 very dark grey (tile / separator)
|
||||
// TEXT 0xFFFF white
|
||||
// TEXT_DIM 0x8410 mid grey
|
||||
inline lv_color_t bg() { return lv_color_hex(0x000000); }
|
||||
inline lv_color_t bgCard() { return lv_color_hex(0x1C1C1E); }
|
||||
inline lv_color_t text() { return lv_color_hex(0xFFFFFF); }
|
||||
inline lv_color_t textDim() { return lv_color_hex(0x9A9A9E); }
|
||||
|
||||
// Tile accent backgrounds (muted, iOS-dark-mode style).
|
||||
inline lv_color_t accentWeather() { return lv_color_hex(0x1B3A5C); } // muted blue
|
||||
inline lv_color_t accentCalendar() { return lv_color_hex(0x3A2A5C); } // muted purple
|
||||
inline lv_color_t accentMvg() { return lv_color_hex(0x2C5C3A); } // muted green
|
||||
|
||||
// Symbol / status colors.
|
||||
inline lv_color_t accentSun() { return lv_color_hex(0xFBC02D); }
|
||||
inline lv_color_t accentRain() { return lv_color_hex(0x4FC3F7); }
|
||||
inline lv_color_t accentUBahn() { return lv_color_hex(0xE62D2D); } // MVV U-Bahn red
|
||||
inline lv_color_t accentSBahn() { return lv_color_hex(0x1A7A3A); } // MVV S-Bahn green
|
||||
inline lv_color_t accentWarn() { return lv_color_hex(0xFFB300); }
|
||||
inline lv_color_t accentError() { return lv_color_hex(0xF44336); }
|
||||
inline lv_color_t accentStorm() { return lv_color_hex(0xFFD54F); }
|
||||
|
||||
} // namespace Theme
|
||||
@@ -0,0 +1,153 @@
|
||||
#include "display_setup.h"
|
||||
#include <LovyanGFX.hpp>
|
||||
#include <driver/i2c.h>
|
||||
#include <board_pins.h>
|
||||
#include <theme.h>
|
||||
|
||||
// Defined at file scope (not anonymous namespace) so it matches the
|
||||
// `extern` declaration in display_setup.h without ambiguity.
|
||||
lv_display_t *lv_display_gfx = nullptr;
|
||||
|
||||
namespace {
|
||||
|
||||
// --- LovyanGFX device for WT32-SC01 Plus ---
|
||||
// ST7796 8-bit parallel panel + FT6336U (FT5x06 family) capacitive touch.
|
||||
class LGfx : public lgfx::LGFX_Device {
|
||||
lgfx::Panel_ST7796 _panel_instance;
|
||||
lgfx::Bus_Parallel8 _bus_instance;
|
||||
lgfx::Light_PWM _light_instance;
|
||||
lgfx::Touch_FT5x06 _touch_instance;
|
||||
|
||||
public:
|
||||
LGfx(void) {
|
||||
// 8-bit parallel i80/8080 bus (ESP32-S3 variant).
|
||||
{
|
||||
auto cfg = _bus_instance.config();
|
||||
cfg.freq_write = 16000000;
|
||||
cfg.freq_read = 8000000;
|
||||
cfg.pin_wr = BoardPins::LCD_WR;
|
||||
cfg.pin_rd = BoardPins::LCD_RD;
|
||||
cfg.pin_rs = BoardPins::LCD_DC; // DC = RS
|
||||
cfg.pin_d0 = BoardPins::LCD_D0;
|
||||
cfg.pin_d1 = BoardPins::LCD_D1;
|
||||
cfg.pin_d2 = BoardPins::LCD_D2;
|
||||
cfg.pin_d3 = BoardPins::LCD_D3;
|
||||
cfg.pin_d4 = BoardPins::LCD_D4;
|
||||
cfg.pin_d5 = BoardPins::LCD_D5;
|
||||
cfg.pin_d6 = BoardPins::LCD_D6;
|
||||
cfg.pin_d7 = BoardPins::LCD_D7;
|
||||
_bus_instance.config(cfg);
|
||||
_panel_instance.setBus(&_bus_instance);
|
||||
}
|
||||
// ST7796 panel geometry / control pins.
|
||||
{
|
||||
auto cfg = _panel_instance.config();
|
||||
cfg.pin_cs = BoardPins::LCD_CS;
|
||||
cfg.pin_rst = BoardPins::LCD_RST;
|
||||
cfg.pin_busy = -1;
|
||||
cfg.panel_width = 320;
|
||||
cfg.panel_height = 480;
|
||||
cfg.offset_x = 0;
|
||||
cfg.offset_y = 0;
|
||||
cfg.offset_rotation = 0;
|
||||
cfg.readable = true;
|
||||
cfg.invert = false;
|
||||
cfg.rgb_order = false;
|
||||
cfg.dlen_16bit = false;
|
||||
cfg.bus_shared = true;
|
||||
cfg.memory_width = 320;
|
||||
cfg.memory_height = 480;
|
||||
_panel_instance.config(cfg);
|
||||
}
|
||||
// Backlight via PWM.
|
||||
{
|
||||
auto cfg = _light_instance.config();
|
||||
cfg.pin_bl = BoardPins::LCD_BACKLIGHT;
|
||||
cfg.invert = false;
|
||||
cfg.freq = 44100;
|
||||
cfg.pwm_channel = 7;
|
||||
_light_instance.config(cfg);
|
||||
_panel_instance.setLight(&_light_instance);
|
||||
}
|
||||
// FT6336U touch (FT5x06 family) on I2C, addr 0x38 (default).
|
||||
{
|
||||
auto cfg = _touch_instance.config();
|
||||
cfg.x_min = 0;
|
||||
cfg.x_max = 319;
|
||||
cfg.y_min = 0;
|
||||
cfg.y_max = 479;
|
||||
cfg.pin_int = BoardPins::TOUCH_INT;
|
||||
cfg.bus_shared = true;
|
||||
cfg.offset_rotation = 0;
|
||||
cfg.i2c_port = I2C_NUM_0;
|
||||
cfg.pin_sda = BoardPins::TOUCH_SDA;
|
||||
cfg.pin_scl = BoardPins::TOUCH_SCL;
|
||||
cfg.i2c_addr = 0x38;
|
||||
cfg.freq = 400000;
|
||||
_touch_instance.config(cfg);
|
||||
_panel_instance.setTouch(&_touch_instance);
|
||||
}
|
||||
setPanel(&_panel_instance);
|
||||
}
|
||||
};
|
||||
|
||||
LGfx lcd;
|
||||
|
||||
// LVGL draw buffers in PSRAM (partial rendering, two buffers).
|
||||
constexpr uint32_t LVGL_BUF_PIXELS = 320 * 80;
|
||||
lv_color_t *lvgl_buf1 = nullptr;
|
||||
lv_color_t *lvgl_buf2 = nullptr;
|
||||
|
||||
// --- LVGL display flush callback -> LovyanGFX ---
|
||||
void lv_display_flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map) {
|
||||
uint32_t w = area->x2 - area->x1 + 1;
|
||||
uint32_t h = area->y2 - area->y1 + 1;
|
||||
lcd.startWrite();
|
||||
lcd.setAddrWindow(area->x1, area->y1, w, h);
|
||||
lcd.writePixels((lgfx::rgb565_t *)px_map, w * h);
|
||||
lcd.endWrite();
|
||||
lv_display_flush_ready(disp);
|
||||
}
|
||||
|
||||
// --- LVGL touch read callback -> LovyanGFX touch ---
|
||||
void lv_touch_read_cb(lv_indev_t *indev, lv_indev_data_t *data) {
|
||||
lgfx::touch_point_t tp;
|
||||
if (lcd.getTouch(&tp)) {
|
||||
data->point.x = tp.x;
|
||||
data->point.y = tp.y;
|
||||
data->state = LV_INDEV_STATE_PRESSED;
|
||||
} else {
|
||||
data->state = LV_INDEV_STATE_RELEASED;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void display_init() {
|
||||
lcd.init();
|
||||
lcd.setRotation(1); // Portrait 320x480 on WT32-SC01 Plus
|
||||
lcd.fillScreen(0x0000); // black (RGB565)
|
||||
lcd.setBrightness(180);
|
||||
|
||||
// Allocate LVGL draw buffers in PSRAM.
|
||||
lvgl_buf1 = (lv_color_t *)heap_caps_malloc(sizeof(lv_color_t) * LVGL_BUF_PIXELS, MALLOC_CAP_SPIRAM);
|
||||
lvgl_buf2 = (lv_color_t *)heap_caps_malloc(sizeof(lv_color_t) * LVGL_BUF_PIXELS, MALLOC_CAP_SPIRAM);
|
||||
|
||||
lv_init();
|
||||
lv_display_gfx = lv_display_create(Theme::SCREEN_W, Theme::SCREEN_H);
|
||||
lv_display_set_color_format(lv_display_gfx, LV_COLOR_FORMAT_RGB565);
|
||||
lv_display_set_buffers(lv_display_gfx, lvgl_buf1, lvgl_buf2,
|
||||
sizeof(lv_color_t) * LVGL_BUF_PIXELS,
|
||||
LV_DISPLAY_RENDER_MODE_PARTIAL);
|
||||
lv_display_set_flush_cb(lv_display_gfx, lv_display_flush_cb);
|
||||
|
||||
lv_indev_t *indev = lv_indev_create();
|
||||
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
|
||||
lv_indev_set_read_cb(indev, lv_touch_read_cb);
|
||||
lv_indev_set_display(indev, lv_display_gfx);
|
||||
}
|
||||
|
||||
void display_loop() {
|
||||
lv_tick_inc(5);
|
||||
lv_timer_handler();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include <lvgl.h>
|
||||
|
||||
// Initializes the WT32-SC01 Plus display (LovyanGFX, ST7796 8-bit parallel,
|
||||
// portrait 320x480) and the FT6336U capacitive touch, wires both into LVGL.
|
||||
// Must be called once from setup() before any UI code.
|
||||
void display_init();
|
||||
|
||||
// LVGL display driver instance (exposed so main loop can drive it).
|
||||
extern lv_display_t *lv_display_gfx;
|
||||
|
||||
// Drive LVGL timers + touch readback. Call once per loop() iteration.
|
||||
void display_loop();
|
||||
Reference in New Issue
Block a user