mirror of
https://github.com/skoelle/wt32sc01-dashboard.git
synced 2026-09-17 17:30:25 +00:00
162 lines
5.4 KiB
C++
162 lines
5.4 KiB
C++
#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 = 20000000;
|
|
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(0); // 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_theme_t *th = lv_theme_default_init(
|
|
lv_display_gfx,
|
|
lv_palette_main(LV_PALETTE_BLUE),
|
|
lv_palette_main(LV_PALETTE_CYAN),
|
|
true,
|
|
LV_FONT_DEFAULT);
|
|
lv_display_set_theme(lv_display_gfx, th);
|
|
|
|
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();
|
|
}
|