HiFi player project, first commit.
This commit is contained in:
commit
4126ea13a1
49 files changed
+6333
No files matched your search
@@ -0,0 +1,215 @@
|
||||
/**
|
||||
****************************************************************************************************
|
||||
* @file spilcd.c
|
||||
* @author HiFi Player Project
|
||||
* @version V1.0
|
||||
* @date 2026-01-01
|
||||
* @brief SPI LCD(ST7789,320x240)驱动
|
||||
* @note 初始化流程与引脚定义参考正点原子 DNESP32S3 标准例程(10_spilcd / 30_music),
|
||||
* 并增加了“刷新完成信号量”,方便 LVGL 在 flush 时等待 DMA 传输结束。
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
#include "spilcd.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_lcd_panel_st7789.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#define TAG "spilcd"
|
||||
|
||||
/* 1: 2.4 寸 320x240 SPILCD 0: 1.3 寸 240x240 SPILCD */
|
||||
#define SPI_LCD_TYPE 1
|
||||
|
||||
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
|
||||
static esp_lcd_panel_io_handle_t s_io_handle = NULL; /* LCD SPI IO 句柄 */
|
||||
static SemaphoreHandle_t s_flush_sem = NULL; /* SPI 传输完成信号量 */
|
||||
static uint16_t s_width = SPI_LCD_H_RES;
|
||||
static uint16_t s_height = SPI_LCD_V_RES;
|
||||
|
||||
/**
|
||||
* @brief LCD 颜色传输完成回调(SPI ISR 上下文)
|
||||
*/
|
||||
static bool lcd_color_trans_done_cb(esp_lcd_panel_io_handle_t panel_io,
|
||||
esp_lcd_panel_io_event_data_t *edata,
|
||||
void *user_ctx)
|
||||
{
|
||||
BaseType_t high_task_woken = pdFALSE;
|
||||
|
||||
if (s_flush_sem != NULL)
|
||||
{
|
||||
xSemaphoreGiveFromISR(s_flush_sem, &high_task_woken);
|
||||
}
|
||||
|
||||
(void)panel_io;
|
||||
(void)edata;
|
||||
(void)user_ctx;
|
||||
|
||||
return (high_task_woken == pdTRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化 SPI LCD
|
||||
*/
|
||||
esp_err_t spilcd_init(void)
|
||||
{
|
||||
if (s_flush_sem == NULL)
|
||||
{
|
||||
s_flush_sem = xSemaphoreCreateBinary();
|
||||
if (s_flush_sem == NULL)
|
||||
{
|
||||
ESP_LOGE(TAG, "create flush semaphore failed");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
}
|
||||
|
||||
/* 打开 LCD 电源 */
|
||||
LCD_PWR(1);
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
|
||||
/* 硬件复位 */
|
||||
LCD_RST(0);
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
LCD_RST(1);
|
||||
vTaskDelay(pdMS_TO_TICKS(120));
|
||||
|
||||
/* ---------------- 挂载到 SPI 总线 ---------------- */
|
||||
esp_lcd_panel_io_spi_config_t io_config = {
|
||||
.dc_gpio_num = LCD_DC_PIN,
|
||||
.cs_gpio_num = LCD_CS_PIN,
|
||||
.pclk_hz = 60 * 1000 * 1000, /* 60MHz */
|
||||
.lcd_cmd_bits = 8,
|
||||
.lcd_param_bits = 8,
|
||||
.spi_mode = 0,
|
||||
.trans_queue_depth = 7,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &s_io_handle));
|
||||
|
||||
/* ---------------- 创建 ST7789 面板 ---------------- */
|
||||
esp_lcd_panel_dev_config_t panel_config = {
|
||||
.reset_gpio_num = GPIO_NUM_NC, /* 复位由 XL9555 控制 */
|
||||
.rgb_ele_order = COLOR_RGB_ELEMENT_ORDER_RGB,
|
||||
.bits_per_pixel = 16,
|
||||
.data_endian = LCD_RGB_DATA_ENDIAN_BIG, /* 屏幕要求高字节在前 */
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(s_io_handle, &panel_config, &panel_handle));
|
||||
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, true));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
|
||||
|
||||
/* 注册颜色传输完成回调 */
|
||||
const esp_lcd_panel_io_callbacks_t cbs = {
|
||||
.on_color_trans_done = lcd_color_trans_done_cb,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_io_register_event_callbacks(s_io_handle, &cbs, NULL));
|
||||
|
||||
spilcd_display_dir(1); /* 横屏 */
|
||||
spilcd_clear(0x0000); /* 上电先刷黑,避免白屏闪烁 */
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置屏幕方向
|
||||
*/
|
||||
void spilcd_display_dir(uint8_t dir)
|
||||
{
|
||||
if (dir == 0) /* 竖屏 */
|
||||
{
|
||||
s_width = SPI_LCD_V_RES;
|
||||
s_height = SPI_LCD_H_RES;
|
||||
esp_lcd_panel_swap_xy(panel_handle, false);
|
||||
esp_lcd_panel_mirror(panel_handle, false, false);
|
||||
|
||||
if (SPI_LCD_TYPE == 0)
|
||||
{
|
||||
esp_lcd_panel_set_gap(panel_handle, 0, 80);
|
||||
}
|
||||
}
|
||||
else /* 横屏 */
|
||||
{
|
||||
s_width = SPI_LCD_H_RES;
|
||||
s_height = SPI_LCD_V_RES;
|
||||
esp_lcd_panel_swap_xy(panel_handle, true);
|
||||
esp_lcd_panel_mirror(panel_handle, true, false);
|
||||
|
||||
if (SPI_LCD_TYPE == 0)
|
||||
{
|
||||
esp_lcd_panel_set_gap(panel_handle, 80, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将一块数据刷到屏幕,并等待 DMA 传输完成
|
||||
*/
|
||||
void spilcd_flush(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, const void *data)
|
||||
{
|
||||
if ((panel_handle == NULL) || (data == NULL) || (s_flush_sem == NULL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (x2 > s_width) x2 = s_width;
|
||||
if (y2 > s_height) y2 = s_height;
|
||||
if ((x1 >= x2) || (y1 >= y2))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* 丢弃上一次传输残留的信号 */
|
||||
while (xSemaphoreTake(s_flush_sem, 0) == pdTRUE)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
esp_err_t ret = esp_lcd_panel_draw_bitmap(panel_handle, x1, y1, x2, y2, data);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "draw bitmap failed: %s", esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
if (xSemaphoreTake(s_flush_sem, pdMS_TO_TICKS(200)) != pdTRUE)
|
||||
{
|
||||
ESP_LOGW(TAG, "wait lcd flush timeout");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 清屏
|
||||
*/
|
||||
void spilcd_clear(uint16_t color)
|
||||
{
|
||||
const uint16_t lines = 24;
|
||||
size_t px_count = (size_t)s_width * lines;
|
||||
|
||||
uint16_t *buffer = heap_caps_malloc(px_count * sizeof(uint16_t), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
|
||||
if (buffer == NULL)
|
||||
{
|
||||
ESP_LOGE(TAG, "no memory for clear buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
/* 转换成大端字节序 */
|
||||
uint16_t color_be = (uint16_t)((color << 8) | (color >> 8));
|
||||
for (size_t i = 0; i < px_count; i++)
|
||||
{
|
||||
buffer[i] = color_be;
|
||||
}
|
||||
|
||||
for (uint16_t y = 0; y < s_height; y += lines)
|
||||
{
|
||||
uint16_t y_end = (uint16_t)((y + lines) > s_height ? s_height : (y + lines));
|
||||
spilcd_flush(0, y, s_width, y_end, buffer);
|
||||
}
|
||||
|
||||
heap_caps_free(buffer);
|
||||
}
|
||||
Reference in new issue
Block a user