适配ESP32-C3开发板成功
1、原有ESP32-S3功能基本实现,有些小Bug需要修复; 2、RAM内存不够导致Img界面图片显示画质不完整,并且当前未开启蓝牙功能,开机蓝牙功能后RAM内存压力加剧;
This commit is contained in:
parent
455c92dbd7
commit
4547e9e732
48
.vscode/c_cpp_properties.json
vendored
48
.vscode/c_cpp_properties.json
vendored
@ -1,25 +1,25 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "ESP-IDF",
|
||||
"compilerPath": "D:/CodeBlocks/MinGW/bin/gcc.exe",
|
||||
"compileCommands": [
|
||||
"${config:idf.buildPath}/compile_commands.json"
|
||||
],
|
||||
"includePath": [
|
||||
"${config:idf.espIdfPath}/components/**",
|
||||
"${config:idf.espIdfPathWin}/components/**",
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"browse": {
|
||||
"path": [
|
||||
"${config:idf.espIdfPath}/components",
|
||||
"${config:idf.espIdfPathWin}/components",
|
||||
"${workspaceFolder}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
"configurations": [
|
||||
{
|
||||
"name": "ESP-IDF",
|
||||
"compilerPath": "/Users/rdzleo/.espressif/tools/xtensa-esp-elf/esp-14.2.0_20241119/xtensa-esp-elf/bin/xtensa-esp32s3-elf-gcc",
|
||||
"compileCommands": [
|
||||
"${config:idf.buildPath}/compile_commands.json"
|
||||
],
|
||||
"includePath": [
|
||||
"${config:idf.espIdfPath}/components/**",
|
||||
"${config:idf.espIdfPathWin}/components/**",
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"browse": {
|
||||
"path": [
|
||||
"${config:idf.espIdfPath}/components",
|
||||
"${config:idf.espIdfPathWin}/components",
|
||||
"${workspaceFolder}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
|
||||
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@ -3,11 +3,11 @@
|
||||
"idf.espIdfPathWin": "D:/Espressif/frameworks/esp-idf-v5.4.1/",
|
||||
"idf.pythonInstallPath": "/opt/homebrew/bin/python3",
|
||||
"idf.openOcdConfigs": [
|
||||
"board/esp32s3-builtin.cfg"
|
||||
"board/esp32c3-bridge.cfg"
|
||||
],
|
||||
"idf.toolsPathWin": "D:\\Espressif",
|
||||
"idf.customExtraVars": {
|
||||
"IDF_TARGET": "esp32s3"
|
||||
"IDF_TARGET": "esp32c3"
|
||||
},
|
||||
"files.associations": {
|
||||
"*.bin": "bibtex",
|
||||
|
||||
@ -20,7 +20,7 @@ dependencies:
|
||||
type: service
|
||||
version: 1.3.1
|
||||
espressif/esp_lcd_st77916:
|
||||
component_hash: 5fa0f8b1274576d4484e2b8d9358e2a5d09c721511bef0dce6a55b4206b5f0e9
|
||||
component_hash: c0a565af3ea85a9d9f1e79b0e4d0829378db319bc4dab4939eca44361b3c5a1b
|
||||
dependencies:
|
||||
- name: espressif/cmake_utilities
|
||||
registry_url: https://components.espressif.com
|
||||
@ -28,11 +28,11 @@ dependencies:
|
||||
version: 0.*
|
||||
- name: idf
|
||||
require: private
|
||||
version: '>5.0.4,!=5.1.1'
|
||||
version: '>=5.4'
|
||||
source:
|
||||
registry_url: https://components.espressif.com/
|
||||
type: service
|
||||
version: 1.0.1
|
||||
version: 2.0.2
|
||||
espressif/esp_lcd_touch:
|
||||
component_hash: 779b4ba2464a3ae85681e4b860caa5fdc35801458c23f3039ee761bae7f442a4
|
||||
dependencies:
|
||||
@ -90,6 +90,6 @@ direct_dependencies:
|
||||
- espressif/esp_lvgl_port
|
||||
- idf
|
||||
- lvgl/lvgl
|
||||
manifest_hash: ecdcccdc402053a695b236c22d3cc28aa507b2bda6e01d835e01cd2f42ab7e0e
|
||||
target: esp32s3
|
||||
manifest_hash: 2e5e8224c989c28cde3f3a2470ecd63548cf45b6263cdcb5a1550808138e5c02
|
||||
target: esp32c3
|
||||
version: 2.0.0
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
// 电池ADC引脚配置
|
||||
#define PIN_BAT_ADC 3 // GPIO3
|
||||
#define PIN_BAT_ADC 2 // GPIO2
|
||||
#define BAT_ADC_CHANNEL ADC_CHANNEL_2 // ADC1_CH2
|
||||
|
||||
// 分压比(实际电池电压 = ADC测量电压 * 此系数)
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
#include "esp_err.h"
|
||||
|
||||
// 按键引脚定义
|
||||
#define PIN_BTN_BOOT 0 // GPIO0 BOOT按键(低电平有效)
|
||||
#define PIN_BTN_KEY2 4 // GPIO4 KEY2按键(低电平有效)
|
||||
#define PIN_BTN_BOOT 9 // GPIO9 BOOT按键(低电平有效)
|
||||
#define PIN_BTN_KEY2 8 // GPIO8 KEY2按键(低电平有效)
|
||||
|
||||
// 按键事件回调函数类型
|
||||
typedef void (*btn_event_cb_t)(int gpio_num, void *usr_data);
|
||||
|
||||
@ -528,9 +528,11 @@ bool fats_img_isOK(char* img_path){
|
||||
return true;
|
||||
}
|
||||
|
||||
// 解码图片
|
||||
// 解码图片(使用1:2缩放,ESP32-C3内存有限,全尺寸360×360×2=253KB超出可用堆)
|
||||
esp_err_t DecodeImg(char *imgpath,uint8_t** imgData,esp_jpeg_image_output_t *outimage)
|
||||
{
|
||||
*imgData = NULL;
|
||||
|
||||
FILE *f = fopen(imgpath, "rb");
|
||||
if(f == NULL){
|
||||
ESP_LOGE(TAG, "OPEN ERROR");
|
||||
@ -538,56 +540,64 @@ esp_err_t DecodeImg(char *imgpath,uint8_t** imgData,esp_jpeg_image_output_t *out
|
||||
}
|
||||
struct stat file_stat;
|
||||
stat(imgpath, &file_stat);
|
||||
*imgData = malloc(360 * 360 *2);
|
||||
// printf("文件大小:%d,分配地址:%p\n",(int)file_stat.st_size,*imgData);
|
||||
|
||||
// 先分配输入缓冲区并读取JPEG文件
|
||||
uint8_t *imgEncoderData = malloc(file_stat.st_size);
|
||||
if (imgEncoderData == NULL) {
|
||||
ESP_LOGE(TAG, "输入缓冲区分配失败(内存不足,需%d字节)", (int)file_stat.st_size);
|
||||
free(*imgData);
|
||||
ESP_LOGE(TAG, "输入缓冲区分配失败(需%d字节)", (int)file_stat.st_size);
|
||||
fclose(f);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
size_t read_len = fread(imgEncoderData,sizeof(uint8_t),file_stat.st_size,f);
|
||||
if (read_len != file_stat.st_size) {
|
||||
ESP_LOGE(TAG, "文件读取不完整(预期:%d 字节,实际:%zu 字节)",
|
||||
(int)file_stat.st_size, read_len);
|
||||
free(imgEncoderData);
|
||||
free(*imgData);
|
||||
fclose(f);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (file_stat.st_size < 2) {
|
||||
ESP_LOGE(TAG, "文件过小,不是有效JPEG");
|
||||
free(imgEncoderData);
|
||||
free(*imgData);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (imgEncoderData[0] != 0xFF || imgEncoderData[1] != 0xD8) {
|
||||
ESP_LOGE(TAG, "JPEG起始标记缺失");
|
||||
free(imgEncoderData);
|
||||
free(*imgData);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (imgEncoderData[file_stat.st_size - 2] != 0xFF || imgEncoderData[file_stat.st_size - 1] != 0xD9) {
|
||||
ESP_LOGE(TAG, "JPEG结束标记缺失");
|
||||
free(imgEncoderData);
|
||||
free(*imgData);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
size_t read_len = fread(imgEncoderData, sizeof(uint8_t), file_stat.st_size, f);
|
||||
fclose(f);
|
||||
uint32_t outbuf_size = 360 * 360 * sizeof(uint8_t) * 2;
|
||||
|
||||
if (read_len != file_stat.st_size) {
|
||||
ESP_LOGE(TAG, "文件读取不完整(预期:%d,实际:%zu)", (int)file_stat.st_size, read_len);
|
||||
free(imgEncoderData);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (file_stat.st_size < 2 || imgEncoderData[0] != 0xFF || imgEncoderData[1] != 0xD8) {
|
||||
ESP_LOGE(TAG, "无效JPEG文件");
|
||||
free(imgEncoderData);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// 配置JPEG解码(1:2缩放,输出缓冲区从253KB降至~63KB)
|
||||
esp_jpeg_image_cfg_t jpeg_cfg = {
|
||||
.indata = imgEncoderData,
|
||||
.indata_size = file_stat.st_size,
|
||||
.outbuf = *imgData,
|
||||
.outbuf_size = outbuf_size,
|
||||
.out_format = JPEG_IMAGE_FORMAT_RGB565,
|
||||
.out_scale = JPEG_IMAGE_SCALE_1_2,
|
||||
.flags = {
|
||||
.swap_color_bytes = true, // 启用字节交换,适配 LVGL 8.3.11 RGB565 格式
|
||||
.swap_color_bytes = true,
|
||||
},
|
||||
};
|
||||
esp_err_t ret = esp_jpeg_decode(&jpeg_cfg,outimage);
|
||||
|
||||
// 先获取缩放后的图片尺寸,精确分配输出缓冲区
|
||||
esp_jpeg_image_output_t img_info;
|
||||
esp_err_t ret = esp_jpeg_get_image_info(&jpeg_cfg, &img_info);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "获取JPEG信息失败");
|
||||
free(imgEncoderData);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
*imgData = malloc(img_info.output_len);
|
||||
if (*imgData == NULL) {
|
||||
ESP_LOGE(TAG, "输出缓冲区分配失败(需%zu字节)", img_info.output_len);
|
||||
free(imgEncoderData);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
jpeg_cfg.outbuf = *imgData;
|
||||
jpeg_cfg.outbuf_size = img_info.output_len;
|
||||
ret = esp_jpeg_decode(&jpeg_cfg, outimage);
|
||||
|
||||
free(imgEncoderData);
|
||||
if (ret != ESP_OK) {
|
||||
free(*imgData);
|
||||
*imgData = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
#include "esp_lvgl_port.h"
|
||||
|
||||
void test_display(esp_lcd_panel_handle_t panel_handle){
|
||||
uint16_t *color_buf = malloc(LCD_WID * 100 * sizeof(uint16_t)); // 10行,每行360像素(RGB565)
|
||||
uint16_t *color_buf = malloc(LCD_WID * 100 * sizeof(uint16_t));
|
||||
if (color_buf == NULL) {
|
||||
ESP_LOGE(LCD_TAG, "红色缓冲区分配失败");
|
||||
return;
|
||||
@ -29,71 +29,25 @@ void test_display(esp_lcd_panel_handle_t panel_handle){
|
||||
}
|
||||
|
||||
void test_gpio(){
|
||||
// SPI LCD引脚测试(C3适配)
|
||||
gpio_config_t led_conf = {};
|
||||
led_conf.mode = GPIO_MODE_OUTPUT;
|
||||
led_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
led_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
led_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
|
||||
led_conf.pin_bit_mask = (1ULL << PIN_LCD_CLK);
|
||||
led_conf.mode = GPIO_MODE_OUTPUT;
|
||||
led_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
led_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
led_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
gpio_config(&led_conf);
|
||||
|
||||
led_conf.pin_bit_mask = (1ULL << PIN_LCD_D0);
|
||||
led_conf.mode = GPIO_MODE_OUTPUT;
|
||||
led_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
led_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
led_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
gpio_config(&led_conf);
|
||||
|
||||
led_conf.pin_bit_mask = (1ULL << PIN_LCD_D1);
|
||||
led_conf.mode = GPIO_MODE_OUTPUT;
|
||||
led_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
led_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
led_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
gpio_config(&led_conf);
|
||||
|
||||
led_conf.pin_bit_mask = (1ULL << PIN_LCD_D2);
|
||||
led_conf.mode = GPIO_MODE_OUTPUT;
|
||||
led_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
led_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
led_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
gpio_config(&led_conf);
|
||||
|
||||
led_conf.pin_bit_mask = (1ULL << PIN_LCD_D3);
|
||||
led_conf.mode = GPIO_MODE_OUTPUT;
|
||||
led_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
led_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
led_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
gpio_config(&led_conf);
|
||||
|
||||
led_conf.pin_bit_mask = (1ULL << PIN_LCD_RST);
|
||||
led_conf.mode = GPIO_MODE_OUTPUT;
|
||||
led_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
led_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
led_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
led_conf.pin_bit_mask = (1ULL << PIN_LCD_MOSI);
|
||||
gpio_config(&led_conf);
|
||||
|
||||
led_conf.pin_bit_mask = (1ULL << PIN_LCD_CS);
|
||||
led_conf.mode = GPIO_MODE_OUTPUT;
|
||||
led_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
led_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
led_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
|
||||
gpio_config(&led_conf);
|
||||
|
||||
led_conf.pin_bit_mask = (1ULL << 36);
|
||||
led_conf.mode = GPIO_MODE_OUTPUT;
|
||||
led_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
led_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
led_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
|
||||
led_conf.pin_bit_mask = (1ULL << PIN_LCD_DC);
|
||||
gpio_config(&led_conf);
|
||||
gpio_set_level(36,1);
|
||||
|
||||
// gpio_set_level(PIN_LCD_CS,1);
|
||||
// gpio_set_level(PIN_LCD_RST,0);
|
||||
// gpio_set_level(PIN_LCD_CLK,1);
|
||||
// gpio_set_level(PIN_LCD_D0,0);
|
||||
// gpio_set_level(PIN_LCD_D1,1);
|
||||
// gpio_set_level(PIN_LCD_D2,0);
|
||||
// gpio_set_level(PIN_LCD_D3,1);
|
||||
}
|
||||
led_conf.pin_bit_mask = (1ULL << PIN_LCD_BL);
|
||||
gpio_config(&led_conf);
|
||||
}
|
||||
|
||||
@ -1,33 +1,31 @@
|
||||
#include "esp_lvgl_port.h"
|
||||
|
||||
#define PIN_NUM_SCL 18 //引脚18 SCL
|
||||
#define PIN_NUM_SDA 17 //引脚17 SDA
|
||||
#define I2C_MASTER_FREQ_HZ 100000
|
||||
#define I2C_MASTER_NUM I2C_NUM_0 // I2C 主机编号 0
|
||||
// I2C引脚(参考spi_lcd项目)
|
||||
#define PIN_NUM_SCL 1 // GPIO1 SCL
|
||||
#define PIN_NUM_SDA 0 // GPIO0 SDA
|
||||
#define I2C_MASTER_FREQ_HZ 400000 // I2C频率400KHz
|
||||
#define I2C_MASTER_NUM I2C_NUM_0 // I2C主机编号0
|
||||
|
||||
#define PIN_LCD_EN 1 //引脚1 使能
|
||||
#define PIN_LCD_D0 11 //引脚11 数据0
|
||||
#define PIN_LCD_D1 13 //引脚13 数据1
|
||||
#define PIN_LCD_D2 14 //引脚14 数据2
|
||||
#define PIN_LCD_D3 21 //引脚21 数据3
|
||||
#define PIN_LCD_CLK 12 //引脚12 时钟
|
||||
#define PIN_LCD_CS 47 //引脚47 片选
|
||||
#define PIN_LCD_RST 7 //引脚7 复位
|
||||
// SPI LCD引脚(参考spi_lcd项目,标准SPI模式)
|
||||
#define PIN_LCD_BL 7 // GPIO7 背光(低电平有效)
|
||||
#define PIN_LCD_MOSI 5 // GPIO5 SPI MOSI
|
||||
#define PIN_LCD_CLK 3 // GPIO3 SPI CLK
|
||||
#define PIN_LCD_CS 4 // GPIO4 片选
|
||||
#define PIN_LCD_DC 6 // GPIO6 数据/命令选择(SPI模式必需)
|
||||
#define PIN_LCD_RST -1 // 不使用硬复位
|
||||
|
||||
#define LCD_HIGH 360
|
||||
#define LCD_WID 360
|
||||
|
||||
#define PIN_TP_RST 6 //引脚6 复位
|
||||
#define PIN_TP_INT 5 //引脚4 中断
|
||||
// 触摸引脚
|
||||
#define PIN_TP_RST -1 // 不使用硬复位
|
||||
#define PIN_TP_INT 10 // GPIO10 触摸中断
|
||||
|
||||
#define LCD_TAG "LCD"
|
||||
#define SPI_LCD_HOST SPI2_HOST // SPI 主机编号 2
|
||||
#define SPI_LCD_HOST SPI2_HOST // SPI主机编号2
|
||||
|
||||
#define PIN_MOTOR_EN -1 // 电机使能
|
||||
#define PIN_BAT_ADC 3 // 电池ADC检测引脚(ADC1_CH2)
|
||||
|
||||
// 注意:V1.0原理图中 GPIO4=KEY2按键, GPIO5=TP_INT
|
||||
// 如果触摸不工作,请检查 PIN_TP_INT 是否与硬件版本匹配
|
||||
#define PIN_MOTOR_EN -1 // 电机使能(未使用)
|
||||
#define PIN_BAT_ADC 2 // GPIO2 电池ADC检测引脚(ADC1_CH2)
|
||||
|
||||
void test_display(esp_lcd_panel_handle_t panel_handle);
|
||||
void test_gpio();
|
||||
void test_gpio();
|
||||
|
||||
@ -2,7 +2,7 @@ dependencies:
|
||||
esp_lvgl_port: 2.5.0
|
||||
lvgl/lvgl:
|
||||
version: 8.3.11
|
||||
esp_lcd_st77916: 1.0.1
|
||||
esp_lcd_st77916: "^2.0.2"
|
||||
esp_lcd_touch: 1.1.2
|
||||
esp_lcd_touch_cst816s: 1.1.0
|
||||
esp_jpeg: 1.3.1
|
||||
@ -1,3 +1,4 @@
|
||||
#include <stdbool.h>
|
||||
#include "esp_lvgl_port.h"
|
||||
#include "esp_lcd_st77916.h"
|
||||
|
||||
@ -6,4 +7,5 @@ void lcd_init();
|
||||
void lvgl_lcd_init();
|
||||
void touch_init();
|
||||
void get_touch(uint16_t* touchx,uint16_t* touchy);
|
||||
void lcd_clear_screen_black(void); // 清空LCD GRAM为黑色
|
||||
void lcd_clear_screen_black(void); // 清空LCD GRAM为黑色
|
||||
void lcd_disp_on_off(bool on_off); // LCD显示开关
|
||||
298
main/lcd/lcd.c
298
main/lcd/lcd.c
@ -5,8 +5,6 @@
|
||||
#include "esp_log.h"
|
||||
#include "lcd.h"
|
||||
#include "esp_lcd_touch_cst816s.h"
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include <string.h>
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
@ -16,43 +14,248 @@ static esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
static esp_lcd_touch_handle_t touch_handle;
|
||||
static esp_lcd_panel_io_handle_t tp_io_handle = NULL;
|
||||
|
||||
// 从参考项目 spi_lcd 提取的正确LCD初始化命令(匹配当前LCD面板硬件)
|
||||
static const st77916_lcd_init_cmd_t lcd_init_cmds[] = {
|
||||
{0xF0, (uint8_t[]){0x28}, 1, 0},
|
||||
{0xF2, (uint8_t[]){0x28}, 1, 0},
|
||||
{0x73, (uint8_t[]){0xF0}, 1, 0},
|
||||
{0x7C, (uint8_t[]){0xD1}, 1, 0},
|
||||
{0x83, (uint8_t[]){0xE0}, 1, 0},
|
||||
{0x84, (uint8_t[]){0x61}, 1, 0},
|
||||
{0xF2, (uint8_t[]){0x82}, 1, 0},
|
||||
{0xF0, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xF0, (uint8_t[]){0x01}, 1, 0},
|
||||
{0xF1, (uint8_t[]){0x01}, 1, 0},
|
||||
{0xB0, (uint8_t[]){0x5E}, 1, 0},
|
||||
{0xB1, (uint8_t[]){0x55}, 1, 0},
|
||||
{0xB2, (uint8_t[]){0x24}, 1, 0},
|
||||
{0xB3, (uint8_t[]){0x01}, 1, 0},
|
||||
{0xB4, (uint8_t[]){0x87}, 1, 0},
|
||||
{0xB5, (uint8_t[]){0x44}, 1, 0},
|
||||
{0xB6, (uint8_t[]){0x8B}, 1, 0},
|
||||
{0xB7, (uint8_t[]){0x40}, 1, 0},
|
||||
{0xB8, (uint8_t[]){0x86}, 1, 0},
|
||||
{0xB9, (uint8_t[]){0x15}, 1, 0},
|
||||
{0xBA, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xBB, (uint8_t[]){0x08}, 1, 0},
|
||||
{0xBC, (uint8_t[]){0x08}, 1, 0},
|
||||
{0xBD, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xBE, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xBF, (uint8_t[]){0x07}, 1, 0},
|
||||
{0xC0, (uint8_t[]){0x80}, 1, 0},
|
||||
{0xC1, (uint8_t[]){0x10}, 1, 0},
|
||||
{0xC2, (uint8_t[]){0x37}, 1, 0},
|
||||
{0xC3, (uint8_t[]){0x80}, 1, 0},
|
||||
{0xC4, (uint8_t[]){0x10}, 1, 0},
|
||||
{0xC5, (uint8_t[]){0x37}, 1, 0},
|
||||
{0xC6, (uint8_t[]){0xA9}, 1, 0},
|
||||
{0xC7, (uint8_t[]){0x41}, 1, 0},
|
||||
{0xC8, (uint8_t[]){0x01}, 1, 0},
|
||||
{0xC9, (uint8_t[]){0xA9}, 1, 0},
|
||||
{0xCA, (uint8_t[]){0x41}, 1, 0},
|
||||
{0xCB, (uint8_t[]){0x01}, 1, 0},
|
||||
{0xCC, (uint8_t[]){0x7F}, 1, 0},
|
||||
{0xCD, (uint8_t[]){0x7F}, 1, 0},
|
||||
{0xCE, (uint8_t[]){0xFF}, 1, 0},
|
||||
{0xD0, (uint8_t[]){0x91}, 1, 0},
|
||||
{0xD1, (uint8_t[]){0x68}, 1, 0},
|
||||
{0xD2, (uint8_t[]){0x68}, 1, 0},
|
||||
{0xF5, (uint8_t[]){0x00, 0xA5}, 2, 0},
|
||||
{0xDD, (uint8_t[]){0x40}, 1, 0},
|
||||
{0xDE, (uint8_t[]){0x40}, 1, 0},
|
||||
{0xF1, (uint8_t[]){0x10}, 1, 0},
|
||||
{0xF0, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xF0, (uint8_t[]){0x02}, 1, 0},
|
||||
{0xE0, (uint8_t[]){0xF0, 0x10, 0x18, 0x0D, 0x0C, 0x38, 0x3E, 0x44, 0x51, 0x39, 0x15, 0x15, 0x30, 0x34}, 14, 0},
|
||||
{0xE1, (uint8_t[]){0xF0, 0x0F, 0x17, 0x0D, 0x0B, 0x07, 0x3E, 0x33, 0x51, 0x39, 0x15, 0x15, 0x30, 0x34}, 14, 0},
|
||||
{0xF0, (uint8_t[]){0x10}, 1, 0},
|
||||
{0xF3, (uint8_t[]){0x10}, 1, 0},
|
||||
{0xE0, (uint8_t[]){0x08}, 1, 0},
|
||||
{0xE1, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xE2, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xE3, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xE4, (uint8_t[]){0xE0}, 1, 0},
|
||||
{0xE5, (uint8_t[]){0x06}, 1, 0},
|
||||
{0xE6, (uint8_t[]){0x21}, 1, 0},
|
||||
{0xE7, (uint8_t[]){0x03}, 1, 0},
|
||||
{0xE8, (uint8_t[]){0x05}, 1, 0},
|
||||
{0xE9, (uint8_t[]){0x02}, 1, 0},
|
||||
{0xEA, (uint8_t[]){0xE9}, 1, 0},
|
||||
{0xEB, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xEC, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xED, (uint8_t[]){0x14}, 1, 0},
|
||||
{0xEE, (uint8_t[]){0xFF}, 1, 0},
|
||||
{0xEF, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xF8, (uint8_t[]){0xFF}, 1, 0},
|
||||
{0xF9, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xFA, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xFB, (uint8_t[]){0x30}, 1, 0},
|
||||
{0xFC, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xFD, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xFE, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xFF, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x60, (uint8_t[]){0x40}, 1, 0},
|
||||
{0x61, (uint8_t[]){0x05}, 1, 0},
|
||||
{0x62, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x63, (uint8_t[]){0x42}, 1, 0},
|
||||
{0x64, (uint8_t[]){0xDA}, 1, 0},
|
||||
{0x65, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x66, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x67, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x68, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x69, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x6A, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x6B, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x70, (uint8_t[]){0x40}, 1, 0},
|
||||
{0x71, (uint8_t[]){0x04}, 1, 0},
|
||||
{0x72, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x73, (uint8_t[]){0x42}, 1, 0},
|
||||
{0x74, (uint8_t[]){0xD9}, 1, 0},
|
||||
{0x75, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x76, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x77, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x78, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x79, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x7A, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x7B, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x80, (uint8_t[]){0x48}, 1, 0},
|
||||
{0x81, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x82, (uint8_t[]){0x07}, 1, 0},
|
||||
{0x83, (uint8_t[]){0x02}, 1, 0},
|
||||
{0x84, (uint8_t[]){0xD7}, 1, 0},
|
||||
{0x85, (uint8_t[]){0x04}, 1, 0},
|
||||
{0x86, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x87, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x88, (uint8_t[]){0x48}, 1, 0},
|
||||
{0x89, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x8A, (uint8_t[]){0x09}, 1, 0},
|
||||
{0x8B, (uint8_t[]){0x02}, 1, 0},
|
||||
{0x8C, (uint8_t[]){0xD9}, 1, 0},
|
||||
{0x8D, (uint8_t[]){0x04}, 1, 0},
|
||||
{0x8E, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x8F, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x90, (uint8_t[]){0x48}, 1, 0},
|
||||
{0x91, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x92, (uint8_t[]){0x0B}, 1, 0},
|
||||
{0x93, (uint8_t[]){0x02}, 1, 0},
|
||||
{0x94, (uint8_t[]){0xDB}, 1, 0},
|
||||
{0x95, (uint8_t[]){0x04}, 1, 0},
|
||||
{0x96, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x97, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x98, (uint8_t[]){0x48}, 1, 0},
|
||||
{0x99, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x9A, (uint8_t[]){0x0D}, 1, 0},
|
||||
{0x9B, (uint8_t[]){0x02}, 1, 0},
|
||||
{0x9C, (uint8_t[]){0xDD}, 1, 0},
|
||||
{0x9D, (uint8_t[]){0x04}, 1, 0},
|
||||
{0x9E, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x9F, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xA0, (uint8_t[]){0x48}, 1, 0},
|
||||
{0xA1, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xA2, (uint8_t[]){0x06}, 1, 0},
|
||||
{0xA3, (uint8_t[]){0x02}, 1, 0},
|
||||
{0xA4, (uint8_t[]){0xD6}, 1, 0},
|
||||
{0xA5, (uint8_t[]){0x04}, 1, 0},
|
||||
{0xA6, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xA7, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xA8, (uint8_t[]){0x48}, 1, 0},
|
||||
{0xA9, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xAA, (uint8_t[]){0x08}, 1, 0},
|
||||
{0xAB, (uint8_t[]){0x02}, 1, 0},
|
||||
{0xAC, (uint8_t[]){0xD8}, 1, 0},
|
||||
{0xAD, (uint8_t[]){0x04}, 1, 0},
|
||||
{0xAE, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xAF, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xB0, (uint8_t[]){0x48}, 1, 0},
|
||||
{0xB1, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xB2, (uint8_t[]){0x0A}, 1, 0},
|
||||
{0xB3, (uint8_t[]){0x02}, 1, 0},
|
||||
{0xB4, (uint8_t[]){0xDA}, 1, 0},
|
||||
{0xB5, (uint8_t[]){0x04}, 1, 0},
|
||||
{0xB6, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xB7, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xB8, (uint8_t[]){0x48}, 1, 0},
|
||||
{0xB9, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xBA, (uint8_t[]){0x0C}, 1, 0},
|
||||
{0xBB, (uint8_t[]){0x02}, 1, 0},
|
||||
{0xBC, (uint8_t[]){0xDC}, 1, 0},
|
||||
{0xBD, (uint8_t[]){0x04}, 1, 0},
|
||||
{0xBE, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xBF, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xC0, (uint8_t[]){0x10}, 1, 0},
|
||||
{0xC1, (uint8_t[]){0x47}, 1, 0},
|
||||
{0xC2, (uint8_t[]){0x56}, 1, 0},
|
||||
{0xC3, (uint8_t[]){0x65}, 1, 0},
|
||||
{0xC4, (uint8_t[]){0x74}, 1, 0},
|
||||
{0xC5, (uint8_t[]){0x88}, 1, 0},
|
||||
{0xC6, (uint8_t[]){0x99}, 1, 0},
|
||||
{0xC7, (uint8_t[]){0x01}, 1, 0},
|
||||
{0xC8, (uint8_t[]){0xBB}, 1, 0},
|
||||
{0xC9, (uint8_t[]){0xAA}, 1, 0},
|
||||
{0xD0, (uint8_t[]){0x10}, 1, 0},
|
||||
{0xD1, (uint8_t[]){0x47}, 1, 0},
|
||||
{0xD2, (uint8_t[]){0x56}, 1, 0},
|
||||
{0xD3, (uint8_t[]){0x65}, 1, 0},
|
||||
{0xD4, (uint8_t[]){0x74}, 1, 0},
|
||||
{0xD5, (uint8_t[]){0x88}, 1, 0},
|
||||
{0xD6, (uint8_t[]){0x99}, 1, 0},
|
||||
{0xD7, (uint8_t[]){0x01}, 1, 0},
|
||||
{0xD8, (uint8_t[]){0xBB}, 1, 0},
|
||||
{0xD9, (uint8_t[]){0xAA}, 1, 0},
|
||||
{0xF3, (uint8_t[]){0x01}, 1, 0},
|
||||
{0xF0, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x3A, (uint8_t[]){0x55}, 1, 0},
|
||||
{0x21, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x11, (uint8_t[]){0x00}, 1, 120},
|
||||
{0x29, (uint8_t[]){0x00}, 1, 0},
|
||||
};
|
||||
|
||||
void lcd_init(){
|
||||
const spi_bus_config_t buscfg = ST77916_PANEL_BUS_QSPI_CONFIG(PIN_LCD_CLK,
|
||||
PIN_LCD_D0,
|
||||
PIN_LCD_D1,
|
||||
PIN_LCD_D2,
|
||||
PIN_LCD_D3,
|
||||
LCD_HIGH * 80 * sizeof(uint16_t));
|
||||
spi_bus_initialize(SPI_LCD_HOST, &buscfg, SPI_DMA_CH_AUTO);
|
||||
// 标准SPI总线配置(CLK + MOSI,无MISO)
|
||||
const spi_bus_config_t buscfg = {
|
||||
.sclk_io_num = PIN_LCD_CLK,
|
||||
.mosi_io_num = PIN_LCD_MOSI,
|
||||
.miso_io_num = -1,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
.max_transfer_sz = LCD_HIGH * 80 * sizeof(uint16_t),
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI_LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
|
||||
// 自定义IO配置,提升SPI时钟从40MHz到80MHz
|
||||
esp_lcd_panel_io_spi_config_t io_config = ST77916_PANEL_IO_QSPI_CONFIG(PIN_LCD_CS, NULL, NULL);
|
||||
io_config.pclk_hz = 80 * 1000 * 1000; // 提升到80MHz(最大值)
|
||||
// 标准SPI IO配置(带DC引脚)
|
||||
esp_lcd_panel_io_spi_config_t io_config = {
|
||||
.dc_gpio_num = PIN_LCD_DC,
|
||||
.cs_gpio_num = PIN_LCD_CS,
|
||||
.pclk_hz = 60 * 1000 * 1000, // C3 SPI最大60MHz
|
||||
.lcd_cmd_bits = 8,
|
||||
.lcd_param_bits = 8,
|
||||
.spi_mode = 0,
|
||||
.trans_queue_depth = 10,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)SPI_LCD_HOST, &io_config, &io_handle));
|
||||
const st77916_vendor_config_t vendor_config = {
|
||||
.flags = {
|
||||
.use_qspi_interface = 1,
|
||||
},
|
||||
|
||||
// ST77916面板配置(通过vendor_config注入正确的初始化命令)
|
||||
st77916_vendor_config_t vendor_cfg = {
|
||||
.init_cmds = lcd_init_cmds,
|
||||
.init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]),
|
||||
};
|
||||
const esp_lcd_panel_dev_config_t panel_config = {
|
||||
.reset_gpio_num = PIN_LCD_RST,
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
|
||||
.bits_per_pixel = 16,
|
||||
.vendor_config = &vendor_config,
|
||||
.vendor_config = &vendor_cfg,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st77916(io_handle, &panel_config, &panel_handle));
|
||||
esp_lcd_panel_reset(panel_handle);
|
||||
esp_lcd_panel_init(panel_handle);
|
||||
esp_lcd_panel_mirror(panel_handle, false, false); // 与参考项目一致
|
||||
|
||||
// 清空LCD GRAM,避免显示上次关机时的残留画面
|
||||
// 创建黑色缓冲区填充整个屏幕
|
||||
size_t clear_buffer_size = LCD_WID * 40; // 每次清除40行
|
||||
uint16_t *clear_buffer = heap_caps_malloc(clear_buffer_size * sizeof(uint16_t), MALLOC_CAP_DMA);
|
||||
if (clear_buffer) {
|
||||
memset(clear_buffer, 0, clear_buffer_size * sizeof(uint16_t)); // 填充黑色(0x0000)
|
||||
memset(clear_buffer, 0, clear_buffer_size * sizeof(uint16_t));
|
||||
|
||||
// 分批填充整个屏幕(避免一次性分配大内存)
|
||||
for (int y = 0; y < LCD_HIGH; y += 40) {
|
||||
int lines = (y + 40 > LCD_HIGH) ? (LCD_HIGH - y) : 40;
|
||||
esp_lcd_panel_draw_bitmap(panel_handle, 0, y, LCD_WID, y + lines, clear_buffer);
|
||||
@ -64,7 +267,8 @@ void lcd_init(){
|
||||
ESP_LOGE(LCD_TAG, "Failed to allocate clear buffer");
|
||||
}
|
||||
|
||||
esp_lcd_panel_disp_on_off(panel_handle, true);
|
||||
// 初始化时不打开显示,等UI渲染完成后由main.c调用lcd_disp_on_off(true)
|
||||
esp_lcd_panel_disp_on_off(panel_handle, false);
|
||||
}
|
||||
|
||||
// 初始化触摸控制器
|
||||
@ -75,16 +279,26 @@ void touch_init(){
|
||||
.rst_gpio_num = PIN_TP_RST,
|
||||
.int_gpio_num = PIN_TP_INT,
|
||||
.levels = {
|
||||
.reset = 0,// 重置电平
|
||||
.interrupt = 0,// 中断电平
|
||||
.reset = 0,
|
||||
.interrupt = 0,
|
||||
},
|
||||
.flags = {
|
||||
.swap_xy = false,// 交换XY轴
|
||||
.mirror_x = false,// 水平镜像
|
||||
.mirror_y = false,// 垂直镜像
|
||||
.swap_xy = 0, // managed版CST816S不在驱动内变换,base库会做单次变换
|
||||
.mirror_x = 0, // 参考项目本地驱动+base库双重变换=恒等,实际传原始坐标
|
||||
.mirror_y = 0, // 所以这里全部设0,直接传原始坐标给LVGL
|
||||
},
|
||||
};
|
||||
// 手动配置I2C IO(不使用宏,因为宏的scl_speed_hz与legacy I2C驱动不兼容)
|
||||
const esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_CST816S_ADDRESS,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 8,
|
||||
.lcd_param_bits = 0,
|
||||
.flags = {
|
||||
.disable_control_phase = 1,
|
||||
},
|
||||
};
|
||||
const esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG();
|
||||
esp_err_t err = esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)I2C_MASTER_NUM, &tp_io_config, &tp_io_handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(LCD_TAG, "Failed to create I2C IO for touch: %s", esp_err_to_name(err));
|
||||
@ -108,13 +322,13 @@ void lvgl_lcd_init(){
|
||||
.timer_period_ms = 5
|
||||
};
|
||||
lvgl_port_init(&lvgl_cfg);
|
||||
|
||||
|
||||
#define LVGL_DRAW_BUF_LINES 30
|
||||
size_t buffer_size = LCD_WID * LVGL_DRAW_BUF_LINES;
|
||||
|
||||
ESP_LOGI(LCD_TAG, "LVGL buffer size: %d bytes (W: %d, Lines: %d)",
|
||||
buffer_size * 2, LCD_WID, LVGL_DRAW_BUF_LINES);
|
||||
|
||||
|
||||
const lvgl_port_display_cfg_t disp_cfg = {
|
||||
.io_handle = io_handle,
|
||||
.panel_handle = panel_handle,
|
||||
@ -122,14 +336,14 @@ void lvgl_lcd_init(){
|
||||
.double_buffer = true,
|
||||
.hres = LCD_WID,
|
||||
.vres = LCD_HIGH,
|
||||
.monochrome = false,// 单色显示
|
||||
.monochrome = false,
|
||||
.rotation = {
|
||||
.swap_xy = false,// 交换XY轴
|
||||
.mirror_x = false,// 水平镜像
|
||||
.mirror_y = false,// 垂直镜像
|
||||
.swap_xy = false,
|
||||
.mirror_x = false,
|
||||
.mirror_y = false,
|
||||
},
|
||||
.flags = {
|
||||
.buff_dma = true,// 使用DMA传输显示缓冲区
|
||||
.buff_dma = true,
|
||||
}
|
||||
};
|
||||
disp_handle = lvgl_port_add_disp(&disp_cfg);
|
||||
@ -144,7 +358,7 @@ void lvgl_lcd_init(){
|
||||
ESP_LOGE(LCD_TAG, "Touch handle is NULL, skipping touch initialization");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void get_touch(uint16_t* touchx,uint16_t* touchy){
|
||||
if (touch_handle == NULL) {
|
||||
ESP_LOGE(LCD_TAG, "Touch handle is NULL, cannot get touch data");
|
||||
@ -159,6 +373,13 @@ void get_touch(uint16_t* touchx,uint16_t* touchy){
|
||||
printf("%x\n",max);
|
||||
}
|
||||
|
||||
// LCD显示开关封装(供main.c在UI渲染完成后调用)
|
||||
void lcd_disp_on_off(bool on_off) {
|
||||
if (panel_handle != NULL) {
|
||||
esp_lcd_panel_disp_on_off(panel_handle, on_off);
|
||||
}
|
||||
}
|
||||
|
||||
// 清空LCD GRAM为黑色(用于低功耗熄屏前,避免残影)
|
||||
void lcd_clear_screen_black(void) {
|
||||
if (panel_handle == NULL) {
|
||||
@ -166,12 +387,11 @@ void lcd_clear_screen_black(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t clear_buffer_size = LCD_WID * 40; // 每次清除40行
|
||||
size_t clear_buffer_size = LCD_WID * 40;
|
||||
uint16_t *clear_buffer = heap_caps_malloc(clear_buffer_size * sizeof(uint16_t), MALLOC_CAP_DMA);
|
||||
if (clear_buffer) {
|
||||
memset(clear_buffer, 0, clear_buffer_size * sizeof(uint16_t)); // 填充黑色(0x0000)
|
||||
memset(clear_buffer, 0, clear_buffer_size * sizeof(uint16_t));
|
||||
|
||||
// 分批填充整个屏幕
|
||||
for (int y = 0; y < LCD_HIGH; y += 40) {
|
||||
int lines = (y + 40 > LCD_HIGH) ? (LCD_HIGH - y) : 40;
|
||||
esp_lcd_panel_draw_bitmap(panel_handle, 0, y, LCD_WID, y + lines, clear_buffer);
|
||||
@ -182,4 +402,4 @@ void lcd_clear_screen_black(void) {
|
||||
} else {
|
||||
ESP_LOGE(LCD_TAG, "Failed to allocate clear buffer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
40
main/main.c
40
main/main.c
@ -1,8 +1,9 @@
|
||||
#include "driver/i2c.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_pm.h"
|
||||
// #include "esp_pm.h" // 暂时禁用PM
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_flash.h"
|
||||
@ -118,6 +119,8 @@ esp_err_t i2c_init(void){
|
||||
i2c_config_t i2c_conf = {
|
||||
.scl_io_num = PIN_NUM_SCL,
|
||||
.sda_io_num = PIN_NUM_SDA,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.master.clk_speed = I2C_MASTER_FREQ_HZ,
|
||||
};
|
||||
@ -212,18 +215,14 @@ void app_main(void)
|
||||
nvs_init();
|
||||
ESP_LOGI("MAIN", "2. NVS已初始化");// NVS已初始化
|
||||
|
||||
// 配置 Power Management(低功耗管理)
|
||||
esp_pm_config_t pm_config = {
|
||||
.max_freq_mhz = 160, // 最大频率 160MHz(与当前CPU频率一致)
|
||||
.min_freq_mhz = 40, // 最小频率 40MHz(保证LVGL正常刷新)
|
||||
.light_sleep_enable = true // 启用自动 Light Sleep
|
||||
};
|
||||
esp_err_t pm_err = esp_pm_configure(&pm_config);
|
||||
if (pm_err == ESP_OK) {
|
||||
ESP_LOGI("MAIN", "2.1 Power Management已启用:40-160MHz动态频率 + 自动Light Sleep");
|
||||
} else {
|
||||
ESP_LOGW("MAIN", "2.1 Power Management启用失败:%s", esp_err_to_name(pm_err));
|
||||
}
|
||||
// 暂时禁用 Power Management,避免动态调频 + Light Sleep 干扰 SPI 时序
|
||||
// 等LCD显示和触摸功能稳定后再启用
|
||||
// esp_pm_config_t pm_config = {
|
||||
// .max_freq_mhz = 160,
|
||||
// .min_freq_mhz = 40,
|
||||
// .light_sleep_enable = true
|
||||
// };
|
||||
// esp_pm_configure(&pm_config);
|
||||
|
||||
lcd_init();
|
||||
ESP_LOGI("MAIN", "3. LCD已初始化");// LCD已初始化
|
||||
@ -243,19 +242,24 @@ void app_main(void)
|
||||
ESP_LOGI("MAIN", "7. SPIFFS处理完成");// SPIFFS处理完成
|
||||
|
||||
// =====================================================================
|
||||
// 显示SquareLine Studio生成的UI界面
|
||||
// 显示SquareLine Studio生成的UI界面(加锁防止LVGL任务抢占渲染未完成的UI)
|
||||
lvgl_port_lock(0);
|
||||
ui_init(); // 初始化UI(含JPEG解码)
|
||||
lvgl_port_unlock();
|
||||
ESP_LOGI("MAIN", "8. SquareLine UI已初始化");// SquareLine UI已初始化
|
||||
|
||||
// 等待LVGL完成屏幕切换和首帧渲染,彻底避免开机闪烁
|
||||
// ui_init()会创建所有屏幕并加载ScreenHome,包括:
|
||||
// 1. JPEG解码(约210ms)
|
||||
// 2. 屏幕对象创建和切换
|
||||
// 3. QSPI传输首帧到LCD(约100ms)
|
||||
// 增加到150ms确保所有渲染完成后再点亮背光
|
||||
vTaskDelay(pdMS_TO_TICKS(150));
|
||||
// 3. SPI传输首帧到LCD(约200ms)
|
||||
// 增加到250ms确保所有渲染完成后再点亮背光(SPI比QSPI慢)
|
||||
vTaskDelay(pdMS_TO_TICKS(250));
|
||||
|
||||
// UI渲染完成后先打开LCD显示,再点亮背光,避免开机闪烁
|
||||
lcd_disp_on_off(true);
|
||||
ESP_LOGI("MAIN", "8.1 LCD显示已打开");
|
||||
|
||||
// UI渲染完成后再点亮背光,避免开机闪烁旧画面
|
||||
pwm_init();
|
||||
ESP_LOGI("MAIN", "9. PWM背光已初始化");// PWM背光已初始化
|
||||
|
||||
|
||||
@ -69,7 +69,7 @@ void pwm_init(){
|
||||
.channel = LEDC_CHANNEL_0,
|
||||
.timer_sel = LEDC_TIMER_0,
|
||||
.intr_type = LEDC_INTR_DISABLE,
|
||||
.gpio_num = PIN_LCD_EN,
|
||||
.gpio_num = PIN_LCD_BL,
|
||||
.duty = 0,
|
||||
.hpoint = 0
|
||||
};
|
||||
@ -269,9 +269,10 @@ void app_img_change(const char *img_name){
|
||||
// 更新图片显示
|
||||
lvgl_port_lock(0);// 锁定LVGL端口
|
||||
lv_img_set_src(app_img, &image);// 设置图片源
|
||||
lv_img_set_zoom(app_img, 512);// 2x缩放补偿(JPEG解码使用1:2缩放节省内存)
|
||||
lv_scr_load(act_mainscreen);// 加载主屏幕
|
||||
lvgl_port_unlock();// 解锁LVGL端口
|
||||
|
||||
|
||||
ESP_LOGI("IMG", "图片显示成功: %s", current_img_name);
|
||||
} else {
|
||||
ESP_LOGE("IMG", "图片解码失败,错误码: %d", ret);
|
||||
@ -336,6 +337,7 @@ void app_img_display(){
|
||||
lvgl_port_lock(0);// 锁定LVGL端口
|
||||
ESP_LOGI("IMG", "设置图片源前");
|
||||
lv_img_set_src(app_img, &image);// 设置图片源
|
||||
lv_img_set_zoom(app_img, 512);// 2x缩放补偿(JPEG解码使用1:2缩放节省内存)
|
||||
ESP_LOGI("IMG", "设置图片源后");
|
||||
lv_obj_center(app_img);// 居中显示图片
|
||||
ESP_LOGI("IMG", "居中显示图片后");
|
||||
@ -792,6 +794,7 @@ void update_ui_ImgBle(const char *img_name) {
|
||||
// 更新ui_ImgBle控件的图片
|
||||
lvgl_port_lock(0);
|
||||
lv_img_set_src(ui_ImgBle, &ui_image);
|
||||
lv_img_set_zoom(ui_ImgBle, 512);// 2x缩放补偿(JPEG解码使用1:2缩放节省内存)
|
||||
lvgl_port_unlock();
|
||||
|
||||
ESP_LOGI("IMG_UI", "ui_ImgBle图片更新成功: %s", img_name);
|
||||
|
||||
@ -1 +1 @@
|
||||
5fa0f8b1274576d4484e2b8d9358e2a5d09c721511bef0dce6a55b4206b5f0e9
|
||||
c0a565af3ea85a9d9f1e79b0e4d0829378db319bc4dab4939eca44361b3c5a1b
|
||||
@ -1,5 +1,22 @@
|
||||
# ChangeLog
|
||||
|
||||
## v2.0.2 - 2025-12-10
|
||||
|
||||
### Bugfix:
|
||||
|
||||
* Fix draw_bitmap not propagating tx_color errors, preventing system deadlock on SPI transmission failures
|
||||
|
||||
## v2.0.1 - 2025-11-12
|
||||
|
||||
* Updated MIPI-DSI structs for IDF6
|
||||
|
||||
## v2.0.0 - 2025-10-29
|
||||
|
||||
### Changes:
|
||||
|
||||
* Compatible with ESP-IDF v6.0
|
||||
* Add MIPI-DSI interface support
|
||||
|
||||
## v1.0.1 - 2025-01-13
|
||||
|
||||
### bugfix:
|
||||
|
||||
@ -0,0 +1 @@
|
||||
{"version":"1.0","algorithm":"sha256","created_at":"2025-11-30T02:16:23.671476+00:00","files":[{"path":"CHANGELOG.md","size":721,"hash":"3b1d8021ed3376be4b10a3a95d57633f085984ad8bd279e784830854408f232d"},{"path":"CMakeLists.txt","size":326,"hash":"df72a05add6a3b6b21f024247919d9bab829bed7b054ccf9038bb0df15f89509"},{"path":"README.md","size":8261,"hash":"ef35bd8f2fa9032b74a0efb78ca343de781e7e9dee263a530e470c86f4c1a50e"},{"path":"esp_lcd_st77916.c","size":1219,"hash":"c028dddc8857b7326133eb9d445c7f3835ef38027bec337d2cab873139533921"},{"path":"esp_lcd_st77916_mipi.c","size":18829,"hash":"b4304ec554e2370e100ac5f897a140bb249d1de0695c0b7fd67f50338b83c709"},{"path":"esp_lcd_st77916_spi.c","size":21541,"hash":"a464c88fcfd485bd418e42cfdd099cede661936ffe81ddcb0f46b3d466cc7f67"},{"path":"idf_component.yml","size":450,"hash":"5985cf795ffa8de4bf7b2df0093c8d35c64f55dd8537716138cd5f9f5b905d7f"},{"path":"license.txt","size":11358,"hash":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30"},{"path":"include/esp_lcd_st77916.h","size":9626,"hash":"4fb9d26532b574a14465dfe3853ea2a1bcab0fac6e28b42ed7f2e5ddd8ef2f87"},{"path":"priv_include/esp_lcd_st77916_interface.h","size":1278,"hash":"f00d59d717ad79bf78575b4685e9f426321c3a0ab9700e2ef23577e808b39251"},{"path":"test_apps/CMakeLists.txt","size":244,"hash":"964560e9e95e960d7a12c0eebb43b78d997f294fa17aa85d24a0a53dc604ed6e"},{"path":"test_apps/pytest_esp_lcd_st77916.py","size":300,"hash":"6513b1e4ab20df1aca721edef3485c23da4c0bc34920537ede6c1203ddd4f16a"},{"path":"test_apps/sdkconfig.defaults","size":257,"hash":"b3f9660085595b907f7411e205468220c2dfb867de4de5d7fb3cbb406651dcab"},{"path":"test_apps/sdkconfig.defaults.esp32p4","size":268,"hash":"1e6eb9fd686be544d3b2088a76cfe0d03127a945c8852bb9fd364e40d92ca7e3"},{"path":"test_apps/sdkconfig.defaults.esp32s3","size":232,"hash":"81eb3953a48b1bc8076d32b3b8ddb6957794f1af03e82faedfa0d919abe4407e"},{"path":"test_apps/main/CMakeLists.txt","size":114,"hash":"ef8db1c6618f6af135742f9dfe28bc3391b0f3ae280714c8110c0235f9091b20"},{"path":"test_apps/main/idf_component.yml","size":159,"hash":"fb0f2c2300bb6f5f80412b27393d83281fc13ed1a6fa8577e6b9f0f8af0d39f7"},{"path":"test_apps/main/test_app_main.c","size":1525,"hash":"29cfa83157f9e48dcf84def2e1835b35fc5dd9b47d59bc95b1ff39f5eede7a2d"},{"path":"test_apps/main/test_esp_lcd_st77916_mipi.c","size":8580,"hash":"708551cd0d8a7d9f5137c30f07908a1b743787923b958fd0f570b8dd9a2444bc"},{"path":"test_apps/main/test_esp_lcd_st77916_spi.c","size":5866,"hash":"9b3b7f597daf342fd8b574d5d85582d48e276c190d32a759291ce9ce4e83f588"}]}
|
||||
@ -1,4 +1,7 @@
|
||||
idf_component_register(SRCS "esp_lcd_st77916.c" INCLUDE_DIRS "include" PRIV_REQUIRES "driver" REQUIRES "esp_lcd")
|
||||
idf_component_register(SRCS "esp_lcd_st77916.c" "esp_lcd_st77916_spi.c" "esp_lcd_st77916_mipi.c"
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_INCLUDE_DIRS "priv_include"
|
||||
REQUIRES "esp_lcd" "driver")
|
||||
|
||||
include(package_manager)
|
||||
cu_pkg_define_version(${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
@ -6,7 +6,9 @@ Implementation of the ST77916 LCD controller with [esp_lcd](https://docs.espress
|
||||
|
||||
| LCD controller | Communication interface | Component name | Link to datasheet |
|
||||
| :------------: | :---------------------: | :------------: | :---------------------------------------------------------------------------: |
|
||||
| ST77916 | SPI/QSPI | esp_lcd_st77916 | [PDF](https://dl.espressif.com/AE/esp-iot-solution/ST77916_SPEC_V1.0.pdf) |
|
||||
| ST77916 | SPI/QSPI/MIPI-DSI | esp_lcd_st77916 | [PDF](https://dl.espressif.com/AE/esp-iot-solution/ST77916_SPEC_V1.0.pdf) |
|
||||
|
||||
**Note**: The MIPI-DSI interface is only supported on ESP32-P4.
|
||||
|
||||
For more information on LCD, please refer to the [LCD documentation](https://docs.espressif.com/projects/esp-iot-solution/en/latest/display/lcd/index.html).
|
||||
|
||||
@ -120,3 +122,53 @@ Alternatively, you can create `idf_component.yml`. More is in [Espressif's docum
|
||||
esp_lcd_panel_init(panel_handle);
|
||||
esp_lcd_panel_disp_on_off(panel_handle, true);
|
||||
```
|
||||
|
||||
### MIPI-DSI Interface
|
||||
|
||||
```c
|
||||
ESP_LOGI(TAG, "Initialize MIPI DSI bus");
|
||||
esp_lcd_dsi_bus_handle_t mipi_dsi_bus = NULL;
|
||||
esp_lcd_dsi_bus_config_t bus_config = ST77916_PANEL_BUS_DSI_1CH_CONFIG();
|
||||
ESP_ERROR_CHECK(esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus));
|
||||
|
||||
ESP_LOGI(TAG, "Install MIPI DBI panel IO");
|
||||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
esp_lcd_dbi_io_config_t dbi_config = ST77916_PANEL_IO_DBI_CONFIG();
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &io_handle));
|
||||
|
||||
/**
|
||||
* Uncomment these line if use custom initialization commands.
|
||||
* The array should be declared as static const and positioned outside the function.
|
||||
*/
|
||||
// static const st77916_lcd_init_cmd_t lcd_init_cmds[] = {
|
||||
// // {cmd, { data }, data_size, delay_ms}
|
||||
// {0xF0, (uint8_t []){0x00, 0x28}, 2, 0},
|
||||
// {0xF2, (uint8_t []){0x00, 0x28}, 2, 0},
|
||||
// ...
|
||||
// };
|
||||
|
||||
ESP_LOGI(TAG, "Install ST77916 panel driver");
|
||||
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
esp_lcd_dpi_panel_config_t dpi_config = ST77916_360_360_PANEL_60HZ_DPI_CONFIG(LCD_COLOR_PIXEL_FORMAT_RGB565);
|
||||
st77916_vendor_config_t vendor_config = {
|
||||
// .init_cmds = lcd_init_cmds, // Uncomment these line if use custom initialization commands
|
||||
// .init_cmds_size = sizeof(lcd_init_cmds) / sizeof(st77916_lcd_init_cmd_t),
|
||||
.flags = {
|
||||
.use_mipi_interface = 1,
|
||||
},
|
||||
.mipi_config = {
|
||||
.dsi_bus = mipi_dsi_bus,
|
||||
.dpi_config = &dpi_config,
|
||||
},
|
||||
};
|
||||
const esp_lcd_panel_dev_config_t panel_config = {
|
||||
.reset_gpio_num = EXAMPLE_PIN_NUM_LCD_RST, // Set to -1 if not use
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
|
||||
.bits_per_pixel = EXAMPLE_LCD_BIT_PER_PIXEL, // 16 or 24
|
||||
.vendor_config = &vendor_config,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st77916(io_handle, &panel_config, &panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
|
||||
```
|
||||
|
||||
@ -1,551 +1,36 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_lcd_panel_interface.h"
|
||||
#include "esp_lcd_panel_io.h"
|
||||
#include "esp_lcd_panel_vendor.h"
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include "esp_lcd_panel_commands.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_lcd_types.h"
|
||||
|
||||
#include "esp_lcd_st77916_interface.h"
|
||||
#include "esp_lcd_st77916.h"
|
||||
|
||||
#define LCD_OPCODE_WRITE_CMD (0x02ULL)
|
||||
#define LCD_OPCODE_READ_CMD (0x0BULL)
|
||||
#define LCD_OPCODE_WRITE_COLOR (0x32ULL)
|
||||
|
||||
#define ST77916_CMD_SET (0xF0)
|
||||
#define ST77916_PARAM_SET (0x00)
|
||||
|
||||
static const char *TAG = "st77916";
|
||||
|
||||
static esp_err_t panel_st77916_del(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_st77916_reset(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_st77916_init(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_st77916_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int y_start, int x_end, int y_end, const void *color_data);
|
||||
static esp_err_t panel_st77916_invert_color(esp_lcd_panel_t *panel, bool invert_color_data);
|
||||
static esp_err_t panel_st77916_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y);
|
||||
static esp_err_t panel_st77916_swap_xy(esp_lcd_panel_t *panel, bool swap_axes);
|
||||
static esp_err_t panel_st77916_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap);
|
||||
static esp_err_t panel_st77916_disp_on_off(esp_lcd_panel_t *panel, bool off);
|
||||
|
||||
typedef struct {
|
||||
esp_lcd_panel_t base;
|
||||
esp_lcd_panel_io_handle_t io;
|
||||
int reset_gpio_num;
|
||||
int x_gap;
|
||||
int y_gap;
|
||||
uint8_t fb_bits_per_pixel;
|
||||
uint8_t madctl_val; // save current value of LCD_CMD_MADCTL register
|
||||
uint8_t colmod_val; // save surrent value of LCD_CMD_COLMOD register
|
||||
const st77916_lcd_init_cmd_t *init_cmds;
|
||||
uint16_t init_cmds_size;
|
||||
struct {
|
||||
unsigned int use_qspi_interface: 1;
|
||||
unsigned int reset_level: 1;
|
||||
} flags;
|
||||
} st77916_panel_t;
|
||||
|
||||
esp_err_t esp_lcd_new_panel_st77916(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel)
|
||||
esp_err_t esp_lcd_new_panel_st77916(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config,
|
||||
esp_lcd_panel_handle_t *ret_panel)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(io && panel_dev_config && ret_panel, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_LOGI(TAG, "version: %d.%d.%d", ESP_LCD_ST77916_VER_MAJOR, ESP_LCD_ST77916_VER_MINOR, ESP_LCD_ST77916_VER_PATCH);
|
||||
ESP_RETURN_ON_FALSE(panel_dev_config && ret_panel, ESP_ERR_INVALID_ARG, TAG, "Invalid arguments");
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
st77916_panel_t *st77916 = NULL;
|
||||
st77916 = calloc(1, sizeof(st77916_panel_t));
|
||||
ESP_GOTO_ON_FALSE(st77916, ESP_ERR_NO_MEM, err, TAG, "no mem for st77916 panel");
|
||||
esp_err_t ret = ESP_ERR_NOT_SUPPORTED;
|
||||
|
||||
if (panel_dev_config->reset_gpio_num >= 0) {
|
||||
gpio_config_t io_conf = {
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pin_bit_mask = 1ULL << panel_dev_config->reset_gpio_num,
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(gpio_config(&io_conf), err, TAG, "configure GPIO for RST line failed");
|
||||
}
|
||||
|
||||
switch (panel_dev_config->rgb_ele_order) {
|
||||
case LCD_RGB_ELEMENT_ORDER_RGB:
|
||||
st77916->madctl_val = 0;
|
||||
break;
|
||||
case LCD_RGB_ELEMENT_ORDER_BGR:
|
||||
st77916->madctl_val |= LCD_CMD_BGR_BIT;
|
||||
break;
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported color element order");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (panel_dev_config->bits_per_pixel) {
|
||||
case 16: // RGB565
|
||||
st77916->colmod_val = 0x55;
|
||||
st77916->fb_bits_per_pixel = 16;
|
||||
break;
|
||||
case 18: // RGB666
|
||||
st77916->colmod_val = 0x66;
|
||||
// each color component (R/G/B) should occupy the 6 high bits of a byte, which means 3 full bytes are required for a pixel
|
||||
st77916->fb_bits_per_pixel = 24;
|
||||
break;
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported pixel width");
|
||||
break;
|
||||
}
|
||||
|
||||
st77916->io = io;
|
||||
st77916->reset_gpio_num = panel_dev_config->reset_gpio_num;
|
||||
st77916->flags.reset_level = panel_dev_config->flags.reset_active_high;
|
||||
#if SOC_MIPI_DSI_SUPPORTED
|
||||
st77916_vendor_config_t *vendor_config = (st77916_vendor_config_t *)panel_dev_config->vendor_config;
|
||||
if (vendor_config) {
|
||||
st77916->init_cmds = vendor_config->init_cmds;
|
||||
st77916->init_cmds_size = vendor_config->init_cmds_size;
|
||||
st77916->flags.use_qspi_interface = vendor_config->flags.use_qspi_interface;
|
||||
if (vendor_config && vendor_config->flags.use_mipi_interface) {
|
||||
ret = esp_lcd_new_panel_st77916_mipi(io, panel_dev_config, ret_panel);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
// Default to SPI/QSPI interface
|
||||
ret = esp_lcd_new_panel_st77916_spi(io, panel_dev_config, ret_panel);
|
||||
}
|
||||
st77916->base.del = panel_st77916_del;
|
||||
st77916->base.reset = panel_st77916_reset;
|
||||
st77916->base.init = panel_st77916_init;
|
||||
st77916->base.draw_bitmap = panel_st77916_draw_bitmap;
|
||||
st77916->base.invert_color = panel_st77916_invert_color;
|
||||
st77916->base.set_gap = panel_st77916_set_gap;
|
||||
st77916->base.mirror = panel_st77916_mirror;
|
||||
st77916->base.swap_xy = panel_st77916_swap_xy;
|
||||
st77916->base.disp_on_off = panel_st77916_disp_on_off;
|
||||
*ret_panel = &(st77916->base);
|
||||
ESP_LOGD(TAG, "new st77916 panel @%p", st77916);
|
||||
|
||||
ESP_LOGI(TAG, "LCD panel create success, version: %d.%d.%d", ESP_LCD_ST77916_VER_MAJOR, ESP_LCD_ST77916_VER_MINOR,
|
||||
ESP_LCD_ST77916_VER_PATCH);
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (st77916) {
|
||||
if (panel_dev_config->reset_gpio_num >= 0) {
|
||||
gpio_reset_pin(panel_dev_config->reset_gpio_num);
|
||||
}
|
||||
free(st77916);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t tx_param(st77916_panel_t *st77916, esp_lcd_panel_io_handle_t io, int lcd_cmd, const void *param, size_t param_size)
|
||||
{
|
||||
if (st77916->flags.use_qspi_interface) {
|
||||
lcd_cmd &= 0xff;
|
||||
lcd_cmd <<= 8;
|
||||
lcd_cmd |= LCD_OPCODE_WRITE_CMD << 24;
|
||||
}
|
||||
return esp_lcd_panel_io_tx_param(io, lcd_cmd, param, param_size);
|
||||
}
|
||||
|
||||
static esp_err_t tx_color(st77916_panel_t *st77916, esp_lcd_panel_io_handle_t io, int lcd_cmd, const void *param, size_t param_size)
|
||||
{
|
||||
if (st77916->flags.use_qspi_interface) {
|
||||
lcd_cmd &= 0xff;
|
||||
lcd_cmd <<= 8;
|
||||
lcd_cmd |= LCD_OPCODE_WRITE_COLOR << 24;
|
||||
}
|
||||
return esp_lcd_panel_io_tx_color(io, lcd_cmd, param, param_size);
|
||||
}
|
||||
|
||||
static esp_err_t panel_st77916_del(esp_lcd_panel_t *panel)
|
||||
{
|
||||
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||
|
||||
if (st77916->reset_gpio_num >= 0) {
|
||||
gpio_reset_pin(st77916->reset_gpio_num);
|
||||
}
|
||||
ESP_LOGD(TAG, "del st77916 panel @%p", st77916);
|
||||
free(st77916);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_st77916_reset(esp_lcd_panel_t *panel)
|
||||
{
|
||||
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = st77916->io;
|
||||
|
||||
// Perform hardware reset
|
||||
if (st77916->reset_gpio_num >= 0) {
|
||||
gpio_set_level(st77916->reset_gpio_num, st77916->flags.reset_level);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
gpio_set_level(st77916->reset_gpio_num, !st77916->flags.reset_level);
|
||||
vTaskDelay(pdMS_TO_TICKS(120));
|
||||
} else { // Perform software reset
|
||||
ESP_RETURN_ON_ERROR(tx_param(st77916, io, LCD_CMD_SWRESET, NULL, 0), TAG, "send command failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(120));
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static const st77916_lcd_init_cmd_t vendor_specific_init_default[] = {
|
||||
{0xF0, (uint8_t[]){0x28}, 1, 0},
|
||||
{0xF2, (uint8_t[]){0x28}, 1, 0},
|
||||
{0x73, (uint8_t[]){0xF0}, 1, 0},
|
||||
{0x7C, (uint8_t[]){0xD1}, 1, 0},
|
||||
{0x83, (uint8_t[]){0xE0}, 1, 0},
|
||||
{0x84, (uint8_t[]){0x61}, 1, 0},
|
||||
{0xF2, (uint8_t[]){0x82}, 1, 0},
|
||||
{0xF0, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xF0, (uint8_t[]){0x01}, 1, 0},
|
||||
{0xF1, (uint8_t[]){0x01}, 1, 0},
|
||||
{0xB0, (uint8_t[]){0x5E}, 1, 0},
|
||||
{0xB1, (uint8_t[]){0x55}, 1, 0},
|
||||
{0xB2, (uint8_t[]){0x24}, 1, 0},
|
||||
{0xB3, (uint8_t[]){0x01}, 1, 0},
|
||||
{0xB4, (uint8_t[]){0x87}, 1, 0},
|
||||
{0xB5, (uint8_t[]){0x44}, 1, 0},
|
||||
{0xB6, (uint8_t[]){0x8B}, 1, 0},
|
||||
{0xB7, (uint8_t[]){0x40}, 1, 0},
|
||||
{0xB8, (uint8_t[]){0x86}, 1, 0},
|
||||
{0xB9, (uint8_t[]){0x15}, 1, 0},
|
||||
{0xBA, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xBB, (uint8_t[]){0x08}, 1, 0},
|
||||
{0xBC, (uint8_t[]){0x08}, 1, 0},
|
||||
{0xBD, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xBE, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xBF, (uint8_t[]){0x07}, 1, 0},
|
||||
{0xC0, (uint8_t[]){0x80}, 1, 0},
|
||||
{0xC1, (uint8_t[]){0x10}, 1, 0},
|
||||
{0xC2, (uint8_t[]){0x37}, 1, 0},
|
||||
{0xC3, (uint8_t[]){0x80}, 1, 0},
|
||||
{0xC4, (uint8_t[]){0x10}, 1, 0},
|
||||
{0xC5, (uint8_t[]){0x37}, 1, 0},
|
||||
{0xC6, (uint8_t[]){0xA9}, 1, 0},
|
||||
{0xC7, (uint8_t[]){0x41}, 1, 0},
|
||||
{0xC8, (uint8_t[]){0x01}, 1, 0},
|
||||
{0xC9, (uint8_t[]){0xA9}, 1, 0},
|
||||
{0xCA, (uint8_t[]){0x41}, 1, 0},
|
||||
{0xCB, (uint8_t[]){0x01}, 1, 0},
|
||||
{0xCC, (uint8_t[]){0x7F}, 1, 0},
|
||||
{0xCD, (uint8_t[]){0x7F}, 1, 0},
|
||||
{0xCE, (uint8_t[]){0xFF}, 1, 0},
|
||||
{0xD0, (uint8_t[]){0x91}, 1, 0},
|
||||
{0xD1, (uint8_t[]){0x68}, 1, 0},
|
||||
{0xD2, (uint8_t[]){0x68}, 1, 0},
|
||||
{0xF5, (uint8_t[]){0x00, 0xA5}, 2, 0},
|
||||
{0xDD, (uint8_t[]){0x40}, 1, 0},
|
||||
{0xDE, (uint8_t[]){0x40}, 1, 0},
|
||||
{0xF1, (uint8_t[]){0x10}, 1, 0},
|
||||
{0xF0, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xF0, (uint8_t[]){0x02}, 1, 0},
|
||||
{0xE0, (uint8_t[]){0xF0, 0x10, 0x18, 0x0D, 0x0C, 0x38, 0x3E, 0x44, 0x51, 0x39, 0x15, 0x15, 0x30, 0x34}, 14, 0},
|
||||
{0xE1, (uint8_t[]){0xF0, 0x0F, 0x17, 0x0D, 0x0B, 0x07, 0x3E, 0x33, 0x51, 0x39, 0x15, 0x15, 0x30, 0x34}, 14, 0},
|
||||
{0xF0, (uint8_t[]){0x10}, 1, 0},
|
||||
{0xF3, (uint8_t[]){0x10}, 1, 0},
|
||||
{0xE0, (uint8_t[]){0x08}, 1, 0},
|
||||
{0xE1, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xE2, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xE3, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xE4, (uint8_t[]){0xE0}, 1, 0},
|
||||
{0xE5, (uint8_t[]){0x06}, 1, 0},
|
||||
{0xE6, (uint8_t[]){0x21}, 1, 0},
|
||||
{0xE7, (uint8_t[]){0x03}, 1, 0},
|
||||
{0xE8, (uint8_t[]){0x05}, 1, 0},
|
||||
{0xE9, (uint8_t[]){0x02}, 1, 0},
|
||||
{0xEA, (uint8_t[]){0xE9}, 1, 0},
|
||||
{0xEB, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xEC, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xED, (uint8_t[]){0x14}, 1, 0},
|
||||
{0xEE, (uint8_t[]){0xFF}, 1, 0},
|
||||
{0xEF, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xF8, (uint8_t[]){0xFF}, 1, 0},
|
||||
{0xF9, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xFA, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xFB, (uint8_t[]){0x30}, 1, 0},
|
||||
{0xFC, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xFD, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xFE, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xFF, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x60, (uint8_t[]){0x40}, 1, 0},
|
||||
{0x61, (uint8_t[]){0x05}, 1, 0},
|
||||
{0x62, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x63, (uint8_t[]){0x42}, 1, 0},
|
||||
{0x64, (uint8_t[]){0xDA}, 1, 0},
|
||||
{0x65, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x66, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x67, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x68, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x69, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x6A, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x6B, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x70, (uint8_t[]){0x40}, 1, 0},
|
||||
{0x71, (uint8_t[]){0x04}, 1, 0},
|
||||
{0x72, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x73, (uint8_t[]){0x42}, 1, 0},
|
||||
{0x74, (uint8_t[]){0xD9}, 1, 0},
|
||||
{0x75, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x76, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x77, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x78, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x79, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x7A, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x7B, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x80, (uint8_t[]){0x48}, 1, 0},
|
||||
{0x81, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x82, (uint8_t[]){0x07}, 1, 0},
|
||||
{0x83, (uint8_t[]){0x02}, 1, 0},
|
||||
{0x84, (uint8_t[]){0xD7}, 1, 0},
|
||||
{0x85, (uint8_t[]){0x04}, 1, 0},
|
||||
{0x86, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x87, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x88, (uint8_t[]){0x48}, 1, 0},
|
||||
{0x89, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x8A, (uint8_t[]){0x09}, 1, 0},
|
||||
{0x8B, (uint8_t[]){0x02}, 1, 0},
|
||||
{0x8C, (uint8_t[]){0xD9}, 1, 0},
|
||||
{0x8D, (uint8_t[]){0x04}, 1, 0},
|
||||
{0x8E, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x8F, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x90, (uint8_t[]){0x48}, 1, 0},
|
||||
{0x91, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x92, (uint8_t[]){0x0B}, 1, 0},
|
||||
{0x93, (uint8_t[]){0x02}, 1, 0},
|
||||
{0x94, (uint8_t[]){0xDB}, 1, 0},
|
||||
{0x95, (uint8_t[]){0x04}, 1, 0},
|
||||
{0x96, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x97, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x98, (uint8_t[]){0x48}, 1, 0},
|
||||
{0x99, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x9A, (uint8_t[]){0x0D}, 1, 0},
|
||||
{0x9B, (uint8_t[]){0x02}, 1, 0},
|
||||
{0x9C, (uint8_t[]){0xDD}, 1, 0},
|
||||
{0x9D, (uint8_t[]){0x04}, 1, 0},
|
||||
{0x9E, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x9F, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xA0, (uint8_t[]){0x48}, 1, 0},
|
||||
{0xA1, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xA2, (uint8_t[]){0x06}, 1, 0},
|
||||
{0xA3, (uint8_t[]){0x02}, 1, 0},
|
||||
{0xA4, (uint8_t[]){0xD6}, 1, 0},
|
||||
{0xA5, (uint8_t[]){0x04}, 1, 0},
|
||||
{0xA6, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xA7, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xA8, (uint8_t[]){0x48}, 1, 0},
|
||||
{0xA9, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xAA, (uint8_t[]){0x08}, 1, 0},
|
||||
{0xAB, (uint8_t[]){0x02}, 1, 0},
|
||||
{0xAC, (uint8_t[]){0xD8}, 1, 0},
|
||||
{0xAD, (uint8_t[]){0x04}, 1, 0},
|
||||
{0xAE, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xAF, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xB0, (uint8_t[]){0x48}, 1, 0},
|
||||
{0xB1, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xB2, (uint8_t[]){0x0A}, 1, 0},
|
||||
{0xB3, (uint8_t[]){0x02}, 1, 0},
|
||||
{0xB4, (uint8_t[]){0xDA}, 1, 0},
|
||||
{0xB5, (uint8_t[]){0x04}, 1, 0},
|
||||
{0xB6, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xB7, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xB8, (uint8_t[]){0x48}, 1, 0},
|
||||
{0xB9, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xBA, (uint8_t[]){0x0C}, 1, 0},
|
||||
{0xBB, (uint8_t[]){0x02}, 1, 0},
|
||||
{0xBC, (uint8_t[]){0xDC}, 1, 0},
|
||||
{0xBD, (uint8_t[]){0x04}, 1, 0},
|
||||
{0xBE, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xBF, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xC0, (uint8_t[]){0x10}, 1, 0},
|
||||
{0xC1, (uint8_t[]){0x47}, 1, 0},
|
||||
{0xC2, (uint8_t[]){0x56}, 1, 0},
|
||||
{0xC3, (uint8_t[]){0x65}, 1, 0},
|
||||
{0xC4, (uint8_t[]){0x74}, 1, 0},
|
||||
{0xC5, (uint8_t[]){0x88}, 1, 0},
|
||||
{0xC6, (uint8_t[]){0x99}, 1, 0},
|
||||
{0xC7, (uint8_t[]){0x01}, 1, 0},
|
||||
{0xC8, (uint8_t[]){0xBB}, 1, 0},
|
||||
{0xC9, (uint8_t[]){0xAA}, 1, 0},
|
||||
{0xD0, (uint8_t[]){0x10}, 1, 0},
|
||||
{0xD1, (uint8_t[]){0x47}, 1, 0},
|
||||
{0xD2, (uint8_t[]){0x56}, 1, 0},
|
||||
{0xD3, (uint8_t[]){0x65}, 1, 0},
|
||||
{0xD4, (uint8_t[]){0x74}, 1, 0},
|
||||
{0xD5, (uint8_t[]){0x88}, 1, 0},
|
||||
{0xD6, (uint8_t[]){0x99}, 1, 0},
|
||||
{0xD7, (uint8_t[]){0x01}, 1, 0},
|
||||
{0xD8, (uint8_t[]){0xBB}, 1, 0},
|
||||
{0xD9, (uint8_t[]){0xAA}, 1, 0},
|
||||
{0xF3, (uint8_t[]){0x01}, 1, 0},
|
||||
{0xF0, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x3A, (uint8_t[]){0x55}, 1, 0},
|
||||
{0x21, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x11, (uint8_t[]){0x00}, 1, 120},
|
||||
{0x29, (uint8_t[]){0x00}, 1, 0}
|
||||
};
|
||||
|
||||
static esp_err_t panel_st77916_init(esp_lcd_panel_t *panel)
|
||||
{
|
||||
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = st77916->io;
|
||||
const st77916_lcd_init_cmd_t *init_cmds = NULL;
|
||||
uint16_t init_cmds_size = 0;
|
||||
bool is_user_set = true;
|
||||
bool is_cmd_overwritten = false;
|
||||
|
||||
ESP_RETURN_ON_ERROR(tx_param(st77916, io, LCD_CMD_MADCTL, (uint8_t[]) {
|
||||
st77916->madctl_val,
|
||||
}, 1), TAG, "send command failed");
|
||||
ESP_RETURN_ON_ERROR(tx_param(st77916, io, LCD_CMD_COLMOD, (uint8_t[]) {
|
||||
st77916->colmod_val,
|
||||
}, 1), TAG, "send command failed");
|
||||
|
||||
// vendor specific initialization, it can be different between manufacturers
|
||||
// should consult the LCD supplier for initialization sequence code
|
||||
if (st77916->init_cmds) {
|
||||
init_cmds = st77916->init_cmds;
|
||||
init_cmds_size = st77916->init_cmds_size;
|
||||
} else {
|
||||
init_cmds = vendor_specific_init_default;
|
||||
init_cmds_size = sizeof(vendor_specific_init_default) / sizeof(st77916_lcd_init_cmd_t);
|
||||
}
|
||||
|
||||
for (int i = 0; i < init_cmds_size; i++) {
|
||||
// Check if the command has been used or conflicts with the internal
|
||||
if (is_user_set && (init_cmds[i].data_bytes > 0)) {
|
||||
switch (init_cmds[i].cmd) {
|
||||
case LCD_CMD_MADCTL:
|
||||
is_cmd_overwritten = true;
|
||||
st77916->madctl_val = ((uint8_t *)init_cmds[i].data)[0];
|
||||
break;
|
||||
case LCD_CMD_COLMOD:
|
||||
is_cmd_overwritten = true;
|
||||
st77916->colmod_val = ((uint8_t *)init_cmds[i].data)[0];
|
||||
break;
|
||||
default:
|
||||
is_cmd_overwritten = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_cmd_overwritten) {
|
||||
is_cmd_overwritten = false;
|
||||
ESP_LOGW(TAG, "The %02Xh command has been used and will be overwritten by external initialization sequence", init_cmds[i].cmd);
|
||||
}
|
||||
}
|
||||
|
||||
// Send command
|
||||
ESP_RETURN_ON_ERROR(tx_param(st77916, io, init_cmds[i].cmd, init_cmds[i].data, init_cmds[i].data_bytes), TAG, "send command failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(init_cmds[i].delay_ms));
|
||||
|
||||
// Check if the current cmd is the "command set" cmd
|
||||
if ((init_cmds[i].cmd == ST77916_CMD_SET)) {
|
||||
is_user_set = ((uint8_t *)init_cmds[i].data)[0] == ST77916_PARAM_SET ? true : false;
|
||||
}
|
||||
}
|
||||
ESP_LOGD(TAG, "send init commands success");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_st77916_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int y_start, int x_end, int y_end, const void *color_data)
|
||||
{
|
||||
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||
assert((x_start < x_end) && (y_start < y_end) && "start position must be smaller than end position");
|
||||
esp_lcd_panel_io_handle_t io = st77916->io;
|
||||
|
||||
x_start += st77916->x_gap;
|
||||
x_end += st77916->x_gap;
|
||||
y_start += st77916->y_gap;
|
||||
y_end += st77916->y_gap;
|
||||
|
||||
// define an area of frame memory where MCU can access
|
||||
ESP_RETURN_ON_ERROR(tx_param(st77916, io, LCD_CMD_CASET, (uint8_t[]) {
|
||||
(x_start >> 8) & 0xFF,
|
||||
x_start & 0xFF,
|
||||
((x_end - 1) >> 8) & 0xFF,
|
||||
(x_end - 1) & 0xFF,
|
||||
}, 4), TAG, "send command failed");
|
||||
ESP_RETURN_ON_ERROR(tx_param(st77916, io, LCD_CMD_RASET, (uint8_t[]) {
|
||||
(y_start >> 8) & 0xFF,
|
||||
y_start & 0xFF,
|
||||
((y_end - 1) >> 8) & 0xFF,
|
||||
(y_end - 1) & 0xFF,
|
||||
}, 4), TAG, "send command failed");
|
||||
// transfer frame buffer
|
||||
size_t len = (x_end - x_start) * (y_end - y_start) * st77916->fb_bits_per_pixel / 8;
|
||||
tx_color(st77916, io, LCD_CMD_RAMWR, color_data, len);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_st77916_invert_color(esp_lcd_panel_t *panel, bool invert_color_data)
|
||||
{
|
||||
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = st77916->io;
|
||||
int command = 0;
|
||||
if (invert_color_data) {
|
||||
command = LCD_CMD_INVON;
|
||||
} else {
|
||||
command = LCD_CMD_INVOFF;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(tx_param(st77916, io, command, NULL, 0), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_st77916_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y)
|
||||
{
|
||||
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = st77916->io;
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
if (mirror_x) {
|
||||
st77916->madctl_val |= BIT(6);
|
||||
} else {
|
||||
st77916->madctl_val &= ~BIT(6);
|
||||
}
|
||||
if (mirror_y) {
|
||||
st77916->madctl_val |= BIT(7);
|
||||
} else {
|
||||
st77916->madctl_val &= ~BIT(7);
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(tx_param(st77916, io, LCD_CMD_MADCTL, (uint8_t[]) {
|
||||
st77916->madctl_val
|
||||
}, 1), TAG, "send command failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t panel_st77916_swap_xy(esp_lcd_panel_t *panel, bool swap_axes)
|
||||
{
|
||||
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = st77916->io;
|
||||
if (swap_axes) {
|
||||
st77916->madctl_val |= LCD_CMD_MV_BIT;
|
||||
} else {
|
||||
st77916->madctl_val &= ~LCD_CMD_MV_BIT;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(tx_param(st77916, io, LCD_CMD_MADCTL, (uint8_t[]) {
|
||||
st77916->madctl_val
|
||||
}, 1), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_st77916_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap)
|
||||
{
|
||||
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||
st77916->x_gap = x_gap;
|
||||
st77916->y_gap = y_gap;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_st77916_disp_on_off(esp_lcd_panel_t *panel, bool on_off)
|
||||
{
|
||||
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = st77916->io;
|
||||
int command = 0;
|
||||
|
||||
if (on_off) {
|
||||
command = LCD_CMD_DISPON;
|
||||
} else {
|
||||
command = LCD_CMD_DISPOFF;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(tx_param(st77916, io, command, NULL, 0), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -0,0 +1,489 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#if SOC_MIPI_DSI_SUPPORTED
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_lcd_panel_commands.h"
|
||||
#include "esp_lcd_panel_interface.h"
|
||||
#include "esp_lcd_panel_io.h"
|
||||
#include "esp_lcd_mipi_dsi.h"
|
||||
#include "esp_lcd_panel_vendor.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_lcd_st77916.h"
|
||||
#include "esp_lcd_st77916_interface.h"
|
||||
|
||||
typedef struct {
|
||||
esp_lcd_panel_io_handle_t io;
|
||||
int reset_gpio_num;
|
||||
uint8_t madctl_val; // save current value of LCD_CMD_MADCTL register
|
||||
uint8_t colmod_val; // save surrent value of LCD_CMD_COLMOD register
|
||||
const st77916_lcd_init_cmd_t *init_cmds;
|
||||
uint16_t init_cmds_size;
|
||||
struct {
|
||||
unsigned int reset_level: 1;
|
||||
} flags;
|
||||
// To save the original functions of MIPI DPI panel
|
||||
esp_err_t (*del)(esp_lcd_panel_t *panel);
|
||||
esp_err_t (*init)(esp_lcd_panel_t *panel);
|
||||
} st77916_mipi_panel_t;
|
||||
|
||||
static const char *TAG = "st77916_mipi";
|
||||
|
||||
static esp_err_t panel_st77916_mipi_del(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_st77916_mipi_init(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_st77916_mipi_reset(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_st77916_mipi_invert_color(esp_lcd_panel_t *panel, bool invert_color_data);
|
||||
static esp_err_t panel_st77916_mipi_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y);
|
||||
static esp_err_t panel_st77916_mipi_disp_on_off(esp_lcd_panel_t *panel, bool on_off);
|
||||
|
||||
esp_err_t esp_lcd_new_panel_st77916_mipi(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config,
|
||||
esp_lcd_panel_handle_t *ret_panel)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(io && panel_dev_config && ret_panel, ESP_ERR_INVALID_ARG, TAG, "invalid arguments");
|
||||
st77916_vendor_config_t *vendor_config = (st77916_vendor_config_t *)panel_dev_config->vendor_config;
|
||||
ESP_RETURN_ON_FALSE(vendor_config && vendor_config->mipi_config.dpi_config && vendor_config->mipi_config.dsi_bus, ESP_ERR_INVALID_ARG, TAG,
|
||||
"invalid vendor config");
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
st77916_mipi_panel_t *st77916_mipi = (st77916_mipi_panel_t *)calloc(1, sizeof(st77916_mipi_panel_t));
|
||||
ESP_RETURN_ON_FALSE(st77916_mipi, ESP_ERR_NO_MEM, TAG, "no mem for st77916_mipi panel");
|
||||
|
||||
if (panel_dev_config->reset_gpio_num >= 0) {
|
||||
gpio_config_t io_conf = {
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pin_bit_mask = 1ULL << panel_dev_config->reset_gpio_num,
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(gpio_config(&io_conf), err, TAG, "configure GPIO for RST line failed");
|
||||
}
|
||||
|
||||
switch (panel_dev_config->rgb_ele_order) {
|
||||
case LCD_RGB_ELEMENT_ORDER_RGB:
|
||||
st77916_mipi->madctl_val = 0;
|
||||
break;
|
||||
case LCD_RGB_ELEMENT_ORDER_BGR:
|
||||
st77916_mipi->madctl_val |= LCD_CMD_BGR_BIT;
|
||||
break;
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported color space");
|
||||
break;
|
||||
}
|
||||
|
||||
st77916_mipi->io = io;
|
||||
st77916_mipi->init_cmds = vendor_config->init_cmds;
|
||||
st77916_mipi->init_cmds_size = vendor_config->init_cmds_size;
|
||||
st77916_mipi->reset_gpio_num = panel_dev_config->reset_gpio_num;
|
||||
st77916_mipi->flags.reset_level = panel_dev_config->flags.reset_active_high;
|
||||
|
||||
// Create MIPI DPI panel
|
||||
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
ESP_GOTO_ON_ERROR(esp_lcd_new_panel_dpi(vendor_config->mipi_config.dsi_bus, vendor_config->mipi_config.dpi_config, &panel_handle), err, TAG,
|
||||
"create MIPI DPI panel failed");
|
||||
ESP_LOGD(TAG, "new MIPI DPI panel @%p", panel_handle);
|
||||
|
||||
// Save the original functions of MIPI DPI panel
|
||||
st77916_mipi->del = panel_handle->del;
|
||||
st77916_mipi->init = panel_handle->init;
|
||||
// Overwrite the functions of MIPI DPI panel
|
||||
panel_handle->del = panel_st77916_mipi_del;
|
||||
panel_handle->init = panel_st77916_mipi_init;
|
||||
panel_handle->reset = panel_st77916_mipi_reset;
|
||||
panel_handle->mirror = panel_st77916_mipi_mirror;
|
||||
panel_handle->invert_color = panel_st77916_mipi_invert_color;
|
||||
panel_handle->disp_on_off = panel_st77916_mipi_disp_on_off;
|
||||
panel_handle->user_data = st77916_mipi;
|
||||
*ret_panel = panel_handle;
|
||||
ESP_LOGD(TAG, "new st77916_mipi panel @%p", st77916_mipi);
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (st77916_mipi) {
|
||||
if (panel_dev_config->reset_gpio_num >= 0) {
|
||||
gpio_reset_pin(panel_dev_config->reset_gpio_num);
|
||||
}
|
||||
free(st77916_mipi);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const st77916_lcd_init_cmd_t vendor_specific_init_default[] = {
|
||||
// {cmd, { data }, data_size, delay_ms}
|
||||
// ===== Page control / config =====
|
||||
{0xF0, (uint8_t[]){0x00, 0x28}, 2, 0},
|
||||
{0xF2, (uint8_t[]){0x00, 0x28}, 2, 0},
|
||||
{0x73, (uint8_t[]){0x00, 0xF0}, 2, 0},
|
||||
{0x7C, (uint8_t[]){0x00, 0xD1}, 2, 0},
|
||||
{0x83, (uint8_t[]){0x00, 0xE0}, 2, 0},
|
||||
{0x84, (uint8_t[]){0x00, 0x61}, 2, 0},
|
||||
{0xF2, (uint8_t[]){0x00, 0x82}, 2, 0},
|
||||
{0xF0, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xF0, (uint8_t[]){0x00, 0x01}, 2, 0},
|
||||
{0xF1, (uint8_t[]){0x00, 0x01}, 2, 0},
|
||||
|
||||
// ===== Register settings (single-param → +0x00) =====
|
||||
{0xB0, (uint8_t[]){0x00, 0x56}, 2, 0},
|
||||
{0xB1, (uint8_t[]){0x00, 0x4D}, 2, 0},
|
||||
{0xB2, (uint8_t[]){0x00, 0x24}, 2, 0},
|
||||
{0xB4, (uint8_t[]){0x00, 0x87}, 2, 0},
|
||||
{0xB5, (uint8_t[]){0x00, 0x44}, 2, 0},
|
||||
{0xB6, (uint8_t[]){0x00, 0x8B}, 2, 0},
|
||||
{0xB7, (uint8_t[]){0x00, 0x40}, 2, 0},
|
||||
{0xB8, (uint8_t[]){0x00, 0x86}, 2, 0},
|
||||
{0xBA, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xBB, (uint8_t[]){0x00, 0x08}, 2, 0},
|
||||
{0xBC, (uint8_t[]){0x00, 0x08}, 2, 0},
|
||||
{0xBD, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xC0, (uint8_t[]){0x00, 0x80}, 2, 0},
|
||||
{0xC1, (uint8_t[]){0x00, 0x10}, 2, 0},
|
||||
{0xC2, (uint8_t[]){0x00, 0x37}, 2, 0},
|
||||
{0xC3, (uint8_t[]){0x00, 0x80}, 2, 0},
|
||||
{0xC4, (uint8_t[]){0x00, 0x10}, 2, 0},
|
||||
{0xC5, (uint8_t[]){0x00, 0x37}, 2, 0},
|
||||
{0xC6, (uint8_t[]){0x00, 0xA9}, 2, 0},
|
||||
{0xC7, (uint8_t[]){0x00, 0x41}, 2, 0},
|
||||
{0xC8, (uint8_t[]){0x00, 0x01}, 2, 0},
|
||||
{0xC9, (uint8_t[]){0x00, 0xA9}, 2, 0},
|
||||
{0xCA, (uint8_t[]){0x00, 0x41}, 2, 0},
|
||||
{0xCB, (uint8_t[]){0x00, 0x01}, 2, 0},
|
||||
{0xD0, (uint8_t[]){0x00, 0x91}, 2, 0},
|
||||
{0xD1, (uint8_t[]){0x00, 0x68}, 2, 0},
|
||||
{0xD2, (uint8_t[]){0x00, 0x68}, 2, 0},
|
||||
|
||||
// ===== Special case: F5 (only add dummy before first arg) =====
|
||||
{0xF5, (uint8_t[]){0x00, 0x00, 0xA5}, 3, 0},
|
||||
|
||||
{0xDD, (uint8_t[]){0x00, 0x4F}, 2, 0},
|
||||
{0xDE, (uint8_t[]){0x00, 0x4F}, 2, 0},
|
||||
{0xF1, (uint8_t[]){0x00, 0x10}, 2, 0},
|
||||
{0xF0, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xF0, (uint8_t[]){0x00, 0x02}, 2, 0},
|
||||
|
||||
// ===== Gamma (multi-param → prepend 0x00) =====
|
||||
{0xE0, (uint8_t[]){0x00, 0xF0, 0x0A, 0x10, 0x09, 0x09, 0x36, 0x35, 0x33, 0x4A, 0x29, 0x15, 0x15, 0x2E, 0x34}, 15, 0},
|
||||
{0xE1, (uint8_t[]){0x00, 0xF0, 0x0A, 0x0F, 0x08, 0x08, 0x05, 0x34, 0x33, 0x4A, 0x39, 0x15, 0x15, 0x2D, 0x33}, 15, 0},
|
||||
|
||||
{0xF0, (uint8_t[]){0x00, 0x10}, 2, 0},
|
||||
{0xF3, (uint8_t[]){0x00, 0x10}, 2, 0},
|
||||
|
||||
// ===== More registers =====
|
||||
{0xE0, (uint8_t[]){0x00, 0x07}, 2, 0},
|
||||
{0xE1, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xE2, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xE3, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xE4, (uint8_t[]){0x00, 0xE0}, 2, 0},
|
||||
{0xE5, (uint8_t[]){0x00, 0x06}, 2, 0},
|
||||
{0xE6, (uint8_t[]){0x00, 0x21}, 2, 0},
|
||||
{0xE7, (uint8_t[]){0x00, 0x01}, 2, 0},
|
||||
{0xE8, (uint8_t[]){0x00, 0x05}, 2, 0},
|
||||
{0xE9, (uint8_t[]){0x00, 0x02}, 2, 0},
|
||||
{0xEA, (uint8_t[]){0x00, 0xDA}, 2, 0},
|
||||
{0xEB, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xEC, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xED, (uint8_t[]){0x00, 0x0F}, 2, 0},
|
||||
{0xEE, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xEF, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xF8, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xF9, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xFA, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xFB, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xFC, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xFD, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xFE, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xFF, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
|
||||
{0x60, (uint8_t[]){0x00, 0x40}, 2, 0},
|
||||
{0x61, (uint8_t[]){0x00, 0x04}, 2, 0},
|
||||
{0x62, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x63, (uint8_t[]){0x00, 0x42}, 2, 0},
|
||||
{0x64, (uint8_t[]){0x00, 0xD9}, 2, 0},
|
||||
{0x65, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x66, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x67, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x68, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x69, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x6A, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x6B, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
|
||||
{0x70, (uint8_t[]){0x00, 0x40}, 2, 0},
|
||||
{0x71, (uint8_t[]){0x00, 0x03}, 2, 0},
|
||||
{0x72, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x73, (uint8_t[]){0x00, 0x42}, 2, 0},
|
||||
{0x74, (uint8_t[]){0x00, 0xD8}, 2, 0},
|
||||
{0x75, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x76, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x77, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x78, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x79, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x7A, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x7B, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
|
||||
{0x80, (uint8_t[]){0x00, 0x48}, 2, 0},
|
||||
{0x81, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x82, (uint8_t[]){0x00, 0x06}, 2, 0},
|
||||
{0x83, (uint8_t[]){0x00, 0x02}, 2, 0},
|
||||
{0x84, (uint8_t[]){0x00, 0xD6}, 2, 0},
|
||||
{0x85, (uint8_t[]){0x00, 0x04}, 2, 0},
|
||||
{0x86, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x87, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
|
||||
{0x88, (uint8_t[]){0x00, 0x48}, 2, 0},
|
||||
{0x89, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x8A, (uint8_t[]){0x00, 0x08}, 2, 0},
|
||||
{0x8B, (uint8_t[]){0x00, 0x02}, 2, 0},
|
||||
{0x8C, (uint8_t[]){0x00, 0xD8}, 2, 0},
|
||||
{0x8D, (uint8_t[]){0x00, 0x04}, 2, 0},
|
||||
{0x8E, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x8F, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
|
||||
{0x90, (uint8_t[]){0x00, 0x48}, 2, 0},
|
||||
{0x91, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x92, (uint8_t[]){0x00, 0x0A}, 2, 0},
|
||||
{0x93, (uint8_t[]){0x00, 0x02}, 2, 0},
|
||||
{0x94, (uint8_t[]){0x00, 0xDA}, 2, 0},
|
||||
{0x95, (uint8_t[]){0x00, 0x04}, 2, 0},
|
||||
{0x96, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x97, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
|
||||
{0x98, (uint8_t[]){0x00, 0x48}, 2, 0},
|
||||
{0x99, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x9A, (uint8_t[]){0x00, 0x0C}, 2, 0},
|
||||
{0x9B, (uint8_t[]){0x00, 0x02}, 2, 0},
|
||||
{0x9C, (uint8_t[]){0x00, 0xDC}, 2, 0},
|
||||
{0x9D, (uint8_t[]){0x00, 0x04}, 2, 0},
|
||||
{0x9E, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0x9F, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
|
||||
{0xA0, (uint8_t[]){0x00, 0x48}, 2, 0},
|
||||
{0xA1, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xA2, (uint8_t[]){0x00, 0x05}, 2, 0},
|
||||
{0xA3, (uint8_t[]){0x00, 0x02}, 2, 0},
|
||||
{0xA4, (uint8_t[]){0x00, 0xD5}, 2, 0},
|
||||
{0xA5, (uint8_t[]){0x00, 0x04}, 2, 0},
|
||||
{0xA6, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xA7, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
|
||||
{0xA8, (uint8_t[]){0x00, 0x48}, 2, 0},
|
||||
{0xA9, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xAA, (uint8_t[]){0x00, 0x07}, 2, 0},
|
||||
{0xAB, (uint8_t[]){0x00, 0x02}, 2, 0},
|
||||
{0xAC, (uint8_t[]){0x00, 0xD7}, 2, 0},
|
||||
{0xAD, (uint8_t[]){0x00, 0x04}, 2, 0},
|
||||
{0xAE, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xAF, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
|
||||
{0xB0, (uint8_t[]){0x00, 0x48}, 2, 0},
|
||||
{0xB1, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xB2, (uint8_t[]){0x00, 0x09}, 2, 0},
|
||||
{0xB3, (uint8_t[]){0x00, 0x02}, 2, 0},
|
||||
{0xB4, (uint8_t[]){0x00, 0xD9}, 2, 0},
|
||||
{0xB5, (uint8_t[]){0x00, 0x04}, 2, 0},
|
||||
{0xB6, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xB7, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
|
||||
{0xB8, (uint8_t[]){0x00, 0x48}, 2, 0},
|
||||
{0xB9, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xBA, (uint8_t[]){0x00, 0x0B}, 2, 0},
|
||||
{0xBB, (uint8_t[]){0x00, 0x02}, 2, 0},
|
||||
{0xBC, (uint8_t[]){0x00, 0xDB}, 2, 0},
|
||||
{0xBD, (uint8_t[]){0x00, 0x04}, 2, 0},
|
||||
{0xBE, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
{0xBF, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
|
||||
{0xC0, (uint8_t[]){0x00, 0x10}, 2, 0},
|
||||
{0xC1, (uint8_t[]){0x00, 0x47}, 2, 0},
|
||||
{0xC2, (uint8_t[]){0x00, 0x56}, 2, 0},
|
||||
{0xC3, (uint8_t[]){0x00, 0x65}, 2, 0},
|
||||
{0xC4, (uint8_t[]){0x00, 0x74}, 2, 0},
|
||||
{0xC5, (uint8_t[]){0x00, 0x88}, 2, 0},
|
||||
{0xC6, (uint8_t[]){0x00, 0x99}, 2, 0},
|
||||
{0xC7, (uint8_t[]){0x00, 0x01}, 2, 0},
|
||||
{0xC8, (uint8_t[]){0x00, 0xBB}, 2, 0},
|
||||
{0xC9, (uint8_t[]){0x00, 0xAA}, 2, 0},
|
||||
|
||||
{0xD0, (uint8_t[]){0x00, 0x10}, 2, 0},
|
||||
{0xD1, (uint8_t[]){0x00, 0x47}, 2, 0},
|
||||
{0xD2, (uint8_t[]){0x00, 0x56}, 2, 0},
|
||||
{0xD3, (uint8_t[]){0x00, 0x65}, 2, 0},
|
||||
{0xD4, (uint8_t[]){0x00, 0x74}, 2, 0},
|
||||
{0xD5, (uint8_t[]){0x00, 0x88}, 2, 0},
|
||||
{0xD6, (uint8_t[]){0x00, 0x99}, 2, 0},
|
||||
{0xD7, (uint8_t[]){0x00, 0x01}, 2, 0},
|
||||
{0xD8, (uint8_t[]){0x00, 0xBB}, 2, 0},
|
||||
{0xD9, (uint8_t[]){0x00, 0xAA}, 2, 0},
|
||||
|
||||
{0xF3, (uint8_t[]){0x00, 0x01}, 2, 0},
|
||||
{0xF0, (uint8_t[]){0x00, 0x00}, 2, 0},
|
||||
|
||||
// ===== Display ON sequence (Video mode) =====
|
||||
{0x21, (uint8_t[]){}, 0, 0},
|
||||
{0x11, (uint8_t[]){}, 0, 120},
|
||||
{0x29, (uint8_t[]){}, 0, 0},
|
||||
{0x00, (uint8_t[]){}, 0, 0},
|
||||
};
|
||||
|
||||
static esp_err_t panel_st77916_mipi_del(esp_lcd_panel_t *panel)
|
||||
{
|
||||
st77916_mipi_panel_t *st77916_mipi = (st77916_mipi_panel_t *)panel->user_data;
|
||||
|
||||
if (st77916_mipi->reset_gpio_num >= 0) {
|
||||
gpio_reset_pin(st77916_mipi->reset_gpio_num);
|
||||
}
|
||||
// Delete MIPI DPI panel
|
||||
st77916_mipi->del(panel);
|
||||
ESP_LOGD(TAG, "del st77916_mipi panel @%p", st77916_mipi);
|
||||
free(st77916_mipi);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_st77916_mipi_init(esp_lcd_panel_t *panel)
|
||||
{
|
||||
st77916_mipi_panel_t *st77916_mipi = (st77916_mipi_panel_t *)panel->user_data;
|
||||
esp_lcd_panel_io_handle_t io = st77916_mipi->io;
|
||||
const st77916_lcd_init_cmd_t *init_cmds = NULL;
|
||||
uint16_t init_cmds_size = 0;
|
||||
bool is_cmd_overwritten = false;
|
||||
|
||||
uint8_t ID[3];
|
||||
ESP_LOGI(TAG, "read ID");
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_rx_param(io, 0x04, ID, 3), TAG, "read ID failed");
|
||||
ESP_LOGI(TAG, "LCD ID: %02X %02X %02X", ID[0], ID[1], ID[2]);
|
||||
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_MADCTL, (uint8_t[]) {
|
||||
st77916_mipi->madctl_val,
|
||||
}, 1), TAG, "send command failed");
|
||||
|
||||
// vendor specific initialization, it can be different between manufacturers
|
||||
// should consult the LCD supplier for initialization sequence code
|
||||
if (st77916_mipi->init_cmds) {
|
||||
init_cmds = st77916_mipi->init_cmds;
|
||||
init_cmds_size = st77916_mipi->init_cmds_size;
|
||||
} else {
|
||||
init_cmds = vendor_specific_init_default;
|
||||
init_cmds_size = sizeof(vendor_specific_init_default) / sizeof(st77916_lcd_init_cmd_t);
|
||||
}
|
||||
|
||||
for (int i = 0; i < init_cmds_size; i++) {
|
||||
// Check if the command has been used or conflicts with the internal
|
||||
if (init_cmds[i].data_bytes > 0) {
|
||||
switch (init_cmds[i].cmd) {
|
||||
case LCD_CMD_MADCTL:
|
||||
is_cmd_overwritten = true;
|
||||
st77916_mipi->madctl_val = ((uint8_t *)init_cmds[i].data)[0];
|
||||
break;
|
||||
case LCD_CMD_COLMOD:
|
||||
is_cmd_overwritten = true;
|
||||
st77916_mipi->colmod_val = ((uint8_t *)init_cmds[i].data)[0];
|
||||
break;
|
||||
default:
|
||||
is_cmd_overwritten = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_cmd_overwritten) {
|
||||
is_cmd_overwritten = false;
|
||||
ESP_LOGW(TAG, "The %02Xh command has been used and will be overwritten by external initialization sequence",
|
||||
init_cmds[i].cmd);
|
||||
}
|
||||
}
|
||||
|
||||
// Send command
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, init_cmds[i].cmd, init_cmds[i].data, init_cmds[i].data_bytes), TAG, "send command failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(init_cmds[i].delay_ms));
|
||||
}
|
||||
ESP_LOGD(TAG, "send init commands success");
|
||||
|
||||
ESP_RETURN_ON_ERROR(st77916_mipi->init(panel), TAG, "init MIPI DPI panel failed");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_st77916_mipi_reset(esp_lcd_panel_t *panel)
|
||||
{
|
||||
st77916_mipi_panel_t *st77916_mipi = (st77916_mipi_panel_t *)panel->user_data;
|
||||
esp_lcd_panel_io_handle_t io = st77916_mipi->io;
|
||||
|
||||
// Perform hardware reset
|
||||
if (st77916_mipi->reset_gpio_num >= 0) {
|
||||
gpio_set_level(st77916_mipi->reset_gpio_num, !st77916_mipi->flags.reset_level);
|
||||
vTaskDelay(pdMS_TO_TICKS(5));
|
||||
gpio_set_level(st77916_mipi->reset_gpio_num, st77916_mipi->flags.reset_level);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
gpio_set_level(st77916_mipi->reset_gpio_num, !st77916_mipi->flags.reset_level);
|
||||
vTaskDelay(pdMS_TO_TICKS(120));
|
||||
} else if (io) { // Perform software reset
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_SWRESET, NULL, 0), TAG, "send command failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(120));
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_st77916_mipi_invert_color(esp_lcd_panel_t *panel, bool invert_color_data)
|
||||
{
|
||||
st77916_mipi_panel_t *st77916_mipi = (st77916_mipi_panel_t *)panel->user_data;
|
||||
esp_lcd_panel_io_handle_t io = st77916_mipi->io;
|
||||
uint8_t command = 0;
|
||||
|
||||
ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_STATE, TAG, "invalid panel IO");
|
||||
|
||||
if (invert_color_data) {
|
||||
command = LCD_CMD_INVON;
|
||||
} else {
|
||||
command = LCD_CMD_INVOFF;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, command, NULL, 0), TAG, "send command failed");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_st77916_mipi_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y)
|
||||
{
|
||||
st77916_mipi_panel_t *st77916_mipi = (st77916_mipi_panel_t *)panel->user_data;
|
||||
esp_lcd_panel_io_handle_t io = st77916_mipi->io;
|
||||
uint8_t madctl_val = st77916_mipi->madctl_val;
|
||||
|
||||
ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_STATE, TAG, "invalid panel IO");
|
||||
|
||||
// Control mirror through LCD command
|
||||
if (mirror_x) {
|
||||
ESP_LOGW(TAG, "Mirror X is not supported");
|
||||
}
|
||||
|
||||
if (mirror_y) {
|
||||
madctl_val |= BIT(7);
|
||||
} else {
|
||||
madctl_val &= ~BIT(7);
|
||||
}
|
||||
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_MADCTL, (uint8_t []) {
|
||||
madctl_val
|
||||
}, 1), TAG, "send command failed");
|
||||
st77916_mipi->madctl_val = madctl_val;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_st77916_mipi_disp_on_off(esp_lcd_panel_t *panel, bool on_off)
|
||||
{
|
||||
st77916_mipi_panel_t *st77916_mipi = (st77916_mipi_panel_t *)panel->user_data;
|
||||
esp_lcd_panel_io_handle_t io = st77916_mipi->io;
|
||||
int command = 0;
|
||||
|
||||
if (on_off) {
|
||||
command = LCD_CMD_DISPON;
|
||||
} else {
|
||||
command = LCD_CMD_DISPOFF;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, command, NULL, 0), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,576 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_lcd_panel_interface.h"
|
||||
#include "esp_lcd_panel_io.h"
|
||||
#include "esp_lcd_panel_vendor.h"
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include "esp_lcd_panel_commands.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "esp_lcd_st77916.h"
|
||||
#include "esp_lcd_st77916_interface.h"
|
||||
|
||||
#define LCD_OPCODE_WRITE_CMD (0x02ULL)
|
||||
#define LCD_OPCODE_READ_CMD (0x0BULL)
|
||||
#define LCD_OPCODE_WRITE_COLOR (0x32ULL)
|
||||
|
||||
#define ST77916_CMD_SET (0xF0)
|
||||
#define ST77916_PARAM_SET (0x00)
|
||||
|
||||
static const char *TAG = "st77916_spi";
|
||||
|
||||
static esp_err_t panel_st77916_del(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_st77916_reset(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_st77916_init(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_st77916_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int y_start, int x_end, int y_end, const void *color_data);
|
||||
static esp_err_t panel_st77916_invert_color(esp_lcd_panel_t *panel, bool invert_color_data);
|
||||
static esp_err_t panel_st77916_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y);
|
||||
static esp_err_t panel_st77916_swap_xy(esp_lcd_panel_t *panel, bool swap_axes);
|
||||
static esp_err_t panel_st77916_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap);
|
||||
static esp_err_t panel_st77916_disp_on_off(esp_lcd_panel_t *panel, bool off);
|
||||
|
||||
typedef struct {
|
||||
esp_lcd_panel_t base;
|
||||
esp_lcd_panel_io_handle_t io;
|
||||
int reset_gpio_num;
|
||||
int x_gap;
|
||||
int y_gap;
|
||||
uint8_t fb_bits_per_pixel;
|
||||
uint8_t madctl_val; // save current value of LCD_CMD_MADCTL register
|
||||
uint8_t colmod_val; // save surrent value of LCD_CMD_COLMOD register
|
||||
const st77916_lcd_init_cmd_t *init_cmds;
|
||||
uint16_t init_cmds_size;
|
||||
struct {
|
||||
unsigned int use_qspi_interface: 1;
|
||||
unsigned int reset_level: 1;
|
||||
} flags;
|
||||
} st77916_panel_t;
|
||||
|
||||
esp_err_t esp_lcd_new_panel_st77916_spi(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(io && panel_dev_config && ret_panel, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
st77916_panel_t *st77916 = NULL;
|
||||
st77916 = calloc(1, sizeof(st77916_panel_t));
|
||||
ESP_GOTO_ON_FALSE(st77916, ESP_ERR_NO_MEM, err, TAG, "no mem for st77916 panel");
|
||||
|
||||
if (panel_dev_config->reset_gpio_num >= 0) {
|
||||
gpio_config_t io_conf = {
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pin_bit_mask = 1ULL << panel_dev_config->reset_gpio_num,
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(gpio_config(&io_conf), err, TAG, "configure GPIO for RST line failed");
|
||||
}
|
||||
|
||||
switch (panel_dev_config->rgb_ele_order) {
|
||||
case LCD_RGB_ELEMENT_ORDER_RGB:
|
||||
st77916->madctl_val = 0;
|
||||
break;
|
||||
case LCD_RGB_ELEMENT_ORDER_BGR:
|
||||
st77916->madctl_val |= LCD_CMD_BGR_BIT;
|
||||
break;
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported color element order");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (panel_dev_config->bits_per_pixel) {
|
||||
case 16: // RGB565
|
||||
st77916->colmod_val = 0x55;
|
||||
st77916->fb_bits_per_pixel = 16;
|
||||
break;
|
||||
case 18: // RGB666
|
||||
st77916->colmod_val = 0x66;
|
||||
// each color component (R/G/B) should occupy the 6 high bits of a byte, which means 3 full bytes are required for a pixel
|
||||
st77916->fb_bits_per_pixel = 24;
|
||||
break;
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported pixel width");
|
||||
break;
|
||||
}
|
||||
|
||||
st77916->io = io;
|
||||
st77916->reset_gpio_num = panel_dev_config->reset_gpio_num;
|
||||
st77916->flags.reset_level = panel_dev_config->flags.reset_active_high;
|
||||
st77916_vendor_config_t *vendor_config = (st77916_vendor_config_t *)panel_dev_config->vendor_config;
|
||||
if (vendor_config) {
|
||||
st77916->init_cmds = vendor_config->init_cmds;
|
||||
st77916->init_cmds_size = vendor_config->init_cmds_size;
|
||||
st77916->flags.use_qspi_interface = vendor_config->flags.use_qspi_interface;
|
||||
}
|
||||
st77916->base.del = panel_st77916_del;
|
||||
st77916->base.reset = panel_st77916_reset;
|
||||
st77916->base.init = panel_st77916_init;
|
||||
st77916->base.draw_bitmap = panel_st77916_draw_bitmap;
|
||||
st77916->base.invert_color = panel_st77916_invert_color;
|
||||
st77916->base.set_gap = panel_st77916_set_gap;
|
||||
st77916->base.mirror = panel_st77916_mirror;
|
||||
st77916->base.swap_xy = panel_st77916_swap_xy;
|
||||
st77916->base.disp_on_off = panel_st77916_disp_on_off;
|
||||
*ret_panel = &(st77916->base);
|
||||
ESP_LOGD(TAG, "new st77916 panel @%p", st77916);
|
||||
|
||||
ESP_LOGI(TAG, "LCD panel create success, version: %d.%d.%d", ESP_LCD_ST77916_VER_MAJOR, ESP_LCD_ST77916_VER_MINOR,
|
||||
ESP_LCD_ST77916_VER_PATCH);
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (st77916) {
|
||||
if (panel_dev_config->reset_gpio_num >= 0) {
|
||||
gpio_reset_pin(panel_dev_config->reset_gpio_num);
|
||||
}
|
||||
free(st77916);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t tx_param(st77916_panel_t *st77916, esp_lcd_panel_io_handle_t io, int lcd_cmd, const void *param, size_t param_size)
|
||||
{
|
||||
if (st77916->flags.use_qspi_interface) {
|
||||
lcd_cmd &= 0xff;
|
||||
lcd_cmd <<= 8;
|
||||
lcd_cmd |= LCD_OPCODE_WRITE_CMD << 24;
|
||||
}
|
||||
return esp_lcd_panel_io_tx_param(io, lcd_cmd, param, param_size);
|
||||
}
|
||||
|
||||
static esp_err_t tx_color(st77916_panel_t *st77916, esp_lcd_panel_io_handle_t io, int lcd_cmd, const void *param, size_t param_size)
|
||||
{
|
||||
if (st77916->flags.use_qspi_interface) {
|
||||
lcd_cmd &= 0xff;
|
||||
lcd_cmd <<= 8;
|
||||
lcd_cmd |= LCD_OPCODE_WRITE_COLOR << 24;
|
||||
}
|
||||
return esp_lcd_panel_io_tx_color(io, lcd_cmd, param, param_size);
|
||||
}
|
||||
|
||||
static esp_err_t panel_st77916_del(esp_lcd_panel_t *panel)
|
||||
{
|
||||
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||
|
||||
if (st77916->reset_gpio_num >= 0) {
|
||||
gpio_reset_pin(st77916->reset_gpio_num);
|
||||
}
|
||||
ESP_LOGD(TAG, "del st77916 panel @%p", st77916);
|
||||
free(st77916);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_st77916_reset(esp_lcd_panel_t *panel)
|
||||
{
|
||||
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = st77916->io;
|
||||
|
||||
// Perform hardware reset
|
||||
if (st77916->reset_gpio_num >= 0) {
|
||||
gpio_set_level(st77916->reset_gpio_num, st77916->flags.reset_level);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
gpio_set_level(st77916->reset_gpio_num, !st77916->flags.reset_level);
|
||||
vTaskDelay(pdMS_TO_TICKS(120));
|
||||
} else { // Perform software reset
|
||||
ESP_RETURN_ON_ERROR(tx_param(st77916, io, LCD_CMD_SWRESET, NULL, 0), TAG, "send command failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(120));
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static const st77916_lcd_init_cmd_t vendor_specific_init_default[] = {
|
||||
{0xF0, (uint8_t []){0x08}, 1, 0},
|
||||
{0xF2, (uint8_t []){0x08}, 1, 0},
|
||||
{0x9B, (uint8_t []){0x51}, 1, 0},
|
||||
{0x86, (uint8_t []){0x53}, 1, 0},
|
||||
{0xF2, (uint8_t []){0x80}, 1, 0},
|
||||
{0xF0, (uint8_t []){0x00}, 1, 0},
|
||||
{0xF0, (uint8_t []){0x01}, 1, 0},
|
||||
{0xF1, (uint8_t []){0x01}, 1, 0},
|
||||
{0xB0, (uint8_t []){0x54}, 1, 0},
|
||||
{0xB1, (uint8_t []){0x3F}, 1, 0},
|
||||
{0xB2, (uint8_t []){0x2A}, 1, 0},
|
||||
{0xB4, (uint8_t []){0x46}, 1, 0},
|
||||
{0xB5, (uint8_t []){0x34}, 1, 0},
|
||||
{0xB6, (uint8_t []){0xD5}, 1, 0},
|
||||
{0xB7, (uint8_t []){0x30}, 1, 0},
|
||||
{0xB8, (uint8_t []){0x04}, 1, 0},
|
||||
{0xBA, (uint8_t []){0x00}, 1, 0},
|
||||
{0xBB, (uint8_t []){0x08}, 1, 0},
|
||||
{0xBC, (uint8_t []){0x08}, 1, 0},
|
||||
{0xBD, (uint8_t []){0x00}, 1, 0},
|
||||
{0xC0, (uint8_t []){0x80}, 1, 0},
|
||||
{0xC1, (uint8_t []){0x10}, 1, 0},
|
||||
{0xC2, (uint8_t []){0x37}, 1, 0},
|
||||
{0xC3, (uint8_t []){0x80}, 1, 0},
|
||||
{0xC4, (uint8_t []){0x10}, 1, 0},
|
||||
{0xC5, (uint8_t []){0x37}, 1, 0},
|
||||
{0xC6, (uint8_t []){0xA9}, 1, 0},
|
||||
{0xC7, (uint8_t []){0x41}, 1, 0},
|
||||
{0xC8, (uint8_t []){0x51}, 1, 0},
|
||||
{0xC9, (uint8_t []){0xA9}, 1, 0},
|
||||
{0xCA, (uint8_t []){0x41}, 1, 0},
|
||||
{0xCB, (uint8_t []){0x51}, 1, 0},
|
||||
{0xD0, (uint8_t []){0x91}, 1, 0},
|
||||
{0xD1, (uint8_t []){0x68}, 1, 0},
|
||||
{0xD2, (uint8_t []){0x69}, 1, 0},
|
||||
{0xF5, (uint8_t []){0x00, 0xA5}, 2, 0},
|
||||
{0xDD, (uint8_t []){0x35}, 1, 0},
|
||||
{0xDE, (uint8_t []){0x35}, 1, 0},
|
||||
{0xF1, (uint8_t []){0x10}, 1, 0},
|
||||
{0xF0, (uint8_t []){0x00}, 1, 0},
|
||||
{0xF0, (uint8_t []){0x02}, 1, 0},
|
||||
{0xE0, (uint8_t []){0x70, 0x09, 0x12, 0x0C, 0x0B, 0x27, 0x38, 0x54, 0x4E, 0x19, 0x15, 0x15, 0x2C, 0x2F}, 14, 0},
|
||||
{0xE1, (uint8_t []){0x70, 0x08, 0x11, 0x0C, 0x0B, 0x27, 0x38, 0x43, 0x4C, 0x18, 0x14, 0x14, 0x2B, 0x2D}, 14, 0},
|
||||
{0xF0, (uint8_t []){0x10}, 1, 0},
|
||||
{0xF3, (uint8_t []){0x10}, 1, 0},
|
||||
{0xE0, (uint8_t []){0x0A}, 1, 0},
|
||||
{0xE1, (uint8_t []){0x00}, 1, 0},
|
||||
{0xE2, (uint8_t []){0x0B}, 1, 0},
|
||||
{0xE3, (uint8_t []){0x00}, 1, 0},
|
||||
{0xE4, (uint8_t []){0xE0}, 1, 0},
|
||||
{0xE5, (uint8_t []){0x06}, 1, 0},
|
||||
{0xE6, (uint8_t []){0x21}, 1, 0},
|
||||
{0xE7, (uint8_t []){0x00}, 1, 0},
|
||||
{0xE8, (uint8_t []){0x05}, 1, 0},
|
||||
{0xE9, (uint8_t []){0x82}, 1, 0},
|
||||
{0xEA, (uint8_t []){0xDF}, 1, 0},
|
||||
{0xEB, (uint8_t []){0x89}, 1, 0},
|
||||
{0xEC, (uint8_t []){0x20}, 1, 0},
|
||||
{0xED, (uint8_t []){0x14}, 1, 0},
|
||||
{0xEE, (uint8_t []){0xFF}, 1, 0},
|
||||
{0xEF, (uint8_t []){0x00}, 1, 0},
|
||||
{0xF8, (uint8_t []){0xFF}, 1, 0},
|
||||
{0xF9, (uint8_t []){0x00}, 1, 0},
|
||||
{0xFA, (uint8_t []){0x00}, 1, 0},
|
||||
{0xFB, (uint8_t []){0x30}, 1, 0},
|
||||
{0xFC, (uint8_t []){0x00}, 1, 0},
|
||||
{0xFD, (uint8_t []){0x00}, 1, 0},
|
||||
{0xFE, (uint8_t []){0x00}, 1, 0},
|
||||
{0xFF, (uint8_t []){0x00}, 1, 0},
|
||||
{0x60, (uint8_t []){0x42}, 1, 0},
|
||||
{0x61, (uint8_t []){0xE0}, 1, 0},
|
||||
{0x62, (uint8_t []){0x40}, 1, 0},
|
||||
{0x63, (uint8_t []){0x40}, 1, 0},
|
||||
{0x64, (uint8_t []){0x02}, 1, 0},
|
||||
{0x65, (uint8_t []){0x00}, 1, 0},
|
||||
{0x66, (uint8_t []){0x40}, 1, 0},
|
||||
{0x67, (uint8_t []){0x03}, 1, 0},
|
||||
{0x68, (uint8_t []){0x00}, 1, 0},
|
||||
{0x69, (uint8_t []){0x00}, 1, 0},
|
||||
{0x6A, (uint8_t []){0x00}, 1, 0},
|
||||
{0x6B, (uint8_t []){0x00}, 1, 0},
|
||||
{0x70, (uint8_t []){0x42}, 1, 0},
|
||||
{0x71, (uint8_t []){0xE0}, 1, 0},
|
||||
{0x72, (uint8_t []){0x40}, 1, 0},
|
||||
{0x73, (uint8_t []){0x40}, 1, 0},
|
||||
{0x74, (uint8_t []){0x02}, 1, 0},
|
||||
{0x75, (uint8_t []){0x00}, 1, 0},
|
||||
{0x76, (uint8_t []){0x40}, 1, 0},
|
||||
{0x77, (uint8_t []){0x03}, 1, 0},
|
||||
{0x78, (uint8_t []){0x00}, 1, 0},
|
||||
{0x79, (uint8_t []){0x00}, 1, 0},
|
||||
{0x7A, (uint8_t []){0x00}, 1, 0},
|
||||
{0x7B, (uint8_t []){0x00}, 1, 0},
|
||||
{0x80, (uint8_t []){0x38}, 1, 0},
|
||||
{0x81, (uint8_t []){0x00}, 1, 0},
|
||||
{0x82, (uint8_t []){0x04}, 1, 0},
|
||||
{0x83, (uint8_t []){0x02}, 1, 0},
|
||||
{0x84, (uint8_t []){0xDC}, 1, 0},
|
||||
{0x85, (uint8_t []){0x00}, 1, 0},
|
||||
{0x86, (uint8_t []){0x00}, 1, 0},
|
||||
{0x87, (uint8_t []){0x00}, 1, 0},
|
||||
{0x88, (uint8_t []){0x38}, 1, 0},
|
||||
{0x89, (uint8_t []){0x00}, 1, 0},
|
||||
{0x8A, (uint8_t []){0x06}, 1, 0},
|
||||
{0x8B, (uint8_t []){0x02}, 1, 0},
|
||||
{0x8C, (uint8_t []){0xDE}, 1, 0},
|
||||
{0x8D, (uint8_t []){0x00}, 1, 0},
|
||||
{0x8E, (uint8_t []){0x00}, 1, 0},
|
||||
{0x8F, (uint8_t []){0x00}, 1, 0},
|
||||
{0x90, (uint8_t []){0x38}, 1, 0},
|
||||
{0x91, (uint8_t []){0x00}, 1, 0},
|
||||
{0x92, (uint8_t []){0x08}, 1, 0},
|
||||
{0x93, (uint8_t []){0x02}, 1, 0},
|
||||
{0x94, (uint8_t []){0xE0}, 1, 0},
|
||||
{0x95, (uint8_t []){0x00}, 1, 0},
|
||||
{0x96, (uint8_t []){0x00}, 1, 0},
|
||||
{0x97, (uint8_t []){0x00}, 1, 0},
|
||||
{0x98, (uint8_t []){0x38}, 1, 0},
|
||||
{0x99, (uint8_t []){0x00}, 1, 0},
|
||||
{0x9A, (uint8_t []){0x0A}, 1, 0},
|
||||
{0x9B, (uint8_t []){0x02}, 1, 0},
|
||||
{0x9C, (uint8_t []){0xE2}, 1, 0},
|
||||
{0x9D, (uint8_t []){0x00}, 1, 0},
|
||||
{0x9E, (uint8_t []){0x00}, 1, 0},
|
||||
{0x9F, (uint8_t []){0x00}, 1, 0},
|
||||
{0xA0, (uint8_t []){0x38}, 1, 0},
|
||||
{0xA1, (uint8_t []){0x00}, 1, 0},
|
||||
{0xA2, (uint8_t []){0x03}, 1, 0},
|
||||
{0xA3, (uint8_t []){0x02}, 1, 0},
|
||||
{0xA4, (uint8_t []){0xDB}, 1, 0},
|
||||
{0xA5, (uint8_t []){0x00}, 1, 0},
|
||||
{0xA6, (uint8_t []){0x00}, 1, 0},
|
||||
{0xA7, (uint8_t []){0x00}, 1, 0},
|
||||
{0xA8, (uint8_t []){0x38}, 1, 0},
|
||||
{0xA9, (uint8_t []){0x00}, 1, 0},
|
||||
{0xAA, (uint8_t []){0x05}, 1, 0},
|
||||
{0xAB, (uint8_t []){0x02}, 1, 0},
|
||||
{0xAC, (uint8_t []){0xDD}, 1, 0},
|
||||
{0xAD, (uint8_t []){0x00}, 1, 0},
|
||||
{0xAE, (uint8_t []){0x00}, 1, 0},
|
||||
{0xAF, (uint8_t []){0x00}, 1, 0},
|
||||
{0xB0, (uint8_t []){0x38}, 1, 0},
|
||||
{0xB1, (uint8_t []){0x00}, 1, 0},
|
||||
{0xB2, (uint8_t []){0x07}, 1, 0},
|
||||
{0xB3, (uint8_t []){0x02}, 1, 0},
|
||||
{0xB4, (uint8_t []){0xDF}, 1, 0},
|
||||
{0xB5, (uint8_t []){0x00}, 1, 0},
|
||||
{0xB6, (uint8_t []){0x00}, 1, 0},
|
||||
{0xB7, (uint8_t []){0x00}, 1, 0},
|
||||
{0xB8, (uint8_t []){0x38}, 1, 0},
|
||||
{0xB9, (uint8_t []){0x00}, 1, 0},
|
||||
{0xBA, (uint8_t []){0x09}, 1, 0},
|
||||
{0xBB, (uint8_t []){0x02}, 1, 0},
|
||||
{0xBC, (uint8_t []){0xE1}, 1, 0},
|
||||
{0xBD, (uint8_t []){0x00}, 1, 0},
|
||||
{0xBE, (uint8_t []){0x00}, 1, 0},
|
||||
{0xBF, (uint8_t []){0x00}, 1, 0},
|
||||
{0xC0, (uint8_t []){0x22}, 1, 0},
|
||||
{0xC1, (uint8_t []){0xAA}, 1, 0},
|
||||
{0xC2, (uint8_t []){0x65}, 1, 0},
|
||||
{0xC3, (uint8_t []){0x74}, 1, 0},
|
||||
{0xC4, (uint8_t []){0x47}, 1, 0},
|
||||
{0xC5, (uint8_t []){0x56}, 1, 0},
|
||||
{0xC6, (uint8_t []){0x00}, 1, 0},
|
||||
{0xC7, (uint8_t []){0x88}, 1, 0},
|
||||
{0xC8, (uint8_t []){0x99}, 1, 0},
|
||||
{0xC9, (uint8_t []){0x33}, 1, 0},
|
||||
{0xD0, (uint8_t []){0x11}, 1, 0},
|
||||
{0xD1, (uint8_t []){0xAA}, 1, 0},
|
||||
{0xD2, (uint8_t []){0x65}, 1, 0},
|
||||
{0xD3, (uint8_t []){0x74}, 1, 0},
|
||||
{0xD4, (uint8_t []){0x47}, 1, 0},
|
||||
{0xD5, (uint8_t []){0x56}, 1, 0},
|
||||
{0xD6, (uint8_t []){0x00}, 1, 0},
|
||||
{0xD7, (uint8_t []){0x88}, 1, 0},
|
||||
{0xD8, (uint8_t []){0x99}, 1, 0},
|
||||
{0xD9, (uint8_t []){0x33}, 1, 0},
|
||||
{0xF3, (uint8_t []){0x01}, 1, 0},
|
||||
{0xF0, (uint8_t []){0x00}, 1, 0},
|
||||
{0xF0, (uint8_t []){0x01}, 1, 0},
|
||||
{0xF1, (uint8_t []){0x01}, 1, 0},
|
||||
{0xA0, (uint8_t []){0x0B}, 1, 0},
|
||||
{0xA3, (uint8_t []){0x2A}, 1, 0},
|
||||
{0xA5, (uint8_t []){0xC3}, 1, 1},
|
||||
{0xA3, (uint8_t []){0x2B}, 1, 0},
|
||||
{0xA5, (uint8_t []){0xC3}, 1, 1},
|
||||
{0xA3, (uint8_t []){0x2C}, 1, 0},
|
||||
{0xA5, (uint8_t []){0xC3}, 1, 1},
|
||||
{0xA3, (uint8_t []){0x2D}, 1, 0},
|
||||
{0xA5, (uint8_t []){0xC3}, 1, 1},
|
||||
{0xA3, (uint8_t []){0x2E}, 1, 0},
|
||||
{0xA5, (uint8_t []){0xC3}, 1, 1},
|
||||
{0xA3, (uint8_t []){0x2F}, 1, 0},
|
||||
{0xA5, (uint8_t []){0xC3}, 1, 1},
|
||||
{0xA3, (uint8_t []){0x30}, 1, 0},
|
||||
{0xA5, (uint8_t []){0xC3}, 1, 1},
|
||||
{0xA3, (uint8_t []){0x31}, 1, 0},
|
||||
{0xA5, (uint8_t []){0xC3}, 1, 1},
|
||||
{0xA3, (uint8_t []){0x32}, 1, 0},
|
||||
{0xA5, (uint8_t []){0xC3}, 1, 1},
|
||||
{0xA3, (uint8_t []){0x33}, 1, 0},
|
||||
{0xA5, (uint8_t []){0xC3}, 1, 1},
|
||||
{0xA0, (uint8_t []){0x09}, 1, 0},
|
||||
{0xF1, (uint8_t []){0x10}, 1, 0},
|
||||
{0xF0, (uint8_t []){0x00}, 1, 0},
|
||||
{0x2A, (uint8_t []){0x00, 0x00, 0x01, 0x67}, 4, 0},
|
||||
{0x2B, (uint8_t []){0x01, 0x68, 0x01, 0x68}, 4, 0},
|
||||
{0x4D, (uint8_t []){0x00}, 1, 0},
|
||||
{0x4E, (uint8_t []){0x00}, 1, 0},
|
||||
{0x4F, (uint8_t []){0x00}, 1, 0},
|
||||
{0x4C, (uint8_t []){0x01}, 1, 10},
|
||||
{0x4C, (uint8_t []){0x00}, 1, 0},
|
||||
{0x2A, (uint8_t []){0x00, 0x00, 0x01, 0x67}, 4, 0},
|
||||
{0x2B, (uint8_t []){0x00, 0x00, 0x01, 0x67}, 4, 0},
|
||||
{0x21, (uint8_t []){0x00}, 1, 0},
|
||||
{0x11, (uint8_t []){0x00}, 1, 120},
|
||||
};
|
||||
|
||||
static esp_err_t panel_st77916_init(esp_lcd_panel_t *panel)
|
||||
{
|
||||
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = st77916->io;
|
||||
const st77916_lcd_init_cmd_t *init_cmds = NULL;
|
||||
uint16_t init_cmds_size = 0;
|
||||
bool is_user_set = true;
|
||||
bool is_cmd_overwritten = false;
|
||||
|
||||
ESP_RETURN_ON_ERROR(tx_param(st77916, io, LCD_CMD_MADCTL, (uint8_t[]) {
|
||||
st77916->madctl_val,
|
||||
}, 1), TAG, "send command failed");
|
||||
ESP_RETURN_ON_ERROR(tx_param(st77916, io, LCD_CMD_COLMOD, (uint8_t[]) {
|
||||
st77916->colmod_val,
|
||||
}, 1), TAG, "send command failed");
|
||||
|
||||
// vendor specific initialization, it can be different between manufacturers
|
||||
// should consult the LCD supplier for initialization sequence code
|
||||
if (st77916->init_cmds) {
|
||||
init_cmds = st77916->init_cmds;
|
||||
init_cmds_size = st77916->init_cmds_size;
|
||||
} else {
|
||||
init_cmds = vendor_specific_init_default;
|
||||
init_cmds_size = sizeof(vendor_specific_init_default) / sizeof(st77916_lcd_init_cmd_t);
|
||||
}
|
||||
|
||||
for (int i = 0; i < init_cmds_size; i++) {
|
||||
// Check if the command has been used or conflicts with the internal
|
||||
if (is_user_set && (init_cmds[i].data_bytes > 0)) {
|
||||
switch (init_cmds[i].cmd) {
|
||||
case LCD_CMD_MADCTL:
|
||||
is_cmd_overwritten = true;
|
||||
st77916->madctl_val = ((uint8_t *)init_cmds[i].data)[0];
|
||||
break;
|
||||
case LCD_CMD_COLMOD:
|
||||
is_cmd_overwritten = true;
|
||||
st77916->colmod_val = ((uint8_t *)init_cmds[i].data)[0];
|
||||
break;
|
||||
default:
|
||||
is_cmd_overwritten = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_cmd_overwritten) {
|
||||
is_cmd_overwritten = false;
|
||||
ESP_LOGW(TAG, "The %02Xh command has been used and will be overwritten by external initialization sequence", init_cmds[i].cmd);
|
||||
}
|
||||
}
|
||||
|
||||
// Send command
|
||||
ESP_RETURN_ON_ERROR(tx_param(st77916, io, init_cmds[i].cmd, init_cmds[i].data, init_cmds[i].data_bytes), TAG, "send command failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(init_cmds[i].delay_ms));
|
||||
|
||||
// Check if the current cmd is the "command set" cmd
|
||||
if ((init_cmds[i].cmd == ST77916_CMD_SET)) {
|
||||
is_user_set = ((uint8_t *)init_cmds[i].data)[0] == ST77916_PARAM_SET ? true : false;
|
||||
}
|
||||
}
|
||||
ESP_LOGD(TAG, "send init commands success");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_st77916_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int y_start, int x_end, int y_end, const void *color_data)
|
||||
{
|
||||
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||
assert((x_start < x_end) && (y_start < y_end) && "start position must be smaller than end position");
|
||||
esp_lcd_panel_io_handle_t io = st77916->io;
|
||||
|
||||
x_start += st77916->x_gap;
|
||||
x_end += st77916->x_gap;
|
||||
y_start += st77916->y_gap;
|
||||
y_end += st77916->y_gap;
|
||||
|
||||
// define an area of frame memory where MCU can access
|
||||
ESP_RETURN_ON_ERROR(tx_param(st77916, io, LCD_CMD_CASET, (uint8_t[]) {
|
||||
(x_start >> 8) & 0xFF,
|
||||
x_start & 0xFF,
|
||||
((x_end - 1) >> 8) & 0xFF,
|
||||
(x_end - 1) & 0xFF,
|
||||
}, 4), TAG, "send command failed");
|
||||
ESP_RETURN_ON_ERROR(tx_param(st77916, io, LCD_CMD_RASET, (uint8_t[]) {
|
||||
(y_start >> 8) & 0xFF,
|
||||
y_start & 0xFF,
|
||||
((y_end - 1) >> 8) & 0xFF,
|
||||
(y_end - 1) & 0xFF,
|
||||
}, 4), TAG, "send command failed");
|
||||
// transfer frame buffer
|
||||
size_t len = (x_end - x_start) * (y_end - y_start) * st77916->fb_bits_per_pixel / 8;
|
||||
ESP_RETURN_ON_ERROR(tx_color(st77916, io, LCD_CMD_RAMWR, color_data, len), TAG, "send color data failed");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_st77916_invert_color(esp_lcd_panel_t *panel, bool invert_color_data)
|
||||
{
|
||||
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = st77916->io;
|
||||
int command = 0;
|
||||
if (invert_color_data) {
|
||||
command = LCD_CMD_INVON;
|
||||
} else {
|
||||
command = LCD_CMD_INVOFF;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(tx_param(st77916, io, command, NULL, 0), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_st77916_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y)
|
||||
{
|
||||
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = st77916->io;
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
if (mirror_x) {
|
||||
st77916->madctl_val |= BIT(6);
|
||||
} else {
|
||||
st77916->madctl_val &= ~BIT(6);
|
||||
}
|
||||
if (mirror_y) {
|
||||
st77916->madctl_val |= BIT(7);
|
||||
} else {
|
||||
st77916->madctl_val &= ~BIT(7);
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(tx_param(st77916, io, LCD_CMD_MADCTL, (uint8_t[]) {
|
||||
st77916->madctl_val
|
||||
}, 1), TAG, "send command failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t panel_st77916_swap_xy(esp_lcd_panel_t *panel, bool swap_axes)
|
||||
{
|
||||
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = st77916->io;
|
||||
if (swap_axes) {
|
||||
st77916->madctl_val |= LCD_CMD_MV_BIT;
|
||||
} else {
|
||||
st77916->madctl_val &= ~LCD_CMD_MV_BIT;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(tx_param(st77916, io, LCD_CMD_MADCTL, (uint8_t[]) {
|
||||
st77916->madctl_val
|
||||
}, 1), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_st77916_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap)
|
||||
{
|
||||
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||
st77916->x_gap = x_gap;
|
||||
st77916->y_gap = y_gap;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_st77916_disp_on_off(esp_lcd_panel_t *panel, bool on_off)
|
||||
{
|
||||
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = st77916->io;
|
||||
int command = 0;
|
||||
|
||||
if (on_off) {
|
||||
command = LCD_CMD_DISPON;
|
||||
} else {
|
||||
command = LCD_CMD_DISPOFF;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(tx_param(st77916, io, command, NULL, 0), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -1,11 +1,11 @@
|
||||
dependencies:
|
||||
cmake_utilities: 0.*
|
||||
idf: '>5.0.4,!=5.1.1'
|
||||
idf: '>=5.4'
|
||||
description: ESP LCD ST77916(SPI & QSPI)
|
||||
issues: https://github.com/espressif/esp-iot-solution/issues
|
||||
repository: git://github.com/espressif/esp-iot-solution.git
|
||||
repository_info:
|
||||
commit_sha: 6a112f4ddfeaf30ec360567ea9260a39e195c385
|
||||
commit_sha: 91aeb7fb41e8a3e76aeb21371f9f83711c74cf3f
|
||||
path: components/display/lcd/esp_lcd_st77916
|
||||
url: https://github.com/espressif/esp-iot-solution/tree/master/components/display/lcd/esp_lcd_st77916
|
||||
version: 1.0.1
|
||||
version: 2.0.2
|
||||
|
||||
@ -7,8 +7,13 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hal/lcd_types.h"
|
||||
#include "esp_lcd_panel_vendor.h"
|
||||
|
||||
#if SOC_MIPI_DSI_SUPPORTED
|
||||
#include "esp_lcd_mipi_dsi.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -33,12 +38,22 @@ typedef struct {
|
||||
*/
|
||||
typedef struct {
|
||||
const st77916_lcd_init_cmd_t *init_cmds; /*!< Pointer to initialization commands array.
|
||||
* Set to NULL if using default commands.
|
||||
* The array should be declared as `static const` and positioned outside the function.
|
||||
* Please refer to `vendor_specific_init_default` in source file
|
||||
*/
|
||||
uint16_t init_cmds_size; /*<! Number of commands in above array */
|
||||
union {
|
||||
#if SOC_MIPI_DSI_SUPPORTED
|
||||
struct {
|
||||
esp_lcd_dsi_bus_handle_t dsi_bus; /*!< MIPI-DSI bus configuration */
|
||||
const esp_lcd_dpi_panel_config_t *dpi_config; /*!< MIPI-DPI panel configuration */
|
||||
} mipi_config;
|
||||
#endif
|
||||
};
|
||||
struct {
|
||||
unsigned int use_qspi_interface: 1; /*<! Set to 1 if use QSPI interface, default is SPI interface */
|
||||
unsigned int use_mipi_interface: 1; /*<! Set to 1 if using MIPI interface, default is SPI interface */
|
||||
unsigned int use_qspi_interface: 1; /*<! Set to 1 if use QSPI interface, default is SPI interface (only valid for SPI mode) */
|
||||
} flags;
|
||||
} st77916_vendor_config_t;
|
||||
|
||||
@ -109,6 +124,95 @@ esp_err_t esp_lcd_new_panel_st77916(const esp_lcd_panel_io_handle_t io, const es
|
||||
}, \
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////// Default Configuration Macros for MIPI-DSI Interface //////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#if SOC_MIPI_DSI_SUPPORTED
|
||||
/**
|
||||
* @brief MIPI-DSI bus configuration structure
|
||||
*
|
||||
* @param[in] lane_num Number of data lanes
|
||||
* @param[in] lane_mbps Lane bit rate in Mbps
|
||||
*
|
||||
*/
|
||||
#define ST77916_PANEL_BUS_DSI_1CH_CONFIG() \
|
||||
{ \
|
||||
.bus_id = 0, \
|
||||
.num_data_lanes = 1, \
|
||||
.phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT, \
|
||||
.lane_bit_rate_mbps = 480, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief MIPI-DBI panel IO configuration structure
|
||||
*
|
||||
*/
|
||||
#define ST77916_PANEL_IO_DBI_CONFIG() \
|
||||
{ \
|
||||
.virtual_channel = 0, \
|
||||
.lcd_cmd_bits = 8, \
|
||||
.lcd_param_bits = 8, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief MIPI DPI configuration structure
|
||||
*
|
||||
* @note refresh_rate = (dpi_clock_freq_mhz * 1000000) / (h_res + hsync_pulse_width + hsync_back_porch + hsync_front_porch)
|
||||
* / (v_res + vsync_pulse_width + vsync_back_porch + vsync_front_porch)
|
||||
*
|
||||
* @param[in] px_format Pixel format of the panel
|
||||
*
|
||||
*/
|
||||
#define ST77916_360_360_PANEL_60HZ_DPI_CONFIG(px_format) \
|
||||
{ \
|
||||
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, \
|
||||
.dpi_clock_freq_mhz = 11, \
|
||||
.virtual_channel = 0, \
|
||||
.pixel_format = px_format, \
|
||||
.num_fbs = 1, \
|
||||
.video_timing = { \
|
||||
.h_size = 360, \
|
||||
.v_size = 360, \
|
||||
.hsync_back_porch = 60, \
|
||||
.hsync_pulse_width = 12, \
|
||||
.hsync_front_porch = 20, \
|
||||
.vsync_back_porch = 20, \
|
||||
.vsync_pulse_width = 12, \
|
||||
.vsync_front_porch = 20, \
|
||||
}, \
|
||||
.flags.use_dma2d = true, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief MIPI DPI configuration structure
|
||||
*
|
||||
* @note refresh_rate = (dpi_clock_freq_mhz * 1000000) / (h_res + hsync_pulse_width + hsync_back_porch + hsync_front_porch)
|
||||
* / (v_res + vsync_pulse_width + vsync_back_porch + vsync_front_porch)
|
||||
*
|
||||
* @param[in] color_format Input color format of the panel
|
||||
*
|
||||
*/
|
||||
#define ST77916_360_360_PANEL_60HZ_DPI_CONFIG_CF(color_format) \
|
||||
{ \
|
||||
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, \
|
||||
.dpi_clock_freq_mhz = 11, \
|
||||
.virtual_channel = 0, \
|
||||
.in_color_format = color_format, \
|
||||
.num_fbs = 1, \
|
||||
.video_timing = { \
|
||||
.h_size = 360, \
|
||||
.v_size = 360, \
|
||||
.hsync_back_porch = 60, \
|
||||
.hsync_pulse_width = 12, \
|
||||
.hsync_front_porch = 20, \
|
||||
.vsync_back_porch = 20, \
|
||||
.vsync_pulse_width = 12, \
|
||||
.vsync_front_porch = 20, \
|
||||
}, \
|
||||
.flags.use_dma2d = true, \
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_lcd_types.h"
|
||||
#include "esp_lcd_panel_vendor.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialize ST77916 LCD panel with SPI/QSPI interface
|
||||
*
|
||||
* @param[in] io LCD panel IO handle
|
||||
* @param[in] panel_dev_config LCD panel device configuration
|
||||
* @param[out] ret_panel LCD panel handle
|
||||
* @return
|
||||
* - ESP_OK: Success
|
||||
* - Otherwise: Fail
|
||||
*/
|
||||
esp_err_t esp_lcd_new_panel_st77916_spi(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel);
|
||||
|
||||
#if SOC_MIPI_DSI_SUPPORTED
|
||||
/**
|
||||
* @brief Initialize ST77916 LCD panel with MIPI interface
|
||||
*
|
||||
* @param[in] io LCD panel IO handle
|
||||
* @param[in] panel_dev_config LCD panel device configuration
|
||||
* @param[out] ret_panel LCD panel handle
|
||||
* @return
|
||||
* - ESP_OK: Success
|
||||
* - Otherwise: Fail
|
||||
*/
|
||||
esp_err_t esp_lcd_new_panel_st77916_mipi(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config,
|
||||
esp_lcd_panel_handle_t *ret_panel);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -1,6 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(test_esp_lcd_st77916)
|
||||
|
||||
@ -1 +1,3 @@
|
||||
idf_component_register(SRCS "test_esp_lcd_st77916.c")
|
||||
idf_component_register(SRC_DIRS "."
|
||||
INCLUDE_DIRS "."
|
||||
WHOLE_ARCHIVE)
|
||||
|
||||
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "unity_test_utils_memory.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
// Some resources are lazy allocated in the LCD driver, the threadhold is left for that case
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (300)
|
||||
|
||||
static size_t before_free_8bit;
|
||||
static size_t before_free_32bit;
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
unity_utils_check_leak(before_free_8bit, after_free_8bit, "8BIT", TEST_MEMORY_LEAK_THRESHOLD);
|
||||
unity_utils_check_leak(before_free_32bit, after_free_32bit, "32BIT", TEST_MEMORY_LEAK_THRESHOLD);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
/**
|
||||
* __ _____ _____ _____ ___ _ __
|
||||
* / _\/__ \___ |___ / _ \/ |/ /_
|
||||
* \ \ / /\/ / / / / (_) | | '_ \
|
||||
* _\ \ / / / / / / \__, | | (_) |
|
||||
* \__/ \/ /_/ /_/ /_/|_|\___/
|
||||
*/
|
||||
printf(" __ _____ _____ _____ ___ _ __\r\n");
|
||||
printf(" / _\\/__ \\___ |___ / _ \\/ |/ /_\r\n");
|
||||
printf(" \\ \\ / /\\/ / / / / (_) | | '_ \\\r\n");
|
||||
printf(" _\\ \\ / / / / / / \\__, | | (_) |\r\n");
|
||||
printf(" \\__/ \\/ /_/ /_/ /_/|_|\\___/\r\n");
|
||||
unity_run_menu();
|
||||
}
|
||||
@ -0,0 +1,245 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#if SOC_MIPI_DSI_SUPPORTED
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include "esp_lcd_panel_io.h"
|
||||
#include "esp_ldo_regulator.h"
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "unity_test_utils_memory.h"
|
||||
|
||||
#include "esp_lcd_mipi_dsi.h"
|
||||
#include "esp_lcd_st77916.h"
|
||||
|
||||
#define TEST_LCD_H_RES (360)
|
||||
#define TEST_LCD_V_RES (360)
|
||||
#define TEST_LCD_BIT_PER_PIXEL (24)
|
||||
#define TEST_PIN_NUM_BK_LIGHT (-1) // set to -1 if not used
|
||||
#define TEST_LCD_BK_LIGHT_ON_LEVEL (1)
|
||||
#define TEST_LCD_BK_LIGHT_OFF_LEVEL !TEST_LCD_BK_LIGHT_ON_LEVEL
|
||||
|
||||
#define TEST_PIN_NUM_LCD_RST (GPIO_NUM_NC)
|
||||
|
||||
#if TEST_LCD_BIT_PER_PIXEL == 24
|
||||
#define TEST_MIPI_DPI_PX_FORMAT (LCD_COLOR_PIXEL_FORMAT_RGB888)
|
||||
#elif TEST_LCD_BIT_PER_PIXEL == 18
|
||||
#define TEST_MIPI_DPI_PX_FORMAT (LCD_COLOR_PIXEL_FORMAT_RGB666)
|
||||
#elif TEST_LCD_BIT_PER_PIXEL == 16
|
||||
#define TEST_MIPI_DPI_PX_FORMAT (LCD_COLOR_PIXEL_FORMAT_RGB565)
|
||||
#endif
|
||||
|
||||
#define TEST_MIPI_DSI_PHY_PWR_LDO_CHAN (3)
|
||||
#define TEST_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV (2500)
|
||||
|
||||
#define TEST_DELAY_TIME_MS (3000)
|
||||
|
||||
static char *TAG = "st77916_mipi_test";
|
||||
|
||||
static esp_ldo_channel_handle_t ldo_mipi_phy = NULL;
|
||||
static esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
static esp_lcd_dsi_bus_handle_t mipi_dsi_bus = NULL;
|
||||
static esp_lcd_panel_io_handle_t mipi_dbi_io = NULL;
|
||||
static SemaphoreHandle_t refresh_finish = NULL;
|
||||
|
||||
IRAM_ATTR static bool test_notify_refresh_ready(esp_lcd_panel_handle_t panel, esp_lcd_dpi_panel_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
SemaphoreHandle_t refresh_finish = (SemaphoreHandle_t)user_ctx;
|
||||
BaseType_t need_yield = pdFALSE;
|
||||
|
||||
xSemaphoreGiveFromISR(refresh_finish, &need_yield);
|
||||
|
||||
return (need_yield == pdTRUE);
|
||||
}
|
||||
|
||||
static void test_init_lcd(void)
|
||||
{
|
||||
#if TEST_PIN_NUM_BK_LIGHT >= 0
|
||||
ESP_LOGI(TAG, "Turn on LCD backlight");
|
||||
gpio_config_t bk_gpio_config = {
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pin_bit_mask = 1ULL << TEST_PIN_NUM_BK_LIGHT
|
||||
};
|
||||
TEST_ESP_OK(gpio_config(&bk_gpio_config));
|
||||
TEST_ESP_OK(gpio_set_level(TEST_PIN_NUM_BK_LIGHT, TEST_LCD_BK_LIGHT_ON_LEVEL));
|
||||
#endif
|
||||
|
||||
// Turn on the power for MIPI DSI PHY, so it can go from "No Power" state to "Shutdown" state
|
||||
#ifdef TEST_MIPI_DSI_PHY_PWR_LDO_CHAN
|
||||
ESP_LOGI(TAG, "MIPI DSI PHY Powered on");
|
||||
esp_ldo_channel_config_t ldo_mipi_phy_config = {
|
||||
.chan_id = TEST_MIPI_DSI_PHY_PWR_LDO_CHAN,
|
||||
.voltage_mv = TEST_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV,
|
||||
};
|
||||
TEST_ESP_OK(esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldo_mipi_phy));
|
||||
#endif
|
||||
|
||||
ESP_LOGI(TAG, "Initialize MIPI DSI bus");
|
||||
esp_lcd_dsi_bus_config_t bus_config = ST77916_PANEL_BUS_DSI_1CH_CONFIG();
|
||||
TEST_ESP_OK(esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus));
|
||||
|
||||
ESP_LOGI(TAG, "Install panel IO");
|
||||
esp_lcd_dbi_io_config_t dbi_config = ST77916_PANEL_IO_DBI_CONFIG();
|
||||
TEST_ESP_OK(esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &mipi_dbi_io));
|
||||
|
||||
ESP_LOGI(TAG, "Install LCD driver of st77916");
|
||||
esp_lcd_dpi_panel_config_t dpi_config = ST77916_360_360_PANEL_60HZ_DPI_CONFIG(TEST_MIPI_DPI_PX_FORMAT);
|
||||
st77916_vendor_config_t vendor_config = {
|
||||
.flags.use_mipi_interface = 1,
|
||||
.mipi_config = {
|
||||
.dsi_bus = mipi_dsi_bus,
|
||||
.dpi_config = &dpi_config,
|
||||
},
|
||||
};
|
||||
const esp_lcd_panel_dev_config_t panel_config = {
|
||||
.reset_gpio_num = TEST_PIN_NUM_LCD_RST,
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
|
||||
.bits_per_pixel = TEST_LCD_BIT_PER_PIXEL,
|
||||
.vendor_config = &vendor_config,
|
||||
};
|
||||
TEST_ESP_OK(esp_lcd_new_panel_st77916(mipi_dbi_io, &panel_config, &panel_handle));
|
||||
TEST_ESP_OK(esp_lcd_panel_reset(panel_handle));
|
||||
TEST_ESP_OK(esp_lcd_panel_init(panel_handle));
|
||||
TEST_ESP_OK(esp_lcd_panel_disp_on_off(panel_handle, true));
|
||||
|
||||
refresh_finish = xSemaphoreCreateBinary();
|
||||
TEST_ASSERT_NOT_NULL(refresh_finish);
|
||||
esp_lcd_dpi_panel_event_callbacks_t cbs = {
|
||||
.on_color_trans_done = test_notify_refresh_ready,
|
||||
};
|
||||
TEST_ESP_OK(esp_lcd_dpi_panel_register_event_callbacks(panel_handle, &cbs, refresh_finish));
|
||||
}
|
||||
|
||||
static void test_deinit_lcd(void)
|
||||
{
|
||||
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
|
||||
TEST_ESP_OK(esp_lcd_panel_io_del(mipi_dbi_io));
|
||||
TEST_ESP_OK(esp_lcd_del_dsi_bus(mipi_dsi_bus));
|
||||
panel_handle = NULL;
|
||||
mipi_dbi_io = NULL;
|
||||
mipi_dsi_bus = NULL;
|
||||
|
||||
if (ldo_mipi_phy) {
|
||||
TEST_ESP_OK(esp_ldo_release_channel(ldo_mipi_phy));
|
||||
ldo_mipi_phy = NULL;
|
||||
}
|
||||
|
||||
vSemaphoreDelete(refresh_finish);
|
||||
refresh_finish = NULL;
|
||||
|
||||
#if TEST_PIN_NUM_BK_LIGHT >= 0
|
||||
TEST_ESP_OK(gpio_reset_pin(TEST_PIN_NUM_BK_LIGHT));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void test_draw_color_bar(esp_lcd_panel_handle_t panel_handle, uint16_t h_res, uint16_t v_res)
|
||||
{
|
||||
uint8_t byte_per_pixel = (TEST_LCD_BIT_PER_PIXEL + 7) / 8;
|
||||
uint16_t row_line = v_res / byte_per_pixel / 8;
|
||||
uint8_t *color = (uint8_t *)heap_caps_calloc(1, row_line * h_res * byte_per_pixel, MALLOC_CAP_DMA);
|
||||
|
||||
for (int j = 0; j < byte_per_pixel * 8; j++) {
|
||||
for (int i = 0; i < row_line * h_res; i++) {
|
||||
for (int k = 0; k < byte_per_pixel; k++) {
|
||||
color[i * byte_per_pixel + k] = (BIT(j) >> (k * 8)) & 0xff;
|
||||
}
|
||||
}
|
||||
TEST_ESP_OK(esp_lcd_panel_draw_bitmap(panel_handle, 0, j * row_line, h_res, (j + 1) * row_line, color));
|
||||
xSemaphoreTake(refresh_finish, portMAX_DELAY);
|
||||
}
|
||||
|
||||
uint16_t color_line = row_line * byte_per_pixel * 8;
|
||||
uint16_t res_line = v_res - color_line;
|
||||
if (res_line) {
|
||||
for (int i = 0; i < res_line * h_res; i++) {
|
||||
for (int k = 0; k < byte_per_pixel; k++) {
|
||||
color[i * byte_per_pixel + k] = 0xff;
|
||||
}
|
||||
}
|
||||
TEST_ESP_OK(esp_lcd_panel_draw_bitmap(panel_handle, 0, color_line, h_res, v_res, color));
|
||||
xSemaphoreTake(refresh_finish, portMAX_DELAY);
|
||||
}
|
||||
|
||||
free(color);
|
||||
}
|
||||
|
||||
TEST_CASE("test st77916 to draw pattern with MIPI interface", "[st77916][draw_pattern]")
|
||||
{
|
||||
ESP_LOGI(TAG, "Initialize LCD device");
|
||||
test_init_lcd();
|
||||
|
||||
ESP_LOGI(TAG, "Show color bar pattern drawn by hardware");
|
||||
TEST_ESP_OK(esp_lcd_dpi_panel_set_pattern(panel_handle, MIPI_DSI_PATTERN_BAR_VERTICAL));
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_TIME_MS));
|
||||
TEST_ESP_OK(esp_lcd_dpi_panel_set_pattern(panel_handle, MIPI_DSI_PATTERN_BAR_HORIZONTAL));
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_TIME_MS));
|
||||
TEST_ESP_OK(esp_lcd_dpi_panel_set_pattern(panel_handle, MIPI_DSI_PATTERN_NONE));
|
||||
|
||||
ESP_LOGI(TAG, "Deinitialize LCD device");
|
||||
test_deinit_lcd();
|
||||
}
|
||||
|
||||
TEST_CASE("test st77916 to draw color bar with MIPI interface", "[st77916][draw_color_bar]")
|
||||
{
|
||||
ESP_LOGI(TAG, "Initialize LCD device");
|
||||
test_init_lcd();
|
||||
|
||||
ESP_LOGI(TAG, "Show color bar drawn by software");
|
||||
test_draw_color_bar(panel_handle, TEST_LCD_H_RES, TEST_LCD_V_RES);
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_TIME_MS));
|
||||
|
||||
ESP_LOGI(TAG, "Deinitialize LCD device");
|
||||
test_deinit_lcd();
|
||||
}
|
||||
|
||||
TEST_CASE("test st77916 to rotate with MIPI interface", "[st77916][mipi-rotate]")
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
uint16_t w = 0;
|
||||
uint16_t h = 0;
|
||||
int64_t t = 0;
|
||||
|
||||
ESP_LOGI(TAG, "Initialize LCD device");
|
||||
test_init_lcd();
|
||||
|
||||
ESP_LOGI(TAG, "Rotate the screen");
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
if (ret != ESP_ERR_NOT_SUPPORTED) {
|
||||
if (i & 4) {
|
||||
w = TEST_LCD_V_RES;
|
||||
h = TEST_LCD_H_RES;
|
||||
} else {
|
||||
w = TEST_LCD_H_RES;
|
||||
h = TEST_LCD_V_RES;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_ASSERT_NOT_EQUAL(esp_lcd_panel_mirror(panel_handle, i & 2, i & 1), ESP_FAIL);
|
||||
ret = esp_lcd_panel_swap_xy(panel_handle, i & 4);
|
||||
TEST_ASSERT_NOT_EQUAL(ret, ESP_FAIL);
|
||||
|
||||
ESP_LOGI(TAG, "Rotation: %d", i);
|
||||
t = esp_timer_get_time();
|
||||
test_draw_color_bar(panel_handle, w, h);
|
||||
t = esp_timer_get_time() - t;
|
||||
ESP_LOGI(TAG, "@resolution %dx%d time per frame=%.2fMS\r\n", w, h, (float)t / 1000.0f);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Deinitialize LCD device");
|
||||
test_deinit_lcd();
|
||||
}
|
||||
#endif
|
||||
@ -141,47 +141,3 @@ TEST_CASE("test st77916 to draw color bar with QSPI interface", "[st77916][qspi]
|
||||
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
|
||||
TEST_ESP_OK(spi_bus_free(TEST_LCD_HOST));
|
||||
}
|
||||
|
||||
// Some resources are lazy allocated in the LCD driver, the threadhold is left for that case
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (-300)
|
||||
|
||||
static size_t before_free_8bit;
|
||||
static size_t before_free_32bit;
|
||||
|
||||
static void check_leak(size_t before_free, size_t after_free, const char *type)
|
||||
{
|
||||
ssize_t delta = after_free - before_free;
|
||||
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
|
||||
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
|
||||
}
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
check_leak(before_free_8bit, after_free_8bit, "8BIT");
|
||||
check_leak(before_free_32bit, after_free_32bit, "32BIT");
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
/**
|
||||
* __ _____ _____ _____ ___ _ __
|
||||
* / _\/__ \___ |___ / _ \/ |/ /_
|
||||
* \ \ / /\/ / / / / (_) | | '_ \
|
||||
* _\ \ / / / / / / \__, | | (_) |
|
||||
* \__/ \/ /_/ /_/ /_/|_|\___/
|
||||
*/
|
||||
printf(" __ _____ _____ _____ ___ _ __\r\n");
|
||||
printf(" / _\\/__ \\___ |___ / _ \\/ |/ /\r\n");
|
||||
printf(" \\ \\ / /\\/ / / / / (_) | | '_ \r\n");
|
||||
printf(" _\\ \\ / / / / / / \\__, | | (_) |\r\n");
|
||||
printf(" \\__/ \\/ /_/ /_/ /_/|_|\\___/\r\n");
|
||||
unity_run_menu();
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
CONFIG_IDF_TARGET="esp32p4"
|
||||
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_PERF=y
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_SPEED_200M=y
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=4096
|
||||
CONFIG_IDF_EXPERIMENTAL_FEATURES=y
|
||||
@ -0,0 +1,8 @@
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_PERF=y
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_MODE_OCT=y
|
||||
CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y
|
||||
CONFIG_SPIRAM_RODATA=y
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
|
||||
@ -0,0 +1 @@
|
||||
{"version": "1.0", "algorithm": "sha256", "created_at": "2025-07-15T10:57:47.123029+00:00", "files": [{"path": "CMakeLists.txt", "size": 97, "hash": "d4040e28d59a678c38fb13f6ff29881cb38f9d2fac05fd4b8aed03217a5c7c8c"}, {"path": "Kconfig", "size": 264, "hash": "761b9f2ac330cba6f0c20e468fccf9b9102ad6850662ae1ca275a96e8618614f"}, {"path": "README.md", "size": 3649, "hash": "5148d990b8ae99f98c658f11c78ce45895d4ff15ea36215a54fd82f4bab124f9"}, {"path": "esp_lcd_touch_cst816s.c", "size": 6287, "hash": "01b3594c722b1fe6f05d254b081d6a4e8014d56b0f0e06c58d298d4fa882ce0c"}, {"path": "idf_component.yml", "size": 310, "hash": "db2bba3e94b118082f0dbcef98a8d29acef18a93d24c4a414661679ab5e0c431"}, {"path": "license.txt", "size": 11358, "hash": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30"}, {"path": "include/esp_lcd_touch_cst816s.h", "size": 2783, "hash": "04963086236fcd655e8181a98cfa30a9aabf1b5ae6ad6917c7b91f8dcf819857"}, {"path": "test_apps/CMakeLists.txt", "size": 323, "hash": "b9ab8ef50938023920a2c970fa71ca85db6a15f7929007f7f10a84402ceee2b8"}, {"path": "test_apps/sdkconfig.defaults", "size": 49, "hash": "dccb276c3ef85f8f4d6c32edf7c8b582cf2d416f42950b778d7af95a9808e7d4"}, {"path": "test_apps/main/CMakeLists.txt", "size": 60, "hash": "f593b1ac477df2a76bb8c338660adcbd45e1f0f7e0bd8ddc135a566e39d1f62d"}, {"path": "test_apps/main/idf_component.yml", "size": 162, "hash": "ef2ce20977812a320b63bf45f407c4d8b24a679f92adb85fd4db574ef115995b"}, {"path": "test_apps/main/test_esp_lcd_touch_cst816s.c", "size": 2080, "hash": "040124f0040988334ae7d40709c3747304e1538d3f8a8e48cbf45cc8121d2be1"}]}
|
||||
@ -166,9 +166,9 @@ static esp_err_t reset(esp_lcd_touch_handle_t tp)
|
||||
{
|
||||
if (tp->config.rst_gpio_num != GPIO_NUM_NC) {
|
||||
ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, tp->config.levels.reset), TAG, "GPIO set level failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(10)); // 优化:200ms → 10ms
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, !tp->config.levels.reset), TAG, "GPIO set level failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(30)); // 优化:200ms → 30ms
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
@ -72,6 +72,7 @@ esp_err_t esp_lcd_touch_new_i2c_cst816s(const esp_lcd_panel_io_handle_t io, cons
|
||||
.dc_low_on_data = 0, \
|
||||
.disable_control_phase = 1, \
|
||||
}, \
|
||||
.scl_speed_hz = 100000 \
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@ -95,9 +95,7 @@ static void lvgl_port_touchpad_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *
|
||||
data->point.x = touchpad_x[0];
|
||||
data->point.y = touchpad_y[0];
|
||||
data->state = LV_INDEV_STATE_PRESSED;
|
||||
ESP_LOGI(TAG, "Touch detected: x=%d, y=%d, count=%d", touchpad_x[0], touchpad_y[0], touchpad_cnt);
|
||||
} else {
|
||||
data->state = LV_INDEV_STATE_RELEASED;
|
||||
// ESP_LOGI(TAG, "Touch released");
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,11 +41,10 @@ extern "C" {
|
||||
#define LV_INDEV_DEF_LONG_PRESS_REP_TIME 100
|
||||
|
||||
|
||||
/*Gesture threshold in pixels*/
|
||||
#define LV_INDEV_DEF_GESTURE_LIMIT 50
|
||||
|
||||
/*手势阈值(像素)*/
|
||||
#define LV_INDEV_DEF_GESTURE_LIMIT 20
|
||||
|
||||
/*滑动前释放时的手势最小速度(像素)*/
|
||||
/*Gesture min velocity at release before swipe (pixels)*/
|
||||
#define LV_INDEV_DEF_GESTURE_MIN_VELOCITY 3
|
||||
|
||||
|
||||
|
||||
1211
sdkconfig.old
1211
sdkconfig.old
File diff suppressed because it is too large
Load Diff
89
性能分析报告.md
Normal file
89
性能分析报告.md
Normal file
@ -0,0 +1,89 @@
|
||||
I (24) boot: ESP-IDF v5.4.2-dirty 2nd stage bootloader
|
||||
I (24) boot: compile time Feb 12 2026 14:18:02
|
||||
I (25) boot: chip revision: v0.4
|
||||
I (25) boot: efuse block revision: v1.3
|
||||
I (29) boot.esp32c3: SPI Speed : 80MHz
|
||||
I (32) boot.esp32c3: SPI Mode : DIO
|
||||
I (36) boot.esp32c3: SPI Flash Size : 8MB
|
||||
I (40) boot: Enabling RNG early entropy source...
|
||||
I (44) boot: Partition Table:
|
||||
I (47) boot: ## Label Usage Type ST Offset Length
|
||||
I (53) boot: 0 nvs WiFi data 01 02 00009000 00006000
|
||||
I (60) boot: 1 phy_init RF data 01 01 0000f000 00001000
|
||||
I (66) boot: 2 factory factory app 00 00 00010000 00400000
|
||||
I (73) boot: 3 storage Unknown data 01 82 00410000 00200000
|
||||
I (79) boot: End of partition table
|
||||
I (83) esp_image: segment 0: paddr=00010020 vaddr=3c070020 size=7c8e4h (510180) map
|
||||
I (171) esp_image: segment 1: paddr=0008c90c vaddr=3fc91000 size=01c10h ( 7184) load
|
||||
I (173) esp_image: segment 2: paddr=0008e524 vaddr=40380000 size=01af4h ( 6900) load
|
||||
I (177) esp_image: segment 3: paddr=00090020 vaddr=42000020 size=6a170h (434544) map
|
||||
I (252) esp_image: segment 4: paddr=000fa198 vaddr=40381af4 size=0f300h ( 62208) load
|
||||
I (264) esp_image: segment 5: paddr=001094a0 vaddr=50000000 size=0001ch ( 28) load
|
||||
I (269) boot: Loaded app from partition at offset 0x10000
|
||||
I (269) boot: Disabling RNG early entropy source...
|
||||
I (281) cpu_start: Unicore app
|
||||
I (290) cpu_start: Pro cpu start user code
|
||||
I (290) cpu_start: cpu freq: 160000000 Hz
|
||||
I (290) app_init: Application information:
|
||||
I (290) app_init: Project name: program
|
||||
I (294) app_init: App version: 455c92d-dirty
|
||||
I (298) app_init: Compile time: Feb 12 2026 14:17:45
|
||||
I (303) app_init: ELF file SHA256: ab5b876f8...
|
||||
I (308) app_init: ESP-IDF: v5.4.2-dirty
|
||||
I (312) efuse_init: Min chip rev: v0.3
|
||||
I (316) efuse_init: Max chip rev: v1.99
|
||||
I (320) efuse_init: Chip rev: v0.4
|
||||
I (324) heap_init: Initializing. RAM available for dynamic allocation:
|
||||
I (330) heap_init: At 3FCA0510 len 0001FAF0 (126 KiB): RAM
|
||||
I (335) heap_init: At 3FCC0000 len 0001C710 (113 KiB): Retention RAM
|
||||
I (341) heap_init: At 3FCDC710 len 00002950 (10 KiB): Retention RAM
|
||||
I (347) heap_init: At 5000001C len 00001FCC (7 KiB): RTCRAM
|
||||
I (353) spi_flash: detected chip: mxic
|
||||
I (356) spi_flash: flash io: dio
|
||||
W (359) i2c: This driver is an old driver, please migrate your application code to adapt `driver/i2c_master.h`
|
||||
I (369) sleep_gpio: Configure to isolate all GPIO pins in sleep state
|
||||
I (375) sleep_gpio: Enable automatic switching of GPIO sleep configuration
|
||||
I (393) coexist: coex firmware version: 7b9a184
|
||||
I (393) coexist: coexist rom version 9387209
|
||||
I (394) main_task: Started on CPU0
|
||||
I (394) main_task: Calling app_main()
|
||||
I (394) MAIN: 1. I2C已初始化
|
||||
I (404) MAIN: 2. NVS已初始化
|
||||
I (404) st77916: version: 2.0.2
|
||||
I (404) st77916_spi: LCD panel create success, version: 2.0.2
|
||||
W (524) st77916_spi: The 3Ah command has been used and will be overwritten by external initialization sequence
|
||||
I (684) LCD: LCD GRAM cleared (black filled)
|
||||
I (694) MAIN: 3. LCD已初始化
|
||||
I (694) gpio: GPIO[10]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:2
|
||||
I (694) CST816S: IC id: 182
|
||||
I (694) LCD: Touch controller initialized successfully
|
||||
I (704) MAIN: 4. 触摸控制器已初始化
|
||||
I (704) LVGL: Starting LVGL task
|
||||
I (704) LCD: LVGL buffer size: 21600 bytes (W: 360, Lines: 30)
|
||||
I (714) LCD: Touch controller added to LVGL
|
||||
I (714) MAIN: 5. LVGL已初始化
|
||||
I (774) FATFS: SPIFFS: Total size: 1920401, Used: 68774
|
||||
I (774) MAIN: 6. FATFS文件系统已初始化
|
||||
I (834) FATFS: 文件名: /spiflash/02.jpg,大小:20498
|
||||
I (834) FATFS: 文件名: /spiflash/default.jpg,大小:47430
|
||||
I (874) MAIN: 7. SPIFFS处理完成
|
||||
I (894) MAIN: 8. SquareLine UI已初始化
|
||||
I (1144) MAIN: 8.1 LCD显示已打开
|
||||
I (1144) MAIN: 9. PWM背光已初始化
|
||||
I (1144) gpio: GPIO[2]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
|
||||
I (1144) BAT: ADC校准初始化成功
|
||||
I (1144) BAT: 电池ADC初始化完成 (GPIO2, ADC1_CH2, 分压比=2)
|
||||
I (1154) MAIN: 10. 电池ADC已初始化
|
||||
I (1154) BAT: ADC原始值=3267, ADC电压=2393mV, 电池电压=4786mV, 电量=100%
|
||||
I (1164) BAT: 电池监控任务已启动,更新间隔5000ms
|
||||
I (1174) MAIN: 11. 电池监控任务已启动
|
||||
I (1174) gpio: GPIO[8]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:2
|
||||
I (1184) gpio: GPIO[9]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:2
|
||||
I (1194) BTN: 按键初始化完成 (BOOT=GPIO9, KEY2=GPIO8)
|
||||
I (1194) MAIN: 12. 按键已初始化
|
||||
I (1204) MAIN: 12.1 BOOT按键回调已注册
|
||||
I (1254) SLEEP: 休眠管理器初始化完成(超时=10s)
|
||||
I (1254) MAIN: 13. 休眠管理器已初始化
|
||||
I (1264) MAIN: 系统初始化完成成功!
|
||||
I (1264) main_task: Returned from app_main()
|
||||
I (6164) BAT: ADC原始值=3276, ADC电压=2400mV, 电池电压=4800mV, 电量=100%
|
||||
371
设备运行日志.md
371
设备运行日志.md
@ -1,282 +1,89 @@
|
||||
rdzleo@RdzleodeMac-Studio dzbj % '/Users/rdzleo/.espressif/python_env/idf5.4_py3.13_env/bin/python3' '/Users/rd
|
||||
zleo/esp/esp-idf/v5.4.2/esp-idf/tools/idf_monitor.py' -p /dev/tty.usbmodem834401 -b 115200 --toolchain-prefix x
|
||||
tensa-esp32s3-elf- --make ''/Users/rdzleo/.espressif/python_env/idf5.4_py3.13_env/bin/python3' '/Users/rdzleo/e
|
||||
sp/esp-idf/v5.4.2/esp-idf/tools/idf.py'' --target esp32s3 '/Users/rdzleo/Desktop/dzbj/build/program.elf'
|
||||
--- Warning: Serial ports accessed as /dev/tty.* will hang gdb if launched.
|
||||
--- Using /dev/cu.usbmodem834401 instead...
|
||||
--- esp-idf-monitor 1.8.0 on /dev/cu.usbmodem834401 115200
|
||||
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H
|
||||
This driver is aESP-ROM:esp32s3-20210327
|
||||
Build:Mar 27 2021
|
||||
rst:0x15 (USB_UART_CHIP_RESET),boot:0x2b (SPI_FAST_FLASH_BOOT)
|
||||
Saved PC:0x40048836
|
||||
--- 0x40048836: uart_tx_one_char_uart in ROM
|
||||
SPIWP:0xee
|
||||
mode:DIO, clock div:1
|
||||
load:0x3fce2820,len:0x16d0
|
||||
load:0x403c8700,len:0x4
|
||||
load:0x403c8704,len:0xec8
|
||||
load:0x403cb700,len:0x3160
|
||||
entry 0x403c8950
|
||||
I (26) boot: ESP-IDF v5.4.2-dirty 2nd stage bootloader
|
||||
I (27) boot: compile time Feb 9 2026 10:08:02
|
||||
I (27) boot: Multicore bootloader
|
||||
I (27) boot: chip revision: v0.2
|
||||
I (30) boot: efuse block revision: v1.3
|
||||
I (34) qio_mode: Enabling default flash chip QIO
|
||||
I (38) boot.esp32s3: Boot SPI Speed : 80MHz
|
||||
I (42) boot.esp32s3: SPI Mode : QIO
|
||||
I (46) boot.esp32s3: SPI Flash Size : 16MB
|
||||
I (50) boot: Enabling RNG early entropy source...
|
||||
I (54) boot: Partition Table:
|
||||
I (57) boot: ## Label Usage Type ST Offset Length
|
||||
I (63) boot: 0 nvs WiFi data 01 02 00009000 00006000
|
||||
I (70) boot: 1 phy_init RF data 01 01 0000f000 00001000
|
||||
I (76) boot: 2 factory factory app 00 00 00010000 00400000
|
||||
I (83) boot: 3 storage Unknown data 01 82 00410000 00200000
|
||||
I (89) boot: End of partition table
|
||||
I (92) esp_image: segment 0: paddr=00010020 vaddr=3c060020 size=78508h (492808) map
|
||||
I (173) esp_image: segment 1: paddr=00088530 vaddr=3fc98600 size=03688h ( 13960) load
|
||||
I (176) esp_image: segment 2: paddr=0008bbc0 vaddr=40374000 size=04458h ( 17496) load
|
||||
I (180) esp_image: segment 3: paddr=00090020 vaddr=42000020 size=5c8ech (379116) map
|
||||
I (241) esp_image: segment 4: paddr=000ec914 vaddr=40378458 size=1015ch ( 65884) load
|
||||
I (253) esp_image: segment 5: paddr=000fca78 vaddr=600fe000 size=0001ch ( 28) load
|
||||
I (262) boot: Loaded app from partition at offset 0x10000
|
||||
I (262) boot: Disabling RNG early entropy source...
|
||||
I (272) octal_psram: ECC is enabled
|
||||
I (272) octal_psram: vendor id : 0x0d (AP)
|
||||
I (272) octal_psram: dev id : 0x02 (generation 3)
|
||||
I (273) octal_psram: density : 0x03 (64 Mbit)
|
||||
I (277) octal_psram: good-die : 0x01 (Pass)
|
||||
I (282) octal_psram: Latency : 0x01 (Fixed)
|
||||
I (286) octal_psram: VCC : 0x01 (3V)
|
||||
I (290) octal_psram: SRF : 0x01 (Fast Refresh)
|
||||
I (295) octal_psram: BurstType : 0x00 ( Wrap)
|
||||
I (299) octal_psram: BurstLen : 0x03 (1024 Byte)
|
||||
I (304) octal_psram: Readlatency : 0x02 (10 cycles@Fixed)
|
||||
I (309) octal_psram: DriveStrength: 0x00 (1/1)
|
||||
I (314) MSPI Timing: PSRAM timing tuning index: 5
|
||||
I (318) esp_psram: Found 8MB PSRAM device
|
||||
I (322) esp_psram: Speed: 80MHz
|
||||
I (364) mmu_psram: Read only data copied and mapped to SPIRAM
|
||||
I (395) mmu_psram: Instructions copied and mapped to SPIRAM
|
||||
I (396) cpu_start: Multicore app
|
||||
I (795) esp_psram: SPI SRAM memory test OK
|
||||
I (803) cpu_start: Pro cpu start user code
|
||||
I (803) cpu_start: cpu freq: 160000000 Hz
|
||||
I (803) app_init: Application information:
|
||||
I (804) app_init: Project name: program
|
||||
I (807) app_init: App version: 1
|
||||
I (811) app_init: Compile time: Feb 9 2026 10:07:49
|
||||
I (816) app_init: ELF file SHA256: fe13bd2c7...
|
||||
I (820) app_init: ESP-IDF: v5.4.2-dirty
|
||||
I (824) efuse_init: Min chip rev: v0.0
|
||||
I (828) efuse_init: Max chip rev: v0.99
|
||||
I (832) efuse_init: Chip rev: v0.2
|
||||
I (836) heap_init: Initializing. RAM available for dynamic allocation:
|
||||
I (842) heap_init: At 3FCACCB0 len 0003CA60 (242 KiB): RAM
|
||||
I (847) heap_init: At 3FCE9710 len 00005724 (21 KiB): RAM
|
||||
I (853) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
|
||||
I (858) heap_init: At 600FE01C len 00001FCC (7 KiB): RTCRAM
|
||||
I (863) esp_psram: Adding pool of 6784K of PSRAM memory to heap allocator
|
||||
I (870) esp_psram: Adding pool of 30K of PSRAM memory gap generated due to end address alignment of drom to the heap allocator
|
||||
I (881) spi_flash: detected chip: generic
|
||||
I (884) spi_flash: flash io: qio
|
||||
W (888) i2c: This driver is an old driver, please migrate your application code to adapt `driver/i2c_master.h`
|
||||
I (897) sleep_gpio: Configure to isolate all GPIO pins in sleep state
|
||||
I (904) sleep_gpio: Enable automatic switching of GPIO sleep configuration
|
||||
I (910) coexist: coex firmware version: 7b9a184
|
||||
I (914) coexist: coexist rom version e7ae62f
|
||||
I (919) main_task: Started on CPU0
|
||||
I (929) esp_psram: Reserving pool of 32K of internal memory for DMA/internal allocations
|
||||
I (929) main_task: Calling app_main()
|
||||
I (929) MAIN: Starting system initialization...
|
||||
I (939) MAIN: 1. Initializing I2C...
|
||||
I (939) MAIN: I2C initialized successfully
|
||||
I (949) MAIN: 2. Initializing NVS...
|
||||
I (949) MAIN: NVS initialized successfully
|
||||
I (949) MAIN: 3. Initializing LCD...
|
||||
I (959) gpio: GPIO[7]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
|
||||
I (959) st77916: LCD panel create success, version: 1.0.1
|
||||
W (1109) st77916: The 3Ah command has been used and will be overwritten by external initialization sequence
|
||||
I (1229) MAIN: LCD initialized successfully
|
||||
I (1229) MAIN: 4. Initializing touch controller...
|
||||
I (1229) gpio: GPIO[4]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:2
|
||||
I (1229) gpio: GPIO[6]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
|
||||
I (1639) CST816S: IC id: 182
|
||||
I (1639) LCD: Touch controller initialized successfully
|
||||
I (1639) MAIN: Touch controller initialized
|
||||
I (1639) MAIN: 5. Initializing LVGL...
|
||||
I (1639) LVGL: Starting LVGL task
|
||||
I (1639) LCD: LVGL buffer size: 21600 bytes (W: 360, Lines: 30)
|
||||
I (1649) LCD: Touch controller added to LVGL
|
||||
I (1649) MAIN: LVGL initialized successfully
|
||||
I (1759) MAIN: LVGL task started
|
||||
I (1759) MAIN: 6. Initializing FATFS...
|
||||
I (1809) FATFS: SPIFFS: Total size: 1920401, Used: 78061
|
||||
I (1809) MAIN: FATFS initialized successfully
|
||||
I (1809) MAIN: 7. Initializing PWM backlight...
|
||||
I (1809) MAIN: PWM backlight initialized successfully
|
||||
I (1809) MAIN: 8. Processing SPIFFS...
|
||||
I (1879) FATFS: 文件名: /spiflash/03.jpg,大小:8805
|
||||
I (1879) FATFS: 文件名: /spiflash/02.jpg,大小:20498
|
||||
I (1879) FATFS: 文件名: /spiflash/default.jpg,大小:47430
|
||||
I (1909) MAIN: 9. Initializing SquareLine UI...
|
||||
I (1969) MAIN: SquareLine UI initialized
|
||||
I (1969) MAIN: 10. Waiting for UI rendering...
|
||||
I (2039) MAIN: Rendering step 1 completed
|
||||
I (2089) MAIN: Rendering step 2 completed
|
||||
I (2139) MAIN: Rendering step 3 completed
|
||||
I (2139) MAIN: UI rendering completed
|
||||
I (2139) MAIN: System initialization finished successfully!
|
||||
I (2139) main_task: Returned from app_main()
|
||||
I (6789) LVGL: Touch detected: x=175, y=36, count=1
|
||||
I (6819) LVGL: Touch detected: x=178, y=41, count=1
|
||||
I (6849) LVGL: Touch detected: x=183, y=50, count=1
|
||||
I (6879) LVGL: Touch detected: x=190, y=65, count=1
|
||||
I (6929) LVGL: Touch detected: x=208, y=122, count=1
|
||||
I (6959) LVGL: Touch detected: x=218, y=161, count=1
|
||||
I (6989) LVGL: Touch detected: x=232, y=201, count=1
|
||||
I (7019) LVGL: Touch detected: x=251, y=243, count=1
|
||||
I (7049) LVGL: Touch detected: x=263, y=265, count=1
|
||||
I (7829) LVGL: Touch detected: x=191, y=328, count=1
|
||||
I (7859) LVGL: Touch detected: x=192, y=326, count=1
|
||||
I (7889) LVGL: Touch detected: x=195, y=313, count=1
|
||||
I (7919) LVGL: Touch detected: x=199, y=287, count=1
|
||||
I (9389) LVGL: Touch detected: x=200, y=34, count=1
|
||||
I (9419) LVGL: Touch detected: x=200, y=34, count=1
|
||||
I (9449) LVGL: Touch detected: x=200, y=34, count=1
|
||||
I (9479) LVGL: Touch detected: x=201, y=36, count=1
|
||||
I (9509) LVGL: Touch detected: x=205, y=49, count=1
|
||||
I (9539) LVGL: Touch detected: x=209, y=66, count=1
|
||||
I (9579) LVGL: Touch detected: x=217, y=100, count=1
|
||||
I (9609) LVGL: Touch detected: x=221, y=121, count=1
|
||||
I (9639) LVGL: Touch detected: x=227, y=141, count=1
|
||||
I (9669) LVGL: Touch detected: x=235, y=161, count=1
|
||||
I (9699) LVGL: Touch detected: x=243, y=178, count=1
|
||||
I (10509) LVGL: Touch detected: x=195, y=326, count=1
|
||||
I (10539) LVGL: Touch detected: x=195, y=325, count=1
|
||||
I (10569) LVGL: Touch detected: x=198, y=313, count=1
|
||||
I (10599) LVGL: Touch detected: x=201, y=290, count=1
|
||||
I (11409) LVGL: Touch detected: x=10, y=157, count=1
|
||||
I (11439) LVGL: Touch detected: x=10, y=157, count=1
|
||||
I (11469) LVGL: Touch detected: x=11, y=157, count=1
|
||||
I (11499) LVGL: Touch detected: x=23, y=157, count=1
|
||||
I (11529) LVGL: Touch detected: x=45, y=157, count=1
|
||||
I (11559) LVGL: Touch detected: x=87, y=157, count=1
|
||||
I (11589) LVGL: Touch detected: x=142, y=157, count=1
|
||||
I (11619) LVGL: Touch detected: x=221, y=157, count=1
|
||||
I (11649) LVGL: Touch detected: x=258, y=157, count=1
|
||||
I (12189) LVGL: Touch detected: x=352, y=159, count=1
|
||||
I (12219) LVGL: Touch detected: x=352, y=159, count=1
|
||||
I (12249) LVGL: Touch detected: x=351, y=159, count=1
|
||||
I (12279) LVGL: Touch detected: x=332, y=156, count=1
|
||||
I (12309) LVGL: Touch detected: x=305, y=152, count=1
|
||||
I (12339) LVGL: Touch detected: x=273, y=146, count=1
|
||||
I (12369) LVGL: Touch detected: x=245, y=141, count=1
|
||||
I (12399) LVGL: Touch detected: x=217, y=137, count=1
|
||||
I (12429) LVGL: Touch detected: x=187, y=132, count=1
|
||||
I (12969) LVGL: Touch detected: x=165, y=36, count=1
|
||||
I (12999) LVGL: Touch detected: x=165, y=36, count=1
|
||||
I (13029) LVGL: Touch detected: x=166, y=40, count=1
|
||||
I (13059) LVGL: Touch detected: x=171, y=56, count=1
|
||||
I (13089) LVGL: Touch detected: x=180, y=86, count=1
|
||||
I (13139) LVGL: Touch detected: x=195, y=137, count=1
|
||||
I (13169) LVGL: Touch detected: x=205, y=168, count=1
|
||||
I (13199) LVGL: Touch detected: x=215, y=193, count=1
|
||||
I (13709) LVGL: Touch detected: x=181, y=321, count=1
|
||||
I (13739) LVGL: Touch detected: x=179, y=312, count=1
|
||||
I (13769) LVGL: Touch detected: x=178, y=291, count=1
|
||||
I (14309) LVGL: Touch detected: x=211, y=25, count=1
|
||||
I (14339) LVGL: Touch detected: x=211, y=25, count=1
|
||||
I (14369) LVGL: Touch detected: x=211, y=28, count=1
|
||||
I (14399) LVGL: Touch detected: x=214, y=39, count=1
|
||||
I (14429) LVGL: Touch detected: x=221, y=62, count=1
|
||||
I (14469) LVGL: Touch detected: x=241, y=112, count=1
|
||||
I (14499) LVGL: Touch detected: x=252, y=139, count=1
|
||||
I (14529) LVGL: Touch detected: x=262, y=161, count=1
|
||||
I (14559) LVGL: Touch detected: x=277, y=189, count=1
|
||||
I (14589) LVGL: Touch detected: x=287, y=203, count=1
|
||||
I (15279) LVGL: Touch detected: x=173, y=324, count=1
|
||||
I (15309) LVGL: Touch detected: x=173, y=320, count=1
|
||||
I (15339) LVGL: Touch detected: x=175, y=309, count=1
|
||||
I (15369) LVGL: Touch detected: x=178, y=286, count=1
|
||||
I (15879) LVGL: Touch detected: x=216, y=56, count=1
|
||||
I (15909) LVGL: Touch detected: x=216, y=56, count=1
|
||||
I (15939) LVGL: Touch detected: x=216, y=56, count=1
|
||||
I (15969) LVGL: Touch detected: x=216, y=57, count=1
|
||||
I (15999) LVGL: Touch detected: x=219, y=64, count=1
|
||||
I (16029) LVGL: Touch detected: x=227, y=86, count=1
|
||||
I (16079) LVGL: Touch detected: x=243, y=129, count=1
|
||||
I (16109) LVGL: Touch detected: x=253, y=156, count=1
|
||||
I (16139) LVGL: Touch detected: x=262, y=177, count=1
|
||||
I (16709) LVGL: Touch detected: x=11, y=134, count=1
|
||||
I (16739) LVGL: Touch detected: x=24, y=136, count=1
|
||||
I (16769) LVGL: Touch detected: x=52, y=139, count=1
|
||||
I (16799) LVGL: Touch detected: x=124, y=146, count=1
|
||||
I (16829) LVGL: Touch detected: x=172, y=151, count=1
|
||||
I (16859) LVGL: Touch detected: x=217, y=154, count=1
|
||||
I (16889) LVGL: Touch detected: x=261, y=154, count=1
|
||||
I (16919) LVGL: Touch detected: x=308, y=153, count=1
|
||||
I (17699) LVGL: Touch detected: x=203, y=27, count=1
|
||||
I (17729) LVGL: Touch detected: x=203, y=28, count=1
|
||||
I (17759) LVGL: Touch detected: x=205, y=36, count=1
|
||||
I (17789) LVGL: Touch detected: x=207, y=52, count=1
|
||||
I (17819) LVGL: Touch detected: x=213, y=79, count=1
|
||||
I (17849) LVGL: Touch detected: x=227, y=116, count=1
|
||||
I (17879) LVGL: Touch detected: x=241, y=151, count=1
|
||||
I (18419) LVGL: Touch detected: x=97, y=130, count=1
|
||||
I (18449) LVGL: Touch detected: x=97, y=130, count=1
|
||||
I (20399) LVGL: Touch detected: x=196, y=32, count=1
|
||||
I (20429) LVGL: Touch detected: x=197, y=35, count=1
|
||||
I (20459) LVGL: Touch detected: x=199, y=42, count=1
|
||||
I (20489) LVGL: Touch detected: x=201, y=55, count=1
|
||||
I (20519) LVGL: Touch detected: x=205, y=77, count=1
|
||||
I (20549) LVGL: Touch detected: x=211, y=104, count=1
|
||||
I (20579) LVGL: Touch detected: x=233, y=158, count=1
|
||||
I (20999) LVGL: Touch detected: x=180, y=337, count=1
|
||||
I (21029) LVGL: Touch detected: x=180, y=333, count=1
|
||||
I (21059) LVGL: Touch detected: x=179, y=315, count=1
|
||||
I (25709) LVGL: Touch detected: x=208, y=35, count=1
|
||||
I (25739) LVGL: Touch detected: x=208, y=35, count=1
|
||||
I (25769) LVGL: Touch detected: x=208, y=38, count=1
|
||||
I (25799) LVGL: Touch detected: x=208, y=48, count=1
|
||||
I (25829) LVGL: Touch detected: x=208, y=66, count=1
|
||||
I (25869) LVGL: Touch detected: x=212, y=132, count=1
|
||||
I (25899) LVGL: Touch detected: x=213, y=150, count=1
|
||||
I (25929) LVGL: Touch detected: x=216, y=195, count=1
|
||||
I (25959) LVGL: Touch detected: x=218, y=214, count=1
|
||||
I (25989) LVGL: Touch detected: x=223, y=227, count=1
|
||||
I (26529) LVGL: Touch detected: x=15, y=118, count=1
|
||||
I (26559) LVGL: Touch detected: x=15, y=118, count=1
|
||||
I (26589) LVGL: Touch detected: x=22, y=119, count=1
|
||||
I (26619) LVGL: Touch detected: x=44, y=123, count=1
|
||||
I (26649) LVGL: Touch detected: x=85, y=130, count=1
|
||||
I (26679) LVGL: Touch detected: x=157, y=141, count=1
|
||||
I (26709) LVGL: Touch detected: x=198, y=148, count=1
|
||||
I (26739) LVGL: Touch detected: x=233, y=152, count=1
|
||||
I (27189) LVGL: Touch detected: x=352, y=168, count=1
|
||||
I (27219) LVGL: Touch detected: x=352, y=168, count=1
|
||||
I (27249) LVGL: Touch detected: x=348, y=168, count=1
|
||||
I (27279) LVGL: Touch detected: x=324, y=167, count=1
|
||||
I (27309) LVGL: Touch detected: x=294, y=164, count=1
|
||||
I (27339) LVGL: Touch detected: x=252, y=161, count=1
|
||||
I (27369) LVGL: Touch detected: x=208, y=157, count=1
|
||||
I (27399) LVGL: Touch detected: x=180, y=153, count=1
|
||||
I (27429) LVGL: Touch detected: x=161, y=148, count=1
|
||||
I (27909) LVGL: Touch detected: x=166, y=336, count=1
|
||||
I (27939) LVGL: Touch detected: x=166, y=328, count=1
|
||||
I (28479) LVGL: Touch detected: x=199, y=325, count=1
|
||||
I (28509) LVGL: Touch detected: x=199, y=325, count=1
|
||||
I (28539) LVGL: Touch detected: x=198, y=322, count=1
|
||||
I (28569) LVGL: Touch detected: x=196, y=312, count=1
|
||||
I (28599) LVGL: Touch detected: x=195, y=292, count=1
|
||||
I (28629) LVGL: Touch detected: x=196, y=254, count=1
|
||||
I (28659) LVGL: Touch detected: x=201, y=162, count=1
|
||||
I (29139) LVGL: Touch detected: x=209, y=15, count=1
|
||||
I (29169) LVGL: Touch detected: x=209, y=16, count=1
|
||||
I (29199) LVGL: Touch detected: x=209, y=28, count=1
|
||||
I (29229) LVGL: Touch detected: x=212, y=55, count=1
|
||||
I (29279) LVGL: Touch detected: x=225, y=123, count=1
|
||||
I (29309) LVGL: Touch detected: x=235, y=166, count=1
|
||||
I (29339) LVGL: Touch detected: x=243, y=199, count=1
|
||||
I (24) boot: ESP-IDF v5.4.2-dirty 2nd stage bootloader
|
||||
I (24) boot: compile time Feb 12 2026 14:18:02
|
||||
I (25) boot: chip revision: v0.4
|
||||
I (25) boot: efuse block revision: v1.3
|
||||
I (29) boot.esp32c3: SPI Speed : 80MHz
|
||||
I (32) boot.esp32c3: SPI Mode : DIO
|
||||
I (36) boot.esp32c3: SPI Flash Size : 8MB
|
||||
I (40) boot: Enabling RNG early entropy source...
|
||||
I (44) boot: Partition Table:
|
||||
I (47) boot: ## Label Usage Type ST Offset Length
|
||||
I (53) boot: 0 nvs WiFi data 01 02 00009000 00006000
|
||||
I (60) boot: 1 phy_init RF data 01 01 0000f000 00001000
|
||||
I (66) boot: 2 factory factory app 00 00 00010000 00400000
|
||||
I (73) boot: 3 storage Unknown data 01 82 00410000 00200000
|
||||
I (79) boot: End of partition table
|
||||
I (83) esp_image: segment 0: paddr=00010020 vaddr=3c070020 size=7c8e4h (510180) map
|
||||
I (171) esp_image: segment 1: paddr=0008c90c vaddr=3fc91000 size=01c10h ( 7184) load
|
||||
I (173) esp_image: segment 2: paddr=0008e524 vaddr=40380000 size=01af4h ( 6900) load
|
||||
I (177) esp_image: segment 3: paddr=00090020 vaddr=42000020 size=6a170h (434544) map
|
||||
I (252) esp_image: segment 4: paddr=000fa198 vaddr=40381af4 size=0f300h ( 62208) load
|
||||
I (264) esp_image: segment 5: paddr=001094a0 vaddr=50000000 size=0001ch ( 28) load
|
||||
I (269) boot: Loaded app from partition at offset 0x10000
|
||||
I (269) boot: Disabling RNG early entropy source...
|
||||
I (281) cpu_start: Unicore app
|
||||
I (290) cpu_start: Pro cpu start user code
|
||||
I (290) cpu_start: cpu freq: 160000000 Hz
|
||||
I (290) app_init: Application information:
|
||||
I (290) app_init: Project name: program
|
||||
I (294) app_init: App version: 455c92d-dirty
|
||||
I (298) app_init: Compile time: Feb 12 2026 14:17:45
|
||||
I (303) app_init: ELF file SHA256: ab5b876f8...
|
||||
I (308) app_init: ESP-IDF: v5.4.2-dirty
|
||||
I (312) efuse_init: Min chip rev: v0.3
|
||||
I (316) efuse_init: Max chip rev: v1.99
|
||||
I (320) efuse_init: Chip rev: v0.4
|
||||
I (324) heap_init: Initializing. RAM available for dynamic allocation:
|
||||
I (330) heap_init: At 3FCA0510 len 0001FAF0 (126 KiB): RAM
|
||||
I (335) heap_init: At 3FCC0000 len 0001C710 (113 KiB): Retention RAM
|
||||
I (341) heap_init: At 3FCDC710 len 00002950 (10 KiB): Retention RAM
|
||||
I (347) heap_init: At 5000001C len 00001FCC (7 KiB): RTCRAM
|
||||
I (353) spi_flash: detected chip: mxic
|
||||
I (356) spi_flash: flash io: dio
|
||||
W (359) i2c: This driver is an old driver, please migrate your application code to adapt `driver/i2c_master.h`
|
||||
I (369) sleep_gpio: Configure to isolate all GPIO pins in sleep state
|
||||
I (375) sleep_gpio: Enable automatic switching of GPIO sleep configuration
|
||||
I (393) coexist: coex firmware version: 7b9a184
|
||||
I (393) coexist: coexist rom version 9387209
|
||||
I (394) main_task: Started on CPU0
|
||||
I (394) main_task: Calling app_main()
|
||||
I (394) MAIN: 1. I2C已初始化
|
||||
I (404) MAIN: 2. NVS已初始化
|
||||
I (404) st77916: version: 2.0.2
|
||||
I (404) st77916_spi: LCD panel create success, version: 2.0.2
|
||||
W (524) st77916_spi: The 3Ah command has been used and will be overwritten by external initialization sequence
|
||||
I (684) LCD: LCD GRAM cleared (black filled)
|
||||
I (694) MAIN: 3. LCD已初始化
|
||||
I (694) gpio: GPIO[10]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:2
|
||||
I (694) CST816S: IC id: 182
|
||||
I (694) LCD: Touch controller initialized successfully
|
||||
I (704) MAIN: 4. 触摸控制器已初始化
|
||||
I (704) LVGL: Starting LVGL task
|
||||
I (704) LCD: LVGL buffer size: 21600 bytes (W: 360, Lines: 30)
|
||||
I (714) LCD: Touch controller added to LVGL
|
||||
I (714) MAIN: 5. LVGL已初始化
|
||||
I (774) FATFS: SPIFFS: Total size: 1920401, Used: 68774
|
||||
I (774) MAIN: 6. FATFS文件系统已初始化
|
||||
I (834) FATFS: 文件名: /spiflash/02.jpg,大小:20498
|
||||
I (834) FATFS: 文件名: /spiflash/default.jpg,大小:47430
|
||||
I (874) MAIN: 7. SPIFFS处理完成
|
||||
I (894) MAIN: 8. SquareLine UI已初始化
|
||||
I (1144) MAIN: 8.1 LCD显示已打开
|
||||
I (1144) MAIN: 9. PWM背光已初始化
|
||||
I (1144) gpio: GPIO[2]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
|
||||
I (1144) BAT: ADC校准初始化成功
|
||||
I (1144) BAT: 电池ADC初始化完成 (GPIO2, ADC1_CH2, 分压比=2)
|
||||
I (1154) MAIN: 10. 电池ADC已初始化
|
||||
I (1154) BAT: ADC原始值=3267, ADC电压=2393mV, 电池电压=4786mV, 电量=100%
|
||||
I (1164) BAT: 电池监控任务已启动,更新间隔5000ms
|
||||
I (1174) MAIN: 11. 电池监控任务已启动
|
||||
I (1174) gpio: GPIO[8]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:2
|
||||
I (1184) gpio: GPIO[9]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:2
|
||||
I (1194) BTN: 按键初始化完成 (BOOT=GPIO9, KEY2=GPIO8)
|
||||
I (1194) MAIN: 12. 按键已初始化
|
||||
I (1204) MAIN: 12.1 BOOT按键回调已注册
|
||||
I (1254) SLEEP: 休眠管理器初始化完成(超时=10s)
|
||||
I (1254) MAIN: 13. 休眠管理器已初始化
|
||||
I (1264) MAIN: 系统初始化完成成功!
|
||||
I (1264) main_task: Returned from app_main()
|
||||
I (6164) BAT: ADC原始值=3276, ADC电压=2400mV, 电池电压=4800mV, 电量=100%
|
||||
369
项目对比分析报告.md
369
项目对比分析报告.md
@ -1,289 +1,80 @@
|
||||
# 项目对比分析报告
|
||||
|
||||
## 1. 项目概述
|
||||
|
||||
本次分析对比了两个基于 ESP32 平台的 LCD 驱动项目,重点分析 d zbj 项目在适配 LVGL 时遇到的问题:
|
||||
|
||||
| 项目名称 | 路径 | 主要功能 |
|
||||
|---------|------|----------|
|
||||
| d zbj 项目 | `/Users/rdzleo/Desktop/dzbj` | 完整的嵌入式应用,包含 LCD 显示、触摸等功能 |
|
||||
| QSPI LCD 驱动版本 | `/Users/rdzleo/Desktop/qspi_lcd_驱动版本` | 专注于 LCD 驱动和触摸功能的实现,LVGL 适配成功 |
|
||||
|
||||
## 2. 项目结构对比
|
||||
|
||||
### 2.1 d zbj 项目结构
|
||||
|
||||
```
|
||||
dzbj/
|
||||
├── main/
|
||||
│ ├── axis/ # 轴控制相关代码
|
||||
│ ├── ble/ # BLE 蓝牙功能
|
||||
│ ├── fatfs/ # 文件系统功能
|
||||
│ ├── gpio/ # GPIO 控制
|
||||
│ ├── lcd/ # LCD 驱动实现
|
||||
│ ├── pages/ # 页面管理
|
||||
│ ├── temp/ # 温度检测
|
||||
│ ├── ui/ # UI 界面(SquareLine Studio 生成)
|
||||
│ ├── wifi/ # WiFi 功能
|
||||
│ └── main.c # 主函数
|
||||
├── build/ # 构建输出
|
||||
└── CMakeLists.txt # 构建配置
|
||||
```
|
||||
|
||||
### 2.2 QSPI LCD 驱动版本结构
|
||||
|
||||
```
|
||||
qspi_lcd_驱动版本/
|
||||
├── main/
|
||||
│ ├── display_touch_manager.h # 显示和触摸管理接口
|
||||
│ ├── lcd_touch_driver.h # LCD 触摸驱动接口
|
||||
│ └── main.c # 主函数
|
||||
├── components/
|
||||
│ └── lvgl/ # LVGL 组件
|
||||
└── CMakeLists.txt # 构建配置
|
||||
```
|
||||
|
||||
## 3. LCD 驱动实现对比
|
||||
|
||||
### 3.1 d zbj 项目 LCD 实现
|
||||
|
||||
**核心文件**:`/Users/rdzleo/Desktop/dzbj/main/lcd/lcd.c`
|
||||
|
||||
**实现特点**:
|
||||
- 使用 QSPI 接口驱动 ST77916 LCD 控制器
|
||||
- 直接调用 ESP-IDF 提供的 LCD 相关 API
|
||||
- 分步骤初始化:SPI 总线 → LCD IO → LCD 面板 → 重置和初始化面板
|
||||
- 支持触摸功能(CST816S 触摸控制器)
|
||||
- 配置了双缓冲和 DMA 传输
|
||||
|
||||
**关键代码**:
|
||||
```c
|
||||
void lcd_init(){
|
||||
const spi_bus_config_t buscfg = ST77916_PANEL_BUS_QSPI_CONFIG(...);
|
||||
spi_bus_initialize(SPI_LCD_HOST, &buscfg, SPI_DMA_CH_AUTO);
|
||||
const esp_lcd_panel_io_spi_config_t io_config = ST77916_PANEL_IO_QSPI_CONFIG(...);
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(...));
|
||||
const st77916_vendor_config_t vendor_config = {
|
||||
.flags = {
|
||||
.use_qspi_interface = 1,
|
||||
},
|
||||
};
|
||||
const esp_lcd_panel_dev_config_t panel_config = {...};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st77916(...));
|
||||
esp_lcd_panel_reset(panel_handle);
|
||||
esp_lcd_panel_init(panel_handle);
|
||||
esp_lcd_panel_disp_on_off(panel_handle, true);
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 QSPI LCD 驱动版本实现
|
||||
|
||||
**核心文件**:通过 `display_manager_init()` 函数实现
|
||||
|
||||
**实现特点**:
|
||||
- 使用显示管理器和触摸管理器的抽象层
|
||||
- 封装了 LCD 初始化的细节
|
||||
- 提供统一的接口函数
|
||||
- 结构更清晰,职责更明确
|
||||
|
||||
**关键代码**:
|
||||
```c
|
||||
void app_main(void) {
|
||||
// 初始化显示管理器
|
||||
esp_err_t ret = display_manager_init();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "显示管理器初始化失败: %s", esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取显示驱动
|
||||
lv_disp_t *display = display_manager_get_display();
|
||||
if (display == NULL) {
|
||||
ESP_LOGE(TAG, "获取显示驱动失败");
|
||||
return;
|
||||
}
|
||||
|
||||
// 初始化触摸管理器
|
||||
ret = touch_manager_init(display);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "触摸管理器初始化失败: %s", esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 驱动实现对比分析
|
||||
|
||||
| 对比项 | d zbj 项目 | QSPI LCD 驱动版本 |
|
||||
|--------|-----------|-------------------|
|
||||
| 接口方式 | 直接调用 ESP-IDF API | 使用抽象层管理器 |
|
||||
| 代码复杂度 | 相对复杂,包含更多细节 | 更简洁,封装了细节 |
|
||||
| 可维护性 | 模块化但分散 | 集中管理,更易维护 |
|
||||
| 灵活性 | 高度灵活,可自定义各环节 | 标准化流程,灵活性稍低 |
|
||||
| 初始化流程 | 线性初始化各组件 | 分层初始化,结构更清晰 |
|
||||
| 错误处理 | 基本错误检查 | 详细的错误处理和日志 |
|
||||
|
||||
## 4. 初始化流程对比
|
||||
|
||||
### 4.1 d zbj 项目初始化流程
|
||||
|
||||
**核心文件**:`/Users/rdzleo/Desktop/dzbj/main/main.c`
|
||||
|
||||
**初始化顺序**:
|
||||
1. `i2c_init()` - 初始化 I2C 总线
|
||||
2. `nvs_init()` - 初始化 NVS 存储
|
||||
3. `lcd_init()` - 初始化 LCD 面板
|
||||
4. `touch_init()` - 初始化触摸控制器
|
||||
5. `lvgl_lcd_init()` - 初始化 LVGL 显示
|
||||
6. `fatfs_init()` - 初始化文件系统
|
||||
7. `pwm_init()` - 初始化 PWM 背光
|
||||
8. `app_test_display()` - 显示测试屏幕
|
||||
|
||||
### 4.2 QSPI LCD 驱动版本初始化流程
|
||||
|
||||
**核心文件**:`/Users/rdzleo/Desktop/qspi_lcd_驱动版本/main/main.c`
|
||||
|
||||
**初始化顺序**:
|
||||
1. `display_manager_init()` - 初始化显示管理器
|
||||
2. `display_manager_get_display()` - 获取显示驱动
|
||||
3. 创建 LVGL 任务
|
||||
4. 等待 LVGL 任务启动
|
||||
5. `ui_init()` - 初始化 SquareLine Studio UI
|
||||
6. 等待 LVGL 完成初始渲染
|
||||
7. `touch_manager_init(display)` - 初始化触摸管理器
|
||||
8. 控制 LCD 开关状态
|
||||
|
||||
## 5. 技术选型对比
|
||||
|
||||
### 5.1 硬件平台
|
||||
|
||||
- **d zbj 项目**:ESP32-S3 系列
|
||||
- **QSPI LCD 驱动版本**:ESP32-S3 系列
|
||||
|
||||
### 5.2 LCD 控制器
|
||||
|
||||
- **d zbj 项目**:ST77916S
|
||||
- **QSPI LCD 驱动版本**:ST77916S
|
||||
|
||||
### 7.3 通信接口
|
||||
|
||||
- **d zbj 项目**:QSPI(LCD)、I2C(触摸)
|
||||
- **QSPI LCD 驱动版本**:QSPI(LCD)、I2C(触摸)
|
||||
|
||||
### 7.4 软件框架
|
||||
|
||||
- **d zbj 项目**:ESP-IDF + LVGL + SquareLine Studio
|
||||
- **QSPI LCD 驱动版本**:ESP-IDF + LVGL + SquareLine Studio
|
||||
|
||||
### 7.5 SDK 配置对比
|
||||
|
||||
| 配置项 | d zbj 项目 | QSPI LCD 驱动版本 |
|
||||
|--------|-----------|-------------------|
|
||||
| ESP-IDF 版本 | 5.4.2 | 最新稳定版 |
|
||||
| 编译器 | xtensa-esp32s3-elf-gcc | xtensa-esp32s3-elf-gcc |
|
||||
| 构建系统 | CMake | CMake |
|
||||
| 目标芯片 | esp32s3 | esp32s3 |
|
||||
|
||||
### 7.6 LVGL 配置对比
|
||||
|
||||
| 配置项 | d zbj 项目 | QSPI LCD 驱动版本 |
|
||||
|--------|-----------|-------------------|
|
||||
| LVGL 版本 | 8.3.11 | 8.3.11 |
|
||||
| 颜色深度 | 16位 (CONFIG_LV_COLOR_DEPTH_16=y) | 16位 (CONFIG_LV_COLOR_DEPTH_16=y) |
|
||||
| 字节交换 | 启用 (CONFIG_LV_COLOR_16_SWAP=y) | 启用 (CONFIG_LV_COLOR_16_SWAP=y) |
|
||||
| 内存大小 | 64KB (CONFIG_LV_MEM_SIZE_KILOBYTES=64) | 32KB (CONFIG_LV_MEM_SIZE_KILOBYTES=32) |
|
||||
| 显示缓冲 | 双缓冲,支持 DMA | 双缓冲,支持 DMA |
|
||||
| 任务优先级 | 4 | 4 |
|
||||
| 任务堆栈大小 | 8192 | 8192 |
|
||||
|
||||
### 7.7 显示缓冲区配置对比
|
||||
|
||||
| 配置项 | d zbj 项目 | QSPI LCD 驱动版本 |
|
||||
|--------|-----------|-------------------|
|
||||
| 缓冲区大小计算 | `LCD_WID*LCD_HIGH/5` | `EXAMPLE_LCD_H_RES * EXAMPLE_LVGL_DRAW_BUF_LINES` (360*30) |
|
||||
| 内存分配方式 | ESP-IDF 标准内存分配 | `spi_bus_dma_memory_alloc` 专门为 SPI DMA 分配 |
|
||||
| 双缓冲 | 启用 | 启用 |
|
||||
| DMA 支持 | 启用 | 启用 |
|
||||
| 刷新机制 | LVGL 标准刷新 | 自定义回调 `example_notify_lvgl_flush_ready` |
|
||||
|
||||
### 7.8 UI 文件对比
|
||||
|
||||
| 对比项 | d zbj 项目 | QSPI LCD 驱动版本 |
|
||||
|--------|-----------|-------------------|
|
||||
| SquareLine Studio 版本 | 相同版本 | 相同版本 |
|
||||
| UI 导出格式 | 压缩的 PNG 格式 | 压缩的 PNG 格式 |
|
||||
| 屏幕数量 | 包含多个屏幕(Home、Set、Img) | 包含多个屏幕(Home、Set、Img) |
|
||||
| 图片资源 | 包含相同的图片资源 | 包含相同的图片资源 |
|
||||
| 组件结构 | 完全相同的组件结构 | 完全相同的组件结构 |
|
||||
| 事件处理 | 相同的事件处理机制 | 相同的事件处理机制 |
|
||||
|
||||
### 7.9 关键差异分析
|
||||
|
||||
1. **内存分配方式**:
|
||||
- qspi_lcd_驱动版本使用 `spi_bus_dma_memory_alloc` 专门为 SPI DMA 传输分配内存
|
||||
- d zbj 项目使用标准内存分配,可能不是最优的 DMA 内存
|
||||
|
||||
2. **显示缓冲区配置**:
|
||||
- qspi_lcd_驱动版本使用固定的 30 行作为缓冲区大小
|
||||
- d zbj 项目使用 `LCD_WID*LCD_HIGH/5` 计算缓冲区大小
|
||||
|
||||
3. **初始化流程**:
|
||||
- qspi_lcd_驱动版本使用管理器模式,分层初始化,包含详细的错误处理
|
||||
- d zbj 项目使用线性初始化流程,错误处理相对简单
|
||||
|
||||
4. **刷新回调**:
|
||||
- qspi_lcd_驱动版本实现了自定义的 `example_notify_lvgl_flush_ready` 回调
|
||||
- d zbj 项目使用 LVGL 标准刷新机制
|
||||
|
||||
### 7.10 花屏问题分析
|
||||
|
||||
基于以上对比,导致 d zbj 项目花屏的可能原因包括:
|
||||
|
||||
1. **内存分配问题**:
|
||||
- 未使用 `spi_bus_dma_memory_alloc` 分配适合 DMA 传输的内存
|
||||
- 可能导致 DMA 传输数据错误,引起花屏
|
||||
|
||||
2. **显示缓冲区配置**:
|
||||
- `LCD_WID*LCD_HIGH/5` 计算出的缓冲区大小可能不合适
|
||||
- 缓冲区过小可能导致显示不完整,过大可能导致内存不足
|
||||
|
||||
3. **初始化流程问题**:
|
||||
- 初始化顺序可能影响硬件状态
|
||||
- 缺少必要的初始化步骤或延迟
|
||||
|
||||
4. **刷新机制问题**:
|
||||
- 缺少自定义的刷新就绪回调
|
||||
- 可能导致 LVGL 与硬件刷新不同步
|
||||
|
||||
## 7. 解决方案
|
||||
|
||||
### 7.1 具体措施
|
||||
|
||||
1. **优化内存分配**:
|
||||
- 使用 `spi_bus_dma_memory_alloc` 专门为 SPI DMA 传输分配内存
|
||||
- 确保内存对齐和连续性,提高 DMA 传输效率
|
||||
|
||||
2. **调整缓冲区配置**:
|
||||
- 参考 QSPI LCD 驱动版本,使用固定行数的缓冲区大小(如 30 行)
|
||||
- 确保缓冲区大小合理,避免内存不足或浪费
|
||||
|
||||
3. **改进刷新机制**:
|
||||
- 实现自定义的 `notify_lvgl_flush_ready` 回调
|
||||
- 确保 LVGL 与硬件刷新同步,减少显示异常
|
||||
|
||||
4. **优化初始化流程**:
|
||||
- 参考 QSPI LCD 驱动版本的管理器模式
|
||||
- 确保初始化顺序正确,添加必要的延迟
|
||||
- 增加详细的错误处理和日志输出
|
||||
|
||||
## 8. 结论
|
||||
|
||||
通过对两个项目的详细对比分析,我们发现导致 d zbj 项目花屏的主要原因是:
|
||||
|
||||
1. **内存分配方式不当**:未使用专门的 `spi_bus_dma_memory_alloc` 函数分配适合 DMA 传输的内存
|
||||
2. **显示缓冲区配置不合理**:缓冲区大小计算方式可能导致内存使用不当
|
||||
3. **刷新机制不同步**:缺少自定义的刷新就绪回调,可能导致 LVGL 与硬件刷新不同步
|
||||
4. **初始化流程差异**:初始化顺序和错误处理的差异可能影响硬件状态
|
||||
|
||||
采用 QSPI LCD 驱动版本的实现方式,特别是内存分配、缓冲区配置和刷新机制的优化,可以有效解决 d zbj 项目的花屏问题,提高 LVGL 适配的稳定性和可靠性。
|
||||
|
||||
一、全尺寸图片 + BLE 同时运行需要多少 SRAM?
|
||||
逐项计算:
|
||||
|
||||
内存需求 大小 说明
|
||||
JPEG 输入缓冲 ~50 KB 从 SPIFFS 读取压缩文件
|
||||
JPEG 输出缓冲 253 KB 360×360×2 RGB565(必须连续)
|
||||
JPEG 解码工作区 ~3 KB TjpgDec scratchpad
|
||||
LVGL .bss 静态 ~50 KB 对象池、样式缓存等
|
||||
LVGL 帧缓冲 ~21 KB 360×30×2 行缓冲
|
||||
FreeRTOS 核心 ~15 KB idle + timer + main 任务栈
|
||||
SPI 驱动 + DMA ~12 KB LCD SPI 传输
|
||||
SPIFFS + VFS ~10 KB 文件系统缓存
|
||||
I2C + 触摸驱动 ~5 KB CST816S
|
||||
BLE 协议栈 ~70-80 KB Bluedroid GATTS + controller
|
||||
BLE 图片接收缓冲 ~10 KB 分包接收临时缓冲
|
||||
系统杂项 ~20 KB HAL/heap管理/日志/NVS等
|
||||
总计 ~520-530 KB 峰值(BLE接收+解码同时)
|
||||
如果 BLE 和图片显示分时复用(先关 BLE 再解码):
|
||||
|
||||
场景 峰值 SRAM
|
||||
仅显示图片(无 BLE) ~440 KB
|
||||
仅 BLE 接收(无图片解码) ~270 KB
|
||||
推荐安全余量 +20% ≈ 530 KB
|
||||
结论:需要至少 ~450KB 可用堆内存,推荐 512KB+ SRAM 或带 PSRAM 的方案。
|
||||
|
||||
二、ESP32 各型号对比
|
||||
ESP32-C 系列(RISC-V 单核,低成本低功耗路线)
|
||||
型号 SRAM PSRAM 支持 能否满足需求 参考价格(模组)
|
||||
ESP32-C3 (当前) 400 KB 不支持 不能 (堆249KB < 253KB输出缓冲) ~¥8-12
|
||||
ESP32-C6 512 KB 支持外部 SPI RAM 勉强可以(无PSRAM时堆~350KB,仍紧张) ~¥12-18
|
||||
ESP32-C5 320 KB 待确认 不能 尚未量产
|
||||
ESP32-S 系列(Xtensa 双核,高性能路线)
|
||||
型号 SRAM PSRAM 能否满足需求 参考价格(模组)
|
||||
ESP32-S3-N4 512 KB 无 勉强(分时复用可行) ~¥15-20
|
||||
ESP32-S3-N4R2 512 KB 2 MB (Quad SPI) 完全满足 ~¥18-22
|
||||
ESP32-S3-N8R8 512 KB 8 MB (Octal SPI) 完全满足,富裕 ~¥22-28
|
||||
ESP32-S3-N16R8 512 KB 8 MB (Octal SPI) 完全满足 ~¥25-32
|
||||
三、综合推荐
|
||||
最佳性价比推荐:ESP32-S3-WROOM-1-N4R2
|
||||
理由:
|
||||
|
||||
内存充裕:512KB SRAM + 2MB PSRAM
|
||||
|
||||
JPEG 输出缓冲(253KB) 放 PSRAM → SRAM 零压力
|
||||
BLE + 图片显示可同时运行,不需要分时复用
|
||||
heap_caps_malloc(size, MALLOC_CAP_SPIRAM) 一行代码搞定
|
||||
与当前项目兼容性最高:
|
||||
|
||||
ESP-IDF v5.4 完全支持
|
||||
SPI LCD 驱动代码基本不变(ST77916 驱动已适配)
|
||||
I2C 触摸驱动完全不变
|
||||
LVGL 代码完全不变
|
||||
BLE 代码完全不变(Bluedroid API 通用)
|
||||
原项目就是从 ESP32-S3 适配来的,回迁难度最低
|
||||
性价比:
|
||||
|
||||
模组单价 ~¥18-22(淘宝散件)
|
||||
比 N4 只贵 ¥3-5,但多了 2MB PSRAM
|
||||
2MB PSRAM 对这个项目绰绰有余(只需 253KB)
|
||||
不需要 N8R8:
|
||||
|
||||
8MB PSRAM 对这个项目严重过剩
|
||||
Octal SPI PSRAM 会多占用 GPIO(虽然 S3 GPIO 充裕)
|
||||
价格高 ¥5-10,没必要
|
||||
如果必须留在 C 系列:ESP32-C6 + 外部 PSRAM
|
||||
ESP32-C6 支持外部 SPI RAM,但需要额外的 PSRAM 芯片
|
||||
增加 BOM 成本和 PCB 复杂度
|
||||
生态不如 S3 成熟
|
||||
不推荐(总成本可能比 S3 模组还高)
|
||||
迁移工作量评估
|
||||
迁移项 难度 说明
|
||||
GPIO 引脚重映射 低 改 gpio.h 中的宏定义
|
||||
SPI LCD 驱动 无需改 esp_lcd + ST77916 驱动通用
|
||||
I2C 触摸 无需改 CST816S 驱动通用
|
||||
LVGL 无需改 esp_lvgl_port 通用
|
||||
JPEG 解码 改 1 行 去掉 JPEG_IMAGE_SCALE_1_2,去掉 lv_img_set_zoom(512)
|
||||
PSRAM 图片缓冲 改 1 行 malloc() → heap_caps_malloc(size, MALLOC_CAP_SPIRAM)
|
||||
BLE 低 Bluedroid API 通用,可能需调整 controller 配置
|
||||
sdkconfig 低 idf.py set-target esp32s3 后重新配置
|
||||
总结:ESP32-S3-N4R2 是当前项目升级的最优选择,迁移成本极低(核心代码几乎不变),只需改 2-3 行代码就能实现全尺寸无损图片显示 + BLE 同时运行。
|
||||
Loading…
x
Reference in New Issue
Block a user