0. 废话
-
别一上来就LVGL嘛,先测测屏幕能不能用先
-
ESP-IDF装好后是有st7789组件的,不用手搓
-
如果急着用,只是想测测屏幕,可以试试这个项目
-
https://github.com/nopnop2002/esp-idf-st7789 在我的设备上改改引脚就能正常跑
1. 正文
1.1 配置头文件
display_config.h
#pragma once
#define DISPLAY_SPI_HOST SPI2_HOST
#define DISPLAY_PIXEL_CLOCK_HZ (20 * 1000 * 1000)
#define DISPLAY_BK_LIGHT_ON_LEVEL 1
#define DISPLAY_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL
#define DISPLAY_PIN_NUM_SCLK 17
#define DISPLAY_PIN_NUM_MOSI 8
#define DISPLAY_PIN_NUM_LCD_DC 16
#define DISPLAY_PIN_NUM_LCD_RST 18
#define DISPLAY_PIN_NUM_LCD_CS -1
#define DISPLAY_PIN_NUM_BK_LIGHT 38
#define DISPLAY_H_RES 240
#define DISPLAY_V_RES 320
DC引脚是用来区分发来的是数据还是命令的
CS引脚是屏幕使能引脚,我没用到,设-1
官方驱动其实也是改改配置就能跑的,不过注意要配全,有很多是跟屏幕的配置而不是驱动芯片的配置,具体看注释
#include "driver/gpio.h"
#include "esp_err.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_st7789.h"
#include "display_config.h"
众所周知,在idf默认的cmake规则下,main/下是不需要规定内置组件的,如果是在其他地方(比如components/下要指定组件)
这里用到的是esp_lcd组件
1.2 简简单单点个灯
static esp_err_t bk_config(void)
{
esp_err_t ret;
gpio_config_t bk_gpio_config = {
.pin_bit_mask = 1ULL << DISPLAY_PIN_NUM_BK_LIGHT,
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
ret = gpio_config(&bk_gpio_config);
ret = gpio_set_level((gpio_num_t)DISPLAY_PIN_NUM_BK_LIGHT, DISPLAY_BK_LIGHT_ON_LEVEL);
return ret;
}
1.3 简简单单配置个SPI
static esp_err_t spi_bus_config(void)
{
spi_bus_config_t buscfg = {
.mosi_io_num = DISPLAY_PIN_NUM_MOSI,
.miso_io_num = -1,
.sclk_io_num = DISPLAY_PIN_NUM_SCLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.data4_io_num = -1,
.data5_io_num = -1,
.data6_io_num = -1,
.data7_io_num = -1,
.data_io_default_level = 0,
.max_transfer_sz = DISPLAY_H_RES * 80 * sizeof(uint16_t),
// .flags = SPICOMMON_BUSFLAG_SLP_ALLOW_PD,
.isr_cpu_id = ESP_INTR_CPU_AFFINITY_AUTO,
// .intr_flags = ESP_INTR_FLAG_EDGE,
};
return spi_bus_initialize(DISPLAY_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
}
1.4 开始用到lcd组件了
到这不得不理解一下下 ESP-IDF所有屏幕方面驱动(官方)的写法了
-
IO层面是配置与硬件相关的信息和操作的(比如接口:SPI,I2C,I80……,接口对应的管脚,bit流如何发出去……)
-
panel层面是在IO层面之上抽象的屏幕的所有行为(初始化、镜像、描点……)
具体可看文档吧
我在一个函数里处理完这些东西,注意,很多配置是跟具体屏幕绑定的
static esp_err_t display_panel_config(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_panel_handle_t* panel_handle)
{
esp_err_t ret;
esp_lcd_panel_io_spi_config_t io_config = {
.cs_gpio_num = DISPLAY_PIN_NUM_LCD_CS,
.dc_gpio_num = DISPLAY_PIN_NUM_LCD_DC,
.spi_mode = 3,
.pclk_hz = DISPLAY_PIXEL_CLOCK_HZ,
.trans_queue_depth = 10,
.on_color_trans_done = NULL,
.user_ctx = nullptr,
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
.cs_ena_pretrans = 0,
.cs_ena_posttrans = 0,
.flags = {
.dc_high_on_cmd = 0,
.dc_low_on_data = 0,
.dc_low_on_param = 0,
.octal_mode = 0,
.quad_mode = 0,
.sio_mode = 0,
.lsb_first = 0,
.cs_high_active = 1,
}
};
ret = esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)DISPLAY_SPI_HOST, &io_config, io_handle);
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = DISPLAY_PIN_NUM_LCD_RST,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR,
.data_endian = LCD_RGB_DATA_ENDIAN_BIG,
.bits_per_pixel = 16,
.flags = {
.reset_active_high = false,
},
.vendor_config = NULL,
};
ret = esp_lcd_new_panel_st7789(*io_handle, &panel_config, panel_handle);
return ret;
}
注意点
1:spi_mode可以试试1或3
2:io_config中出现了三个东西——命令、参数、数据,在我看来命令和参数是一个东西,它们各自的位宽,DC拉高拉低是发哪个,要看手册
3:一般都是大端、高位先行的
4:可能有人会用并行或单线SPI,那就使能octal_mode……这几个
5:BGR格式比较常见
1.5 结束咯
依次调用上面的函数,就可以用esp_lcd_panel_系列函数操作,为用esp_lvgl_port等组件接入lvgl打下基础
void app_main(void)
{
bk_config();
spi_bus_config();
esp_lcd_panel_io_handle_t io_handle = NULL;
esp_lcd_panel_handle_t panel_handle = NULL;
display_panel_config(&io_handle, &panel_handle);
esp_lcd_panel_reset(panel_handle);
esp_lcd_panel_init(panel_handle);
esp_lcd_panel_swap_xy(panel_handle, true);
esp_lcd_panel_invert_color(panel_handle, true);
esp_lcd_panel_mirror(panel_handle, false, true);
esp_lcd_panel_disp_on_off(panel_handle, true);
// 测试程序,,如果成功,你将看到一个绿绿的屏幕
uint16_t bitmap[100];
for (int i = 0; i < 100; i++) {
bitmap[i] = 0x6666;
}
for (int y = 0; y < DISPLAY_H_RES; y += 10) {
for (int x = 0; x < DISPLAY_V_RES; x += 10) {
int w = (x + 10 > DISPLAY_V_RES) ? (DISPLAY_V_RES - x) : 10;
int h = (y + 10 > DISPLAY_H_RES) ? (DISPLAY_H_RES - y) : 10;
esp_lcd_panel_draw_bitmap(panel_handle, x, y, x + w, y + h, bitmap);
}
}
return ESP_OK;
}