diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,2 +1,2 @@ -idf_component_register(SRCS "main.c" "wifi.c" "usb_cdc.c" "can.c" +idf_component_register(SRCS "main.c" "wifi.c" "usb_cdc.c" "can.c" "display.c" INCLUDE_DIRS .) diff --git a/main/display.c b/main/display.c new file mode 100644 --- /dev/null +++ b/main/display.c @@ -0,0 +1,265 @@ +// +// display +// + +#include "display.h" +#include "esp_err.h" +#include "esp_log.h" +#include "esp_check.h" +#include "driver/i2c.h" +#include "driver/gpio.h" +#include "driver/spi_master.h" +#include "esp_lcd_panel_io.h" +#include "esp_lcd_panel_vendor.h" +#include "esp_lcd_panel_ops.h" +#include "esp_lvgl_port.h" + + + + +#include "esp_lcd_touch_tt21100.h" + +/* LCD size */ +#define EXAMPLE_LCD_H_RES (320) +#define EXAMPLE_LCD_V_RES (240) + +/* LCD settings */ +#define EXAMPLE_LCD_SPI_NUM (SPI3_HOST) +#define EXAMPLE_LCD_PIXEL_CLK_HZ (40 * 1000 * 1000) +#define EXAMPLE_LCD_CMD_BITS (8) +#define EXAMPLE_LCD_PARAM_BITS (8) +#define EXAMPLE_LCD_COLOR_SPACE (ESP_LCD_COLOR_SPACE_BGR) +#define EXAMPLE_LCD_BITS_PER_PIXEL (16) +#define EXAMPLE_LCD_DRAW_BUFF_DOUBLE (1) +#define EXAMPLE_LCD_DRAW_BUFF_HEIGHT (50) +#define EXAMPLE_LCD_BL_ON_LEVEL (1) + +/* LCD pins */ +#define EXAMPLE_LCD_GPIO_SCLK (GPIO_NUM_7) +#define EXAMPLE_LCD_GPIO_MOSI (GPIO_NUM_6) +#define EXAMPLE_LCD_GPIO_RST (GPIO_NUM_48) +#define EXAMPLE_LCD_GPIO_DC (GPIO_NUM_4) +#define EXAMPLE_LCD_GPIO_CS (GPIO_NUM_5) +#define EXAMPLE_LCD_GPIO_BL (GPIO_NUM_45) + +/* Touch settings */ +#define EXAMPLE_TOUCH_I2C_NUM (0) +#define EXAMPLE_TOUCH_I2C_CLK_HZ (400000) + +/* LCD touch pins */ +#define EXAMPLE_TOUCH_I2C_SCL (GPIO_NUM_18) +#define EXAMPLE_TOUCH_I2C_SDA (GPIO_NUM_8) +#define EXAMPLE_TOUCH_GPIO_INT (GPIO_NUM_20) + +static const char *TAG = "EXAMPLE"; + +/* LCD IO and panel */ +static esp_lcd_panel_io_handle_t lcd_io = NULL; +static esp_lcd_panel_handle_t lcd_panel = NULL; +static esp_lcd_touch_handle_t touch_handle = NULL; + +/* LVGL display and touch */ +static lv_disp_t *lvgl_disp = NULL; +static lv_indev_t *lvgl_touch_indev = NULL; + + + +static esp_err_t __lcd_init(void) +{ + esp_err_t ret = ESP_OK; + + /* LCD backlight */ + gpio_config_t bk_gpio_config = { + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 1ULL << EXAMPLE_LCD_GPIO_BL + }; + ESP_ERROR_CHECK(gpio_config(&bk_gpio_config)); + + /* LCD initialization */ + ESP_LOGD(TAG, "Initialize SPI bus"); + const spi_bus_config_t buscfg = { + .sclk_io_num = EXAMPLE_LCD_GPIO_SCLK, + .mosi_io_num = EXAMPLE_LCD_GPIO_MOSI, + .miso_io_num = GPIO_NUM_NC, + .quadwp_io_num = GPIO_NUM_NC, + .quadhd_io_num = GPIO_NUM_NC, + .max_transfer_sz = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_DRAW_BUFF_HEIGHT * sizeof(uint16_t), + }; + ESP_RETURN_ON_ERROR(spi_bus_initialize(EXAMPLE_LCD_SPI_NUM, &buscfg, SPI_DMA_CH_AUTO), TAG, "SPI init failed"); + + ESP_LOGD(TAG, "Install panel IO"); + const esp_lcd_panel_io_spi_config_t io_config = { + .dc_gpio_num = EXAMPLE_LCD_GPIO_DC, + .cs_gpio_num = EXAMPLE_LCD_GPIO_CS, + .pclk_hz = EXAMPLE_LCD_PIXEL_CLK_HZ, + .lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS, + .lcd_param_bits = EXAMPLE_LCD_PARAM_BITS, + .spi_mode = 0, + .trans_queue_depth = 10, + }; + ESP_GOTO_ON_ERROR(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)EXAMPLE_LCD_SPI_NUM, &io_config, &lcd_io), err, TAG, "New panel IO failed"); + + ESP_LOGD(TAG, "Install LCD driver"); + const esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = EXAMPLE_LCD_GPIO_RST, + .color_space = EXAMPLE_LCD_COLOR_SPACE, + .bits_per_pixel = EXAMPLE_LCD_BITS_PER_PIXEL, + }; + ESP_GOTO_ON_ERROR(esp_lcd_new_panel_st7789(lcd_io, &panel_config, &lcd_panel), err, TAG, "New panel failed"); + + esp_lcd_panel_reset(lcd_panel); + esp_lcd_panel_init(lcd_panel); + esp_lcd_panel_mirror(lcd_panel, true, true); + esp_lcd_panel_disp_on_off(lcd_panel, true); + + /* LCD backlight on */ + ESP_ERROR_CHECK(gpio_set_level(EXAMPLE_LCD_GPIO_BL, EXAMPLE_LCD_BL_ON_LEVEL)); + + return ret; + +err: + if (lcd_panel) { + esp_lcd_panel_del(lcd_panel); + } + if (lcd_io) { + esp_lcd_panel_io_del(lcd_io); + } + spi_bus_free(EXAMPLE_LCD_SPI_NUM); + return ret; +} + + +// static esp_err_t app_touch_init(void) +// { +// /* Initilize I2C */ +// const i2c_config_t i2c_conf = { +// .mode = I2C_MODE_MASTER, +// .sda_io_num = EXAMPLE_TOUCH_I2C_SDA, +// .sda_pullup_en = GPIO_PULLUP_DISABLE, +// .scl_io_num = EXAMPLE_TOUCH_I2C_SCL, +// .scl_pullup_en = GPIO_PULLUP_DISABLE, +// .master.clk_speed = EXAMPLE_TOUCH_I2C_CLK_HZ +// }; +// ESP_RETURN_ON_ERROR(i2c_param_config(EXAMPLE_TOUCH_I2C_NUM, &i2c_conf), TAG, "I2C configuration failed"); +// ESP_RETURN_ON_ERROR(i2c_driver_install(EXAMPLE_TOUCH_I2C_NUM, i2c_conf.mode, 0, 0, 0), TAG, "I2C initialization failed"); + +// /* Initialize touch HW */ +// const esp_lcd_touch_config_t tp_cfg = { +// .x_max = EXAMPLE_LCD_H_RES, +// .y_max = EXAMPLE_LCD_V_RES, +// .rst_gpio_num = GPIO_NUM_NC, // Shared with LCD reset +// .int_gpio_num = EXAMPLE_TOUCH_GPIO_INT, +// .levels = { +// .reset = 0, +// .interrupt = 0, +// }, +// .flags = { +// .swap_xy = 0, +// .mirror_x = 1, +// .mirror_y = 0, +// }, +// }; +// esp_lcd_panel_io_handle_t tp_io_handle = NULL; +// const esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_TT21100_CONFIG(); +// ESP_RETURN_ON_ERROR(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)EXAMPLE_TOUCH_I2C_NUM, &tp_io_config, &tp_io_handle), TAG, ""); +// return esp_lcd_touch_new_i2c_tt21100(tp_io_handle, &tp_cfg, &touch_handle); +// } + +static esp_err_t __lvgl_init(void) +{ + /* Initialize LVGL */ + const lvgl_port_cfg_t lvgl_cfg = { + .task_priority = 4, /* LVGL task priority */ + .task_stack = 4096, /* LVGL task stack size */ + .task_affinity = -1, /* LVGL task pinned to core (-1 is no affinity) */ + .task_max_sleep_ms = 500, /* Maximum sleep in LVGL task */ + .timer_period_ms = 5 /* LVGL timer tick period in ms */ + }; + ESP_RETURN_ON_ERROR(lvgl_port_init(&lvgl_cfg), TAG, "LVGL port initialization failed"); + + /* Add LCD screen */ + ESP_LOGD(TAG, "Add LCD screen"); + const lvgl_port_display_cfg_t disp_cfg = { + .io_handle = lcd_io, + .panel_handle = lcd_panel, + .buffer_size = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_DRAW_BUFF_HEIGHT * sizeof(uint16_t), + .double_buffer = EXAMPLE_LCD_DRAW_BUFF_DOUBLE, + .hres = EXAMPLE_LCD_H_RES, + .vres = EXAMPLE_LCD_V_RES, + .monochrome = false, + /* Rotation values must be same as used in esp_lcd for initial settings of the screen */ + .rotation = { + .swap_xy = false, + .mirror_x = true, + .mirror_y = true, + }, + .flags = { + .buff_dma = true, + } + }; + lvgl_disp = lvgl_port_add_disp(&disp_cfg); + + /* Add touch input (for selected screen) */ + // const lvgl_port_touch_cfg_t touch_cfg = { + // .disp = lvgl_disp, + // .handle = touch_handle, + // }; + // lvgl_touch_indev = lvgl_port_add_touch(&touch_cfg); + + return ESP_OK; +} + +static void _app_button_cb(lv_event_t *e) +{ + lv_disp_rot_t rotation = lv_disp_get_rotation(lvgl_disp); + rotation++; + if (rotation > LV_DISP_ROT_270) { + rotation = LV_DISP_ROT_NONE; + } + + /* LCD HW rotation */ + lv_disp_set_rotation(lvgl_disp, rotation); +} + +static void show_stuff(void) +{ + lv_obj_t *scr = lv_scr_act(); + + /* Task lock */ + lvgl_port_lock(0); + + /* Your LVGL objects code here .... */ + + /* Label */ + lv_obj_t *label = lv_label_create(scr); + lv_label_set_recolor(label, true); + lv_obj_set_width(label, EXAMPLE_LCD_H_RES); + lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0); + lv_label_set_text(label, "#FF0000 "LV_SYMBOL_BELL" Hello world Espressif and LVGL "LV_SYMBOL_BELL"#\n#FF9400 "LV_SYMBOL_WARNING" For simplier initialization, use BSP "LV_SYMBOL_WARNING" #"); + lv_obj_align(label, LV_ALIGN_CENTER, 0, -30); + + /* Button */ + lv_obj_t *btn = lv_btn_create(scr); + label = lv_label_create(btn); + lv_label_set_text_static(label, "Rotate screen"); + lv_obj_align(btn, LV_ALIGN_BOTTOM_MID, 0, -30); + lv_obj_add_event_cb(btn, _app_button_cb, LV_EVENT_CLICKED, NULL); + + /* Task unlock */ + lvgl_port_unlock(); +} + +void display_init(void) +{ + /* LCD HW initialization */ + ESP_ERROR_CHECK(__lcd_init()); + + /* Touch initialization */ +// ESP_ERROR_CHECK(app_touch_init()); + + /* LVGL initialization */ + ESP_ERROR_CHECK(__lvgl_init()); + + /* Show LVGL objects */ + show_stuff(); +} \ No newline at end of file diff --git a/main/display.h b/main/display.h new file mode 100644 --- /dev/null +++ b/main/display.h @@ -0,0 +1,6 @@ +#ifndef _DISPLAY_H_ +#define _DISPLAY_H_ + +void display_init(void); + +#endif \ No newline at end of file diff --git a/main/idf_component.yml b/main/idf_component.yml --- a/main/idf_component.yml +++ b/main/idf_component.yml @@ -1,4 +1,6 @@ ## IDF Component Manager Manifest File dependencies: + espressif/esp_lcd_touch_tt21100: "*" + espressif/esp_lvgl_port: "*" espressif/esp_tinyusb: "^1" idf: "^5.0" diff --git a/main/main.c b/main/main.c --- a/main/main.c +++ b/main/main.c @@ -15,6 +15,7 @@ #include "wifi.h" #include "usb_cdc.h" #include "can.h" +#include "display.h" // Private variables @@ -42,4 +43,7 @@ void app_main(void) // Initialize canbus can_init(); + // Initialize display + display_init(); + }