Description
I am using a Black&White 0.96inch OLED Display to display status of Fan Mode and the sensor values
- There is a button(or via an MQTT Command), the user can change the Fan Mode and this is reflected on the OLED and after 5 seconds(using timer) Sensor data is display(the sensor data is refreshed every 2 minutes)
- On Some Custom PCB (4/40 for now), which doing extended testing we observe that after a certain while the ESP restarts citing that there has been an attempt to do “memcpy in ROM”
- Now, I tried reproducing the issue by pressing the button at close intervals (like 30 times a minute) and I didn’t observe a crash for 3-4 minutes straight and then I stopped, currently my system has been running normally for 3.5Hours with me repeating this 30 times a minute thing for 2 minutes every hour.
- For one instance I got the error back trace from the ESP such as
Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC : 0x420168ea PS : 0x00060b30 A0 : 0x820169db A1 : 0x3fcd57e0
--- 0x420168ea: get_prop_core at C:/Akash/Firmwares/Hive/Hive_E_ESPIDF_514/Hive_E/managed_components/lvgl__lvgl/src/core/lv_obj_style.c:613
A2 : 0x3fcaf568 A3 : 0x00000000 A4 : 0x00000000 A5 : 0x00000000
A6 : 0x00000002 A7 : 0xb33fffff A8 : 0x820168bd A9 : 0x3fcd57c0
A10 : 0x00000001 A11 : 0x00588f0e A12 : 0x00000000 A13 : 0x00000000
A14 : 0x00060023 A15 : 0x00000003 SAR : 0x0000001f EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000004 LBEG : 0x40056f5c LEND : 0x40056f72 LCOUNT : 0xffffffff
--- 0x40056f5c: memcpy in ROM
0x40056f72: memcpy in ROM
Backtrace: 0x420168e7:0x3fcd57e0 0x420169d8:0x3fcd5830 0x420150a5:0x3fcd5860 0x42014567:0x3fcd5890 0x42014900:0x3fcd58d0 0x420148e5:0x3fcd58f0 0x42014984:0x3fcd5910 0x42018995:0x3fcd5930 0x4201d695:0x3fcd5960 0x4201d746:0x3fcd5980 0x42010aac:0x3fcd59a0 0x40380006:0x3fcd59c0
--- 0x420168e7: get_prop_core at C:/Akash/Firmwares/Hive/Hive_E_ESPIDF_514/Hive_E/managed_components/lvgl__lvgl/src/core/lv_obj_style.c:612
0x420169d8: lv_obj_get_style_prop at C:/Akash/Firmwares/Hive/Hive_E_ESPIDF_514/Hive_E/managed_components/lvgl__lvgl/src/core/lv_obj_style.c:229
0x420150a5: lv_obj_get_style_base_dir at C:/Akash/Firmwares/Hive/Hive_E_ESPIDF_514/Hive_E/managed_components/lvgl__lvgl/src/core/lv_obj_style_gen.h:567
(inlined by) lv_obj_get_scroll_left at C:/Akash/Firmwares/Hive/Hive_E_ESPIDF_514/Hive_E/managed_components/lvgl__lvgl/src/core/lv_obj_scroll.c:167
0x42014567: lv_obj_refr_size at C:/Akash/Firmwares/Hive/Hive_E_ESPIDF_514/Hive_E/managed_components/lvgl__lvgl/src/core/lv_obj_pos.c:90
0x42014900: layout_update_core at C:/Akash/Firmwares/Hive/Hive_E_ESPIDF_514/Hive_E/managed_components/lvgl__lvgl/src/core/lv_obj_pos.c:1135
0x420148e5: layout_update_core at C:/Akash/Firmwares/Hive/Hive_E_ESPIDF_514/Hive_E/managed_components/lvgl__lvgl/src/core/lv_obj_pos.c:1130 (discriminator 3)
0x42014984: lv_obj_update_layout at C:/Akash/Firmwares/Hive/Hive_E_ESPIDF_514/Hive_E/managed_components/lvgl__lvgl/src/core/lv_obj_pos.c:316
0x42018995: _lv_disp_refr_timer at C:/Akash/Firmwares/Hive/Hive_E_ESPIDF_514/Hive_E/managed_components/lvgl__lvgl/src/core/lv_refr.c:308
0x4201d695: lv_timer_exec at C:/Akash/Firmwares/Hive/Hive_E_ESPIDF_514/Hive_E/managed_components/lvgl__lvgl/src/misc/lv_timer.c:313 (discriminator 2)
0x4201d746: lv_timer_handler at C:/Akash/Firmwares/Hive/Hive_E_ESPIDF_514/Hive_E/managed_components/lvgl__lvgl/src/misc/lv_timer.c:109
0x42010aac: lvgl_port_task at C:/Akash/Firmwares/Hive/Hive_E_ESPIDF_514/Hive_E/managed_components/espressif__esp_lvgl_port/esp_lvgl_port.c:691
0x40380006: vPortTaskWrapper at C:/ESP/esp-idf/v5.1.4/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:162
What MCU/Processor/Board and compiler are you using?
ESP32-S3 MCU on a Custom Board, with ESP IDF 5.1.4 on VS Code
What LVGL version are you using?
lvgl/lvgl: “^8.3.0”
esp_lvgl_port: “^1”
These have been added in dependencies in idf_component.yml
What do you want to achieve?
I want to figure out why there is this failure and why it is affecting my system and getting the ESP to restart after a random amount of hours.
The last time I observed it was after 12 hours of leaving the system ON and on 12 or 15th button press this issue was seen.
What have you tried so far?
I added multiple checks like to not create an existing label, check if the screen is active.
The function to update the screen display_data() is called by a button Interrupt, MQTT task if there is a command or by Admin Task to update status every 2 minutes.
Is there some status that I need to check like a mutex sort of thing before transitioning between display data function calls?
I call the display data function like
display_data(disp_handle, "CONNECTING", 0, NULL, LV_ALIGN_CENTER); or display_data(disp_handle, "Deep Clean", 0, NULL, LV_ALIGN_CENTER);
display_data(disp_handle, "PM2.5", pm2_5, NULL, LV_ALIGN_CENTER);
Code to reproduce
void init_lcd()
{
#if LCD_DISPLAY_DEBUG == ON
ESP_LOGI("Display", "Install panel IO");
#endif
esp_lcd_panel_io_i2c_config_t io_config =
{
.dev_addr = EXAMPLE_I2C_HW_ADDR, // I2C address of the SSD1306 display.
.control_phase_bytes = 1, // Control phase bytes (as per SSD1306 datasheet).
.lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS, // Command bits for the LCD (as per SSD1306 datasheet).
.lcd_param_bits = EXAMPLE_LCD_CMD_BITS, // Parameter bits for the LCD (as per SSD1306 datasheet).
.dc_bit_offset = 6, // Data/Command bit offset (as per SSD1306 datasheet).
};
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)I2C_HOST, &io_config, &io_handle));
panel_handle = NULL;
esp_lcd_panel_dev_config_t panel_config =
{
.bits_per_pixel = 1, // Number of bits per pixel (monochrome display).
.reset_gpio_num = EXAMPLE_PIN_NUM_RST, // GPIO number for the reset pin.
};
ESP_ERROR_CHECK(esp_lcd_new_panel_ssd1306(io_handle, &panel_config, &panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
const lvgl_port_cfg_t lvgl_cfg = ESP_LVGL_PORT_INIT_CONFIG();
lvgl_port_init(&lvgl_cfg);
const lvgl_port_display_cfg_t disp_cfg =
{
.io_handle = io_handle, // Handle for the panel IO interface.
.panel_handle = panel_handle, // Handle for the panel.
.buffer_size = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES, // Buffer size based on resolution.
.double_buffer = true, // Enable double buffering for smoother rendering.
.hres = EXAMPLE_LCD_H_RES, // Horizontal resolution of the display.
.vres = EXAMPLE_LCD_V_RES, // Vertical resolution of the display.
.monochrome = true, // Set display to monochrome mode.
.rotation =
{
.swap_xy = false, // No swapping of X and Y coordinates.
.mirror_x = false, // No mirroring along the X-axis.
.mirror_y = false, // No mirroring along the Y-axis.
}
};
disp_handle = lvgl_port_add_disp(&disp_cfg);
const esp_lcd_panel_io_callbacks_t cbs =
{
.on_color_trans_done = notify_lvgl_flush_ready, // Callback to notify when LVGL flush is ready.
};
esp_lcd_panel_io_register_event_callbacks(io_handle, &cbs, disp_handle);
lv_disp_set_rotation(disp_handle, LV_DISP_ROT_180); // Set the rotation of the display to 180 degrees.
}
void display_data(lv_disp_t *disp, const char* label_text, uint16_t value, const char* unit_symbol, lv_align_t alignment)
{
#if LCD_DISPLAY_DEBUG == ON
ESP_LOGI("DisplayData", "Entering display_data function");
ESP_LOGI("DisplayData", "Parameters - label_text: %s, value: %d, unit_symbol: %s, alignment: %d", label_text, value, unit_symbol ? unit_symbol : "NULL", alignment);
#endif
// Get the active screen for the given display.
lv_obj_t *scr = lv_disp_get_scr_act(disp);
if (scr == NULL) {
#if LCD_DISPLAY_DEBUG == ON
ESP_LOGE("DisplayData", "Active screen is NULL");
#endif
return;
}
// If label_main does not exist, create it.
if (label_main == NULL) {
#if LCD_DISPLAY_DEBUG == ON
ESP_LOGI("DisplayData", "Creating new main label");
#endif
label_main = lv_label_create(scr);
lv_label_set_long_mode(label_main, LV_LABEL_LONG_WRAP);
lv_obj_set_style_text_font(label_main, &font_articulate_regular_18_8bpp, LV_PART_MAIN | LV_STATE_DEFAULT); // Use custom font
}
// Update the text of the main label.
lv_label_set_text(label_main, label_text);
// If label_value does not exist, create it.
if (label_value == NULL) {
#if LCD_DISPLAY_DEBUG == ON
ESP_LOGI("DisplayData", "Creating new value label");
#endif
label_value = lv_label_create(scr);
lv_label_set_long_mode(label_value, LV_LABEL_LONG_WRAP);
lv_obj_set_style_text_font(label_value, &font_articulate_regular_26_8bpp, LV_PART_MAIN | LV_STATE_DEFAULT); // Use custom font
}
char buf[20]; // Format the value and the unit symbol into the buffer.
// Check if value is NULL or 0 (since I want to display nothing for NULL value)
if (value == 0)
{
// If value is 0, check if it's a text (unit_symbol) to display, else display nothing
if (unit_symbol != NULL) {
snprintf(buf, sizeof(buf), "%s", unit_symbol); // Show the text if unit_symbol is not NULL
}
else {
snprintf(buf, sizeof(buf), " "); // Display nothing if no unit_symbol
}
}
else {
// For non-zero values, display normally
if (unit_symbol != NULL) {
snprintf(buf, sizeof(buf), "%d%s", value, unit_symbol); // Show value with unit symbol
}
else {
snprintf(buf, sizeof(buf), "%d", value); // Just display the numeric value
}
}
lv_label_set_text(label_value, buf); // Update the text of the value label.
// Get screen dimensions
lv_coord_t screen_width = lv_obj_get_width(scr);
lv_coord_t screen_height = lv_obj_get_height(scr);
// Set a fixed y-coordinate for vertical alignment (center of the screen)
lv_coord_t label_y = screen_height / 2 - 9; // Static vertical alignment
lv_coord_t value_y = screen_height / 2 - 15; // Static vertical alignment
lv_coord_t label_x = 12; // Set a fixed x-coordinate for the label (left-aligned), Fixed padding from the left
lv_coord_t value_x = screen_width - 58; // Set a fixed x-coordinate for the value (right-aligned), Fixed padding from the right
lv_obj_align(label_main, LV_ALIGN_TOP_LEFT, label_x, label_y); // Align the main label to the left, with fixed y-coordinate
lv_obj_align(label_value, LV_ALIGN_TOP_LEFT, value_x, value_y); // Align the value label to the right, with fixed y-coordinate
#if LCD_DISPLAY_DEBUG == ON
ESP_LOGI("DisplayData", "Exiting display_data function");
ESP_LOGI("DisplayData", " ");
#endif
}
Screenshot and/or video
This is basic OLED Display which shows CONNECTING, CONNECTED, Standard, Turbo or PM2.5 140 or CO2 1456 etc