Lv.label_set_text_fmt(), Cant update label on the screen

Description

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

ESP32-2432S028, CYD, VS PlatformIO, eez Studio

What LVGL version are you using?

9.2.2

What do you want to achieve?

Update label using function lv.label_set_text_fmt(objects.label_number, “%d”, counter) after click on Button. New displayed value should be value of counter.
Function is in void loop() of main.cpp.

What have you tried so far?

Check counter value, by debug printf. It is O.K., counter is updated after each click on button.Counter is defined as integer.
Check that object.label_number is not NULL, it is O.K.
Check for label overlay, but project is simple, there is not other label.
But text label with text “NUM” always remain with the same.
I try to use some help of Copilot, but it finished always in dead end. I am just learning programming and spent on this problem about 2 months.

Code to reproduce

main.cpp

/*
// LVGL demo for ESP32 with TFT_eSPI and XPT2046 touch controller
#include <Arduino.h>
#include <memory>
#include <lvgl.h>
#include "vars.h"
#include "ui.h"
#include "screens.h"
#include <TFT_eSPI.h>
#include <XPT2046_Touchscreen.h>

lv_disp_t *disp;        // Global display variable
lv_indev_t *indev;      // Touchscreen input device
uint8_t *draw_buf;      // Display buffer
uint32_t lastTick = 0;  // Used to track the tick timer

// The CYD touch uses some non default SPI pins
// The touch CS pin is defined in the User_Setup.h file
// The touch IRQ pin is defined in the XPT2046_Touchscreen.h file
#define XPT2046_IRQ 36
#define XPT2046_MOSI 32
#define XPT2046_MISO 39
#define XPT2046_CLK 25
#define XPT2046_CS 33
#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)) 
 
TFT_eSPI tft = TFT_eSPI();
SPIClass touchscreenSpi = SPIClass(VSPI);
XPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);
uint16_t touchScreenMinimumX = 200, touchScreenMaximumX = 3700, touchScreenMinimumY = 240, touchScreenMaximumY = 3800;

//lvgl function to display message from LVGL if LV_USE_LOG is enabled
#if LV_USE_LOG != 0
void my_print(lv_log_level_t level, const char *buf) {
  LV_UNUSED(level);
  Serial.println(buf);
  Serial.flush();
}
#endif

//transfer the display buffer to the screen
// This function is called by LVGL to flush the display buffer to the screen
void my_disp_flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_p) {
  if (area->x2 < 0 || area->y2 < 0 || area->x1 > TFT_HOR_RES - 1 || area->y1 > TFT_VER_RES - 1) {
      lv_display_flush_ready(disp);
      return;
  }

  // Set the address window for the area to be updated
  tft.startWrite();
  tft.setAddrWindow(area->x1, area->y1, area->x2 - area->x1 + 1, area->y2 - area->y1 + 1);
 // Push the pixel data to the display
  tft.pushColors((uint16_t *)color_p, (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1), true);
  tft.endWrite();

  // Notify LVGL that the flush is complete
  lv_display_flush_ready(disp);
/*    
  // Debugging output
  Serial.print("Flushing area: x1=");
  Serial.print(area->x1);
  Serial.print(", y1=");
  Serial.print(area->y1);
  Serial.print(", x2=");
  Serial.print(area->x2);
  Serial.print(", y2=");
  Serial.println(area->y2);
  */
}

/*Read the touchpad*/
 void my_touchpad_read(lv_indev_t *indev, lv_indev_data_t *data) {
   if (touchscreen.touched()) {
     TS_Point p = touchscreen.getPoint();
        
     //Map this to the pixel position
     data->point.x = map(p.x, touchScreenMinimumX, touchScreenMaximumX, 0, TFT_HOR_RES - 1); /* Touchscreen X calibration */
     data->point.y = map(p.y, touchScreenMinimumY, touchScreenMaximumY, 1, TFT_VER_RES - 1); /* Touchscreen Y calibration */
     data->state = LV_INDEV_STATE_PRESSED;
    /*  
     //Serial.print("Touch detected at: ");
    Serial.print("Raw X: ");
    Serial.print(p.x);
    Serial.print(", Raw Y: ");
    Serial.print(p.y);
    Serial.print(" -> Mapped X: ");
    Serial.print(data->point.x);
    Serial.print(", Mapped Y: ");
    Serial.println(data->point.y); 
*/
   } else {
     data->state = LV_INDEV_STATE_RELEASED;
   }
     
   
 }
  
 void setup() {   
   Serial.begin(115200);
   //Initialize the display ADDED
   tft.init();
   tft.setRotation(1); // Set display to landscape mode
   
    Serial.println("LVGL demo setup");           //(LVGL_Arduino);
   //Some basic info on the Serial console
   //String LVGL_Arduino = "LVGL demo ";
   //LVGL_Arduino += String('V') + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();
   
      //Initialise the touchscreen
   touchscreenSpi.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS); /* Start second SPI bus for touchscreen */
   touchscreen.begin(touchscreenSpi);                                         /* Touchscreen init */
   touchscreen.setRotation(1);                                      /* Inverted landscape orientation to match screen */
   /* Inverted landscape orientation to match screen */
   
   //Initialise LVGL GUI
   lv_init();
   // Allocate the display buffer
   draw_buf = new uint8_t[DRAW_BUF_SIZE];

   // Create the display
   disp = lv_display_create(TFT_HOR_RES, TFT_VER_RES);
   // Set the flush callback
   lv_display_set_flush_cb(disp, my_disp_flush);
   // Set the display buffers
   lv_display_set_buffers(disp, draw_buf, NULL, DRAW_BUF_SIZE, LV_DISPLAY_RENDER_MODE_PARTIAL);

   //Initialize the XPT2046 input device driver
   indev = lv_indev_create();
   lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
   lv_indev_set_read_cb(indev, my_touchpad_read);
 
   //Done
   Serial.println("LVGL Setup done");
 
   //Integrate EEZ Studio GUI
   ui_init();
   // Create screens
   create_screens();
  }
   
 void loop() {
   lv_tick_inc(millis() - lastTick);  //Update the tick timer. Tick is new for LVGL 9
   lastTick = millis();
   lv_timer_handler();  //Update the UI
   delay(5);


   Serial.print("Counter: ");
   Serial.println(counter);

   printf("Counter: %d\n", counter);
   //lv_label_set_text_fmt(objects.label_number, "%d", counter);
   
  }
   */
screen.c:
```c
/*
#include <string.h>
#include <stdio.h>
#include "screens.h"
#include "images.h"
#include "fonts.h"
#include "actions.h"
#include "vars.h"
#include "styles.h"
#include "ui.h"

#include <string.h>

objects_t objects;
lv_obj_t *tick_value_change_obj;

void create_screen_main() {
    lv_obj_t *obj = lv_obj_create(0);
    objects.main = obj;
    lv_obj_set_pos(obj, 0, 0);
    lv_obj_set_size(obj, 320, 240);
    {
        lv_obj_t *parent_obj = obj;
        {
            // ButtonIncrease
            lv_obj_t *obj = lv_btn_create(parent_obj);
            objects.button_increase = obj;
            lv_obj_set_pos(obj, 83, 103);
            lv_obj_set_size(obj, 154, 80);
            lv_obj_add_event_cb(obj, action_increase_by_one, LV_EVENT_CLICKED, (void *)0);
            lv_obj_set_style_radius(obj, 40, LV_PART_MAIN | LV_STATE_DEFAULT);
            lv_obj_set_style_opa(obj, 50, LV_PART_MAIN | LV_STATE_DEFAULT);
        }
        {
            // LabelNumber
            lv_obj_t *obj = lv_label_create(parent_obj);
            objects.label_number = obj;
            lv_obj_set_pos(obj, 127, 49);
            lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
            lv_label_set_text(obj, "NUM");
            lv_obj_add_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE);
            lv_obj_set_style_text_font(obj, &lv_font_montserrat_26, LV_PART_MAIN | LV_STATE_DEFAULT);
        }
    }
    
    tick_screen_main();
}


void tick_screen_main() {
}



typedef void (*tick_screen_func_t)();
tick_screen_func_t tick_screen_funcs[] = {
    tick_screen_main,
};
void tick_screen(int screen_index) {
    tick_screen_funcs[screen_index]();
}
void tick_screen_by_id(enum ScreensEnum screenId) {
    tick_screen_funcs[screenId - 1]();
}

void create_screens() {
    lv_disp_t *dispp = lv_disp_get_default();
    lv_theme_t *theme = lv_theme_default_init(dispp, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_RED), false, LV_FONT_DEFAULT);
    lv_disp_set_theme(dispp, theme);
    
    create_screen_main();
}
*/

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

Hi Kamil,
I use the Arduino IDE, but the code below works for me.
This does NOT use lv_tick_inc() in loop()

void loop() {
  lv_timer_handler();
  Alarm.delay(1); // NON-BLOCKING delay
}

Tick_inc is handled by a callback -

static ARDUINO_ISR_ATTR uint32_t tick_cb(void) {
  return millis();
}
...
  lv_init();
  lv_tick_set_cb(tick_cb);

Hope this is of some help.

1 Like

Primary i dont see in your code how is counter declared or where. Second you cant update and refresh label on every loop …

1 Like

Westcott,
Thank you for your time.
I have tried your code, it compiles, but there was not any change.
In your code it is interrupt, concerning timer function tick_cb. Generally, it could be a timer problem? Maybe not in my case.

Hi Marian, counter is declared in vars.h: “extern int counter;” Than in actions.c, there is defined event function to increase this counter after click on Button. In “actions.h”, there is declared function “extern void action_increase_by_one(lv_event_t * e)”;
I have tried to update it outside of loop - in screens.c, in case that is changed. But it was the same, no update of label “NUM”.
By the way, update inside loop, even if not done in each loop, could be done after certain loop, when counter is changed? Am I wrong?

vars.h :

#ifndef EEZ_LVGL_UI_VARS_H
#define EEZ_LVGL_UI_VARS_H

#include <stdint.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

// enum declarations
#ifndef VARS_H
#define VARS_H

extern int counter;

#endif


// Flow global variables

enum FlowGlobalVariables {
    FLOW_GLOBAL_VARIABLE_NONE
};

// Native global variables



#ifdef __cplusplus
}
#endif

#endif /*EEZ_LVGL_UI_VARS_H*/

actions.h

#ifndef EEZ_LVGL_UI_EVENTS_H
#define EEZ_LVGL_UI_EVENTS_H

#include <lvgl.h>

#ifdef __cplusplus
extern "C" {
#endif

extern void action_increase_by_one(lv_event_t * e);



#ifdef __cplusplus
}
#endif
#endif /*EEZ_LVGL_UI_EVENTS_H*/

actions.c

 #include <stdio.h>
#include "actions.h"
#include "screens.h"
#include "vars.h"
#include <lvgl.h>


void action_increase_by_one(lv_event_t * e) {
    counter++;

    // Debug print to Serial
    //printf("Counter value: %d\n", counter);
    printf("Counter value: %d, label ptr: %p\n", counter, (void*)objects.label_number);   
    //char buffer[16];
    //snprintf(buffer, sizeof(buffer), "%d", counter);
    //lv_label_set_text(objects.label_number, buffer);
} 

I dont use eez, but start with place

lv_label_set_text(objects.label_number, "NEW");

inside update counter event func. And show where you have extern objects…

1 Like

Marian, if I set text to: lv_label_set_text(obj, "NEW"); I just replace “NUM” label on the display.
In my Code to reproduce, there is a mistake: function: ```
lv_label_set_text_fmt(objects.label_number, “%d”, counter);

This function is disabled by remark // and normally should not be disabled. Sorry.

Is replaced on display ??? This is test ! And not obj , but as i write.

1 Like

Yes it is test. But problem was not solved, just text was changed. Label itself was not replaced by expected value of counter. But anyway thank you.

show where you place this code and do as is writed

1 Like

I put this code in screen.c (LabelNumber):

#include <string.h>
#include <stdio.h>
#include "screens.h"
#include "images.h"
#include "fonts.h"
#include "actions.h"
#include "vars.h"
#include "styles.h"
#include "ui.h"

#include <string.h>

objects_t objects;
lv_obj_t *tick_value_change_obj;

void create_screen_main() {
    lv_obj_t *obj = lv_obj_create(0);
    objects.main = obj;
    lv_obj_set_pos(obj, 0, 0);
    lv_obj_set_size(obj, 320, 240);
    {
        lv_obj_t *parent_obj = obj;
        {
            // ButtonIncrease
            lv_obj_t *obj = lv_btn_create(parent_obj);
            objects.button_increase = obj;
            lv_obj_set_pos(obj, 83, 103);
            lv_obj_set_size(obj, 154, 80);
            lv_obj_add_event_cb(obj, action_increase_by_one, LV_EVENT_CLICKED, (void *)0);
            lv_obj_set_style_radius(obj, 40, LV_PART_MAIN | LV_STATE_DEFAULT);
            lv_obj_set_style_opa(obj, 50, LV_PART_MAIN | LV_STATE_DEFAULT);
        }
        {
            // LabelNumber
            lv_obj_t *obj = lv_label_create(parent_obj);
            objects.label_number = obj;
            lv_obj_set_pos(obj, 127, 49);
            lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
            lv_label_set_text(obj, "NEW");
            lv_obj_add_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE);
            lv_obj_set_style_text_font(obj, &lv_font_montserrat_26, LV_PART_MAIN | LV_STATE_DEFAULT);
        }
    }
    
    tick_screen_main();
}


void tick_screen_main() {
}



typedef void (*tick_screen_func_t)();
tick_screen_func_t tick_screen_funcs[] = {
    tick_screen_main,
};
void tick_screen(int screen_index) {
    tick_screen_funcs[screen_index]();
}
void tick_screen_by_id(enum ScreensEnum screenId) {
    tick_screen_funcs[screenId - 1]();
}

void create_screens() {
    lv_disp_t *dispp = lv_disp_get_default();
    lv_theme_t *theme = lv_theme_default_init(dispp, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_RED), false, LV_FONT_DEFAULT);
    lv_disp_set_theme(dispp, theme);
    
    create_screen_main();
}

Sorry but you seems be big noob. In create screen leave as you have NUM!
And test event reaction and your code then place next my line into PRESSED event . Display must change on button press. After this work i can help you place formated conter value.

void action_increase_by_one(lv_event_t * e) {
    counter++;
lv_label_set_text(objects.label_number, "OMG");
} 

Yes, you are right, I am new in programming

  1. In create screen I have leave NUM.
  2. I put your suggested code in file action.c. I put there “OMG” not “NUM”?
  3. After compile, there is NUM on screen.
  4. I tested action_increase_by_one() by Serial Monitor. Counter was increased after each click and is very stable - just after value change.
  5. I did not place your suggested code to PRESSED event. My event code is inside screen.c in ButtonIncrease and there is not PRESSED event, there is Click event. Line is: lv_obj_add_event_cb(obj, action_increase_by_one, LV_EVENT_CLICKED, (void *)0);

Your plan is learn somethink or dont ? Now for test you can use CLICKED too.
Is action increase by one as i type code now and dont update to omg after CLICK ?

NUM must change .

1 Like

Sorry for my delay, it was night and I was sleeping.

NUM was not changed, it remain the same after click! No OMG.
Here is list of actions.c with your code:

#include <stdio.h>
#include "actions.h"
#include "screens.h"
#include "vars.h"
#include <lvgl.h>


void action_increase_by_one(lv_event_t * e) {
    counter++;
    lv_label_set_text(objects.label_number, "OMG");
    //lv_label_set_text_fmt(objects.label_number, "%d", counter);
    // Debug print to Serial
    //printf("Counter value: %d\n", counter);
    //printf("Counter value: %d, label ptr: %p\n", counter, (void*)objects.label_number);   
    //char buffer[16];
    //snprintf(buffer, sizeof(buffer), "%d", counter);
    //lv_label_set_text(objects.label_number, buffer);
}

Here is main.cpp, void loop():

 void loop() {     
   lv_tick_inc(millis() - lastTick);  //Update the tick timer. Tick is new for LVGL 9
   lastTick = millis();
   lv_timer_handler();  //Update the UI
   delay(5);

   Serial.print("Counter: ");
   Serial.println(counter);
   printf("Counter: %d\n", counter);
   lv_label_set_text_fmt(objects.label_number, "%d", counter);
                         }

The same result If I put function
lv_label_set_text_fmt(objects.label_number, "%d", counter);

directly to actions.c to void action_increase_by_one().

Primary change your loop code to this

void loop() {     
static int lastcounter;

   lv_tick_inc(millis() - lastTick);  //Update the tick timer. Tick is new for LVGL 9
   lastTick = millis();
   lv_timer_handler();  //Update the UI
   delay(5);

if(lastcounter!=counter) {
   Serial.print("Counter: ");
   Serial.println(counter);
  lastcounter=counter;
  }
}

and show serial output when click

1 Like

And search all occurence of this in VS Code click Find in Files Ctrl+Shift+F
show here all returns

1 Like

screens.h :
extern objects_t objects;

screens.c :
objects_t objects;

Ok and what click and println counter log?

1 Like

But there is not problem a value of counter. It is increased after aech event. Problem is concerning mentioned function?