Description
I have a C++ class that creates and updates an LVGL meter. Everything works fine if I don’t use animations. When I do use the animation in updateValue(), it crashes. Maybe the approach I’m using is completely wrong, I couldn’t find many examples online.
Edit: The reason I want to use a class like I did is to give the ability to the user to create X number of Meters and display them. In other words I want to create my meters when nessecary.
What MCU/Processor/Board and compiler are you using?
ESP32 / Platform IO / Arduino framework
What do you want to achieve?
Use the animation in updateValue().
What have you tried so far?
I had a lot of trouble making lv_anim_set_custom_exec_cb work, I started using lv_anim_set_exec_cb but couldn’t pass animCallback(void *indic, int32_t val) because it expected a free function. With some help I found that I could use a lamda with no capture like I did .
Right now, Serial.println(“before”); and Serial.println(“AFTER”); executes 2 times before it crashes so I know the code gets to animCallback().
The error seems to happen inside lv_timer_exec() which is in my loop.
Here is the only error message that I manage to get:
Backtrace: 0x00000012:0x3ffb2200 0x400e900c:0x3ffb2220 0x400d2b10:0x3ffb2250 0x400fbd65:0x3ffb2290
#0 0x00000012:0x3ffb2200 in ?? ??:0
#1 0x400e900c:0x3ffb2220 in lv_timer_exec at .pio/libdeps/esp32-3248S035C/lvgl/src/misc/lv_timer.c:313
(inlined by) lv_timer_handler at .pio/libdeps/esp32-3248S035C/lvgl/src/misc/lv_timer.c:109
#2 0x400d2b10:0x3ffb2250 in loop() at src/main.cpp:56
#3 0x400fbd65:0x3ffb2290 in loopTask(void*) at C:/Users/Emilio/.platformio/packages/framework-arduinoespressif32/cores/esp32/main.cpp:50
Code to reproduce
*** meter.cpp
#include "meter.hpp"
#include "lvgl.h"
#include <Arduino.h>
Meter::Meter(lv_obj_t *parent, int min, int max)
: meter(nullptr), indicator(nullptr), min_value(min), max_value(max), current_value(0), peak_value(0)
{
meter = lv_meter_create(parent);
lv_obj_set_size(meter, 200, 200);
lv_obj_center(meter);
lv_meter_scale_t *scale = lv_meter_add_scale(meter);
lv_meter_set_scale_ticks(meter, scale, 41, 2, 10, lv_palette_main(LV_PALETTE_GREY));
lv_meter_set_scale_major_ticks(meter, scale, 8, 4, 15, lv_color_black(), 10);
lv_meter_indicator_t *indic;
indic = lv_meter_add_arc(meter, scale, 3, lv_palette_main(LV_PALETTE_BLUE), 0);
lv_meter_set_indicator_start_value(meter, indic, 0);
lv_meter_set_indicator_end_value(meter, indic, 20);
indic = lv_meter_add_scale_lines(meter, scale, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_BLUE), false, 0);
lv_meter_set_indicator_start_value(meter, indic, 0);
lv_meter_set_indicator_end_value(meter, indic, 20);
indic = lv_meter_add_arc(meter, scale, 3, lv_palette_main(LV_PALETTE_RED), 0);
lv_meter_set_indicator_start_value(meter, indic, 80);
lv_meter_set_indicator_end_value(meter, indic, 100);
indic = lv_meter_add_scale_lines(meter, scale, lv_palette_main(LV_PALETTE_RED), lv_palette_main(LV_PALETTE_RED), false, 0);
lv_meter_set_indicator_start_value(meter, indic, 80);
lv_meter_set_indicator_end_value(meter, indic, 100);
indicator = lv_meter_add_needle_line(meter, scale, 4, lv_palette_main(LV_PALETTE_GREY), -10);
}
void Meter::animCallback(void *indic, int32_t val)
{
Serial.println("before");
lv_meter_set_indicator_value(this->meter, static_cast<lv_meter_indicator_t *>(indic), val);
Serial.println("AFTER");
}
void Meter::updateValue(int value)
{
if (value > peak_value)
{
peak_value = value;
}
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, indicator);
lv_anim_set_time(&a, 10);
lv_anim_set_user_data(&a, this);
lv_anim_set_custom_exec_cb(&a, [](lv_anim_t *anim, int32_t val)
{
auto *self = static_cast<Meter *>(lv_anim_get_user_data(anim)); // retrieve this
self->animCallback(anim->var, val); });
lv_anim_set_values(&a, current_value, value);
lv_anim_start(&a);
current_value = value;
}
void Meter::resetPeak()
{
peak_value = current_value;
}
*** main.cpp
#include <Arduino.h>
#include <esp32_smartdisplay.h>
#include <ui/ui.h>
#include <random>
#include <iomanip>
#include "custom_ui/lv_custom_meter.h"
#include "custom_ui/parameter/meter.hpp"
std::random_device rd;
std::mt19937 gen(rd());
lv_obj_t *meter;
Meter *p_meter;
void onSettingsClick(lv_event_t *e)
{
lv_disp_load_scr(ui_Gauge);
Serial.println("ALLO222");
}
void onHamburgerClick(lv_event_t *e)
{
lv_disp_load_scr(ui_Navigation);
Serial.println("ALLO222111");
}
double generateRandomNumber(double lower_bound, double upper_bound)
{
std::uniform_real_distribution<double> distribution(lower_bound, upper_bound);
double random_number = distribution(gen);
return random_number;
}
void setup()
{
smartdisplay_init();
Serial.begin(115200);
Serial.setDebugOutput(true);
auto disp = lv_disp_get_default();
lv_disp_set_rotation(disp, LV_DISP_ROT_90);
// lv_disp_set_rotation(disp, LV_DISP_ROT_180);
// lv_disp_set_rotation(disp, LV_DISP_ROT_270);
ui_init();
lv_obj_t *screen = lv_scr_act();
// Use the custom meter
//meter = lv_custom_meter_create(screen, 0, 100);
p_meter = new Meter(screen, 0, 100);
}
void loop()
{
lv_timer_handler();
Serial.println(lv_scr_act() == ui_Gauge);
double generated_number = generateRandomNumber(0, 30);
char buffer[20]; // Adjust the size based on your needs
snprintf(buffer, sizeof(buffer), "%.2f", generated_number);
Serial.println(generated_number);
int myInt = round(generated_number);
p_meter->updateValue(6);
if (lv_scr_act() == ui_Gauge)
{
delay(1000);
// Serial.println(buffer);
// lv_label_set_text(ui_GaugeValueLabel, buffer);
// lv_arc_set_value(ui_GaugeArc, generated_number);
}
}
Screenshot and/or video
I don’t have any but the only thing that’s happening is that the display turns on, the error happens, turns off and reloads.