Add LVGL and set up with display/touch drivers

This commit is contained in:
maddiebaka
2025-12-26 11:04:16 -05:00
parent cb92f69ee3
commit 3256ab2e65
7 changed files with 269 additions and 58 deletions
+53 -1
View File
@@ -1,4 +1,19 @@
dependencies:
atanisoft/esp_lcd_touch_xpt2046:
component_hash:
7e6381b67b6e487379118368b8e91624dc87036ef5734818de1db9eb35697998
dependencies:
- name: espressif/esp_lcd_touch
registry_url: https://components.espressif.com
require: private
version: '>=1.0.4'
- name: idf
require: private
version: '>=4.4'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.6
espressif/cmake_utilities:
component_hash:
351350613ceafba240b761b4ea991e0f231ac7a9f59a9ee901f751bddc0bb18f
@@ -25,13 +40,50 @@ dependencies:
registry_url: https://components.espressif.com/
type: service
version: 2.0.1
espressif/esp_lcd_touch:
component_hash:
3f85a7d95af876f1a6ecca8eb90a81614890d0f03a038390804e5a77e2caf862
dependencies:
- name: idf
require: private
version: '>=4.4.2'
source:
registry_url: https://components.espressif.com
type: service
version: 1.2.1
espressif/esp_lvgl_port:
component_hash:
f872401524cb645ee6ff1c9242d44fb4ddcfd4d37d7be8b9ed3f4e85a404efcd
dependencies:
- name: idf
require: private
version: '>=5.1'
- name: lvgl/lvgl
registry_url: https://components.espressif.com
require: public
version: '>=8,<10'
source:
registry_url: https://components.espressif.com/
type: service
version: 2.7.0
idf:
source:
type: idf
version: 5.5.1
lvgl/lvgl:
component_hash:
17e68bfd21f0edf4c3ee838e2273da840bf3930e5dbc3bfa6c1190c3aed41f9f
dependencies: []
source:
registry_url: https://components.espressif.com/
type: service
version: 9.4.0
direct_dependencies:
- atanisoft/esp_lcd_touch_xpt2046
- espressif/esp_lcd_ili9341
- espressif/esp_lvgl_port
- idf
manifest_hash: 5c04a0422ee419cb472e6df05c9d4292985ae0cd069ef8404da0161609cc967c
- lvgl/lvgl
manifest_hash: d2b549f17124d3d38e4add4614fb10956ada1a576e4c5f6a623ea3756bcd3ba5
target: esp32
version: 2.0.0
+2 -1
View File
@@ -1,3 +1,4 @@
idf_component_register(SRCS "spincoat-plater-firmware.c" "dshot_esc_encoder.c" "display.c"
PRIV_REQUIRES esp_driver_rmt esp_driver_gpio esp_driver_uart esp_driver_spi esp_lcd unity
PRIV_REQUIRES esp_driver_rmt esp_driver_gpio esp_driver_uart esp_driver_spi
esp_lcd unity lvgl esp_lvgl_port esp_lcd_touch_xpt2046
INCLUDE_DIRS ".")
+34 -6
View File
@@ -9,36 +9,64 @@ menu "Pin Mapping Configuration"
default 27
help
This is the pin used for receiving UART telemetry from the ESC.
config TFT_MISO_PIN
config TFT_MISO
int "SPI LCD MISO pin"
default 12
help
This is the pin for MISO on the SPI LCD.
config TFT_MOSI_PIN
config TFT_MOSI
int "SPI LCD MOSI pin"
default 13
help
This is the pin for MOSI on the SPI LCD.
config TFT_SCKL_PIN
config TFT_SCKL
int "SPI LCD SCKL pin"
default 14
help
This is the pin for SCKL on the SPI LCD.
config TFT_CS_PIN
config TFT_CS
int "SPI LCD CS pin"
default 15
help
This is the pin for CS on the SPI LCD.
config TFT_DC_PIN
config TFT_DC
int "SPI LCD DC pin"
default 2
help
This is the pin for DC on the SPI LCD.
config TFT_BL_PIN
config TFT_BL
int "SPI LCD BL (backlight) pin"
default 21
help
This is the pin for backlight control on the SPI LCD.
config TOUCH_IRQ
int "SPI touchscreen IRQ pin"
default 36
help
This is the pin for IRQ on the SPI touchscreen.
config TOUCH_MOSI
int "SPI touchscreen MOSI pin"
default 32
help
This is the pin for MOSI on the SPI touchscreen.
config TOUCH_MISO
int "SPI touchscreen MISO pin"
default 39
help
This is the pin for MISO on the SPI touchscreen.
config TOUCH_CLK
int "SPI touchscreen CLK pin"
default 25
help
This is the pin for CLK on the SPI touchscreen.
config TOUCH_CS
int "SPI touchscreen CS pin"
default 33
help
This is the pin for CS on the SPI touchscreen.
config TFT_HRES
int "The horizontal resolution of the TFT display"
default 320
+167 -37
View File
@@ -18,9 +18,17 @@
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_commands.h"
#include "esp_lcd_ili9341.h"
#include "esp_lcd_touch_xpt2046.h"
#include "lvgl.h"
#include "esp_lvgl_port.h"
SemaphoreHandle_t refresh_finish = NULL;
esp_lcd_panel_io_handle_t io_handle = NULL;
esp_lcd_panel_handle_t panel_handle = NULL;
esp_lcd_touch_handle_t tp = NULL;
static const char * TAG = "spincoat-plater-firmware/display";
/**
@@ -36,29 +44,108 @@ IRAM_ATTR static bool notify_refresh_ready(esp_lcd_panel_io_handle_t panel_io, e
}
/**
* Draws a test bitmap of stripes of colors to the LCD.
* Callback for LVGL pointer input device, it reads from the esp_lcd_touch driver and updates
* the LVGL internal state for event handling.
*/
void test_draw_bitmap(esp_lcd_panel_handle_t panel_handle)
{
refresh_finish = xSemaphoreCreateBinary();
TEST_ASSERT_NOT_NULL(refresh_finish);
void touch_driver_read(lv_indev_t * indev, lv_indev_data_t * data) {
ESP_ERROR_CHECK(esp_lcd_touch_read_data(tp));
uint16_t row_line = TFT_VRES / TFT_BPP;
uint8_t byte_per_pixel = TFT_BPP / 8;
uint8_t *color = (uint8_t *)heap_caps_calloc(1, row_line * TFT_VRES * byte_per_pixel, MALLOC_CAP_DMA);
TEST_ASSERT_NOT_NULL(color);
uint16_t x[1];
uint16_t y[1];
uint16_t strength[1];
uint8_t count = 0;
for (int j = 0; j < TFT_BPP; j++) {
for (int i = 0; i < row_line * TFT_HRES ; i++) {
for (int k = 0; k < byte_per_pixel; k++) {
color[i * byte_per_pixel + k] = (SPI_SWAP_DATA_TX(BIT(j), TFT_BPP) >> (k * 8)) & 0xff;
}
}
TEST_ESP_OK(esp_lcd_panel_draw_bitmap(panel_handle, 0, j * row_line, TFT_HRES , (j + 1) * row_line, color));
xSemaphoreTake(refresh_finish, portMAX_DELAY);
bool touchpad_pressed = esp_lcd_touch_get_coordinates(tp, x, y, strength, &count, 1);
if(touchpad_pressed == true) {
//ESP_LOGI(TAG, "Touchpad pressed from LVGL..\n");
data->point.x = x[0];
data->point.y = y[0];
data->state = LV_INDEV_STATE_PRESSED;
} else {
data->state = LV_INDEV_STATE_RELEASED;
}
free(color);
vSemaphoreDelete(refresh_finish);
}
/**
* Callback for LVGL button events.
*/
static void btn_event_cb(lv_event_t * e) {
lv_event_code_t code = lv_event_get_code(e);
//ESP_LOGI(TAG, "Button callback fired.");
if(code == LV_EVENT_CLICKED) {
ESP_LOGI(TAG, "LVGL button pressed.");
}
}
/**
* Draws a test UI
*/
void lv_example_btn_1(void)
{
lv_obj_t * label;
lv_obj_t * btn1 = lv_btn_create(lv_scr_act());
lv_obj_add_event_cb(btn1, btn_event_cb, LV_EVENT_ALL, NULL);
lv_obj_set_width(btn1, 120);
lv_obj_set_height(btn1, 100);
lv_obj_align(btn1, LV_ALIGN_CENTER, 0, -40);
label = lv_label_create(btn1);
lv_label_set_text(label, "Button");
lv_obj_center(label);
lv_obj_t * btn2 = lv_btn_create(lv_scr_act());
lv_obj_add_event_cb(btn2, btn_event_cb, LV_EVENT_ALL, NULL);
lv_obj_align(btn2, LV_ALIGN_CENTER, 0, 40);
lv_obj_add_flag(btn2, LV_OBJ_FLAG_CHECKABLE);
lv_obj_set_height(btn2, LV_SIZE_CONTENT);
label = lv_label_create(btn2);
lv_label_set_text(label, "Toggle");
lv_obj_center(label);
}
/**
* Initializes the SPI bus and starts communication with xpt2046 touch controller.
*/
void init_touchscreen_xpt2046(void) {
ESP_LOGI(TAG, "Initialize touchscreen SPI bus");
const spi_bus_config_t ts_bus_config = {
.mosi_io_num = CONFIG_TOUCH_MOSI,
.miso_io_num = CONFIG_TOUCH_MISO,
.sclk_io_num = CONFIG_TOUCH_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4096,
};
ESP_ERROR_CHECK(spi_bus_initialize(TOUCH_SPI_HOST, &ts_bus_config, SPI_DMA_CH_AUTO));
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
esp_lcd_panel_io_spi_config_t tp_io_config = ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG(CONFIG_TOUCH_CS);
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(TOUCH_SPI_HOST, &tp_io_config, &tp_io_handle));
esp_lcd_touch_config_t tp_cfg = {
.x_max = TFT_HRES,
.y_max = TFT_VRES,
.rst_gpio_num = -1,
.int_gpio_num = -1,
.flags = {
.swap_xy = 1,
.mirror_x = 0,
.mirror_y = 0,
},
};
ESP_LOGI(TAG, "Initialize touch controller XPT2046");
ESP_ERROR_CHECK(esp_lcd_touch_new_spi_xpt2046(tp_io_handle, &tp_cfg, &tp));
ESP_LOGI(TAG, "Finished initialization of XPT2046 touch driver");
}
/**
@@ -68,7 +155,7 @@ void init_spi_lcd(void) {
ESP_LOGI(TAG, "Turn on backlight");
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << GPIO_TFT_BL),
.pin_bit_mask = (1ULL << CONFIG_TFT_BL),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
@@ -76,22 +163,21 @@ void init_spi_lcd(void) {
};
gpio_config(&io_conf);
gpio_set_level(GPIO_TFT_BL, 1);
gpio_set_level(CONFIG_TFT_BL, 1);
ESP_LOGI(TAG, "Initialize SPI bus");
const spi_bus_config_t bus_config = ILI9341_PANEL_BUS_SPI_CONFIG(GPIO_TFT_SCKL,
GPIO_TFT_MOSI, TFT_HRES * 80 * TFT_BPP / 8);
const spi_bus_config_t bus_config = ILI9341_PANEL_BUS_SPI_CONFIG(CONFIG_TFT_SCKL,
CONFIG_TFT_MOSI, TFT_HRES * 80 * TFT_BPP / 8);
TEST_ESP_OK(spi_bus_initialize(LCD_SPI_HOST, &bus_config, SPI_DMA_CH_AUTO));
ESP_LOGI(TAG, "Install panel IO");
esp_lcd_panel_io_handle_t io_handle = NULL;
const esp_lcd_panel_io_spi_config_t io_config = ILI9341_PANEL_IO_SPI_CONFIG(GPIO_TFT_CS, GPIO_TFT_DC,
const esp_lcd_panel_io_spi_config_t io_config = ILI9341_PANEL_IO_SPI_CONFIG(CONFIG_TFT_CS, CONFIG_TFT_DC,
notify_refresh_ready, NULL);
TEST_ESP_OK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_SPI_HOST, &io_config, &io_handle));
ESP_LOGI(TAG, "Install ili9341 panel driver");
esp_lcd_panel_handle_t panel_handle = NULL;
const esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = -1, // Shared with Touch reset
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
@@ -113,15 +199,59 @@ void init_spi_lcd(void) {
TEST_ESP_OK(esp_lcd_panel_disp_on_off(panel_handle, true));
#endif
ESP_LOGI(TAG, "Finished init of spi LCD.");
ESP_LOGI(TAG, "Drawing bitmap.");;
test_draw_bitmap(panel_handle);
vTaskDelay(pdMS_TO_TICKS(3000));
// Tear it back down, move this into a function to clean up after ourselves if it's ever needed.
ESP_LOGI(TAG, "Destroying and cleaning up LCD/SPI handles.");
gpio_reset_pin(GPIO_TFT_BL);
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
TEST_ESP_OK(spi_bus_free(LCD_SPI_HOST));
ESP_LOGI(TAG, "Finished init of spi LCD");
}
/**
* Initializes the LVGL display and sets everything up so that LVGL can draw to the TFT LCD.
*/
void init_lvgl_display(void) {
static lv_disp_t * disp_handle = NULL;
const lvgl_port_cfg_t lvgl_cfg = ESP_LVGL_PORT_INIT_CONFIG();
TEST_ESP_OK(lvgl_port_init(&lvgl_cfg));
const lvgl_port_display_cfg_t disp_cfg = {
.io_handle = io_handle,
.panel_handle = panel_handle,
.buffer_size = LVGL_BUF_SIZE,
.double_buffer = true,
.hres = TFT_HRES,
.vres = TFT_VRES,
.monochrome = false,
.color_format = LV_COLOR_FORMAT_RGB565,
.rotation = {
.swap_xy = true,
.mirror_x = false,
.mirror_y = false,
},
.flags = {
.buff_dma = false,
.swap_bytes = false,
}
};
disp_handle = lvgl_port_add_disp(&disp_cfg);
}
/**
* Initializes the LVGL input driver as a pointer type so that LVGL can read input and dispatch
* UI events.
*/
void init_input(void) {
lv_indev_t * indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
lv_indev_set_read_cb(indev, touch_driver_read);
}
/**
* Main function that completely initializes the TFT LCD, the touchscreen, the LVGL display,
* input device and draws the UI.
*/
void init_display(void) {
init_spi_lcd();
init_touchscreen_xpt2046();
init_lvgl_display();
init_input();
lv_example_btn_1();
}
+9 -12
View File
@@ -4,17 +4,14 @@
#include "esp_lcd_panel_io.h"
#define LCD_SPI_HOST SPI2_HOST
#define LCD_SPI_HOST SPI2_HOST
#define TOUCH_SPI_HOST SPI3_HOST
#define GPIO_TFT_MISO CONFIG_TFT_MISO_PIN
#define GPIO_TFT_MOSI CONFIG_TFT_MOSI_PIN
#define GPIO_TFT_SCKL CONFIG_TFT_SCKL_PIN
#define GPIO_TFT_CS CONFIG_TFT_CS_PIN
#define GPIO_TFT_DC CONFIG_TFT_DC_PIN
#define GPIO_TFT_BL CONFIG_TFT_BL_PIN // Backlight
#define TFT_HRES CONFIG_TFT_HRES
#define TFT_VRES CONFIG_TFT_VRES
#define TFT_BPP CONFIG_TFT_BPP
#define TFT_HRES CONFIG_TFT_HRES
#define TFT_VRES CONFIG_TFT_VRES
#define TFT_BPP CONFIG_TFT_BPP
#define LVGL_BUF_SIZE TFT_VRES * TFT_HRES / 10 * (TFT_BPP / 8)
/**
* Draws a test bitmap of stripes of colors to the LCD.
@@ -22,6 +19,6 @@
void test_draw_bitmap(esp_lcd_panel_handle_t panel_handle);
/**
* Initializes the SPI LCD in preparation for writing graphics to it.
* Initializes the display TFT and touchscreen.
*/
void init_spi_lcd(void);
void init_display(void);
+3
View File
@@ -15,3 +15,6 @@ dependencies:
# # All dependencies of `main` are public by default.
# public: true
espressif/esp_lcd_ili9341: ^2.0.0
lvgl/lvgl: ^9.4.0
espressif/esp_lvgl_port: ^2.3.0
atanisoft/esp_lcd_touch_xpt2046: ^1.0.2
+1 -1
View File
@@ -206,7 +206,7 @@ void parse_telemetry(void) {
}
void app_main(void) {
init_spi_lcd();
init_display();
init_rmt_esc_tx();
throttle.throttle = 300;