Description
I need to display a spinner, then run a time consuming task, then stop displaying the spinner.
I have created a small piece of test code, that I wrapped in the xGuiSemaphore
, just in case that was the reason the spinner was not displaying.
What MCU/Processor/Board and compiler are you using?
ESP32, ili9488
What LVGL version are you using?
LVGL 8.1
What do you want to achieve?
Display a spinner when performing time consuming task eg: drawing new screen / loading data.
Display a spinner after a menu button click before branching to a new screen, while the screen is drawing and loading.
What have you tried so far?
Migrated to LVGL 8.1 from 7, and now just cannot get the spinner to work properly in the circumstances mentioned above
Code to reproduce
I have added a RTOS task to create a spinner, then pause 5 seconds, then display the spinner for 1 second every 5 seconds as a test.
After my home screen is displayed, I start the RTOS task.
LVGL is running on Core1 of the ESP32
/**
* Do the home screen layout ... then ...
* (I also run the RTOS task on the same core.)
*/
xTaskCreatePinnedToCore(vShowSpinnerTask, "ShowSpinnerTask", 2048, NULL, 2, NULL, 1);
static void vShowSpinnerTask(void *pvParameters)
{
lv_obj_t *busy_spinner = lv_spinner_create(lv_layer_top(), 1000, 60);
lv_obj_set_size(busy_spinner, 100, 100);
lv_obj_align(busy_spinner, LV_ALIGN_CENTER, 0, 0);
lv_obj_add_flag(busy_spinner, LV_OBJ_FLAG_HIDDEN);
vTaskDelay(pdMS_TO_TICKS(5000));
for(;;)
{
xSemaphoreTake(xGuiSemaphore, portMAX_DELAY);
ESP_LOGW(TAG, "Showing Spinner ............................");
lv_obj_clear_flag(busy_spinner, LV_OBJ_FLAG_HIDDEN);
vTaskDelay(pdMS_TO_TICKS(1000));
lv_obj_add_flag(busy_spinner, LV_OBJ_FLAG_HIDDEN);
xSemaphoreGive(xGuiSemaphore);
vTaskDelay(pdMS_TO_TICKS(5000));
}
vTaskDelete(NULL);
}
Result
I can see that the task is executed repeatedly, as I can se the ESP_LOGW output in the console.
The home page displays, but the spinner never shows up.
The GUI task is implemented in the following manner
/**
* Gui task for setup of LVGL TFT and Touch drivers and buffers.
* @note 2021-06-30 15:00 This has been modified to be compatible with LVGL 8.0
*
*/
static void guiTask(void *pvParameter)
{
(void)pvParameter;
loadassist_backlight_on = 1;
xGuiSemaphore = xSemaphoreCreateMutex();
lv_init();
/* Initialize SPI or I2C bus used by the drivers */
lvgl_driver_init();
lv_color_t *buf1 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
assert(buf1 != NULL);
/* Use double buffered when not working with monochrome displays */
#ifndef CONFIG_LV_TFT_DISPLAY_MONOCHROME
lv_color_t *buf2 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
assert(buf2 != NULL);
#else
static lv_color_t *buf2 = NULL;
#endif
static lv_disp_draw_buf_t disp_buf;
uint32_t size_in_px = DISP_BUF_SIZE;
#if defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_IL3820 || defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_JD79653A || defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_UC8151D
/* Actual size in pixels, not bytes. */
size_in_px *= 8;
#endif
/* Initialize the working buffer depending on the selected display.
* NOTE: buf2 == NULL when using monochrome displays. */
lv_disp_draw_buf_init(&disp_buf, buf1, buf2, size_in_px);
static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.flush_cb = disp_driver_flush;
/* When using a monochrome display we need to register the callbacks:
* - rounder_cb
* - set_px_cb */
#ifdef CONFIG_LV_TFT_DISPLAY_MONOCHROME
disp_drv.rounder_cb = disp_driver_rounder;
disp_drv.set_px_cb = disp_driver_set_px;
#endif
disp_drv.hor_res = CONFIG_APP_LV_DISPLAY_HOR_RES;
disp_drv.ver_res = CONFIG_APP_LV_DISPLAY_VER_RES;
disp_drv.full_refresh = 1;
disp_drv.draw_buf = &disp_buf;
lv_disp_drv_register(&disp_drv);
/* Register an input device when enabled on the menuconfig */
#if CONFIG_LV_TOUCH_CONTROLLER != TOUCH_CONTROLLER_NONE
lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.read_cb = touch_driver_read;
indev_drv.type = LV_INDEV_TYPE_POINTER;
lv_indev_drv_register(&indev_drv);
#endif
/* Create and start a periodic timer interrupt to call lv_tick_inc */
const esp_timer_create_args_t periodic_timer_args = {
.callback = &lv_tick_task,
.name = "periodic_gui"};
esp_timer_handle_t periodic_timer;
ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, LV_TICK_PERIOD_MS * 1000));
/* Create the default application */
create_default_application();
while (1)
{
/**
* Delay 1 tick (assumes FreeRTOS tick is 10ms)
* The timing is not critical but it should be about 5 milliseconds to keep the system responsive.
* https://docs.lvgl.io/latest/en/html/porting/task-handler.html
*/
vTaskDelay(pdMS_TO_TICKS(10));
/* Try to take the semaphore, call lvgl related function on success */
if (pdTRUE == xSemaphoreTake(xGuiSemaphore, portMAX_DELAY))
{
/**
* @note if app_backlight_on is False,
* then don't handle any LVGL tasks, as there should be none
*/
if (app_backlight_on)
{
lv_task_handler();
}
xSemaphoreGive(xGuiSemaphore);
}
}
/* A task should NEVER return */
free(buf1);
#ifndef CONFIG_LV_TFT_DISPLAY_MONOCHROME
free(buf2);
#endif
vTaskDelete(NULL);
}