226 lines
6.7 KiB
C
226 lines
6.7 KiB
C
|
|
/*
|
||
|
|
* LVGL bring-up for ESP32-2432S028R ("Cheap Yellow Display")
|
||
|
|
* ESP-IDF 5.2+ / LVGL 9 / esp_lvgl_port 2.x
|
||
|
|
*
|
||
|
|
* main/idf_component.yml:
|
||
|
|
* dependencies:
|
||
|
|
* idf: ">=5.2"
|
||
|
|
* espressif/esp_lvgl_port: "^2"
|
||
|
|
* espressif/esp_lcd_ili9341: "^1"
|
||
|
|
* atanisoft/esp_lcd_touch_xpt2046: "^1"
|
||
|
|
*
|
||
|
|
* main/CMakeLists.txt:
|
||
|
|
* idf_component_register(SRCS "testing.c"
|
||
|
|
* PRIV_REQUIRES esp_driver_gpio esp_driver_spi esp_lcd
|
||
|
|
* INCLUDE_DIRS ".")
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include "freertos/FreeRTOS.h"
|
||
|
|
#include "freertos/task.h"
|
||
|
|
#include "driver/gpio.h"
|
||
|
|
#include "driver/spi_master.h"
|
||
|
|
#include "esp_lcd_panel_io.h"
|
||
|
|
#include "esp_lcd_panel_ops.h"
|
||
|
|
#include "esp_lcd_panel_vendor.h"
|
||
|
|
#include "esp_lcd_touch_xpt2046.h"
|
||
|
|
#include "esp_lvgl_port.h"
|
||
|
|
#include "esp_err.h"
|
||
|
|
#include "esp_log.h"
|
||
|
|
|
||
|
|
static const char *TAG = "cyd";
|
||
|
|
|
||
|
|
/* ---- Display: ILI9341 on SPI2 (HSPI) ---- */
|
||
|
|
#define LCD_HOST SPI2_HOST
|
||
|
|
#define PIN_LCD_SCLK 14
|
||
|
|
#define PIN_LCD_MOSI 13
|
||
|
|
#define PIN_LCD_MISO 12
|
||
|
|
#define PIN_LCD_CS 15
|
||
|
|
#define PIN_LCD_DC 2
|
||
|
|
#define PIN_LCD_RST -1 /* tied high on this board */
|
||
|
|
#define PIN_LCD_BL 21 /* active high */
|
||
|
|
|
||
|
|
/* ---- Touch: XPT2046 on SPI3 (VSPI) ---- */
|
||
|
|
#define TOUCH_HOST SPI3_HOST
|
||
|
|
#define PIN_TP_SCLK 25
|
||
|
|
#define PIN_TP_MOSI 32
|
||
|
|
#define PIN_TP_MISO 39 /* input-only pin, fine for MISO */
|
||
|
|
#define PIN_TP_CS 33
|
||
|
|
#define PIN_TP_IRQ 36 /* input-only pin */
|
||
|
|
|
||
|
|
#define LCD_H_RES 240
|
||
|
|
#define LCD_V_RES 320
|
||
|
|
#define LCD_CMD_BITS 8
|
||
|
|
#define LCD_PARAM_BITS 8
|
||
|
|
#define LCD_PIXEL_CLOCK_HZ (40 * 1000 * 1000)
|
||
|
|
|
||
|
|
/* XPT2046 is slow — datasheet max is ~2.5 MHz. Going faster gives
|
||
|
|
* garbage coordinates that look like random taps. */
|
||
|
|
#define TOUCH_CLOCK_HZ (2 * 1000 * 1000)
|
||
|
|
|
||
|
|
/* Partial draw buffer. No PSRAM on this board, so keep it modest:
|
||
|
|
* 240 * 40 * 2 bytes = 19.2 KB per buffer, doubled = 38.4 KB. */
|
||
|
|
#define LVGL_BUF_LINES 40
|
||
|
|
|
||
|
|
static esp_lcd_panel_handle_t s_panel = NULL;
|
||
|
|
static esp_lcd_panel_io_handle_t s_panel_io = NULL;
|
||
|
|
static esp_lcd_touch_handle_t s_touch = NULL;
|
||
|
|
static lv_display_t *s_disp = NULL;
|
||
|
|
static lv_indev_t *s_indev = NULL;
|
||
|
|
|
||
|
|
static void backlight_init(void)
|
||
|
|
{
|
||
|
|
const gpio_config_t cfg = {
|
||
|
|
.mode = GPIO_MODE_OUTPUT,
|
||
|
|
.pin_bit_mask = 1ULL << PIN_LCD_BL,
|
||
|
|
};
|
||
|
|
ESP_ERROR_CHECK(gpio_config(&cfg));
|
||
|
|
gpio_set_level(PIN_LCD_BL, 0); /* off until the panel is ready */
|
||
|
|
}
|
||
|
|
|
||
|
|
static void display_init(void)
|
||
|
|
{
|
||
|
|
ESP_LOGI(TAG, "init LCD SPI bus");
|
||
|
|
const spi_bus_config_t bus = {
|
||
|
|
.sclk_io_num = PIN_LCD_SCLK,
|
||
|
|
.mosi_io_num = PIN_LCD_MOSI,
|
||
|
|
.miso_io_num = PIN_LCD_MISO,
|
||
|
|
.quadwp_io_num = -1,
|
||
|
|
.quadhd_io_num = -1,
|
||
|
|
.max_transfer_sz = LCD_H_RES * LVGL_BUF_LINES * sizeof(uint16_t),
|
||
|
|
};
|
||
|
|
ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &bus, SPI_DMA_CH_AUTO));
|
||
|
|
|
||
|
|
const esp_lcd_panel_io_spi_config_t io_cfg = {
|
||
|
|
.cs_gpio_num = PIN_LCD_CS,
|
||
|
|
.dc_gpio_num = PIN_LCD_DC,
|
||
|
|
.spi_mode = 0,
|
||
|
|
.pclk_hz = LCD_PIXEL_CLOCK_HZ,
|
||
|
|
.trans_queue_depth = 10,
|
||
|
|
.lcd_cmd_bits = LCD_CMD_BITS,
|
||
|
|
.lcd_param_bits = LCD_PARAM_BITS,
|
||
|
|
};
|
||
|
|
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(
|
||
|
|
(esp_lcd_spi_bus_handle_t)LCD_HOST, &io_cfg, &s_panel_io));
|
||
|
|
|
||
|
|
const esp_lcd_panel_dev_config_t panel_cfg = {
|
||
|
|
.reset_gpio_num = PIN_LCD_RST,
|
||
|
|
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR, /* CYD is BGR */
|
||
|
|
.bits_per_pixel = 16,
|
||
|
|
};
|
||
|
|
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(s_panel_io, &panel_cfg, &s_panel));
|
||
|
|
|
||
|
|
ESP_ERROR_CHECK(esp_lcd_panel_reset(s_panel));
|
||
|
|
ESP_ERROR_CHECK(esp_lcd_panel_init(s_panel));
|
||
|
|
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(s_panel, false));
|
||
|
|
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(s_panel, true));
|
||
|
|
}
|
||
|
|
|
||
|
|
static void touch_init(void)
|
||
|
|
{
|
||
|
|
ESP_LOGI(TAG, "init touch SPI bus");
|
||
|
|
const spi_bus_config_t bus = {
|
||
|
|
.sclk_io_num = PIN_TP_SCLK,
|
||
|
|
.mosi_io_num = PIN_TP_MOSI,
|
||
|
|
.miso_io_num = PIN_TP_MISO,
|
||
|
|
.quadwp_io_num = -1,
|
||
|
|
.quadhd_io_num = -1,
|
||
|
|
.max_transfer_sz = 0,
|
||
|
|
};
|
||
|
|
ESP_ERROR_CHECK(spi_bus_initialize(TOUCH_HOST, &bus, SPI_DMA_DISABLED));
|
||
|
|
|
||
|
|
esp_lcd_panel_io_handle_t tp_io = NULL;
|
||
|
|
esp_lcd_panel_io_spi_config_t tp_io_cfg = ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG(PIN_TP_CS);
|
||
|
|
tp_io_cfg.pclk_hz = TOUCH_CLOCK_HZ;
|
||
|
|
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(
|
||
|
|
(esp_lcd_spi_bus_handle_t)TOUCH_HOST, &tp_io_cfg, &tp_io));
|
||
|
|
|
||
|
|
const esp_lcd_touch_config_t tp_cfg = {
|
||
|
|
.x_max = LCD_H_RES,
|
||
|
|
.y_max = LCD_V_RES,
|
||
|
|
.rst_gpio_num = GPIO_NUM_NC,
|
||
|
|
.int_gpio_num = GPIO_NUM_NC,
|
||
|
|
.flags = {
|
||
|
|
.swap_xy = 0,
|
||
|
|
.mirror_x = 1,
|
||
|
|
.mirror_y = 0,
|
||
|
|
},
|
||
|
|
};
|
||
|
|
ESP_ERROR_CHECK(esp_lcd_touch_new_spi_xpt2046(tp_io, &tp_cfg, &s_touch));
|
||
|
|
}
|
||
|
|
|
||
|
|
static void lvgl_init(void)
|
||
|
|
{
|
||
|
|
const lvgl_port_cfg_t port_cfg = ESP_LVGL_PORT_INIT_CONFIG();
|
||
|
|
ESP_ERROR_CHECK(lvgl_port_init(&port_cfg));
|
||
|
|
|
||
|
|
const lvgl_port_display_cfg_t disp_cfg = {
|
||
|
|
.io_handle = s_panel_io,
|
||
|
|
.panel_handle = s_panel,
|
||
|
|
.buffer_size = LCD_H_RES * LVGL_BUF_LINES,
|
||
|
|
.double_buffer = true,
|
||
|
|
.hres = LCD_H_RES,
|
||
|
|
.vres = LCD_V_RES,
|
||
|
|
.monochrome = false,
|
||
|
|
.rotation = {
|
||
|
|
.swap_xy = false,
|
||
|
|
.mirror_x = false,
|
||
|
|
.mirror_y = false,
|
||
|
|
},
|
||
|
|
.flags = {
|
||
|
|
.buff_dma = true,
|
||
|
|
},
|
||
|
|
};
|
||
|
|
s_disp = lvgl_port_add_disp(&disp_cfg);
|
||
|
|
|
||
|
|
const lvgl_port_touch_cfg_t touch_cfg = {
|
||
|
|
.disp = s_disp,
|
||
|
|
.handle = s_touch,
|
||
|
|
};
|
||
|
|
s_indev = lvgl_port_add_touch(&touch_cfg);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void build_ui(void)
|
||
|
|
{
|
||
|
|
/* Any LVGL call from outside the port task must be locked. */
|
||
|
|
if (!lvgl_port_lock(0)) {
|
||
|
|
ESP_LOGE(TAG, "could not take LVGL lock");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
lv_obj_t *scr = lv_screen_active();
|
||
|
|
|
||
|
|
lv_obj_t *label = lv_label_create(scr);
|
||
|
|
lv_label_set_text(label, "Reflow Plate");
|
||
|
|
lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 20);
|
||
|
|
|
||
|
|
lv_obj_t *arc = lv_arc_create(scr);
|
||
|
|
lv_obj_set_size(arc, 180, 180);
|
||
|
|
lv_arc_set_range(arc, 0, 260);
|
||
|
|
lv_arc_set_value(arc, 25);
|
||
|
|
lv_obj_center(arc);
|
||
|
|
|
||
|
|
lv_obj_t *temp = lv_label_create(scr);
|
||
|
|
lv_label_set_text(temp, "25 \xC2\xB0""C");
|
||
|
|
lv_obj_center(temp);
|
||
|
|
|
||
|
|
lvgl_port_unlock();
|
||
|
|
}
|
||
|
|
|
||
|
|
void app_main(void)
|
||
|
|
{
|
||
|
|
backlight_init();
|
||
|
|
display_init();
|
||
|
|
touch_init();
|
||
|
|
lvgl_init();
|
||
|
|
build_ui();
|
||
|
|
|
||
|
|
gpio_set_level(PIN_LCD_BL, 1); /* backlight on, no white flash */
|
||
|
|
|
||
|
|
/* The LVGL port runs its own task and handles lv_timer_handler().
|
||
|
|
* Your control loop lives here, or better, in its own task. */
|
||
|
|
|
||
|
|
while (1) {
|
||
|
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||
|
|
}
|
||
|
|
}
|