Porté con éxito la biblioteca gráfica LVGL al STM32F407; la pantalla LCD es el modelo MSP3526. Si desea cambiar a otra pantalla, solo modifique el controlador LCD. El proyecto incluye versiones con FreeRTOS y sin sistema operativo (bare-metal). La pantalla se controla mediante SPI+DMA.
LCD de 3,5" con resolución 320×480, controlador ST7796, interfaz SPI; táctil capacitivo con chip FT6336U, interfaz I²C.
Con el MCU sobre-clocked, la tasa de refresco completo es de ~9 FPS; en refresco parcial supera los 30 FPS. Para SPI creo que es aceptable.
- STM32 lee el sensor de temperatura/humedad SHTC3 por I²C hardware: https://blog.zeruns.com/archives/692.html
- Plantilla STM32F407 con U8g2 ya portado: https://blog.zeruns.com/archives/722.html
- Controlador para OLED 0,96" en STM32G4 (HAL), I²C hardware/software: https://blog.zeruns.com/archives/776.html
Grupo de técnicos en electrónía/MCU: 2169025065
Imágenes de resultado
Vídeo demo: https://www.bilibili.com/video/BV1Ni421S7ta/
Introducción a LVGL
LVGL (Light and Versatile Graphics Library) es una biblioteca gráfica libre y de código abierto que proporciona todo lo necesario para crear GUI embebidas: widgets fáciles de usar, efectos visuales atractivos y bajo consumo de memoria.
Características principales:
- Componentes gráficos modulares y potentes: botones, gráficos, listas, deslizadores, imágenes, etc.
- Motor gráfico avanzado: animaciones, anti-aliasing, transparencias, desplazamiento suave, mezcla de capas.
- Soporta múltiples dispositivos de entrada: táctil, teclado, codificador, teclas.
- Soporte para varias pantallas.
- Independiente del hardware; funciona en cualquier display.
- Configurable y recortable (mínimo: 64 kB Flash, 16 kB RAM).
- UTF-8 para múltiples idiomas: chino, japonés, coreano, árabe, etc.
- Diseño y maquetado estilo-CSS (Flexbox, Grid).
- Compatible con SO, memoria externa y aceleración por hardware (DMA2D de STM32, PXP de NXP, VGLite).
- Renderizado fluido incluso con un solo frame-buffer.
- Escrito completamente en C y utilizable desde C++.
- Soporte de MicroPython; ver: LVGL API in Micropython.
- Simulador para desarrollo sin hardware.
- Ejemplos abundantes.
- Documentación y referencia de API completa, en línea o PDF.
- Licencia MIT: gratis y abierto.
Requisitos mínimos:
- Microcontrolador/procesador de 16, 32 o 64 bits.
- Velocidad de reloj recomendada >16 MHz.
- Flash/ROM: >64 kB (recomendado >180 kB).
- RAM:
– Estática: ~2 kB (depende de widgets).
– Heap: >2 kB (recomendado 8 kB).
– Datos dinámicos: >2 kB (recomendado 16 kB; configurar LV_MEM_SIZE).
– Buffer de pantalla: >ancho en píxeles (recomendado 10×ancho).
– Un frame-buffer en el MCU o en controlador externo. - Compilador C99 o superior.
Web oficial: https://lvgl.io/
Conexionado
| Pantalla LCD | MCU/board | Descripción |
|---|---|---|
| GND | GND | Tierra |
| VCC | 5 V ó 3,3 V | Alimentación positiva |
| LCD_CS | PE6 | Chip-select SPI |
| LCD_RST | PC1 | Reset LCD |
| LCD_RS | PC0 | Comando / datos |
| SDI(MOSI) | PB5 | Datos SPI (MOSI) |
| SCK | PB3 | Reloj SPI |
| LED | 3,3 V | LED retro-iluminación (puede usar IO) |
| SDO(MISO) | PB4 | Datos SPI (MISO) |
| CTP_SCL | PB8 | I²C clock del táctil |
| CTP_RST | PB7 | Reset del táctil |
| CTP_SDA | PB9 | I²C datos del táctil |
| CTP_INT | PB6 | Interrupción del táctil |
Nota: en mi placa el pin PB4 no sale en los headers laterales; está en el conector JTAG.
Descargas y documentación
Docs on-line de la pantalla: https://url.zeruns.com/68x3Y
Pack de docs (mirror 1): https://www.123pan.com/s/2Y9Djv-rZevH.html
Pack de docs (mirror 2): https://url.zeruns.com/gzBO4
Proyecto bare-metal STM32F407+LVGL (mirror 1): https://url.zeruns.com/X242k
Proyecto bare-metal (mirror 2): https://pan.baidu.com/s/1vAhHijYd_aWvRr3_c1_WtA?pwd=ry4g
Proyecto FreeRTOS STM32F407+LVGL (mirror 1): https://www.123pan.com/s/2Y9Djv-CzevH.html
Proyecto FreeRTOS (mirror 2): https://url.zeruns.com/0iOHF
¡No olvides dar una Star!
Repo abierto (Gitee): https://gitee.com/zeruns/STM32F407_LVGL_Template_MSP3526
Repo abierto (GitHub): https://github.com/zeruns/STM32F407_LVGL_Template_MSP3526
En Gitee/GitHub la versión más reciente usa FreeRTOS; la versión bare-metal está en Releases (v0.1.3).
Proyecto generado con STM32CubeMX, desarrollado con Keil5 + VScode + EIDE.
Seguí los tutoriales de Zhengdian Yuan.
Tutoriales en vídeo de Zhengdian Yuan (mirror 1): https://www.123pan.com/s/2Y9Djv-0ZevH.html
Tutoriales en vídeo (mirror 2): https://www.alipan.com/s/Pd6TDfT2rBL
Instrucciones de uso
Descarga el código, compila y programa; funcionará de inmediato.
Para ocultar el monitor de FPS y memoria, cambia a 0 estos defines en lv_conf.h:
/*1: Show CPU usage and FPS count*/
#define LV_USE_PERF_MONITOR 1
#if LV_USE_PERF_MONITOR
#define LV_USE_PERF_MONITOR_POS LV_ALIGN_BOTTOM_RIGHT
#endif
/*1: Show the used memory and the memory fragmentation
* Requires LV_MEM_CUSTOM = 0*/
#define LV_USE_MEM_MONITOR 1
#if LV_USE_MEM_MONITOR
#define LV_USE_MEM_MONITOR_POS LV_ALIGN_BOTTOM_LEFT
#endif
```
Si usas la versión de FreeRTOS, escribe el código en el archivo `freertos.c`; puedes crear hilos y semáforos con STM32CubeMX y luego generar el código, que se escribe en las posiciones especificadas según la norma; al regenerar no se sobrescribirá tu código. Para la versión bare-metal simplemente escribe el código directamente en `main.c`.
Si necesitas desactivar el programa Demo, solo comenta el código que se muestra en la siguiente imagen.

## Direcciones de compra de componentes
- Placa de desarrollo STM32F407VET6: [https://s.click.taobao.com/sQSMWmt](https://s.click.taobao.com/t?e=m%3D2%26s%3DGxUVgIOWBWVw4vFB6t2Z2ueEDrYVVa64g3vZOarmkFi53hKxp7mNFrMfIvbtZ%2F%2B2IT%2BVhjqUP7X0JlhLk0Jl4QTquP0kWxBLBDnvz6xo38xspWc9%2BCL4bTGF1ceZMhPo8mL8HhJ3EdVrH4ks4QyiY4z4rjZDGVMAhscfsB2%2FyzZJq71CBMBeP%2F1SarTXhIOTsgIpc1WFZiJNubylQlnZt0ft88oCh4qlKjZ0Zrpn9cYR7kNHbGZ5w15bTaW0%2FWfaQBd0yVbMw3IeTeL3FeYp0owmLWBgEm80VKxcI130SjETn2JhMaQNtYWLhXkoGmYygFktLIh%2BAXuBHaXkFVFVVsYOae24fhW0&union_lens=lensId%3APUB%401716477927%40212abf30_0d16_18fa60ea164_1890%40025BlJPZdLaOG4oFPxX7gKUY%40eyJmbG9vcklkIjo4MDY3NCwiic3BtQiiI6Il9wb3J0YWxfdjJfcGFnZXNfcHJvbW9fZ29vZHNfaW5kZXhfaHRtIiiwiic3JjRmxvb3JJZCI6IjgwNjc0In0ie%3BtkScm%3AselectionPlaza_site_4358%3Bscm%3A1007.30148.329090.pub_search-item_5a7fc953-12f7-46f5-8abf-f0725f8174cf_)
- Programador Daplink: [https://s.click.taobao.com/9kMKWmt](https://s.click.taobao.com/t?e=m%3D2%26s%3DTHTCnVvsTHtw4vFB6t2Z2ueEDrYVVa64YUrQeSeIhnK53hKxp7mNFrMfIvbtZ%2F%2B2mFKI%2FmDcMIH0JlhLk0Jl4QTquP0kWxBLBDnvz6xo38xspWc9%2BCL4bTGF1ceZMhPo8mL8HhJ3EdVrH4ks4QyiY4z4rjZDGVMAFBcM8wkWlGmBPeR%2FUFCetKLWMw3EOEsyJN2owMjhufwDudUsQ2T%2Bdnc9abdYtRqDTzYdoB%2FDOjstFZhpb%2ByhLzPbHWUbis%2BWsZGiFV6vs3eSWi1ViPhRlULEkqTedE399KEV1g6mN9AKChukhDzWey1fmH6DK4UhxgxdTc00KD8%3D&union_lens=lensId%3APUB%401716478245%4021673e1b_0d06_18fa6137a23_e4cb%40023uxCV3Edv0RnAmphuKflFP%40eyJmbG9vcklkIjo4MDY3NCwiic3BtQiiI6Il9wb3J0YWxfdjJfcGFnZXNfcHJvbW9fZ29vZHNfaW5kZXhfaHRtIiiwiic3JjRmxvb3JJZCI6IjgwNjc0In0ie%3BtkScm%3AselectionPlaza_site_4358%3Bscm%3A1007.30148.329090.pub_search-item_be2f7d85-fcee-40ff-96c5-d9d5bd472c5d_)
- Pantalla MSP3526: [https://s.click.taobao.com/i1Z29nt](https://s.click.taobao.com/t?e=m%3D2%26s%3DepCXgq%2FZmWBw4vFB6t2Z2ueEDrYVVa64g3vZOarmkFi53hKxp7mNFrMfIvbtZ%2F%2B2tJl3z4Kcvjj0JlhLk0Jl4QTquP0kWxBLBDnvz6xo38xspWc9%2BCL4bTGF1ceZMhPo8mL8HhJ3EdVrH4ks4QyiY4z4rjZDGVMA%2FEM5jbZlb7P9R7R4oT9ML5ESMSIvSnZOMN7NXhFCiynJvjSktgLu1nmUrf%2BRsjyAm8kA6wY1r21y2p9AgG%2F91VmfPAhbcEJheBtNII99o%2FtnjWeMZ%2B39PZGZ9wPRcXV%2BQ%2FMlsmagC3ST4aDEgnPNca8ZkUY0DmW2xiXvDf8DaRs%3D&skuId=5223178287593&union_lens=lensId%3APUB%401716478528%40212c5298_0d1d_18fa617cd1e_3501%40034rs5qkRnldNGhC5eLF4gZ4%40eyJmbG9vcklkIjo4NTQ2Nywiic3BtQiiI6Il9wb3J0YWxfdjJfcGFnZXNfcHJvbW9fZ29vZHNfZGV0YWlsX2h0bSIsInNyY0Zsb29ySWQiiOiiI4MDY3NCJ9%3BtkScm%3AselectionPlaza_site_4358%3Bscm%3A1007.30148.329090.pub_search-item_18bdbb55-0a4c-494e-96fc-a14c1b4c6732_)
- Cables Dupont: [https://s.click.taobao.com/W1wHWmt](https://s.click.taobao.com/t?e=m%3D2%26s%3DD%2BKEsm2G8bhw4vFB6t2Z2ueEDrYVVa64g3vZOarmkFi53hKxp7mNFrMfIvbtZ%2F%2B2Sn8%2BqdSFAFT0JlhLk0Jl4QTquP0kWxBLBDnvz6xo38xspWc9%2BCL4bTGF1ceZMhPo8mL8HhJ3EdVrH4ks4QyiY4z4rjZDGVMAhscfsB2%2FyzZJq71CBMBeP%2F1SarTXhIOTsgIpc1WFZiJNubylQlnZt5Tr%2BZsTRXxVoTwQXkQy%2BZ5FeGSAzHUbnuYhpSNeyz6v9H5aeGRpz8mogVv1SEjhEYwmLWBgEm80VKxcI130SjETn2JhMaQNtYWLhXkoGmYyO0%2FufYOLJc1EEap0MMy2i8YOae24fhW0&union_lens=lensId%3APUB%401716478612%402104b45c_0cd2_18fa619123a_652e%40023dY61JLu6wYjo297E4L0ip%40eyJmbG9vcklkIjo4MDY3NCwiic3BtQiiI6Il9wb3J0YWxfdjJfcGFnZXNfcHJvbW9fZ29vZHNfaW5kZXhfaHRtIiiwiic3JjRmxvb3JJZCI6IjgwNjc0In0ie%3BtkScm%3AselectionPlaza_site_4358%3Bscm%3A1007.30148.329090.pub_search-item_c09a2639-b75e-40a9-8886-2b13dfb05f6a_)
- Placa de desarrollo STM32F407VGT6: [https://s.click.taobao.com/VjC29nt](https://s.click.taobao.com/t?e=m%3D2%26s%3DimgWkSQh79Jw4vFB6t2Z2ueEDrYVVa64g3vZOarmkFi53hKxp7mNFrMfIvbtZ%2F%2B2VCC9Q%2BPYiL70JlhLk0Jl4QTquP0kWxBLBDnvz6xo38xspWc9%2BCL4bTGF1ceZMhPo8mL8HhJ3EdVrH4ks4QyiY4z4rjZDGVMAhscfsB2%2FyzZJq71CBMBeP%2F1SarTXhIOTsgIpc1WFZiJNubylQlnZt1PgRVjPwS2ItjXwer7KgrNYvdwnwfvUuaclSgSzfliuRVQ2zHzYrnKVyphVinEJT4wmLWBgEm80VKxcI130SjETn2JhMaQNtYWLhXkoGmYy0ZHJIUNbntFzUAbdwYp3usYOae24fhW0&union_lens=lensId%3APUB%401716478657%4021547cbb_0d71_18fa619c373_1476%40027J4l8QPFtC3F2VYygWUUdV%40eyJmbG9vcklkIjo4MDY3NCwiic3BtQiiI6Il9wb3J0YWxfdjJfcGFnZXNfcHJvbW9fZ29vZHNfaW5kZXhfaHRtIiiwiic3JjRmxvb3JJZCI6IjgwNjc0In0ie%3BtkScm%3AselectionPlaza_site_4358%3Bscm%3A1007.30148.329090.pub_search-item_a456d2bb-5c50-4eb6-a55f-0e6f4ff87eed_)
## Fragmentos de código principales
Básicamente, en el archivo `lv_port_disp.c`, dentro de la función `disp_flush`, se llama a la siguiente función de rellenado de LCD. El controlador LCD se modificó basándose en el ejemplo oficial de la pantalla.
```c
/**
* @brief Rellena un área rectangular específica de la pantalla LCD
* Rellena el área indicada de la LCD con valores de color de la biblioteca LVGL.
* @param sx Coordenada X inicial
* @param sy Coordenada Y inicial
* @param ex Coordenada X final
* @param ey Coordenada Y final
* @param color_p Puntero al color a rellenar
*/
void LCD_Fill_LVGL(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, lv_color_t *color_p)
{
uint32_t i, j;
uint16_t width = ex - sx + 1; // calcula el ancho del área
uint16_t height = ey - sy + 1; // calcula la altura del área
uint32_t Pixel = width * height; // calcula el número de píxeles
LCD_SetWindows(sx, sy, ex, ey); // establece la ventana de visualización
// for (i = 0; i < height; i++)
// {
// for (j = 0; j < width; j++){
// Lcd_WriteData_16Bit(color_p->full); // escribe dato
// }
// }
// valor de división de datos para envío por lotes
#define data_split 3000
uint8_t data[Pixel * 2]; // array para almacenar datos de color
for (i = 0; i < Pixel; i++)
{
// convierte color de 16 bits a dos bytes
data[i * 2] = (color_p->full) >> 8; // byte alto
data[i * 2 + 1] = (uint8_t)(color_p->full); // byte bajo
color_p++; // siguiente color
// si hay más de 10000 píxeles, envía por lotes
if (Pixel > 10000)
{
if ((i + 1) % data_split == 0)
{
if ((i + 1) == data_split)
{
Lcd_WriteData_DMA(data, data_split * 2); // envía vía DMA
}
else
{
while (HAL_SPI_GetState(LCD_SPI) != HAL_SPI_STATE_READY); // espera SPI libre
uint8_t *temp = &data[((uint16_t)((i + 1) / data_split) - 1) * data_split * 2];
Lcd_WriteData_DMA(temp, data_split * 2);
}
}
else if (((i + 1) % data_split > 0) && ((i + 1) > data_split) && (i == (Pixel - 1)))
{
if ((uint16_t)((i + 1) / data_split) == 1)
{
while (HAL_SPI_GetState(LCD_SPI) != HAL_SPI_STATE_READY)
;
uint8_t *temp = &data[data_split * 2];
Lcd_WriteData_DMA(temp, ((i + 1) % data_split) * 2);
}
else
{
while (HAL_SPI_GetState(LCD_SPI) != HAL_SPI_STATE_READY)
;
uint8_t *temp = &data[(uint16_t)((i + 1) / data_split) * data_split * 2];
Lcd_WriteData_DMA(temp, ((i + 1) % data_split) * 2);
}
}
}
}
if (Pixel <= 10000)
{
// si los datos son menores de 10000*2 bytes, envía de una vez
Lcd_WriteData_DMA(data, Pixel * 2);
}
LCD_SetWindows(0, 0, lcddev.width - 1, lcddev.height - 1); // restablece ventana a pantalla completa
}
Otros proyectos open-source recomendados
- Desarrollé un medidor de energía trifásico y lo liberé como open-source, permite monitorear fácilmente el consumo eléctrico del hogar: https://blog.zeruns.com/archives/771.html
- Plantilla de proyecto STM32F407 con biblioteca U8g2 portada: https://blog.zeruns.com/archives/722.html
- Placa mínima CH32V307VCT6 de QinHeng liberada como open-source: https://blog.zeruns.com/archives/726.html
- Módulo de alimentación DCDC auto-elevador-reductor LM25118: https://blog.zeruns.com/archives/727.html
- Módulo boost de alta potencia con rectificación síncrona EG1164, eficiencia hasta 97 %: https://blog.zeruns.com/archives/730.html
- Nodo 4G de monitoreo ambiental basado en Air700E (temp., humedad, presión) subiendo datos por MQTT a Alibaba Cloud IoT: https://blog.zeruns.com/archives/747.html
- Carga electrónica inteligente basada en CH32V307, proyecto del concurso embebidos liberado: https://blog.zeruns.com/archives/785.html
Recomendaciones de lectura
- VPS/Servidores cloud de alta relación calidad-precio: https://blog.zeruns.com/archives/383.html
- Tutorial de creación de servidor Minecraft: https://blog.zeruns.com/tag/mc/
- Revisión rápida de la fuente digital RD6012P de Ruideng, 60 V 12 A: https://blog.zeruns.com/archives/740.html
- Experiencia de desempaque de la impresora 3D Bambu Lab P1SC: https://blog.zeruns.com/archives/770.html
- Comparativa real de capacitores e inductores de distintas marcas y tipos (D, Q, ESR, X): https://blog.zeruns.com/archives/765.html
- Prueba y desmontaje de un cargador de 120 W por 2,6 ¥ en el centro comercial Douyin: https://blog.zeruns.com/archives/786.html





