ESP32设备出现Guru Meditation错误(内核恐慌)

人工智能 2026-07-12

我有一个来自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(假设 strideCANVAS_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字节一次),以缩小故障的具体地址。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章