HiFi player project, first commit.
This commit is contained in:
commit
4126ea13a1
49 files changed
+6333
No files matched your search
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
****************************************************************************************************
|
||||
* @file lvgl_port.c
|
||||
* @author HiFi Player Project
|
||||
* @version V1.0
|
||||
* @date 2026-01-01
|
||||
* @brief LVGL 8.x 移植层
|
||||
*
|
||||
* 移植要点:
|
||||
* 1. 绘图缓冲区必须放在内部 RAM,并带 DMA 能力(SPI DMA 不能直接读 PSRAM)。
|
||||
* 2. flush_cb 中把 LVGL 的小端 RGB565 数据做字节交换,再交给 spilcd_flush()。
|
||||
* 3. spilcd_flush() 是阻塞的(等 SPI 传输完成回调),因此这里调用后可以直接
|
||||
* lv_disp_flush_ready(),实现简单可靠。
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
#include "lvgl_port.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
|
||||
#include "lvgl.h"
|
||||
#include "spilcd.h"
|
||||
|
||||
#define TAG "lvgl_port"
|
||||
|
||||
#define DISP_HOR_RES SPI_LCD_H_RES /* 320 */
|
||||
#define DISP_VER_RES SPI_LCD_V_RES /* 240 */
|
||||
#define DRAW_BUF_LINES 40 /* 单缓冲区高度(40 行约 25KB) */
|
||||
#define LVGL_TASK_STACK (8 * 1024)
|
||||
#define LVGL_TASK_PRIO 4
|
||||
|
||||
static lv_disp_draw_buf_t s_draw_buf;
|
||||
static lv_disp_drv_t s_disp_drv;
|
||||
static lv_color_t *s_draw_buf_mem = NULL;
|
||||
static esp_timer_handle_t s_tick_timer = NULL;
|
||||
|
||||
/**
|
||||
* @brief LVGL 刷新回调:把绘制好的区域送到 SPI LCD
|
||||
*/
|
||||
static void disp_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_p)
|
||||
{
|
||||
int32_t width = lv_area_get_width(area);
|
||||
int32_t height = lv_area_get_height(area);
|
||||
uint32_t pixels = (uint32_t)width * (uint32_t)height;
|
||||
uint16_t *buf = (uint16_t *)color_p;
|
||||
|
||||
/* LVGL 内部是 RGB565 小端,ST7789 要求高字节在前,这里原地交换 */
|
||||
for (uint32_t i = 0; i < pixels; i++)
|
||||
{
|
||||
buf[i] = (uint16_t)((buf[i] << 8) | (buf[i] >> 8));
|
||||
}
|
||||
|
||||
/* x2 / y2 使用“不包含”的坐标 */
|
||||
spilcd_flush((uint16_t)area->x1, (uint16_t)area->y1,
|
||||
(uint16_t)(area->x2 + 1), (uint16_t)(area->y2 + 1), buf);
|
||||
|
||||
lv_disp_flush_ready(drv);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LVGL 1ms 时基
|
||||
*/
|
||||
static void lv_tick_cb(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
lv_tick_inc(1);
|
||||
}
|
||||
|
||||
esp_err_t lvgl_port_init(void)
|
||||
{
|
||||
lv_init();
|
||||
|
||||
/* ---------------- 绘图缓冲区(内部 DMA RAM) ---------------- */
|
||||
size_t pixel_count = (size_t)DISP_HOR_RES * DRAW_BUF_LINES;
|
||||
|
||||
s_draw_buf_mem = (lv_color_t *)heap_caps_malloc(pixel_count * sizeof(lv_color_t),
|
||||
MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
|
||||
if (s_draw_buf_mem == NULL)
|
||||
{
|
||||
ESP_LOGE(TAG, "no memory for LVGL draw buffer");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
lv_disp_draw_buf_init(&s_draw_buf, s_draw_buf_mem, NULL, pixel_count);
|
||||
|
||||
/* ---------------- 注册显示设备 ---------------- */
|
||||
lv_disp_drv_init(&s_disp_drv);
|
||||
s_disp_drv.hor_res = DISP_HOR_RES;
|
||||
s_disp_drv.ver_res = DISP_VER_RES;
|
||||
s_disp_drv.draw_buf = &s_draw_buf;
|
||||
s_disp_drv.flush_cb = disp_flush_cb;
|
||||
lv_disp_drv_register(&s_disp_drv);
|
||||
|
||||
/* ---------------- 1ms 时基 ---------------- */
|
||||
const esp_timer_create_args_t timer_args = {
|
||||
.callback = lv_tick_cb,
|
||||
.name = "lv_tick",
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_timer_create(&timer_args, &s_tick_timer));
|
||||
ESP_ERROR_CHECK(esp_timer_start_periodic(s_tick_timer, 1000)); /* 1000us */
|
||||
|
||||
ESP_LOGI(TAG, "LVGL %d.%d.%d ready, draw buffer %u px",
|
||||
LVGL_VERSION_MAJOR, LVGL_VERSION_MINOR, LVGL_VERSION_PATCH,
|
||||
(unsigned)pixel_count);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void lvgl_task(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
while (1)
|
||||
{
|
||||
lv_timer_handler();
|
||||
vTaskDelay(pdMS_TO_TICKS(5));
|
||||
}
|
||||
}
|
||||
|
||||
void lvgl_port_start(void)
|
||||
{
|
||||
if (xTaskCreate(lvgl_task, "lvgl", LVGL_TASK_STACK, NULL, LVGL_TASK_PRIO, NULL) != pdPASS)
|
||||
{
|
||||
ESP_LOGE(TAG, "create lvgl task failed");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user