Doing any LVGL operation in the timer loop hangs the app

What do you want to achieve?

I’m trying to make components (like a button or just a pin short) interact with LVGL. In this specific instance, I’m trying to scroll a container object.

Unfortunately, every time I do that, the app calls my scrolling code once and then everything hangs and if enabled, watchdog bites with a similar trace:

Backtrace: 0x4202F19A:0x3FC95E60 0x4202F5B0:0x3FC95E80 0x40378FCD:0x3FC95EB0 0x42008DA8:0x3FCABDE0 0x4200906B:0x3FCABE50 0x42009178:0x3FCABE80 0x4200931E:0x3FCABEA0 0x4200E995:0x3FCABED0 0x4200EA3F:0x3FCABEF0 0x42002252:0x3FCABF10 0x42044AB7:0x3FCAC010 0x4037BF4D:0x3FCAC040

E (10672) task_wdt: Task watchdog got triggered. The following tasks/users did not reset the watchdog in time:
E (10672) task_wdt:  - IDLE0 (CPU 0)
E (10672) task_wdt: Tasks currently running:
E (10672) task_wdt: CPU 0: main
E (10672) task_wdt: CPU 1: IDLE1
E (10672) task_wdt: Print CPU 0 (current core) backtrace

No actual scrolling ever happens, unless I put the scroll code before the loop, in which case the app starts with the container already scrolled.

What have you tried so far?

Scrolling with and without animation, changing the background of the container every second in the loop as an attempt to see any change whatsoever (still hangs), disabling watchdog (still hangs but silently), increasing vTaskDelay

Code to reproduce

lv_obj_t *container;

void ui_init(void)
{
    lv_obj_t *scr = lv_scr_act();
    container = lv_obj_create(scr);

    lv_obj_set_style_pad_all(container, 0, 0);
    lv_obj_set_style_pad_row(container, 0, 0);
    lv_obj_set_style_pad_column(container, 0, 0);

    lv_obj_set_size(container, LCD_H_RES, LCD_V_RES);

    lv_obj_set_layout(container, LV_LAYOUT_FLEX);
    lv_obj_set_flex_flow(container, LV_FLEX_FLOW_COLUMN);
    lv_obj_set_scroll_dir(container, LV_DIR_VER);

    for (int i = 0; i < 5; i++)
    {
        lv_obj_t *rect = lv_obj_create(container);
        lv_obj_set_size(rect, LCD_H_RES, 80);
        lv_obj_set_style_bg_color(rect, lv_palette_main(LV_PALETTE_RED), 0);
    }
}

// in the end of app_main, after all display and lvgl initialization
while (1)
{
    lv_timer_handler();
    int level = gpio_get_level(BUTTON_PIN);
    if (level == 0 && prev == 1)
    {
        printf("pressed\n");
        lv_obj_scroll_by(container, 0, 80, LV_ANIM_OFF);
    }
    prev = level;
    vTaskDelay(pdMS_TO_TICKS(10));
}

Screenshot and/or video


Environment

  • MCU/MPU/Board: ESP32-S3 (esp32-s3-lcd-1.3 by WaveShare)
  • LVGL version: 8.4.0 (I’ll attempt to upgrade once I get at least something working, but I doubt the version is part of the issue)

You dont show all code and setup but seems your tick counter is stopped. LVGL require it primary. In arduino tick can setup in lvconf as custom …

Too you use vTaskDelay seems RTOS used, but how ?

Below is the full code. Can be a bit messy in places, but I followed some code by the manufacturer and staple stitched stuff to make it actually display. Upon reviewing it again, I realized I had forgotten to include the lv_disp_flush_ready call in the flush_ready_cb, but now it just reboots with the following trace upon shorting the pin:

pressed
Guru Meditation Error: Core  0 panic'ed (StoreProhibited). Exception was unhandled.

Core  0 register dump:
PC      : 0x40381b22  PS      : 0x00060133  A0      : 0x803814f8  A1      : 0x3fcabc90  
A2      : 0x3fcca548  A3      : 0x0001c800  A4      : 0x80376a5c  A5      : 0x00000001
A6      : 0x3fc981ec  A7      : 0x3fca8cb4  A8      : 0x3fca85c4  A9      : 0xf206f206
A10     : 0x0000000a  A11     : 0x0000001e  A12     : 0xf206f206  A13     : 0x40000000  
A14     : 0x3fcabe50  A15     : 0x0000cdcd  SAR     : 0x00000007  EXCCAUSE: 0x0000001d
EXCVADDR: 0xf206f212  LBEG    : 0x400570e8  LEND    : 0x400570f3  LCOUNT  : 0x00000000  


Backtrace: 0x40381b1f:0x3fcabc90 0x403814f5:0x3fcabcb0 0x40377b8d:0x3fcabcd0 0x40377ca5:0x3fcabcf0 0x40377cd5:0x3fcabd20 0x40377ec0:0x3fcabd40 0x42001ece:0x3fcabd60 0x42041081:0x3fcabd90 0x4200893f:0x3fcabdc0 0x42008ed9:0x3fcabde0 0x4200902f:0x3fcabe50 0x4200913c:0x3fcabe80 0x420092e2:0x3fcabea0 0x4200e959:0x3fcabed0 0x4200ea03:0x3fcabef0 0x42002238:0x3fcabf10 0x42044b2f:0x3fcac010 0x4037bf4d:0x3fcac040




ELF file SHA256: 1f6dbc4aa

Rebooting...
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_sh8601.h"
#include "lvgl.h"
#include "esp_timer.h"
#include "esp_task_wdt.h"
#include "rtc_wdt.h"

#define LCD_HOST SPI2_HOST
#define LCD_H_RES 240
#define LCD_V_RES 240
#define LCD_DMA_LINE (LCD_V_RES / 2)

#define PIN_NUM_MOSI 41
#define PIN_NUM_CLK 40
#define PIN_NUM_CS 39
#define PIN_NUM_RST 42
#define PIN_NUM_DC 38
#define PIN_NUM_BL 4

#define LVGL_TICK_PERIOD_MS 2

#define BUTTON_PIN 3

lv_obj_t *container;

static const sh8601_lcd_init_cmd_t lcd_init_cmds[] = {
    {0x36, (uint8_t[]){0xC0}, 1, 0},
    {0x3A, (uint8_t[]){0x05}, 1, 0},
    {0xB2, (uint8_t[]){0x0C, 0x0C, 0x00, 0x33, 0x33}, 5, 0},
    {0xB4, (uint8_t[]){0x01}, 1, 0},
    {0xC0, (uint8_t[]){0x2C, 0x2D}, 2, 0},
    {0xC5, (uint8_t[]){0x2E}, 1, 0},
    {0x21, NULL, 0, 0},
    {0x2A, (uint8_t[]){0x00, 0x00, 0x00, 0xEF}, 4, 0},
    {0x2B, (uint8_t[]){0x00, 0x00, 0x00, 0xEF}, 4, 0},
    {0x11, NULL, 0, 120},
    {0x29, NULL, 0, 0},
};

static bool flush_ready_cb(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
{
    lv_disp_drv_t *disp_drv = (lv_disp_drv_t *)user_ctx;
    lv_disp_flush_ready(disp_drv);
    return false;
}

static void lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map)
{
    esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t)drv->user_data;

    int x1 = area->x1;
    int x2 = area->x2;
    int y1 = area->y1 + 80;
    int y2 = area->y2 + 80;

    size_t width = x2 - x1 + 1;
    size_t height = y2 - y1 + 1;
    size_t px_count = width * height;

    uint16_t *swap_buf = heap_caps_malloc(px_count * sizeof(uint16_t), MALLOC_CAP_DMA);
    if (!swap_buf)
    {
        ESP_LOGE("LVGL", "Failed to allocate swap buffer!");
        lv_disp_flush_ready(drv);
        return;
    }

    for (size_t i = 0; i < px_count; i++)
    {
        uint16_t color = color_map[i].full;
        swap_buf[i] = (color >> 8) | (color << 8);
    }

    esp_lcd_panel_draw_bitmap(panel_handle, x1, y1, x2 + 1, y2 + 1, swap_buf);
    heap_caps_free(swap_buf);
}

static void lv_tick_cb(void *arg)
{
    lv_tick_inc(LVGL_TICK_PERIOD_MS);
}

void ui_init(void)
{
    lv_obj_t *scr = lv_scr_act();
    container = lv_obj_create(scr);

    lv_obj_set_style_pad_all(container, 0, 0);
    lv_obj_set_style_pad_row(container, 0, 0);
    lv_obj_set_style_pad_column(container, 0, 0);

    lv_obj_set_size(container, LCD_H_RES, LCD_V_RES);

    lv_obj_set_layout(container, LV_LAYOUT_FLEX);
    lv_obj_set_flex_flow(container, LV_FLEX_FLOW_COLUMN);
    lv_obj_set_scroll_dir(container, LV_DIR_VER);

    for (int i = 0; i < 5; i++)
    {
        lv_obj_t *rect = lv_obj_create(container);
        lv_obj_set_size(rect, LCD_H_RES, 80);
        lv_obj_set_style_bg_color(rect, lv_palette_main(LV_PALETTE_RED), 0);
    }
}

void app_main(void)
{
    ESP_LOGI("App", "Starting app_main");

    static lv_disp_draw_buf_t draw_buf;
    static lv_disp_drv_t disp_drv;

    gpio_config_t gpio_conf = {
        .intr_type = GPIO_INTR_DISABLE,
        .mode = GPIO_MODE_OUTPUT,
        .pin_bit_mask = (1ULL << PIN_NUM_RST) | (1ULL << PIN_NUM_BL),
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .pull_up_en = GPIO_PULLUP_ENABLE,
    };

    ESP_ERROR_CHECK(gpio_config(&gpio_conf));
    gpio_set_level(PIN_NUM_BL, 1);

    gpio_config_t button_conf = {
        .pin_bit_mask = (1ULL << BUTTON_PIN),
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = GPIO_PULLUP_ENABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_NEGEDGE};

    ESP_ERROR_CHECK(gpio_config(&button_conf));

    spi_bus_config_t bus_conf = {
        .mosi_io_num = PIN_NUM_MOSI,
        .miso_io_num = -1,
        .sclk_io_num = PIN_NUM_CLK,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = LCD_H_RES * LCD_DMA_LINE * sizeof(uint16_t),
    };

    ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &bus_conf, SPI_DMA_CH_AUTO));

    esp_lcd_panel_io_handle_t io_handle = NULL;
    esp_lcd_panel_io_spi_config_t io_config = {
        .dc_gpio_num = PIN_NUM_DC,
        .cs_gpio_num = PIN_NUM_CS,
        .pclk_hz = 20 * 1000 * 1000,
        .lcd_cmd_bits = 8,
        .lcd_param_bits = 8,
        .spi_mode = 0,
        .trans_queue_depth = 10,
        .on_color_trans_done = flush_ready_cb,
        .user_ctx = &disp_drv};

    ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(LCD_HOST, &io_config, &io_handle));

    sh8601_vendor_config_t vendor_config = {
        .init_cmds = lcd_init_cmds,
        .init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]),
    };

    esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = PIN_NUM_RST,
        .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
        .bits_per_pixel = 16,
        .data_endian = LCD_RGB_DATA_ENDIAN_BIG,
        .vendor_config = &vendor_config,
    };

    esp_lcd_panel_handle_t panel_handle = NULL;

    ESP_ERROR_CHECK(esp_lcd_new_panel_sh8601(io_handle, &panel_config, &panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
    ESP_LOGI("Panel", "Panel initialized");

    lv_init();

    static lv_color_t *buf1 = NULL, *buf2 = NULL;
    buf1 = heap_caps_malloc(LCD_H_RES * LCD_DMA_LINE * sizeof(lv_color_t), MALLOC_CAP_DMA);
    buf2 = heap_caps_malloc(LCD_H_RES * LCD_DMA_LINE * sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf1 && buf2);
    lv_disp_draw_buf_init(&draw_buf, buf1, buf2, LCD_H_RES * LCD_V_RES);

    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = LCD_H_RES;
    disp_drv.ver_res = LCD_V_RES;
    disp_drv.flush_cb = lvgl_flush_cb;
    disp_drv.draw_buf = &draw_buf;
    disp_drv.user_data = panel_handle;
    lv_disp_drv_register(&disp_drv);

    // Start LVGL tick
    const esp_timer_create_args_t tick_timer_args = {
        .callback = lv_tick_cb,
        .name = "lvgl_tick",
    };
    esp_timer_handle_t tick_timer;
    ESP_ERROR_CHECK(esp_timer_create(&tick_timer_args, &tick_timer));
    ESP_ERROR_CHECK(esp_timer_start_periodic(tick_timer, LVGL_TICK_PERIOD_MS * 1000));

    ui_init();

    int prev = 1;

    while (1)
    {
        lv_timer_handler();

        int level = gpio_get_level(BUTTON_PIN);

        if (level == 0 && prev == 1)
        {
            printf("pressed\n");
            lv_obj_scroll_by(container, 0, 80, LV_ANIM_OFF);
        }

        prev = level;

        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

primary enable backtrace decoder…

This is the decoded stack trace:

pressed
Guru Meditation Error: Core  0 panic'ed (StoreProhibited). Exception was unhandled.

Core  0 register dump:
PC      : 0x40381b22  PS      : 0x00060133  A0      : 0x803814f8  A1      : 0x3fcabc90  
  #0  0x40381b22 in remove_free_block at D:\.platformio\packages\framework-espidf\components\heap\tlsf/tlsf_control_functions.h:374
      (inlined by) block_locate_free at D:\.platformio\packages\framework-espidf\components\heap\tlsf/tlsf_control_functions.h:619
      (inlined by) tlsf_malloc at D:\.platformio\packages\framework-espidf\components\heap\tlsf/tlsf.c:443

A2      : 0x3fcca548  A3      : 0x0001c800  A4      : 0x80376a5c  A5      : 0x00000001  
A6      : 0x3fc981ec  A7      : 0x3fca8cb4  A8      : 0x3fca85c4  A9      : 0xf206f206
A10     : 0x0000000a  A11     : 0x0000001e  A12     : 0xf206f206  A13     : 0x40000000
A14     : 0x3fcabe50  A15     : 0x0000cdcd  SAR     : 0x00000007  EXCCAUSE: 0x0000001d
EXCVADDR: 0xf206f212  LBEG    : 0x400570e8  LEND    : 0x400570f3  LCOUNT  : 0x00000000


Backtrace: 0x40381b1f:0x3fcabc90 0x403814f5:0x3fcabcb0 0x40377b8d:0x3fcabcd0 0x40377ca5:0x3fcabcf0 0x40377cd5:0x3fcabd20 0x40377ec0:0x3fcabd40 0x42001ece:0x3fcabd60 0x42041081:0x3fcabd90 0x4200893f:0x3fcabdc0 0x42008ed9:0x3fcabde0 0x4200902f:0x3fcabe50 0x4200913c:0x3fcabe80 0x420092e2:0x3fcabea0 0x4200e959:0x3fcabed0 0x4200ea03:0x3fcabef0 0x42002238:0x3fcabf10 0x42044b2f:0x3fcac010 0x4037bf4d:0x3fcac040
  #0  0x40381b1f in remove_free_block at D:\.platformio\packages\framework-espidf\components\heap\tlsf/tlsf_control_functions.h:373 (discriminator 1)
      (inlined by) block_locate_free at D:\.platformio\packages\framework-espidf\components\heap\tlsf/tlsf_control_functions.h:619 (discriminator 1)
      (inlined by) tlsf_malloc at D:\.platformio\packages\framework-espidf\components\heap\tlsf/tlsf.c:443 (discriminator 1)
  #1  0x403814f5 in multi_heap_malloc_impl at D:\.platformio\packages\framework-espidf\components\heap/multi_heap.c:209
  #2  0x40377b8d in aligned_or_unaligned_alloc at D:\.platformio\packages\framework-espidf\components\heap/heap_caps_base.c:82
  #3  0x40377ca5 in heap_caps_aligned_alloc_base at D:\.platformio\packages\framework-espidf\components\heap/heap_caps_base.c:156
  #4  0x40377cd5 in heap_caps_malloc_base at D:\.platformio\packages\framework-espidf\components\heap/heap_caps_base.c:176
  #5  0x40377ec0 in heap_caps_malloc at D:\.platformio\packages\framework-espidf\components\heap/heap_caps.c:84
  #6  0x42001ece in lvgl_flush_cb at src/main.c:67
  #7  0x42041081 in call_flush_cb at .pio/libdeps/freenove_esp32_s3_wroom/lvgl/src/core/lv_refr.c:1322
  #8  0x4200893f in draw_buf_flush at .pio/libdeps/freenove_esp32_s3_wroom/lvgl/src/core/lv_refr.c:1297
  #9  0x42008ed9 in refr_area_part at .pio/libdeps/freenove_esp32_s3_wroom/lvgl/src/core/lv_refr.c:796
  #10 0x4200902f in refr_area at .pio/libdeps/freenove_esp32_s3_wroom/lvgl/src/core/lv_refr.c:678
  #11 0x4200913c in refr_invalid_areas at .pio/libdeps/freenove_esp32_s3_wroom/lvgl/src/core/lv_refr.c:616
  #12 0x420092e2 in _lv_disp_refr_timer at .pio/libdeps/freenove_esp32_s3_wroom/lvgl/src/core/lv_refr.c:324
  #13 0x4200e959 in lv_timer_exec at .pio/libdeps/freenove_esp32_s3_wroom/lvgl/src/misc/lv_timer.c:313 (discriminator 2)
  #14 0x4200ea03 in lv_timer_handler at .pio/libdeps/freenove_esp32_s3_wroom/lvgl/src/misc/lv_timer.c:109
  #15 0x42002238 in app_main at src/main.c:216
  #16 0x42044b2f in main_task at D:\.platformio\packages\framework-espidf\components\freertos/app_startup.c:208
  #17 0x4037bf4d in vPortTaskWrapper at D:\.platformio\packages\framework-espidf\components\freertos\FreeRTOS-Kernel\portable\xtensa/port.c:139

your crash line… require knowledge about DMA and available RAM …

You opened my eyes and helped me solve it, thanks :slightly_smiling_face: