Can't create task

Description

I would like to create a task like in the documentation in the example. However, that doesn’t work for me.

Error:
1.)
In function ‘void my_task(lv_task_t*)’:
NEW_TICK_BIB:19:32: error: invalid conversion from ‘void*’ to ‘uint32_t* {aka unsigned int*}’ [-fpermissive]
uint32_t * user_data = task->user_data;

What MCU/Processor/Board and compiler are you using?

ESP8266 / Arduino IDE

What LVGL version are you using?

Latest

What do you want to achieve?

Create a task that work.

Code to reproduce

The code block(s) should be formatted like:

#include <lvgl.h>
#include <TFT_eSPI.h>
#include <Ticker.h>



#define LVGL_TICK_PERIOD 20

Ticker tick; /* timer for interrupt handler */
TFT_eSPI tft = TFT_eSPI(); /* TFT instance */
static lv_disp_buf_t disp_buf;
static lv_color_t buf[LV_HOR_RES_MAX * 10];



void my_task(lv_task_t * task)
{
  /*Use the user_data*/
  uint32_t * user_data = task->user_data;
  printf("my_task called with user data: %d\n", *user_data);

 
}



static uint32_t user_data = 10;
lv_task_t * task = lv_task_create(my_task, 500, LV_TASK_PRIO_MID, &user_data);


void top_bar(void)
{
  /*Create a Tab view object*/
  lv_obj_t *tabview;
  tabview = lv_tabview_create(lv_scr_act(), NULL);

  /*Add 3 tabs (the tabs are page (lv_page) and can be scrolled*/
  lv_obj_t *tab1 = lv_tabview_add_tab(tabview, "Home");
  lv_obj_t *tab2 = lv_tabview_add_tab(tabview, "Auto");
  lv_obj_t *tab3 = lv_tabview_add_tab(tabview, "Einstel.");


  /*Add content to the tabs*/
  static lv_color_t needle_colors[3];
    needle_colors[0] = LV_COLOR_BLUE;
    needle_colors[1] = LV_COLOR_ORANGE;
    needle_colors[2] = LV_COLOR_PURPLE;

    /*Create a gauge*/
    lv_obj_t * gauge1 = lv_gauge_create(tab1, NULL);
    lv_gauge_set_needle_count(gauge1, 3, needle_colors);
    lv_obj_set_size(gauge1, 150, 150);
    lv_obj_align(gauge1, NULL, LV_ALIGN_CENTER, 70, 0);

    /*Set the values*/
    lv_gauge_set_value(gauge1, 0, 10);
    lv_gauge_set_value(gauge1, 1, 20);
    lv_gauge_set_value(gauge1, 2, 30);

    lv_obj_t * label;
    lv_obj_t * label1;

    lv_obj_t * btn1 = lv_btn_create(tab1, NULL);
    lv_obj_align(btn1, NULL, LV_ALIGN_CENTER, -70, 40);
    label = lv_label_create(btn1, NULL);
    lv_label_set_text(label, "Start");

    lv_obj_t * btn2 = lv_btn_create(tab1, NULL);
    lv_obj_align(btn2, NULL, LV_ALIGN_CENTER, -70, -40);
    label1 = lv_label_create(btn2, NULL);
    lv_label_set_text(label1, "Stop");
}




#if USE_LV_LOG != 0
/* Serial debugging */
void my_print(lv_log_level_t level, const char * file, uint32_t line, const char * dsc)
{

  Serial.printf("%s@%d->%s\r\n", file, line, dsc);
  delay(100);
}
#endif

/* Display flushing */
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
  uint16_t c;

  tft.startWrite(); /* Start new TFT transaction */
  tft.setAddrWindow(area->x1, area->y1, (area->x2 - area->x1 + 1), (area->y2 - area->y1 + 1)); /* set the working window */
  for (int y = area->y1; y <= area->y2; y++) {
    for (int x = area->x1; x <= area->x2; x++) {
      c = color_p->full;
      tft.writeColor(c, 1);
      color_p++;
    }
  }
  tft.endWrite(); /* terminate TFT transaction */
  lv_disp_flush_ready(); /* tell lvgl that flushing is done */
}

/* Interrupt driven periodic handler */
static void lv_tick_handler(void)
{

  lv_tick_inc(LVGL_TICK_PERIOD);
}

/* Reading input device (simulated encoder here) */
bool read_encoder(lv_indev_drv_t * indev, lv_indev_data_t * data)
{
  static int32_t last_diff = 0;
  int32_t diff = 0; /* Dummy - no movement */
  int btn_state = LV_INDEV_STATE_REL; /* Dummy - no press */

  data->enc_diff = diff - last_diff;;
  data->state = btn_state;

  last_diff = diff;

  return false;
}



void setup() {

  Serial.begin(115200); /* prepare for possible serial debug */

  lv_init();

#if USE_LV_LOG != 0
  lv_log_register_print(my_print); /* register print function for debugging */
#endif

  tft.begin(); /* TFT init */
  tft.setRotation(3); /* Landscape orientation */

  lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10);

  /*Initialize the display*/
  lv_disp_drv_t disp_drv;
  lv_disp_drv_init(&disp_drv);
  disp_drv.hor_res = 320;
  disp_drv.ver_res = 240;
  disp_drv.flush_cb = my_disp_flush;
  disp_drv.buffer = &disp_buf;
  lv_disp_drv_register(&disp_drv);


  /*Initialize the touch pad*/
  lv_indev_drv_t indev_drv;
  lv_indev_drv_init(&indev_drv);
  indev_drv.type = LV_INDEV_TYPE_ENCODER;
  indev_drv.read_cb = read_encoder;
  lv_indev_drv_register(&indev_drv);
  
  /*Initialize the graphics library's tick*/
  tick.attach_ms(LVGL_TICK_PERIOD, lv_tick_handler);

}


void loop()
{

  lv_task_handler(); /* let the GUI do its work */
  delay(5);

}

Screenshot and/or video

If possible, add screenshots and/or videos about the current state.

You need to cast the user data to the type you want as it’s stored as a void*. Try:

void my_task(lv_task_t * task)
{
  /*Use the user_data*/
  uint32_t * user_data = (uint32_t*)task->user_data;
  printf("my_task called with user data: %d\n", *user_data);
}
1 Like

Thank you for your quick reply. The error message is gone. However, I am not sure if my task hanlder is working properly. I added the code for the tab bar to the task. However, now only the board led lights up every 500ms but the display remains white. Do you have to start the task handler separately or pay attention to something else?
best regards
David

LVGL tasks are not preemptive; if you do not return from a task, LVGL will never run. Think of them more like periodic callbacks than OS tasks.

1 Like

Thank you for your answer. I don’t quite understand how to proceed. I’ve read the documentation. Have a look at the examples. If I just copy the examples in the setup function, then at least I have them on the screen. What is the best way to proceed if, for example, I just want to run a tab bar functional. In which functions do I have to write what. And which commands do I have to call where to start the functions?

UI setup code (e.g. creating objects, etc.) goes in setup. Don’t call any LVGL functions outside of setup before lv_init gets called. That might be part of your problem; in your original example, you are calling lv_task_create to initialize a global variable. That doesn’t work. It needs to be inside setup after lv_init.

Then, the only thing you should need to call in loop is lv_task_handler.

1 Like

Many thanks for your response embeddedt. Okay, that’s good to know. Now it works at least for the first 2-3 seconds. Then the ESP8266 resets itself again and again. It must have something to do with the code and the task. If I don’t have the task in the code, it doesn’t always reset itself. However, I do not notice where in the code it could be.

#include <lvgl.h>
#include <TFT_eSPI.h>
#include <Ticker.h>

#define LVGL_TICK_PERIOD 20

static void controls_create(lv_obj_t * parent);
static void visuals_create(lv_obj_t * parent);

Ticker tick; /* timer for interrupt handler */
TFT_eSPI tft = TFT_eSPI(); /* TFT instance */
static lv_disp_buf_t disp_buf;
static lv_color_t buf[LV_HOR_RES_MAX * 10];

int randInt;




void my_task(lv_task_t * task)
{
  /*Use the user_data*/
  uint32_t * user_data = (uint32_t*) task->user_data;
  printf("my_task called with user data: %d\n", *user_data);
  randInt=random(0,100);
  top_bar();
  
}

void top_bar(void)
{
  lv_obj_t *tabview;
  tabview = lv_tabview_create(lv_scr_act(), NULL);

  
  lv_obj_t *tab1 = lv_tabview_add_tab(tabview, "Home");
  lv_obj_t *tab2 = lv_tabview_add_tab(tabview, "Auto");
  lv_obj_t *tab3 = lv_tabview_add_tab(tabview, "Einstel.");


  
  static lv_color_t needle_colors[3];
    needle_colors[0] = LV_COLOR_BLUE;
    needle_colors[1] = LV_COLOR_ORANGE;
    needle_colors[2] = LV_COLOR_PURPLE;

   
    lv_obj_t * gauge1 = lv_gauge_create(tab1, NULL);
    lv_gauge_set_needle_count(gauge1, 3, needle_colors);
    lv_obj_set_size(gauge1, 150, 150);
    lv_obj_align(gauge1, NULL, LV_ALIGN_CENTER, 70, 0);

   
    lv_gauge_set_value(gauge1, 0, randInt);
    lv_gauge_set_value(gauge1, 1, 20);
    lv_gauge_set_value(gauge1, 2, 30);

    lv_obj_t * label;
    lv_obj_t * label1;

    lv_obj_t * btn1 = lv_btn_create(tab1, NULL);
    lv_obj_align(btn1, NULL, LV_ALIGN_CENTER, -70, 40);
    label = lv_label_create(btn1, NULL);
    lv_label_set_text(label, "Start");

    lv_obj_t * btn2 = lv_btn_create(tab1, NULL);
    lv_obj_align(btn2, NULL, LV_ALIGN_CENTER, -70, -40);
    label1 = lv_label_create(btn2, NULL);
    lv_label_set_text(label1, "Stop");
}







/* Display flushing */
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
  uint16_t c;

  tft.startWrite(); /* Start new TFT transaction */
  tft.setAddrWindow(area->x1, area->y1, (area->x2 - area->x1 + 1), (area->y2 - area->y1 + 1)); /* set the working window */
  for (int y = area->y1; y <= area->y2; y++) {
    for (int x = area->x1; x <= area->x2; x++) {
      c = color_p->full;
      tft.writeColor(c, 1);
      color_p++;
    }
  }
  tft.endWrite(); /* terminate TFT transaction */
  lv_disp_flush_ready(disp); /* tell lvgl that flushing is done */
}

/* Interrupt driven periodic handler */
static void lv_tick_handler(void)
{

  lv_tick_inc(LVGL_TICK_PERIOD);
}

/* Reading input device (simulated encoder here) */
bool read_encoder(lv_indev_drv_t * indev, lv_indev_data_t * data)
{
  static int32_t last_diff = 0;
  int32_t diff = 0; /* Dummy - no movement */
  int btn_state = LV_INDEV_STATE_REL; /* Dummy - no press */

  data->enc_diff = diff - last_diff;;
  data->state = btn_state;

  last_diff = diff;

  return false;
}



void setup() {

  Serial.begin(115200); /* prepare for possible serial debug */

  lv_init();

#if USE_LV_LOG != 0
  lv_log_register_print(my_print); /* register print function for debugging */
#endif

  tft.begin(); /* TFT init */
  tft.setRotation(3); /* Landscape orientation */

  lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10);

  /*Initialize the display*/
  lv_disp_drv_t disp_drv;
  lv_disp_drv_init(&disp_drv);
  disp_drv.hor_res = 320;
  disp_drv.ver_res = 240;
  disp_drv.flush_cb = my_disp_flush;
  disp_drv.buffer = &disp_buf;
  lv_disp_drv_register(&disp_drv);


  /*Initialize the touch pad*/
  lv_indev_drv_t indev_drv;
  lv_indev_drv_init(&indev_drv);
  indev_drv.type = LV_INDEV_TYPE_ENCODER;
  indev_drv.read_cb = read_encoder;
  lv_indev_drv_register(&indev_drv);

  randomSeed(analogRead(14));
  /*Initialize the graphics library's tick*/
  tick.attach_ms(LVGL_TICK_PERIOD, lv_tick_handler);
  //top_bar();

  /////////////////////////---UI---///////////////////////////////////////////////
  static uint32_t user_data = 10;
  lv_task_t * task = lv_task_create(my_task, 500, LV_TASK_PRIO_MID, &user_data);
}


void loop()
{
  
  
  lv_task_handler(); /* let the GUI do its work */
  delay(5);
  
}

The resets are triggered by the Watchdog.

Are you intending to create a new tabview every 500ms? Right now you call top_bar multiple times, meaning that tabviews will keep stacking on top of each other, consuming memory.

Hello embeddedt. No, I don’t really intend to. I want to match the needle to display the random values. I thought I would have to call up the whole function regularly to update the new needle status. How can I do that better?

Store a reference to the object and just call lv_gauge_set_value when you want to change the value. The objects only need to be created once.

Hello how can I store the reference to the object ?
Thanks !

You just need an lv_obj_t * variable somewhere in your code which you can access from multiple functions.

Ok thanks it works !