Open tremblayraphael29 opened 2 years ago
I have based my example off this repo and I have spent EXTREMELY LONG TIME and nights debugging a similar issue. In short, this is fixed by two following things:
IRAM_ATTR
attribute to the lv_tick_task
-DLV_ATTRIBUTE_TICK_INC=IRAM_ATTR
to the platformio.ini build_flags
(or applying LV_ATTRIBUTE_TICK_INC=IRAM_ATTR
in your lvgl config).When it manifests:
Wifi.begin(...)
Preferences.
Why it happens:
IRAM_ATTR
the code is not in the cache, it's impossible to exec interruption handlernoInterrupts()
and interrupts()
, you might reduce the scope of the problem, but instead you get some severe watchdog problems which cause unexpected restarts.Hope it helps some people. I will try to create a PR to this repo a bit shortly after (but if someone wants to do that first, feel free to do so).
Hmm, we saw a MemFault/BusFault after executing lv_font_get_glyph_dsc_fmt_txt() in one of our nightly tests.
We never saw this kind of error before and we yet couldn't reproduce the issue.
I just saw you also mention "lv_font_get_glyph_dsc_fmt_txt" in your logs and we also use the the cache options of the microcontroller. But we are running on a STM32H7 so a really different platform...
and we also use the the cache options of the microcontroller.
@Viatorus if that's the same issue, you can relatively easy rule it out:
lv_tick_task
. LVGL will be effectively broken, but all function calls will continue working as normal. If the application has stopped crashing, then you have the same issue as I had.I just saw you also mention "lv_font_get_glyph_dsc_fmt_txt" in your logs
In my case stacktraces were basically useless, because the program memmory was not accessible. Therefore the execution jumped to random addresses of the code. Ideally debugger is needed to find a cause for such an issue, but unfortunately I didn't have any access to it.
I have a same problem.
void scanWifi(void *parameter) {
lv_obj_t *display = (lv_obj_t *) parameter;
lv_obj_t *list = lv_list_create(display);
lv_obj_set_size(list, LV_PCT(100), LV_PCT(100));
WiFi.begin();
int n = WiFi.scanNetworks();
Serial.println("[*] Scan done");
if (n < 0) {
Serial.println("[-] No WiFi networks found");
} else {
Serial.println((String) "[+] " + n + " WiFi networks found\n");
for (int i = 0; i < n; ++i) {
lv_list_add_btn(list, NULL, WiFi.SSID(i).c_str());
vTaskDelay(10 / portTICK_PERIOD_MS);
}
}
vTaskDelete(TaskHandle_2);
}
xTaskCreate(scanWifi, "scanWifi", 1024 * 10, (void *) display, 10, &TaskHandle_2);
This issue or pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Exactly the same issue. It simply crash and crash and took me long time trying to solve the problem by increasing stack amount,adding some vTaskDelay, some sort like that,but these did nothing good...as @derlaft 's advice,adding iram attr actually helps a lot. Now my issue is like random wdt reset. Working hard on it.
@Potak0 btw I wrote a sligthly more detailed writeup here, it might contain a bit more details and debugging steps which could help you
@derlaft that does increased my understanding.thanks a lot.
I've also been dealing with a similar issue. In my case, the problem arises after calling the WiFi.begin() function. The microcontroller doesn't restart, but the display randomly glitches or stays black. I got the code from a design made in SquareLine Studio. I tried adding the attribute -DLV_ATTRIBUTE_TICK_INC=IRAM_ATTR to the platformio.ini build_flags, but it didn't improve things. As a temporary solution, I'm calling the "tft.init()" function after waiting for the wifi to connect. It's not the most sophisticated solution, but it buys me time to find a more accurate one.
WiFi.begin(ssid_sta, password_sta);
WiFi.waitForConnectResult(1000);
tft.init();
The post from @derlaft explaining the origin of the problem helped me a lot. And wanting to understand better, I looked for diagrams of how the ESP32 is internally structured on the Espressif and Xtensa websites to see how the buses and modules are interconnected, but I didn't have any success.
@axlb97 I've just checked my platformio.ini
and it has also:
-DLV_ATTRIBUTE_TIMER_HANDLER=IRAM_ATTR
-DLV_ATTRIBUTE_FLUSH_READY=IRAM_ATTR
I don't remember why I added them (likely for performance), but double-checking if they help you should not hurt
What else comes to my mind:
@derlaft
@axlb97 I've just checked my
platformio.ini
and it has also:
-DLV_ATTRIBUTE_TIMER_HANDLER=IRAM_ATTR
-DLV_ATTRIBUTE_FLUSH_READY=IRAM_ATTR
I don't remember why I added them (likely for performance), but double-checking if they help you should not hurt
I'm going to remove the call to tft.init()
and add those attributes to platformio.ini
to see if it improves. Calling tft.init()
makes the display go black for a second and it's annoying.
If the device doesn't have a connection, it retries the reconnection every 20 seconds, so every 20 seconds tft.init()
is called.
In setup(), i disabled the auto-reconnection with WiFi.setAutoreconnect(false).
But seeing that calling a function of tft to resolve the issue makes me suspect that it's maybe a problem with that library and not with lvgl, idk.
Since i need to have them finished soon since these devices are required in the laboratories where i work i started working on a parallel code where i use sprites to shape the interface, after all, it's a very simple design. But i haven't made much progress yet. i wasn't very happy with that because that way I can't use the Montserrat font.
What else comes to my mind:
- Do you (or maybe the display) use ADC2? (It's shared with Wi-Fi)
Now that I notice, something like that. I don't use ADC2, but the DC pin of the display is connected to GPIO2 (ADC2_2), maybe causing issues.
- Try changing the drawing loop RTOS priority to a higher value (maybe weird issues are called by interrupts in the drawing routines; example how I do that (sorry, that code is not very high quality, but should give an example))
- Would generally be interesting to look at your display driver func.
Since the code related to lvgl is generated by Squareline Studio when exporting the project (I don't have any previous experience with lvgl before this. In fact, I came to know lvgl thanks to squareline studio while looking for an easy way to design my interfaces.) I couldn't find where the tasks are declared and what priority they are assigned. A similar function to the one you showed me is this one (also generated by Squareline Studio).
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
uint32_t w = (area->x2 - area->x1 + 1);
uint32_t h = (area->y2 - area->y1 + 1);
tft.startWrite();
tft.setAddrWindow(area->x1, area->y1, w, h);
tft.pushColors((uint16_t *)&color_p->full, w * h, true);
tft.endWrite();
lv_disp_flush_ready(disp);
}
I've created another task to execute the lv_timer_handler() function every 5ms
xTaskCreatePinnedToCore(taskDisplayHandler, "TaskDisplayHandler", 4096, NULL, 20, NULL, 1);
Its definition:
LV_ATTRIBUTE_TIMER_HANDLER uint32_t lv_timer_handler(void)
{
TIMER_TRACE("begin");
/*Avoid concurrent running of the timer handler*/
static bool already_running = false;
if(already_running) {
TIMER_TRACE("already running, concurrent calls are not allow, returning");
return 1;
}
already_running = true;
if(lv_timer_run == false) {
already_running = false; /*Release mutex*/
return 1;
}
static uint32_t idle_period_start = 0;
static uint32_t busy_time = 0;
uint32_t handler_start = lv_tick_get();
if(handler_start == 0) {
static uint32_t run_cnt = 0;
run_cnt++;
if(run_cnt > 100) {
run_cnt = 0;
LV_LOG_WARN("It seems lv_tick_inc() is not called.");
}
}
/*Run all timer from the list*/
lv_timer_t * next;
do {
timer_deleted = false;
timer_created = false;
LV_GC_ROOT(_lv_timer_act) = _lv_ll_get_head(&LV_GC_ROOT(_lv_timer_ll));
while(LV_GC_ROOT(_lv_timer_act)) {
/*The timer might be deleted if it runs only once ('repeat_count = 1')
*So get next element until the current is surely valid*/
next = _lv_ll_get_next(&LV_GC_ROOT(_lv_timer_ll), LV_GC_ROOT(_lv_timer_act));
if(lv_timer_exec(LV_GC_ROOT(_lv_timer_act))) {
/*If a timer was created or deleted then this or the next item might be corrupted*/
if(timer_created || timer_deleted) {
TIMER_TRACE("Start from the first timer again because a timer was created or deleted");
break;
}
}
LV_GC_ROOT(_lv_timer_act) = next; /*Load the next timer*/
}
} while(LV_GC_ROOT(_lv_timer_act));
uint32_t time_till_next = LV_NO_TIMER_READY;
next = _lv_ll_get_head(&LV_GC_ROOT(_lv_timer_ll));
while(next) {
if(!next->paused) {
uint32_t delay = lv_timer_time_remaining(next);
if(delay < time_till_next)
time_till_next = delay;
}
next = _lv_ll_get_next(&LV_GC_ROOT(_lv_timer_ll), next); /*Find the next timer*/
}
busy_time += lv_tick_elaps(handler_start);
uint32_t idle_period_time = lv_tick_elaps(idle_period_start);
if(idle_period_time >= IDLE_MEAS_PERIOD) {
idle_last = (busy_time * 100) / idle_period_time; /*Calculate the busy percentage*/
idle_last = idle_last > 100 ? 0 : 100 - idle_last; /*But we need idle time*/
busy_time = 0;
idle_period_start = lv_tick_get();
}
already_running = false; /*Release the mutex*/
TIMER_TRACE("finished (%d ms until the next timer call)", time_till_next);
return time_till_next;
}
We use GitHub issues for development related discussions.
Describe the issue The problem only happens when I integrate a task that connects the esp32 to a wifi access point. In fact, the task is not even executed yet that I get a “Panic Core dump (LoadStore Error)”. So the error does not come from an error in the task itself.
Code to reproduce the issue lv_port_esp32 (lv_demo_widget) with wifi station connect task
ESP32 Chip version ESP32 devkit (4 MB flash, chip revision 1, ESP32-D0WDQ6)
ESP-IDF version version : 4.3
Compilation warnings/errors (if available) Console terminal result :
LOG LVGL DETAILS