Files
Reflow-plate/main/main.c

226 lines
6.7 KiB
C
Raw Normal View History

2026-09-13 20:50:51 +00:00
/*
* 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));
}
}