Tried compiling that code but there were a few problems with it:
- Changed the function prototype to
lv_obj_t *lv_example_slider_1(void);
- Added the missing parameter in
lv_refr_now()
Here’s the corrected code:
#include "esp_log.h"
#include <stdio.h>
#include <unistd.h>
#include <sys/lock.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.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_lcd_panel_st7789.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "esp_check.h"
#include "esp_err.h"
#include "esp_log.h"
#include "lvgl.h"
static const char *TAG = "MyDisplay";
/* LCD size */
#define DISP_HOR_RES 320
#define DISP_VER_RES 172
/* LCD settings */
#define DISP_DRAW_BUFF_HEIGHT 50
/* LCD pins */
#define DISP_SPI_NUM SPI2_HOST
#define DISP_GPIO_SCLK GPIO_NUM_12
#define DISP_GPIO_MOSI GPIO_NUM_11
#define DISP_GPIO_RST -1 // Not connected
#define DISP_GPIO_DC GPIO_NUM_47
#define DISP_GPIO_CS GPIO_NUM_45
#define DISP_GPIO_BL GPIO_NUM_48
#define BUFFER_SIZE (DISP_HOR_RES * DISP_VER_RES * sizeof(uint16_t) / 10)
static esp_lcd_panel_handle_t panel_handle = NULL;
static esp_lcd_panel_io_handle_t io_handle = NULL;
static lv_display_t *display = NULL;
static void *buf1 = NULL;
static void *buf2 = NULL;
/* Function prototypes */
lv_obj_t *lv_example_slider_1(void);
// This gets called when the DMA transfer of the buffer data has completed
static bool notify_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 = (lv_display_t *)user_ctx;
lv_display_flush_ready(disp); // I have tried to change this to the global display variable, no change
return false;
}
static void flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map)
{
int x1 = area->x1;
int x2 = area->x2;
int y1 = area->y1 + 34; // Offset image to compensate for smaller 172px resolution
int y2 = area->y2 + 34; // Offset image to compensate for smaller 172px resolution
// uncomment the following line if the colors are wrong
lv_draw_sw_rgb565_swap(px_map, (x2 + 1 - x1) * (y2 + 1 - y1)); // I have tried with and without this
esp_lcd_panel_draw_bitmap((esp_lcd_panel_handle_t)lv_display_get_user_data(disp), x1, y1, x2 + 1, y2 + 1, px_map);
}
static esp_err_t lvgl_init(void)
{
display = lv_display_create(DISP_HOR_RES, DISP_VER_RES);
buf1 = heap_caps_calloc(1, BUFFER_SIZE, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
buf2 = heap_caps_calloc(1, BUFFER_SIZE, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
lv_display_set_buffers(display, buf1, buf2, BUFFER_SIZE, LV_DISPLAY_RENDER_MODE_PARTIAL);
lv_display_set_user_data(display, panel_handle);
lv_display_set_color_format(display, LV_COLOR_FORMAT_RGB565);
lv_display_set_flush_cb(display, flush_cb);
const esp_lcd_panel_io_callbacks_t cbs = {
.on_color_trans_done = notify_flush_ready,
};
/* Register done callback */
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_register_event_callbacks(io_handle, &cbs, display), TAG, "esp_lcd_panel_io_register_event_callbacks error"); // I have tried to use
ESP_RETURN_ON_ERROR(esp_lcd_panel_init(panel_handle), TAG, "esp_lcd_panel_init error");
// Hardware rotate 90°
uint8_t madctl = 0x60; // Rotate reg 0x00 0x60 0xC0 0xA0
esp_lcd_panel_io_tx_param(io_handle, 0x36, &madctl, 1);
esp_lcd_panel_io_tx_param(io_handle, 0x21, NULL, 0); // Inverted color fix (to get normal colors)
return ESP_OK;
}
static esp_err_t display_init(void)
{
// LCD backlight and DC
gpio_config_t gpio_cfg = {
.pin_bit_mask = (1ULL << DISP_GPIO_BL) | (1ULL << DISP_GPIO_DC),
.mode = GPIO_MODE_OUTPUT,
};
ESP_ERROR_CHECK(gpio_config(&gpio_cfg));
gpio_set_level(DISP_GPIO_BL, 1); // Turn on backlight
gpio_set_level(DISP_GPIO_DC, 1); // Default to data mode
// LCD initialization
ESP_LOGD(TAG, "Initialize SPI bus");
spi_bus_config_t buscfg = {};
buscfg.sclk_io_num = DISP_GPIO_SCLK;
buscfg.mosi_io_num = DISP_GPIO_MOSI;
buscfg.miso_io_num = GPIO_NUM_NC;
buscfg.quadwp_io_num = GPIO_NUM_NC;
buscfg.quadhd_io_num = GPIO_NUM_NC;
buscfg.max_transfer_sz = BUFFER_SIZE; // DISP_HOR_RES * DISP_DRAW_BUFF_HEIGHT * sizeof(uint16_t);
ESP_RETURN_ON_ERROR(spi_bus_initialize(DISP_SPI_NUM, &buscfg, SPI_DMA_CH_AUTO), TAG, "SPI init failed");
esp_lcd_panel_io_spi_config_t io_config = {
.dc_gpio_num = DISP_GPIO_DC,
.cs_gpio_num = DISP_GPIO_CS,
.pclk_hz = 80 * 1000 * 1000,
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
.spi_mode = 0,
.trans_queue_depth = 10,
};
ESP_RETURN_ON_ERROR(esp_lcd_new_panel_io_spi(DISP_SPI_NUM, &io_config, &io_handle), TAG, "SPI init failed");
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = DISP_GPIO_RST,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.bits_per_pixel = 16,
.flags = {.reset_active_high = 0}};
ESP_RETURN_ON_ERROR(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle), TAG, "Display init failed");
// Reset the display
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
// Initialize LCD panel
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
// Vendor specific settings
// Turn on the screen
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
return ESP_OK;
}
static void lvgl_tick_increment(void *arg)
{
// Tell LVGL how many milliseconds have elapsed
lv_tick_inc(2);
}
static esp_err_t lvgl_tick_init(void)
{
esp_timer_handle_t tick_timer;
// Tick interface for LVGL (using esp_timer to generate 2ms periodic event)
const esp_timer_create_args_t lvgl_tick_timer_args = {
.callback = &lvgl_tick_increment,
.name = "LVGL tick",
};
ESP_RETURN_ON_ERROR(esp_timer_create(&lvgl_tick_timer_args, &tick_timer), TAG, "Creating LVGL timer filed!");
return esp_timer_start_periodic(tick_timer, 2 * 1000); // 2 ms
}
static void lvgl_task(void *arg)
{
vTaskDelay(1000 / portTICK_PERIOD_MS);
esp_log_level_set("lcd_panel", ESP_LOG_VERBOSE);
esp_log_level_set("lcd_panel.st7789", ESP_LOG_VERBOSE);
esp_log_level_set(TAG, ESP_LOG_VERBOSE);
esp_err_t ret = display_init();
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "ST7789 failed to initilize");
while (1)
;
}
ret = lvgl_init();
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "LVGL Display failed to initialize");
while (1)
;
}
// Create a slider
lv_obj_t *slider = lv_example_slider_1();
// Handle LVGL tasks
int32_t count = 1;
int32_t increment = 1;
lv_slider_set_value(slider, 1, LV_ANIM_ON);
lv_refr_now(display);
while (1)
{
vTaskDelay(pdMS_TO_TICKS(10));
if (count == 100 || count == 0) {
increment = -increment;
}
count += increment;
lv_slider_set_value(slider, count, LV_ANIM_ON);
lv_refr_now(display);
lv_task_handler();
}
}
lv_obj_t *lv_example_slider_1(void)
{
/*Create a screen*/
lv_obj_t *screen = lv_screen_active();
lv_obj_set_style_bg_color(screen, lv_color_black(), 0);
/*Create a slider in the center of the display*/
lv_obj_t *slider = lv_slider_create(lv_screen_active());
lv_obj_center(slider);
lv_obj_set_height(slider, 30);
/* Change indicator (filled part) color */
lv_obj_set_style_bg_color(slider, lv_palette_main(LV_PALETTE_GREEN), LV_PART_INDICATOR);
lv_obj_set_style_bg_color(slider, lv_palette_main(LV_PALETTE_LIME), LV_PART_KNOB);
return slider;
}
// we are going to have the tick run on core 0 This is so the interrupt is
// also executed on core 0. I move the lvgl task to core 1 and bumped up
// the priority to 22 so it will have the highest priority.
void tick_task(void *args)
{
esp_err_t ret = lvgl_tick_init();
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Timer failed to initialize");
while (1)
;
}
}
void app_main()
{
vTaskDelay(1000 / portTICK_PERIOD_MS);
TaskHandle_t taskHandle = NULL;
TaskHandle_t tickHandle = NULL;
lv_init();
xTaskCreatePinnedToCore(lvgl_task, "LVGL task", 8192, NULL, 22, &taskHandle, 1); // stack, params, prio, handle, core
xTaskCreatePinnedToCore(tick_task, "LVGL tick task", 4096, NULL, 4, &tickHandle, 0); // stack, params, prio, handle, core
ESP_LOGI("CoreCheck", "Running on core %d", xPortGetCoreID());
}
But it’s crashing my device:
ELF file SHA256: 2e8639fc1
Rebooting...
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0xc (RTC_SW_CPU_RST),boot:0x2f (SPI_FAST_FLASH_BOOT)
Saved PC:0x4037756c
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce2810,len:0x178c
load:0x403c8700,len:0x4
load:0x403c8704,len:0xcb8
load:0x403cb700,len:0x2db0
entry 0x403c890c
␛[0;32mI (26) boot: ESP-IDF 5.3.1 2nd stage bootloader␛[0m
␛[0;32mI (26) boot: compile time Mar 17 2025 10:18:28␛[0m
␛[0;32mI (26) boot: Multicore bootloader␛[0m
␛[0;32mI (29) boot: chip revision: v0.2␛[0m
␛[0;32mI (33) boot.esp32s3: Boot SPI Speed : 80MHz␛[0m
␛[0;32mI (38) boot.esp32s3: SPI Mode : DIO␛[0m
␛[0;32mI (43) boot.esp32s3: SPI Flash Size : 8MB␛[0m
␛[0;32mI (47) boot: Enabling RNG early entropy source...␛[0m
␛[0;32mI (53) boot: Partition Table:␛[0m
␛[0;32mI (56) boot: ## Label Usage Type ST Offset Length␛[0m
␛[0;32mI (64) boot: 0 nvs WiFi data 01 02 00009000 00006000␛[0m
␛[0;32mI (71) boot: 1 phy_init RF data 01 01 0000f000 00001000␛[0m
␛[0;32mI (78) boot: 2 factory factory app 00 00 00010000 00100000␛[0m
␛[0;32mI (86) boot: End of partition table␛[0m
␛[0;32mI (90) esp_image: segment 0: paddr=00010020 vaddr=3c050020 size=120fch ( 73980) map␛[0m
␛[0;32mI (112) esp_image: segment 1: paddr=00022124 vaddr=3fc94b00 size=02bach ( 11180) load␛[0m
␛[0;32mI (115) esp_image: segment 2: paddr=00024cd8 vaddr=40374000 size=0b340h ( 45888) load␛[0m
␛[0;32mI (128) esp_image: segment 3: paddr=00030020 vaddr=42000020 size=4e8d4h (321748) map␛[0m
␛[0;32mI (186) esp_image: segment 4: paddr=0007e8fc vaddr=4037f340 size=05708h ( 22280) load␛[0m
␛[0;32mI (198) boot: Loaded app from partition at offset 0x10000␛[0m
␛[0;32mI (198) boot: Disabling RNG early entropy source...␛[0m
␛[0;32mI (210) cpu_start: Multicore app␛[0m
␛[0;32mI (219) cpu_start: Pro cpu start user code␛[0m
␛[0;32mI (219) cpu_start: cpu freq: 240000000 Hz␛[0m
␛[0;32mI (220) app_init: Application information:␛[0m
␛[0;32mI (222) app_init: Project name: espidf-lcd-test␛[0m
␛[0;32mI (228) app_init: App version: 7974892-dirty␛[0m
␛[0;32mI (233) app_init: Compile time: Mar 17 2025 10:17:43␛[0m
␛[0;32mI (239) app_init: ELF file SHA256: 2e8639fc1...␛[0m
␛[0;32mI (245) app_init: ESP-IDF: 5.3.1␛[0m
␛[0;32mI (249) efuse_init: Min chip rev: v0.0␛[0m
␛[0;32mI (254) efuse_init: Max chip rev: v0.99 ␛[0m
␛[0;32mI (259) efuse_init: Chip rev: v0.2␛[0m
␛[0;32mI (264) heap_init: Initializing. RAM available for dynamic allocation:␛[0m
␛[0;32mI (271) heap_init: At 3FCA82E8 len 00041428 (261 KiB): RAM␛[0m
␛[0;32mI (277) heap_init: At 3FCE9710 len 00005724 (21 KiB): RAM␛[0m
␛[0;32mI (283) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM␛[0m
␛[0;32mI (289) heap_init: At 600FE100 len 00001EE8 (7 KiB): RTCRAM␛[0m
␛[0;32mI (297) spi_flash: detected chip: gd␛[0m
␛[0;32mI (300) spi_flash: flash io: dio␛[0m
␛[0;32mI (304) sleep: Configure to isolate all GPIO pins in sleep state␛[0m
␛[0;32mI (311) sleep: Enable automatic switching of GPIO sleep configuration␛[0m
␛[0;32mI (318) main_task: Started on CPU0␛[0m
␛[0;32mI (328) main_task: Calling app_main()␛[0m
␛[0;31mE (1328) FreeRTOS: FreeRTOS Task "LVGL tick task" should not return, Aborting now!␛[0m
abort() was called at PC 0x4037be2b on core 0
Backtrace: 0x40377632:0x3fcb01c0 0x4037b379:0x3fcb01e0 0x40382951:0x3fcb0200 0x4037be2b:0x3fcb0270