#include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/gpio.h" #include "driver/spi_master.h" #include "esp_timer.h" #include "esp_lcd_panel_io.h" #include "esp_lcd_panel_vendor.h" #include "esp_lcd_panel_ops.h" #include "esp_err.h" #include "esp_log.h" #include "lvgl.h" #include "esp_lcd_sh8601.h" #include "ui.h" #define LCD_HOST (SPI2_HOST) #define PIN_NUM_LCD_CS (GPIO_NUM_12) #define PIN_NUM_LCD_PCLK (GPIO_NUM_10) #define PIN_NUM_LCD_DATA0 (GPIO_NUM_13) #define PIN_NUM_LCD_DATA1 (GPIO_NUM_11) #define PIN_NUM_LCD_DATA2 (GPIO_NUM_14) #define PIN_NUM_LCD_DATA3 (GPIO_NUM_9) #define PIN_NUM_LCD_RST (GPIO_NUM_8) #define PIN_NUM_BK_LIGHT (GPIO_NUM_17) #define LCD_H_RES 471 #define LCD_V_RES 466 #define LCD_BIT_PER_PIXEL 16 #define LCD_BK_LIGHT_ON_LEVEL 1 static const char *TAG = "main"; static const sh8601_lcd_init_cmd_t lcd_init_cmds[] = { {0xFE, (uint8_t []){0x00}, 0, 0}, {0xC4, (uint8_t []){0x80}, 1, 0}, {0x3A, (uint8_t []){0x55}, 1, 0}, {0x35, (uint8_t []){0x00}, 0, 10}, {0x53, (uint8_t []){0x20}, 1, 10}, {0x51, (uint8_t []){0xFF}, 1, 10}, {0x63, (uint8_t []){0xFF}, 1, 10}, {0x2A, (uint8_t []){0x00,0x06,0x01,0xDD}, 4, 0}, {0x2B, (uint8_t []){0x00,0x00,0x01,0xD1}, 4, 0}, {0x11, (uint8_t []){0x00}, 0, 60}, {0x29, (uint8_t []){0x00}, 0, 0}, }; static lv_disp_t *disp = NULL; static esp_lcd_panel_handle_t panel_handle = NULL; void lvgl_flush_cb(lv_display_t *disp_drv, const lv_area_t *area, uint8_t *color_map); static bool notify_lvgl_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx) { lv_display_t *disp_drv = (lv_display_t *)user_ctx; lv_disp_flush_ready(disp_drv); return true; } static void lv_tick_inc_cb(void *arg) { lv_tick_inc((uint32_t)(uintptr_t)arg); } void lvgl_display_init(void) { 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)); gpio_set_level(PIN_NUM_BK_LIGHT, LCD_BK_LIGHT_ON_LEVEL); ESP_LOGI(TAG, "Backlight turned on"); disp = lv_display_create(LCD_H_RES, LCD_V_RES); lv_display_set_color_format(disp, LV_COLOR_FORMAT_RGB565); lv_display_set_flush_cb(disp, lvgl_flush_cb); size_t buf_size = (LCD_H_RES * LCD_V_RES / 10) * LV_COLOR_FORMAT_GET_SIZE(LV_COLOR_FORMAT_NATIVE); uint8_t *buf1 = heap_caps_aligned_alloc(64, buf_size, MALLOC_CAP_DMA); assert(buf1); lv_display_set_buffers(disp, buf1, NULL, buf_size, LV_DISPLAY_RENDER_MODE_PARTIAL); spi_bus_config_t buscfg = SH8601_PANEL_BUS_QSPI_CONFIG( PIN_NUM_LCD_PCLK, PIN_NUM_LCD_DATA0, PIN_NUM_LCD_DATA1, PIN_NUM_LCD_DATA2, PIN_NUM_LCD_DATA3, LCD_H_RES * LCD_V_RES * LCD_BIT_PER_PIXEL / 8 ); ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO)); esp_lcd_panel_io_handle_t io_handle = NULL; esp_lcd_panel_io_spi_config_t io_config = SH8601_PANEL_IO_QSPI_CONFIG( PIN_NUM_LCD_CS, notify_lvgl_flush_ready, (void *)disp ); ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &io_handle)); sh8601_vendor_config_t vendor_config = { .init_cmds = lcd_init_cmds, .init_cmds_size = sizeof(lcd_init_cmds) / sizeof(sh8601_lcd_init_cmd_t), .flags = { .use_qspi_interface = 1, } }; esp_lcd_panel_dev_config_t panel_config = { .reset_gpio_num = PIN_NUM_LCD_RST, .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, .bits_per_pixel = LCD_BIT_PER_PIXEL, .vendor_config = &vendor_config, }; ESP_LOGI(TAG, "Installing SH8601 LCD panel driver"); ESP_ERROR_CHECK(esp_lcd_new_panel_sh8601(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)); // Actually show somthing on the screen! create_ui(); } void lvgl_flush_cb(lv_display_t *disp_drv, const lv_area_t *area, uint8_t *color_map) { esp_lcd_panel_draw_bitmap(panel_handle, area->x1, area->y1, area->x2 + 1, area->y2 + 1, color_map); // flush_ready is called from the notify callback } void app_main(void) { lv_init(); lvgl_display_init(); const esp_timer_create_args_t lvgl_tick_timer_args = { .callback = &lv_tick_inc_cb, .arg = (void*)1, .dispatch_method = ESP_TIMER_TASK, .name = "lv_tick" }; esp_timer_handle_t lvgl_tick_timer; ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer)); ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, 1000)); while (1) { lv_timer_handler(); vTaskDelay(pdMS_TO_TICKS(5)); } }