lvgl embedded gui migration esp32 stm32

LVGL Migration 8.4 to 9.3: Embedded GUI Evolution

Guía completa para migrar proyectos de LVGL 8.4 a 9.3. Aprende los cambios principales, nuevas características y cómo actualizar tu código embedded.

Por Jesus Velez

LVGL Migration 8.4 to 9.3: Embedded GUI Evolution

LVGL (Light and Versatile Graphics Library) es una de las librerías GUI más populares para sistemas embebidos. La migración de la versión 8.4 a 9.3 trae cambios significativos y mejoras importantes. Esta guía te ayudará a migrar exitosamente.

Cambios Principales en LVGL 9.3

1. Arquitectura de Display Refactorizada

LVGL 8.4:

// Configuración antigua
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf_1[MY_DISP_HOR_RES * 10];

lv_disp_draw_buf_init(&draw_buf, buf_1, NULL, MY_DISP_HOR_RES * 10);

static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = MY_DISP_HOR_RES;
disp_drv.ver_res = MY_DISP_VER_RES;
disp_drv.flush_cb = my_disp_flush;
disp_drv.draw_buf = &draw_buf;
lv_disp_drv_register(&disp_drv);

LVGL 9.3:

// Nueva arquitectura
static lv_display_t * disp;

void display_init(void) {
    disp = lv_display_create(MY_DISP_HOR_RES, MY_DISP_VER_RES);
    
    // Configurar buffer
    static lv_color_t buf_1[MY_DISP_HOR_RES * 10];
    lv_display_set_buffers(disp, buf_1, NULL, sizeof(buf_1), LV_DISPLAY_RENDER_MODE_PARTIAL);
    
    // Configurar callback de flush
    lv_display_set_flush_cb(disp, my_disp_flush);
    
    // Configuraciones adicionales
    lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_0);
    lv_display_set_color_format(disp, LV_COLOR_FORMAT_RGB565);
}

2. Sistema de Input Simplificado

LVGL 8.4:

// Input device antiguo
static lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = my_touchpad_read;
lv_indev_drv_register(&indev_drv);

LVGL 9.3:

// Nuevo sistema de input
lv_indev_t * indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
lv_indev_set_read_cb(indev, my_touchpad_read);

// Para displays específicos
lv_indev_set_display(indev, disp);

Migración de Drivers

Driver de Display ESP32 Actualizado

#include "lvgl.h"
#include "driver/spi_master.h"

static lv_display_t * disp;
static spi_device_handle_t spi;

// Callback actualizado para LVGL 9.3
static void my_disp_flush(lv_display_t * display, 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);
    
    // Enviar datos al display via SPI
    send_display_data(area, px_map, w * h * 2);
    
    // Notificar a LVGL que el flush terminó
    lv_display_flush_ready(display);
}

void display_init(void) {
    // Inicializar SPI
    init_spi_display();
    
    // Crear display
    disp = lv_display_create(240, 320);
    
    // Configurar buffers
    static lv_color_t buf_1[240 * 40];
    static lv_color_t buf_2[240 * 40];
    lv_display_set_buffers(disp, buf_1, buf_2, sizeof(buf_1), LV_DISPLAY_RENDER_MODE_PARTIAL);
    
    // Configurar callbacks
    lv_display_set_flush_cb(disp, my_disp_flush);
    lv_display_set_color_format(disp, LV_COLOR_FORMAT_RGB565);
}

Driver de Touch Actualizado

// Touch driver para LVGL 9.3
static void my_touchpad_read(lv_indev_t * indev, lv_indev_data_t * data) {
    static int16_t last_x = 0;
    static int16_t last_y = 0;
    
    if (touch_is_pressed()) {
        data->state = LV_INDEV_STATE_PRESSED;
        data->point.x = get_touch_x();
        data->point.y = get_touch_y();
        
        last_x = data->point.x;
        last_y = data->point.y;
    } else {
        data->state = LV_INDEV_STATE_RELEASED;
        data->point.x = last_x;
        data->point.y = last_y;
    }
}

void input_init(void) {
    // Inicializar hardware de touch
    init_touch_hardware();
    
    // Crear input device
    lv_indev_t * indev = lv_indev_create();
    lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
    lv_indev_set_read_cb(indev, my_touchpad_read);
    
    // Asociar con display
    lv_indev_set_display(indev, disp);
}

Nuevas Características

Vector Graphics Support

// Crear gráficos vectoriales
void create_vector_graphics(void) {
    lv_obj_t * canvas = lv_canvas_create(lv_screen_active());
    lv_canvas_set_buffer(canvas, canvas_buf, 200, 200, LV_COLOR_FORMAT_RGB565);
    
    // Crear path vector
    lv_vector_path_t * path = lv_vector_path_create(LV_VECTOR_PATH_QUALITY_MEDIUM);
    
    // Dibujar formas
    lv_vector_path_move_to(path, 50, 50);
    lv_vector_path_line_to(path, 150, 50);
    lv_vector_path_line_to(path, 100, 150);
    lv_vector_path_close(path);
    
    // Aplicar al canvas
    lv_vector_dsc_t vector_dsc;
    lv_vector_dsc_init(&vector_dsc);
    vector_dsc.fill_dsc.color = lv_color_hex(0x00FF00);
    
    lv_canvas_draw_vector(canvas, path, &vector_dsc);
    lv_vector_path_delete(path);
}

Tema Mejorado

// Aplicar tema moderno
void apply_modern_theme(void) {
    lv_theme_t * theme = lv_theme_default_init(
        disp,
        lv_palette_main(LV_PALETTE_BLUE),
        lv_palette_main(LV_PALETTE_RED),
        true,  // Modo oscuro
        LV_FONT_DEFAULT
    );
    
    lv_display_set_theme(disp, theme);
}

Migración de UI

Antes (LVGL 8.4)

void create_ui_old(void) {
    lv_obj_t * screen = lv_scr_act();
    
    lv_obj_t * label = lv_label_create(screen);
    lv_label_set_text(label, "Hello LVGL 8.4!");
    lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
}

Después (LVGL 9.3)

void create_ui_new(void) {
    lv_obj_t * screen = lv_screen_active();
    
    // Aplicar tema
    apply_modern_theme();
    
    // Crear card con sombra
    lv_obj_t * card = lv_obj_create(screen);
    lv_obj_set_size(card, 200, 100);
    lv_obj_center(card);
    lv_obj_set_style_shadow_width(card, 15, 0);
    lv_obj_set_style_shadow_opa(card, LV_OPA_30, 0);
    
    lv_obj_t * label = lv_label_create(card);
    lv_label_set_text(label, "Hello LVGL 9.3!");
    lv_obj_set_style_text_font(label, &lv_font_montserrat_16, 0);
    lv_obj_center(label);
    
    // Animación de entrada
    lv_anim_t anim;
    lv_anim_init(&anim);
    lv_anim_set_var(&anim, card);
    lv_anim_set_values(&anim, -100, 0);
    lv_anim_set_time(&anim, 500);
    lv_anim_set_exec_cb(&anim, (lv_anim_exec_xcb_t)lv_obj_set_y);
    lv_anim_start(&anim);
}

Optimizaciones

Configuración de Memoria

// lv_conf.h optimizado
#define LV_MEM_SIZE             (48 * 1024U)
#define LV_USE_IMG_CACHE        1
#define LV_IMG_CACHE_DEF_SIZE   1
#define LV_USE_DRAW_MASKS       1

Performance Monitoring

void enable_performance_monitoring(void) {
    lv_obj_t * perf_label = lv_label_create(lv_screen_active());
    lv_obj_align(perf_label, LV_ALIGN_TOP_LEFT, 10, 10);
    
    lv_timer_create(update_performance_stats, 1000, perf_label);
}

static void update_performance_stats(lv_timer_t * timer) {
    lv_obj_t * label = (lv_obj_t*)timer->user_data;
    
    lv_mem_monitor_t mem_mon;
    lv_mem_monitor(&mem_mon);
    
    lv_label_set_text_fmt(label, "MEM: %lu/%lu KB", 
        (mem_mon.total_size - mem_mon.free_size) / 1024, 
        mem_mon.total_size / 1024);
}

Troubleshooting

Display no inicializa

void debug_display_init(void) {
    ESP_LOGI("LVGL", "Creating display...");
    disp = lv_display_create(240, 320);
    
    if (!disp) {
        ESP_LOGE("LVGL", "Failed to create display");
        return;
    }
    
    ESP_LOGI("LVGL", "Display created successfully");
    
    // Verificar buffer allocation
    static lv_color_t buf_1[240 * 40];
    lv_display_set_buffers(disp, buf_1, NULL, sizeof(buf_1), LV_DISPLAY_RENDER_MODE_PARTIAL);
    
    ESP_LOGI("LVGL", "Buffers configured");
}

Checklist de Migración

  • Actualizar lv_conf.h con nuevas opciones
  • Migrar inicialización de display a lv_display_create()
  • Actualizar callbacks de flush y input
  • Convertir lv_scr_act() a lv_screen_active()
  • Probar todas las funcionalidades
  • Optimizar configuración de memoria
  • Implementar nuevas características (vector graphics, etc.)

Conclusión

LVGL 9.3 ofrece:

  • API más simple y consistente
  • Mejor rendimiento y optimizaciones
  • Nuevas características como vector graphics
  • Mejor soporte para displays múltiples

La migración requiere actualizar el código de inicialización, pero las mejoras valen la pena para proyectos embebidos modernos.

Deja un comentario