Login
1 branch 0 tags
Ben (Desktop/Arch) Code cleanup b2535ca 1 month ago 24 Commits
moon / firmware / esp32 / main / lvgl_port_esp32.c
/**
 * @file lvgl_port_esp32.c
 * LVGL display driver for ESP32-S3 with ST7735
 */

#include "lvgl_port.h"
#include "moon.h"
#include "st7735.h"
#include <string.h>

// Draw buffer for partial refresh (32 lines at 160px, ARGB8888)
#define DRAW_BUF_LINES 32
static uint8_t draw_buf[SCREEN_WIDTH * DRAW_BUF_LINES * 4];

// RGB666 output buffer (3 bytes per pixel)
static uint8_t rgb666_buf[SCREEN_WIDTH * DRAW_BUF_LINES * 3];

static lv_display_t *display;

// Convert ARGB8888 to RGB666 (3 bytes per pixel)
static inline void argb_to_rgb666(uint32_t argb, uint8_t *out) {
    out[0] = (argb >> 16) & 0xFC;  // R: top 6 bits
    out[1] = (argb >> 8) & 0xFC;   // G: top 6 bits
    out[2] = argb & 0xFC;          // B: top 6 bits
}

// Flush callback - converts ARGB8888 to RGB666 and sends to ST7735
static void flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map) {
    (void)disp;

    int x1 = area->x1;
    int y1 = area->y1;
    int x2 = area->x2;
    int y2 = area->y2;
    int width = x2 - x1 + 1;
    int height = y2 - y1 + 1;
    int pixel_count = width * height;

    // Convert ARGB8888 to RGB666
    uint32_t *src = (uint32_t *)px_map;
    uint8_t *dst = rgb666_buf;
    for (int i = 0; i < pixel_count; i++) {
        argb_to_rgb666(src[i], dst);
        dst += 3;
    }

    // Set window and write pixels
    st7735_set_window(x1, y1, x2, y2);
    st7735_write_pixels_rgb666(rgb666_buf, pixel_count);

    lv_display_flush_ready(disp);
}

void lvgl_port_init(void) {
    lv_init();

    // Create display with ARGB8888 color format
    display = lv_display_create(SCREEN_WIDTH, SCREEN_HEIGHT);
    lv_display_set_color_format(display, LV_COLOR_FORMAT_ARGB8888);

    // Set draw buffers (single buffer mode)
    lv_display_set_buffers(display, draw_buf, NULL,
                           sizeof(draw_buf), LV_DISPLAY_RENDER_MODE_PARTIAL);

    // Set flush callback
    lv_display_set_flush_cb(display, flush_cb);
}

lv_display_t *lvgl_port_get_display(void) {
    return display;
}