T-Display-S3-long FreeRTOS 当有可用堆空间时内存分配失败

问题描述 投票:0回答:1

我正在尝试为 T-Display-S3-long 进行编程,我已经下载了 AXS15231B.cpp 库并测试了显示 3 个静态分配图像的基本程序。我的目标是拥有一个 RTOS 任务来相应地处理 UI 渲染。我现在正在测试的程序非常简单,它只是启动任务并在屏幕上绘制四个矩形(或者至少这是应该发生的情况)。配置设置为使用 DMA 在屏幕上绘制,因此当它尝试绘制第一个矩形时,AXS15231B 库会尝试分配内存以适合内部的矩形像素,并将它们通过 DMA -> QSPI 推送到显示器。尽管此分配失败,并且由于我启用了内存和堆损坏检测,整个程序都会重新启动。我增加了绘图任务的堆栈大小以及 main_app 函数的堆栈大小,还添加了一些日志以查看分配前的可用堆大小,这似乎足以进行分配。 Balow 我已经发布了代码和日志:

app_main.cpp

static uint16_t col_back = 0x07ba;
static uint16_t col1 = 0x07ba;
static uint16_t col2 = 0xfc60;
static uint16_t col3 = 0xd800;
static uint16_t col4 = 0x16e0;

void test_lcd(void *arg) {
    xSemaphoreTake(sync_lcd_task, portMAX_DELAY);

    pinMode(TFT_BL, OUTPUT);
    digitalWrite(TFT_BL, HIGH);
    ESP_LOGI(TFT_TAG, "Display Initialised");
    axs15231_init();
    lcd_setRotation(1);
    while(1) {
        digitalWrite(TFT_BL, HIGH);
        lcd_fill(10 , 20, 150, 160, col1);
        lcd_fill(170, 20, 310, 160, col2);
        lcd_fill(330, 20, 470, 160, col3);
        lcd_fill(490, 20, 630, 160, col4);
        vTaskDelay(10000);
    }
    
}

void app_main(void)
{
    ESP_LOGI("main", "Free Heap size %d", xPortGetFreeHeapSize());
    //Allow other core to finish initialization
    vTaskDelay(pdMS_TO_TICKS(100));

    //Create semaphores to synchronize
    sync_wifi_prov_task = xSemaphoreCreateBinary();
    sync_stats_task = xSemaphoreCreateBinary();
    sync_lcd_task = xSemaphoreCreateBinary();

    xTaskCreatePinnedToCore(provision_wifi, WIFI_PROV_TASK_NAME, 4096, NULL, WIFI_PROV_PRIO, NULL, 0);
    ESP_LOGI("main", "Free Heap size %d", xPortGetFreeHeapSize());
    xTaskCreatePinnedToCore(stats_task, STATS_TASK_NAME, 4096, NULL, STATS_TASK_PRIO, NULL, tskNO_AFFINITY);
    ESP_LOGI("main", "Free Heap size %d", xPortGetFreeHeapSize());
    xTaskCreatePinnedToCore(test_lcd, "lcd_test", 220000, NULL, 4, NULL, 1);
    ESP_LOGI("main", "Free Heap size %d", xPortGetFreeHeapSize());

    xSemaphoreGive(sync_lcd_task);
    xSemaphoreGive(sync_wifi_prov_task);
    xSemaphoreGive(sync_stats_task);
}

我修改了在 AXS15231B 库上失败的函数,在分配前添加两个日志:

static const char *TFT_TAG = "display";
void lcd_fill(uint16_t xsta,
              uint16_t ysta,
              uint16_t xend,
              uint16_t yend,
              uint16_t color)
{

    uint16_t w = xend - xsta;
    uint16_t h = yend - ysta;
    uint32_t size = w * h * 2;
    ESP_LOGI(TFT_TAG, "Free Heap size %d", xPortGetFreeHeapSize());
    ESP_LOGI(TFT_TAG, "Trying to allocate %lu bytes", size);
    uint16_t *color_p = (uint16_t *)heap_caps_malloc(size, MALLOC_CAP_INTERNAL);
    if (color_p == NULL) {
        ESP_LOGE(TFT_TAG, "Failed to allocate memory (%lu bytes)", size);
        return;
    }
    int i = 0;
    for(i = 0; i < w * h ; i+=1)
    {
        color_p[i] = color;
    }

    lcd_PushColors(xsta, ysta, w, h, color_p);
    free(color_p);
}

运行时得到的日志:

Task allocation on app_main:
I (454) main: Free Heap size 296752
I (558) main: Free Heap size 291928
I (558) main: Free Heap size 287440
I (565) main: Free Heap size 67048
...
Memory allocation on AXS15231B:
...
I (1377) display: Free Heap size 44024
I (1378) display: Trying to allocate 39200 bytes

Mem alloc fail. size 0x00009920 caps 0x00000800


Backtrace: 0x40375c72:0x3fce7c40 0x4037e47d:0x3fce7c60 0x403765dd:0x3fce7c80 0x40376632:0x3fce7ce0 0x40376d15:0x3fce7d00 0x40376e3d:0x3fce7d50 0x4200c238:0x3fce7d70 0x4200ba76:0x3fce7da0 0x403811de:0x3fce7dc0
0x40375c72: panic_abort at C:/Users/~/esp/esp-idf/components/esp_system/panic.c:452

0x4037e47d: esp_system_abort at C:/Users/~/esp/esp-idf/components/esp_system/port/esp_system_chip.c:84

0x403765dd: heap_caps_alloc_failed at C:/Users/~/esp/esp-idf/components/heap/heap_caps.c:96

0x40376632: heap_caps_malloc at C:/Users/~/esp/esp-idf/components/heap/heap_caps.c:201

0x40376d15: trace_malloc at C:/Users/~/esp/esp-idf/components/heap/include/heap_trace.inc:95

0x40376e3d: __wrap_heap_caps_malloc at C:/Users/~/esp/esp-idf/components/heap/include/heap_trace.inc:184

0x4200c238: lcd_fill(unsigned short, unsigned short, unsigned short, unsigned short, unsigned short) at ###/main/AXS15231B.cpp:284

0x4200ba76: test_lcd(void*) at ###/main/app_main.cpp:48 (discriminator 1)

0x403811de: vPortTaskWrapper at C:/Users/~/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:162

如上所述,可用空间为 44024,它尝试分配 39200。 既然有足够的内存,为什么分配会失败以及如何克服这个问题?

进一步增加任务堆栈大小也没有帮助,我想这个任务应该在编译时静态分配,并为帧缓冲区提供足够的内存,但我不明白为什么动态分配不起作用。

memory-management heap-memory freertos dma esp-idf
1个回答
0
投票

xPortGetFreeHeapSize()
内部调用
heap_caps_get_free_size()
。它的文档说“可能无法分配这个大小的单个内存块。”

另外,为什么要为名为“lcd_test”的任务分配 220000 字节的堆栈?通常,您只需要这个大小的一小部分作为堆栈。如果您有该大小的任何数据,请尽量不要将其放在堆栈上,而是在堆上使用动态分配。

© www.soinside.com 2019 - 2024. All rights reserved.