123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- #include "lcd_st7701.h"
- #include "esp_log.h"
- #include "esp_heap_caps.h"
- #include "driver/i2c.h"
- #include "driver/spi_master.h"
- #include "esp_lcd_panel_ops.h"
- #include "esp_lcd_panel_io.h"
- #include "esp_lcd_panel_io_additions.h"
- #include "esp_lcd_st7701.h"
- #include "esp_lcd_touch.h"
- #include "lvgl_port.h"
- static const char *TAG = "lcd_st7701";
- static bool backlight_status = false;
- #define SCREEN_FACTORY_YY // 鱼鹰屏
- // #define SCREEN_FACTORY_HM // 禾木屏
- #ifdef SCREEN_FACTORY_HM
- #include "esp_lcd_touch_gt911.h"
- #endif
- #ifdef SCREEN_FACTORY_YY
- #include "esp_lcd_touch_ft5x06.h"
- #endif
- // LCD初始化命令
- static const st7701_lcd_init_cmd_t lcd_init_cmds[] = {
- // {cmd, { data }, data_size, delay_ms}
- #ifdef SCREEN_FACTORY_HM
- {0xFF, (uint8_t[]) {0x77, 0x01, 0x00, 0x00, 0x10}, 5, 0},
- {0xC0, (uint8_t[]) {0x3B, 0x00}, 2, 0},
- {0xC1, (uint8_t[]) {0x0D, 0x02}, 2, 0},
- {0xC2, (uint8_t[]) {0x31, 0x05}, 2, 0},
- {0xCD, (uint8_t[]) {0x08}, 1, 0},
- {0xB0,
- (uint8_t[]) {0x00, 0x11, 0x18, 0x0E, 0x11, 0x06, 0x07, 0x08, 0x07, 0x22, 0x04, 0x12, 0x0F, 0xAA, 0x31, 0x18},
- 16, 0},
- {0xB1,
- (uint8_t[]) {0x00, 0x11, 0x19, 0x0E, 0x12, 0x07, 0x08, 0x08, 0x08, 0x22, 0x04, 0x11, 0x11, 0xA9, 0x32, 0x18},
- 16, 0},
- {0xFF, (uint8_t[]) {0x77, 0x01, 0x00, 0x00, 0x11}, 5, 0},
- {0xB0, (uint8_t[]) {0x60}, 1, 0},
- {0xB1, (uint8_t[]) {0x32}, 1, 0},
- {0xB2, (uint8_t[]) {0x07}, 1, 0},
- {0xB3, (uint8_t[]) {0x80}, 1, 0},
- {0xB5, (uint8_t[]) {0x49}, 1, 0},
- {0xB7, (uint8_t[]) {0x85}, 1, 0},
- {0xB8, (uint8_t[]) {0x21}, 1, 0},
- {0xC1, (uint8_t[]) {0x78}, 1, 0},
- {0xC2, (uint8_t[]) {0x78}, 1, 0},
- {0xE0, (uint8_t[]) {0x00, 0x1B, 0x02}, 3, 0},
- {0xE1, (uint8_t[]) {0x08, 0xA0, 0x00, 0x00, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x44, 0x44}, 11, 0},
- {0xE2, (uint8_t[]) {0x11, 0x11, 0x44, 0x44, 0xED, 0xA0, 0x00, 0x00, 0xEC, 0xA0, 0x00, 0x00}, 12, 0},
- {0xE3, (uint8_t[]) {0x00, 0x00, 0x11, 0x11}, 4, 0},
- {0xE4, (uint8_t[]) {0x44, 0x44}, 2, 0},
- {0xE5,
- (uint8_t[]) {0x0A, 0xE9, 0xD8, 0xA0, 0x0C, 0xEB, 0xD8, 0xA0, 0x0E, 0xED, 0xD8, 0xA0, 0x10, 0xEF, 0xD8, 0xA0},
- 16, 0},
- {0xE6, (uint8_t[]) {0x00, 0x00, 0x11, 0x11}, 4, 0},
- {0xE7, (uint8_t[]) {0x44, 0x44}, 2, 0},
- {0xE8,
- (uint8_t[]) {0x09, 0xE8, 0xD8, 0xA0, 0x0B, 0xEA, 0xD8, 0xA0, 0x0D, 0xEC, 0xD8, 0xA0, 0x0F, 0xEE, 0xD8, 0xA0},
- 16, 0},
- {0xEB, (uint8_t[]) {0x02, 0x00, 0xE4, 0xE4, 0x88, 0x00, 0x40}, 7, 0},
- {0xEC, (uint8_t[]) {0x3C, 0x00}, 2, 0},
- {0xED,
- (uint8_t[]) {0xAB, 0x89, 0x76, 0x54, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x20, 0x45, 0x67, 0x98, 0xBA},
- 16, 0},
- {0x36, (uint8_t[]) {0x00}, 1, 0},
- {0xFF, (uint8_t[]) {0x77, 0x01, 0x00, 0x00, 0x13}, 5, 0},
- {0xE5, (uint8_t[]) {0xE4}, 1, 0},
- {0xFF, (uint8_t[]) {0x77, 0x01, 0x00, 0x00, 0x00}, 5, 0},
- {0x3A, (uint8_t[]) {0x60}, 1, 0},
- {0x20, (uint8_t[]) {}, 0, 0},
- {0x11, (uint8_t[]) {}, 0, 100},
- {0x29, (uint8_t[]) {}, 0, 50}
- #endif
- #ifdef SCREEN_FACTORY_YY
- {0xFF, (uint8_t[]) {0x77, 0x01, 0x00, 0x00, 0x13}, 5, 0},
- {0xEF, (uint8_t[]) {0x08}, 1, 0},
- {0xFF, (uint8_t[]) {0x77, 0x01, 0x00, 0x00, 0x10}, 5, 0},
- {0xC0, (uint8_t[]) {0x3B, 0x00}, 2, 0},
- {0xC1, (uint8_t[]) {0x0B, 0x02}, 2, 0},
- {0xC2, (uint8_t[]) {0x37, 0x02}, 2, 0},
- {0xCC, (uint8_t[]) {0x10}, 1, 0},
- {0xB0,
- (uint8_t[]) {0x00, 0x0F, 0x16, 0x0E, 0x11, 0x07, 0x09, 0x09, 0x08, 0x23, 0x05, 0x11, 0x0F, 0x28, 0x2D, 0x18},
- 16, 0},
- {0xB1,
- (uint8_t[]) {0x00, 0x0F, 0x16, 0x0E, 0x11, 0x07, 0x09, 0x08, 0x09, 0x23, 0x05, 0x11, 0x0F, 0x28, 0x2D, 0x18},
- 16, 0},
- {0xFF, (uint8_t[]) {0x77, 0x01, 0x00, 0x00, 0x11}, 5, 0},
- {0xB0, (uint8_t[]) {0x4D}, 1, 0},
- {0xB1, (uint8_t[]) {0x33}, 1, 0},
- {0xB2, (uint8_t[]) {0x87}, 1, 0},
- {0xB5, (uint8_t[]) {0x4B}, 1, 0},
- {0xB7, (uint8_t[]) {0x8C}, 1, 0},
- {0xB8, (uint8_t[]) {0x20}, 1, 0},
- {0xC1, (uint8_t[]) {0x78}, 1, 0},
- {0xC2, (uint8_t[]) {0x78}, 1, 0},
- {0xD0, (uint8_t[]) {0x88}, 1, 0},
- {0xE0, (uint8_t[]) {0x00, 0x00, 0x02}, 3, 0},
- {0xE1, (uint8_t[]) {0x02, 0xF0, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x00, 0x44, 0x44}, 11, 0},
- {0xE2, (uint8_t[]) {0x10, 0x10, 0x40, 0x40, 0xF2, 0xF0, 0x00, 0x00, 0xF2, 0xF0, 0x00, 0x00}, 12, 0},
- {0xE3, (uint8_t[]) {0x00, 0x00, 0x11, 0x11}, 4, 0},
- {0xE4, (uint8_t[]) {0x44, 0x44}, 2, 0},
- {0xE5,
- (uint8_t[]) {0x07, 0xEF, 0xF0, 0xF0, 0x09, 0xF1, 0xF0, 0xF0, 0x03, 0xF3, 0xF0, 0xF0, 0x05, 0xED, 0xF0, 0xF0},
- 16, 0},
- {0xE6, (uint8_t[]) {0x00, 0x00, 0x11, 0x11}, 4, 0},
- {0xE7, (uint8_t[]) {0x44, 0x44}, 2, 0},
- {0xE8,
- (uint8_t[]) {0x08, 0xF0, 0xF0, 0xF0, 0x0A, 0xF2, 0xF0, 0xF0, 0x04, 0xF4, 0xF0, 0xF0, 0x06, 0xEE, 0xF0, 0xF0},
- 16, 0},
- {0xEB, (uint8_t[]) {0x00, 0x00, 0xE4, 0xE4, 0x44, 0x88, 0x40}, 7, 0},
- {0xEC, (uint8_t[]) {0x78, 0x00}, 2, 0},
- {0xED,
- (uint8_t[]) {0x20, 0xF9, 0x87, 0x76, 0x65, 0x54, 0x4F, 0xFF, 0xFF, 0xF4, 0x45, 0x56, 0x67, 0x78, 0x9F, 0x02},
- 16, 0},
- {0xEF, (uint8_t[]) {0x10, 0x0D, 0x04, 0x08, 0x3F, 0x1F}, 6, 0},
- // 退出睡眠模式和开启显示的命令保持不变
- {0x11, (uint8_t[]) {0x00}, 0, 120}, // Sleep Out
- {0x29, (uint8_t[]) {0x00}, 0, 0}, // Display On
- #endif
- };
- static void spi_soft_init(void) {
- gpio_config_t io_conf1 = {
- .mode = GPIO_MODE_OUTPUT,
- .pin_bit_mask = 1ULL << LCD_IO_SPI_CS,
- };
- gpio_config(&io_conf1);
- gpio_set_level(LCD_IO_SPI_CS, 1);
- gpio_config_t io_conf2 = {
- .mode = GPIO_MODE_OUTPUT,
- .pin_bit_mask = 1ULL << LCD_IO_SPI_SCL,
- };
- gpio_config(&io_conf2);
- gpio_set_level(LCD_IO_SPI_SCL, 1);
- gpio_config_t io_conf3 = {
- .mode = GPIO_MODE_OUTPUT,
- .pin_bit_mask = 1ULL << LCD_IO_SPI_SDA,
- };
- gpio_config(&io_conf3);
- gpio_set_level(LCD_IO_SPI_SDA, 1);
- }
- static void spi_soft_write_9bits(uint16_t data) {
- uint8_t i;
- LCD_CS_Clr();
- for (i = 0; i < 9; i++) {
- LCD_SCK_Clr();
- if (data & 0x100) LCD_SDA_Set();
- else
- LCD_SDA_Clr();
- LCD_SCK_Set();
- data <<= 1;
- }
- LCD_CS_Set();;
- }
- static void st7701_write_cmd(uint8_t cmd) {
- uint16_t temp = 0;
- temp = temp | cmd;
- spi_soft_write_9bits(temp);
- }
- static void st7701_write_data(uint8_t data) {
- uint16_t temp = 0x100;
- temp = temp | data;
- spi_soft_write_9bits(temp);
- }
- IRAM_ATTR static bool
- rgb_lcd_on_vsync_event(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_data_t *edata, void *user_ctx) {
- // 最小化中断处理时间
- return lvgl_port_notify_rgb_vsync();
- }
- esp_err_t lcd_st7701_init(void) {
- // 配置背光GPIO
- if (PIN_NUM_BK_LIGHT >= 0) {
- gpio_config_t bk_gpio_config = {
- .mode = GPIO_MODE_OUTPUT,
- .pin_bit_mask = 1ULL << PIN_NUM_BK_LIGHT};
- ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
- }
- // 安装3线SPI面板IO
- ESP_LOGI(TAG, "Install 3-wire SPI panel IO");
- spi_line_config_t line_config = {
- .cs_io_type = IO_TYPE_GPIO,
- .cs_gpio_num = LCD_IO_SPI_CS,
- .scl_io_type = IO_TYPE_GPIO,
- .scl_gpio_num = LCD_IO_SPI_SCL,
- .sda_io_type = IO_TYPE_GPIO,
- .sda_gpio_num = LCD_IO_SPI_SDA,
- .io_expander = NULL,
- };
- esp_lcd_panel_io_3wire_spi_config_t io_config = ST7701_PANEL_IO_3WIRE_SPI_CONFIG(line_config, 0);
- esp_lcd_panel_io_handle_t io_handle = NULL;
- ESP_ERROR_CHECK(esp_lcd_new_panel_io_3wire_spi(&io_config, &io_handle));
- for (int i = 0; i < sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]); i++) {
- st7701_write_cmd(lcd_init_cmds[i].cmd);
- for (int n = 0; n < lcd_init_cmds[i].data_bytes; n++) {
- st7701_write_data(((uint8_t *) lcd_init_cmds[i].data)[n]);
- }
- vTaskDelay(pdMS_TO_TICKS(lcd_init_cmds[i].delay_ms));
- }
- // 安装RGB面板
- ESP_LOGI(TAG, "Install ST7701 panel driver");
- esp_lcd_panel_handle_t lcd_handle = NULL;
- esp_lcd_rgb_panel_config_t rgb_config = {
- .clk_src = LCD_CLK_SRC_DEFAULT,
- .psram_trans_align = 64,
- .data_width = RGB_DATA_WIDTH,
- .bits_per_pixel = RGB_BIT_PER_PIXEL,
- .de_gpio_num = LCD_IO_RGB_DE,
- .pclk_gpio_num = LCD_IO_RGB_PCLK,
- .vsync_gpio_num = LCD_IO_RGB_VSYNC,
- .hsync_gpio_num = LCD_IO_RGB_HSYNC,
- .disp_gpio_num = LCD_IO_RGB_DISP,
- .data_gpio_nums = {
- LCD_IO_RGB_DATA0,
- LCD_IO_RGB_DATA1,
- LCD_IO_RGB_DATA2,
- LCD_IO_RGB_DATA3,
- LCD_IO_RGB_DATA4,
- LCD_IO_RGB_DATA5,
- LCD_IO_RGB_DATA6,
- LCD_IO_RGB_DATA7,
- LCD_IO_RGB_DATA8,
- LCD_IO_RGB_DATA9,
- LCD_IO_RGB_DATA10,
- LCD_IO_RGB_DATA11,
- LCD_IO_RGB_DATA12,
- LCD_IO_RGB_DATA13,
- LCD_IO_RGB_DATA14,
- LCD_IO_RGB_DATA15,
- },
- .timings = ST7701_480_480_PANEL_60HZ_RGB_TIMING(),
- .flags.fb_in_psram = 1,
- .num_fbs = LVGL_PORT_LCD_RGB_BUFFER_NUMS,
- .bounce_buffer_size_px = RGB_BOUNCE_BUFFER_SIZE,
- };
- rgb_config.timings.h_res = LCD_H_RES;
- rgb_config.timings.v_res = LCD_V_RES;
- st7701_vendor_config_t vendor_config = {
- .rgb_config = &rgb_config,
- .init_cmds = lcd_init_cmds,
- .init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]),
- .flags = {
- .auto_del_panel_io = 0,
- .mirror_by_cmd = 1,
- },
- };
- const esp_lcd_panel_dev_config_t panel_config = {
- .reset_gpio_num = LCD_IO_RST,
- .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
- .bits_per_pixel = LCD_BIT_PER_PIXEL,
- .vendor_config = &vendor_config,
- };
- ESP_ERROR_CHECK(esp_lcd_new_panel_st7701(io_handle, &panel_config, &lcd_handle));
- ESP_ERROR_CHECK(esp_lcd_panel_reset(lcd_handle));
- ESP_ERROR_CHECK(esp_lcd_panel_init(lcd_handle));
- esp_lcd_panel_disp_on_off(lcd_handle, true);
- // 初始化I2C
- ESP_LOGI(TAG, "Initialize I2C");
- const i2c_config_t i2c_conf = {
- .mode = I2C_MODE_MASTER,
- .sda_io_num = PIN_NUM_TOUCH_SDA,
- .scl_io_num = PIN_NUM_TOUCH_SCL,
- .sda_pullup_en = GPIO_PULLUP_ENABLE,
- .scl_pullup_en = GPIO_PULLUP_ENABLE,
- .master.clk_speed = 400000,
- };
- ESP_ERROR_CHECK(i2c_param_config(TOUCH_HOST, &i2c_conf));
- ESP_ERROR_CHECK(i2c_driver_install(TOUCH_HOST, i2c_conf.mode, 0, 0, 0));
- // 初始化触摸控制器
- #ifdef SCREEN_FACTORY_HM
- ESP_LOGI(TAG, "Initialize touch controller GT911");
- esp_lcd_panel_io_handle_t tp_io_handle = NULL;
- esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG();
- ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t) TOUCH_HOST, &tp_io_config, &tp_io_handle));
- #endif
- #ifdef SCREEN_FACTORY_YY
- ESP_LOGI(TAG, "Initialize touch controller FT5x06");
- esp_lcd_panel_io_handle_t tp_io_handle = NULL;
- esp_lcd_panel_io_i2c_config_t tp_io_config = {
- .dev_addr = ESP_LCD_TOUCH_IO_I2C_FT5x06_ADDRESS,
- .control_phase_bytes = 1,
- .dc_bit_offset = 0,
- .lcd_cmd_bits = 8,
- .flags = {
- .disable_control_phase = 1,
- }};
- ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t) TOUCH_HOST, &tp_io_config, &tp_io_handle));
- #endif
- esp_lcd_touch_config_t tp_cfg = {
- .x_max = LCD_H_RES,
- .y_max = LCD_V_RES,
- .rst_gpio_num = PIN_NUM_TOUCH_RST,
- .int_gpio_num = PIN_NUM_TOUCH_INT,
- .levels = {
- .reset = 0,
- .interrupt = 0,
- },
- .flags = {
- .swap_xy = 0,
- .mirror_x = 0,
- .mirror_y = 0,
- },
- };
- ESP_LOGI(TAG, "Create touch handle");
- esp_lcd_touch_handle_t tp = NULL;
- #ifdef SCREEN_FACTORY_HM
- ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_gt911(tp_io_handle, &tp_cfg, &tp));
- #endif
- #ifdef SCREEN_FACTORY_YY
- ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_ft5x06(tp_io_handle, &tp_cfg, &tp));
- #endif
- assert(tp != NULL);
- // 初始化LVGL
- ESP_ERROR_CHECK(lvgl_port_init(lcd_handle, tp));
- // 注册RGB面板事件回调
- esp_lcd_rgb_panel_event_callbacks_t cbs = {
- #if RGB_BOUNCE_BUFFER_SIZE > 0
- .on_bounce_frame_finish = rgb_lcd_on_vsync_event,
- #else
- .on_vsync = rgb_lcd_on_vsync_event,
- #endif
- };
- esp_lcd_rgb_panel_register_event_callbacks(lcd_handle, &cbs, NULL);
- return ESP_OK;
- }
- esp_err_t lcd_st7701_backlight_on(void) {
- if (PIN_NUM_BK_LIGHT >= 0) {
- st7701_write_cmd(0x11);
- vTaskDelay(120);
- st7701_write_cmd(0x29);
- ESP_LOGI(TAG, "Turn on LCD backlight");
- backlight_status = true;
- return gpio_set_level(PIN_NUM_BK_LIGHT, LCD_BK_LIGHT_ON_LEVEL);
- }
- return ESP_OK;
- }
- bool lcd_st7701_get_blacklight() {
- return backlight_status;
- }
- esp_err_t lcd_st7701_backlight_off(void) {
- if (PIN_NUM_BK_LIGHT >= 0) {
- st7701_write_cmd(0x10);
- vTaskDelay(120);
- st7701_write_cmd(0x28);
- ESP_LOGI(TAG, "Turn off LCD backlight");
- backlight_status = false;
- return gpio_set_level(PIN_NUM_BK_LIGHT, LCD_BK_LIGHT_OFF_LEVEL);
- }
- return ESP_OK;
- }
|