Cannot change widgets

Description

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

I am running on a ESP32 S3 DevKit C board with Arduino Framework.
As IDE I am using PlatformIO.

What LVGL version are you using?

v9

What do you want to achieve?

I am trying to get familiar with LVGL and started a small test project.
I am using TFT_eSPI as driver with my SPI connected display. The display is using ST7789.
I want to draw a simple label in the middle of the active screen. The screen is white, that’s why I think lvl is working. In addition I see a label, but it has always the value “text” and it’s always in the upper left corner.

What have you tried so far?

I tried adding different widgets. It seems that only the first widget drawn, is actually shown.
But the behaviour is identical for all widgets - always on the upper left corner.

Code to reproduce

The code block(s) should be formatted like:

void begin()
{
    lv_init();
    uint8_t draw_buf[DRAW_BUF_SIZE];
    display = lv_tft_espi_create(TFT_HOR_RES, TFT_VER_RES, draw_buf, DRAW_BUF_SIZE);
    TFT_eSPI *tft = (TFT_eSPI *)lv_display_get_driver_data(display);
    tft->invertDisplay(0);

    xTaskCreate(tick, "tick", 3000, NULL, 1, NULL);
    xTaskCreate(timer, "disp", 10000, NULL, 1, NULL);

    lv_obj_t *label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "Hello Arduino, I'm LVGL!");
    lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);

    lv_obj_t *slider = lv_slider_create(lv_scr_act());
    lv_slider_set_range(slider, 0, 100);
    lv_obj_set_pos(slider, 20, 100);
    lv_obj_set_width(slider, 150);
}
void timer(void *ctx)
{
    while (1)
    {
        lv_timer_handler();
        vTaskDelay(20 / portTICK_PERIOD_MS);
    }
}

void tick(void *ctx)
{
    while (1)
    {
        lv_tick_inc(5);
        vTaskDelay(5 / portTICK_PERIOD_MS);
    }
}

Screenshot and/or video

The above code does produce this output.

I found out, that I need to put the lv_timer_handler() in the main loop of Arduino.
BUT it is still not working properly.

For some reason I have to call lv_timer_handler() once after initialising and creating the labels.
And widgets never update. I try to change the text of a label, when a button (not UI Button, but external switch) is pressed. But nothing happens …

This is my current code

void setup()
{
  nhd.begin();

  sw.attachClick(click);
}

void click()
{
  Serial.println("Click ...");
  nhd.change();
}

void loop()
{
  sw();

  lv_timer_handler();
  vTaskDelay(5 / portTICK_PERIOD_MS);
}

Class for display

#define TFT_HOR_RES 320
#define TFT_VER_RES 240
#define DRAW_BUF_SIZE (TFT_HOR_RES * TFT_VER_RES / 10 * (LV_COLOR_DEPTH / 8))

class NHD
{
protected:
    lv_display_t *display;
    lv_obj_t *label;
    lv_obj_t *label1;

public:
    void begin();
    void change();
};

void NHD::begin()
{
    lv_init();
    uint8_t draw_buf[DRAW_BUF_SIZE];
    display = lv_tft_espi_create(TFT_HOR_RES, TFT_VER_RES, draw_buf, DRAW_BUF_SIZE);
    TFT_eSPI *tft = (TFT_eSPI *)lv_display_get_driver_data(display);
    tft->invertDisplay(0);

    label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "Hello Arduino, I'm LVGL!");
    lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);

    label1 = lv_label_create(lv_scr_act());
    lv_label_set_text(label1, "Hallo!");
    lv_obj_align(label1, LV_ALIGN_CENTER, 0, 30);

    lv_timer_handler(); // <-- if this is missing, I am getting panics
}

void NHD::change()
{
    lv_label_set_text(label1, "It's me");
}

I enabled logging and see the following message, when trying to change the text.

[Info]  (11.895, +11805)         lv_draw_buf_reshape: Draw buf too small for new shape lv_draw_buf.c:233
[Info]  (11.895, +0)     lv_draw_buf_reshape: Draw buf too small for new shape lv_draw_buf.c:233

I increased the buffer from #define DRAW_BUF_SIZE (TFT_HOR_RES * TFT_VER_RES / 10 * (LV_COLOR_DEPTH / 8)) to define #define DRAW_BUF_SIZE (TFT_HOR_RES * TFT_VER_RES / 5), but still getting this message.

Is this related to something different?
Is the buffer still not big enough? I’ve read, that typically 1/10 of the display size is sufficient.
I am just drawing 2 labels … is it really that memory intensive?

Hi,

have you checked the migration docs? There’s a section mentioning lv_display_set_buffers which I think it worth checking out (maybe it’s inside lv_tft_espi_create).

https://docs.lvgl.io/master/CHANGELOG.html

Good Morning,

thanks for pointing this out.
I was actually not aware of that, but unfortunately it doesn’t solve the problem.

I am still getting this log

[Info]  (32.976, +1284)  lv_draw_buf_reshape: Draw buf too small for new shape lv_draw_buf.c:233
[Info]  (32.976, +0)     lv_draw_buf_reshape: Draw buf too small for new shape lv_draw_buf.c:233

My buffer size is now

#define DRAW_BUF_SIZE (TFT_HOR_RES * TFT_VER_RES / 10 * (LV_COLOR_DEPTH / 8))

following the example LVGL_Arduino.ino.
In fact, I already tried this buffer size yesterday already without knowing it is specified in bytes.

I’ve now only 1 label and try to change the text of it.
It still says buff to small. It feels strange, as 1 label can’t take such an amount of memory, right?

EDIT:
Even with a buffer size as big as the display, I am getting the same error.
#define DRAW_BUF_SIZE (TFT_HOR_RES * TFT_VER_RES * (LV_COLOR_DEPTH / 8))

It feels, that it is related to something different.
As I am completely new to lvgl, could you guide me to dig deeper?

I added a log statement to see the required size and the actual size of the buffer.

I added these two LV_LOG_INFO lines in lv_draw_buf.c file at line 232.

    LV_LOG_INFO("Draw Buffer size is %" LV_PRId32, draw_buf->data_size);
    LV_LOG_INFO("Required size is %" LV_PRId32, size);
    if(size > draw_buf->data_size) {
        LV_LOG_INFO("Draw buf too small for new shape");
        return NULL;
    }

The following log is printed, when I try to change the label’s text based on the click event of a tactile switch.

[Info]  (12.331, +8991)  lv_draw_buf_reshape: Draw Buffer size is 15360 lv_draw_buf.c:232
[Info]  (12.331, +0)     lv_draw_buf_reshape: Required size is 3744 lv_draw_buf.c:233
[Info]  (12.390, +59)    lv_draw_buf_reshape: Draw Buffer size is 40 lv_draw_buf.c:232
[Info]  (12.478, +88)    lv_draw_buf_reshape: Required size is 64 lv_draw_buf.c:233
[Info]  (12.563, +85)    lv_draw_buf_reshape: Draw buf too small for new shape lv_draw_buf.c:235
[Info]  (12.663, +100)   lv_draw_buf_reshape: Draw Buffer size is 64 lv_draw_buf.c:232
[Info]  (12.752, +89)    lv_draw_buf_reshape: Required size is 88 lv_draw_buf.c:233
[Info]  (12.837, +85)    lv_draw_buf_reshape: Draw buf too small for new shape lv_draw_buf.c:235
[Info]  (12.937, +100)   lv_draw_buf_reshape: Draw Buffer size is 88 lv_draw_buf.c:232
[Info]  (13.026, +89)    lv_draw_buf_reshape: Required size is 88 lv_draw_buf.c:233
[Info]  (13.113, +87)    lv_draw_buf_reshape: Draw Buffer size is 88 lv_draw_buf.c:232
[Info]  (13.200, +87)    lv_draw_buf_reshape: Required size is 22 lv_draw_buf.c:233
[Info]  (13.286, +86)    lv_draw_buf_reshape: Draw Buffer size is 88 lv_draw_buf.c:232
[Info]  (13.374, +88)    lv_draw_buf_reshape: Required size is 64 lv_draw_buf.c:233
[Info]  (13.459, +85)    lv_draw_buf_reshape: Draw Buffer size is 88 lv_draw_buf.c:232
[Info]  (13.548, +89)    lv_draw_buf_reshape: Required size is 15 lv_draw_buf.c:233
[Info]  (13.633, +85)    lv_draw_buf_reshape: Draw Buffer size is 88 lv_draw_buf.c:232
[Info]  (13.722, +89)    lv_draw_buf_reshape: Required size is 56 lv_draw_buf.c:233

The first line shows the size of the buffer, I am creating.
But as you can see for the following two calls of the lv_draw_buf_reshape the size is not sufficient.
Can you make sense of it?

I’ve tried to reproduce the issue with the simulator, but it’s working there.
I am running with PlatformIO und SDL on MacOS.

This is my sample code:

#include "lvgl.h"
#include "app_hal.h"

#include "demos/lv_demos.h"

lv_obj_t *label1;
lv_obj_t *btn1;

void clicked(lv_event_t *event)
{
  lv_label_set_text(label1, "changed");
}

void draw()
{
  label1 = lv_label_create(lv_scr_act());
  lv_label_set_text(label1, "Hallo!");
  lv_obj_align(label1, LV_ALIGN_CENTER, 0, 0);

  btn1 = lv_btn_create(lv_scr_act());
  lv_obj_align(btn1, LV_ALIGN_CENTER, 0, 30);
  lv_obj_t *btn_text = lv_label_create(btn1);
  lv_label_set_text(btn_text, "Click me!");
  lv_obj_add_event_cb(btn1, clicked, LV_EVENT_CLICKED, NULL);
}

int main(void)
{
  lv_init();

  hal_setup();

  draw();

  hal_loop();
}

It seems to be related to either the Arduino framework or the hardware.
The requested buffer is not very big, so it’s astonishing why the allocated buffer is too small.

Does anybody have an idea?

– EDIT
I noticed, that the simulator project was not updated yet and it’s running with lvgl 8.2.0.
Simply updating to v9 didn’t work due to some compilation errors with SDL. As stated in the change log, that might be not that easy …
Will the simulator project updated at some point?

– EDIT2
I actually can add another label on switch pressed, but I cannot change the text of an existing label.
It feels a bit weird … Does that make sense to anyone?
Any help is appreciated, as I am stuck.

Hello,

Try making thelabel1 variable static: static lv_obj_t* label1. Furthermore, you have not set label1 as the child object of the button, but instead you have set btn_text as the child.

try doing this:

  btn1 = lv_btn_create(lv_scr_act());
  lv_obj_align(btn1, LV_ALIGN_CENTER, 0, 30);
  label1 = lv_label_create(btn1);
  lv_label_set_text(btn_text, "Click me!");
  lv_obj_add_event_cb(btn1, clicked, LV_EVENT_CLICKED, NULL);

Hallo @Tinus,

thanks for your reply.
You’re referring to the code I’ve used in the simulator, right?
Actually, the simulator is working as it is …

I have the problems when running on ESP32 with Arduino framework.
I’ve a class holding the labels and a method change trying to modify the screen, when a external switch is pressed.

Code looks now like this:
NHD.h

#ifndef NHD_H
#define NHD_H

#include <TFT_eSPI.h>
#include "../lib/lvgl/lvgl.h"

/*Set to your screen resolution*/
#define TFT_HOR_RES 320
#define TFT_VER_RES 240
#define DRAW_BUF_SIZE (TFT_HOR_RES * TFT_VER_RES / 10 * (LV_COLOR_DEPTH / 8))

class NHD
{
protected:
    lv_display_t *display;
    lv_obj_t *label;
    lv_obj_t *label1;
public:
    void begin();
    void change();
};

#endif

NHD.cpp

void NHD::begin()
{
    lv_init();

    uint8_t draw_buf[DRAW_BUF_SIZE];
    display = lv_tft_espi_create(TFT_HOR_RES, TFT_VER_RES, draw_buf, DRAW_BUF_SIZE);
    TFT_eSPI *tft = (TFT_eSPI *)lv_display_get_driver_data(display);
    tft->invertDisplay(0);

    xTaskCreate(tick, "tick", 3000, NULL, 1, NULL);

    label1 = lv_label_create(lv_scr_act());
    lv_label_set_text(label1, "Hallo!");
    lv_obj_align(label1, LV_ALIGN_CENTER, 0, 30);

    lv_timer_handler();
}

void NHD::change()
{
    if (label == NULL)
    {
        label = lv_label_create(lv_scr_act());
        lv_label_set_text(label, "This is a extremely long text and it will scroll ...");
        lv_obj_align(label, LV_ALIGN_LEFT_MID, 5, 0);
    }
    else
    {
        lv_label_set_text(label, "other text");
        lv_obj_set_style_border_color(label, lv_palette_main(LV_PALETTE_BLUE), LV_PART_MAIN);
        lv_obj_set_style_border_width(label, 5, LV_PART_MAIN);
    }
}

I have problems making the lv_objs static in that class.
Is it necessary?

change is called, when I press the switch.
When I try to add a label or to change an existing one, I see the message lv_draw_buf_reshape: Draw buf too small for new shape lv_draw_buf.c:235