ESP32设备出现Guru Meditation错误(内核恐慌)
我有一个来自M5Stack的小型微处理器设备,叫做 M5Dial。它配备了一个小型的240px x 240px屏幕,尽管可见区域是圆形的,而不是方形。它使用ESP32S3架构。
我正在尝试让LVGL在它上面工作。我使用idf.py作为我的构建和烧写系统,我已经让一个基本的基于USB的串行控制台工作起来。我也让UI演示工作起来了。然而LVGL基元似乎会让设备崩溃。该设备仍然可以刷写。
我怀疑我在C 语言里没有分配足够的内存。我已经在不少循环里摸索过,包括向AI求助,可能已经走到了死胡同。以下是我的代码:
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "lv_demos.h"
#include "bsp/esp-bsp.h"
#include "lvgl.h" // Include LVGL header for drawing functions
static char *TAG = "app_main";
#define CANVAS_WIDTH 240
#define CANVAS_HEIGHT 240
#define BITS_PER_PIXEL 32 // 4 bytes for ARGB8888
#define LOG_MEM_INFO (0)
void draw_graphics_canvas2(lv_obj_t *canvas) {
ESP_LOGI(TAG, "Clear canvas");
// Clear the canvas with a black background
lv_canvas_fill_bg(canvas, lv_color_make(255, 255, 0), LV_OPA_100);
ESP_LOGI(TAG, "Have we crashed"); // We do not get here
}
void app_main(void) {
/* Initialize display and LVGL */
bsp_display_start();
/* Set display brightness to 100% */
bsp_display_backlight_on();
lv_init(); // Initialize LVGL
ESP_LOGI(TAG, "Display LVGL demo");
bsp_display_lock(0);
// THIS WORKS, SO LET'S TRY PRIMITIVES INSTEAD
//lv_demo_widgets();
// Create a canvas object
lv_obj_t *canvas = lv_canvas_create(lv_scr_act());
lv_obj_set_size(canvas, CANVAS_WIDTH, CANVAS_HEIGHT); // Set canvas size
lv_obj_set_pos(canvas, 0, 0); // Position it on the screen
uint8_t* canvas_buffer = lv_malloc(LV_CANVAS_BUF_SIZE(CANVAS_WIDTH, CANVAS_HEIGHT, BITS_PER_PIXEL, 0));
if (!canvas_buffer) {
ESP_LOGE(TAG, "Failed to allocate memory for canvas buffer");
return; // Handle memory allocation failure.
}
// Allocate the buffer for the canvas
lv_canvas_set_buffer(canvas, canvas_buffer, CANVAS_WIDTH, CANVAS_HEIGHT, LV_COLOR_FORMAT_ARGB8888);
// Draw graphics on the canvas
draw_graphics_canvas2(canvas);
// Refresh the canvas to ensure it updates on the display
lv_obj_invalidate(canvas);
// Create an infinite sleep loop
while (1) {
// Delay for a long time (e.g., 1 hour = 3600 seconds = 3600000 milliseconds)
vTaskDelay(pdMS_TO_TICKS(3600000)); // Converts milliseconds to ticks
}
bsp_display_unlock();
}
这里是串行控制台输出(包括我自己的串行调试)。你可以看到它已经到了 Clear canvas,但还没有到达 Have we crashed。
ELF file SHA256: 2fee38b22
Rebooting...
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0xc (RTC_SW_CPU_RST),boot:0x2b (SPI_FAST_FLASH_BOOT)
Saved PC:0x40375c54
--- 0x40375c54: esp_restart_noos at /home/user/esp/esp-idf/components/esp_system/port/soc/esp32s3/system_internal.c:162
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce2810,len:0x1564
load:0x403c8700,len:0x4
load:0x403c8704,len:0xd24
load:0x403cb700,len:0x2ed4
entry 0x403c8928
I (26) boot: ESP-IDF v5.4.3 2nd stage bootloader
I (26) boot: compile time Feb 16 2026 00:52:53
I (26) boot: Multicore bootloader
I (27) boot: chip revision: v0.2
I (29) boot: efuse block revision: v1.3
I (33) boot.esp32s3: Boot SPI Speed : 80MHz
I (37) boot.esp32s3: SPI Mode : DIO
I (40) boot.esp32s3: SPI Flash Size : 2MB
I (44) boot: Enabling RNG early entropy source...
I (49) boot: Partition Table:
I (51) boot: ## Label Usage Type ST Offset Length
I (58) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (64) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (71) boot: 2 factory factory app 00 00 00010000 00100000
I (77) boot: End of partition table
I (80) esp_image: segment 0: paddr=00010020 vaddr=3c060020 size=160e0h ( 90336) map
I (104) esp_image: segment 1: paddr=00026108 vaddr=3fc96300 size=02d8ch ( 11660) load
I (107) esp_image: segment 2: paddr=00028e9c vaddr=40374000 size=0717ch ( 29052) load
I (114) esp_image: segment 3: paddr=00030020 vaddr=42000020 size=5c4f8h (378104) map
I (182) esp_image: segment 4: paddr=0008c520 vaddr=4037b17c size=0b100h ( 45312) load
I (192) esp_image: segment 5: paddr=00097628 vaddr=50000000 size=0001ch ( 28) load
I (199) boot: Loaded app from partition at offset 0x10000
I (200) boot: Disabling RNG early entropy source...
I (210) cpu_start: Multicore app
I (220) cpu_start: Pro cpu start user code
I (220) cpu_start: cpu freq: 160000000 Hz
I (220) app_init: Application information:
I (220) app_init: Project name: graphics_primitives
I (225) app_init: App version: 1
I (228) app_init: Compile time: Feb 16 2026 01:40:15
I (233) app_init: ELF file SHA256: 2fee38b22...
I (237) app_init: ESP-IDF: v5.4.3
I (241) efuse_init: Min chip rev: v0.0
I (245) efuse_init: Max chip rev: v0.99
I (249) efuse_init: Chip rev: v0.2
I (253) heap_init: Initializing. RAM available for dynamic allocation:
I (259) heap_init: At 3FCA9D88 len 0003F988 (254 KiB): RAM
I (264) heap_init: At 3FCE9710 len 00005724 (21 KiB): RAM
I (270) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (275) heap_init: At 600FE000 len 00001FE8 (7 KiB): RTCRAM
I (281) spi_flash: detected chip: gd
I (283) spi_flash: flash io: dio
W (286) spi_flash: Detected size(8192k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (299) sleep_gpio: Configure to isolate all GPIO pins in sleep state
I (305) sleep_gpio: Enable automatic switching of GPIO sleep configuration
I (312) main_task: Started on CPU0
I (322) main_task: Calling app_main()
I (322) LVGL: Starting LVGL task
I (322) gpio: GPIO[8]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (332) gc9a01: LCD panel create success, version: 2.0.4
I (452) gpio: GPIO[14]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:2
I (482) gpio: GPIO[42]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (482) button: IoT Button Version: 4.1.5
I (482) gpio: GPIO[41]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (492) gpio: GPIO[40]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (502) Knob: Iot Knob Config Succeed, encoder A:41, encoder B:40, direction:0, Version: 1.0.2
I (512) M5Dial: Setting LCD backlight: 100%
I (512) app_main: Display LVGL demo
I (522) app_main: Clear canvas
Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC : 0x4037f8d4 PS : 0x00060033 A0 : 0x80378c84 A1 : 0x3fc97610
--- 0x4037f8d4: vTaskGenericNotifyGiveFromISR at /home/user/esp/esp-idf/components/freertos/FreeRTOS-Kernel/tasks.c:6190
A2 : 0xffffff00 A3 : 0x00000000 A4 : 0x3fc97630 A5 : 0x3fcad668
A6 : 0x3fc99454 A7 : 0x00000000 A8 : 0x00000050 A9 : 0x00000150
A10 : 0x00000001 A11 : 0xffffffff A12 : 0x00000000 A13 : 0x00060023
A14 : 0x3fcaa5c8 A15 : 0x0000cdcd SAR : 0x00000004 EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000050 LBEG : 0x400556d5 LEND : 0x400556e5 LCOUNT : 0xfffffffd
--- 0x400556d5: strlen in ROM
--- 0x400556e5: strlen in ROM
Backtrace: 0x4037f8d1:0x3fc97610 0x40378c81:0x3fc97630 0x4037705d:0x3fc97660 0x40377681:0x3fc97680 0x42022760:0x3fcad430 0x4200a1d9:0xffffff00 |<-CORRUPTED
--- 0x4037f8d1: vTaskGenericNotifyGiveFromISR at /home/user/esp/esp-idf/components/freertos/FreeRTOS-Kernel/tasks.c:6190
--- 0x40378c81: timer_alarm_handler at /home/user/esp/esp-idf/components/esp_timer/src/esp_timer.c:487
--- 0x4037705d: timer_alarm_isr at /home/user/esp/esp-idf/components/esp_timer/src/esp_timer_impl_systimer.c:93
--- 0x40377681: _xt_lowint1 at /home/user/esp/esp-idf/components/xtensa/xtensa_vectors.S:1240
--- 0x42022760: lv_canvas_fill_bg at /home/user/Documents/Development/Hardware/ESP32/graphics_primitives/managed_components/lvgl__lvgl/src/widgets/canvas/lv_canvas.c:330
--- 0x4200a1d9: draw_graphics_canvas2 at /home/user/Documents/Development/Hardware/ESP32/graphics_primitives/main/graphics_primitives.c:72
我认为 LV_CANVAS_BUF_SIZE 能算出需要保留多少内存,然后 lv_malloc() 才会进行分配。现在似乎有东西在起作用,因为屏幕变白,我猜这是 bsp_display_backlight_on()。所以我觉得 lv_canvas_fill_bg 出了问题,或者至少我是用错了它。当它崩溃时,屏幕又变黑,设备重启,代码重新开始。因此这里的效果是白屏闪烁(显然不是我想要的)。
我接下来可以尝试什么?我可以看到某些东西是 CORRUPTED,但我想不出具体是什么。我的目标是让 lv_draw_line 工作,但我认为我应该先把屏幕填满再说!
解决方案
Caveat: 我对ESP32或 LVGL不是太熟,但我对硬件/软件帧缓冲熟悉。
你的 LV_CANVAS_BUF_SIZE 调用不对。你把第四个参数设为0。这是 stride(跨行步幅)参数。[若你还不知道] 这个“stride”是两行之间的字节数(例如,第0 行的像素0 与第1 行的像素0 之间的字节数)。
因此,第四个参数应该是:CANVAS_WIDTH * 4(假设 stride 是 CANVAS_WIDTH,但在某些设置中,stride可能更大(例如基于硬件中的行填充向上取整到某个倍数))。
缓冲区所需的空间大小应该是 CANVAS_HEIGHT * stride。因此,大约/至少230,400字节或0x038400字节。
请注意,"corruption" 值是0xFFFFFF00,这是白色的RGBA值(也在 A2 中)。
基于图像/段映射,缓冲区所在的区域应该在段3,从虚拟地址0x42000020开始。但是,从 heap_init,在0x3FCA9D88处有一个区域。这些似乎是唯一足够大、能容纳缓冲区的区域。
从寄存器转储来看,寄存器 A5 的值是 0x3FCAD668。这是唯一一个能够将数据保存在堆区、足以容纳缓冲区的寄存器。它距离起始地址的偏移是0x38E0吗?
我猜测(与你的一样)是 lv_malloc 的大小不够。
我对这里的具体细节了解不多,但我会希望段0x42000020与来自 heap_init 的0x3FCA9D88能够匹配?也许还有进一步的虚拟转换?
如果你能打印出 lv_malloc 的返回值(以及它参数的值)会有帮助。
你已经有UART打印工作了——太好了。不过如果你也能让JTAG/gdb/其他调试方式工作起来,应该也会有帮助。
与其执行 lv_canvas_fill_bg,你不妨改成在一个循环中直接向缓冲区写入字节,使用0xFFFFFF00(地址的 printf)。并且可以根据需要调整打印频率(例如每256字节一次),以缩小故障的具体地址。