Основная проблема в том, что в исходной собранной библиотеке arduino-esp32 для PlatformIO функции сбора статистики (vTaskGetRunTimeStats / vTaskList) отключены. Библиотека используется как есть, ссылки на гайды по сборке своих библиотек устарели (404), а актуальных доступных всем инструкций просто нет. К тому же issues по добавлению этих функций также не рассматривают, т.к. они связаны с использованием сторонней библиотеки.

Чтобы добавить эти функции - нужно пересобрать библиотеку с измененными параметрами. В качестве OS используем Ubuntu (Windows - пользователи могут поднять виртуалку в WSL).

Esp32 arduino lib builder

Инструкция установке билдера и сборке есть на официальном сайте. Устанавливаем зависимости:

sudo apt-get install git wget curl libssl-dev libncurses-dev flex bison gperf cmake ninja-build ccache jq python3

sudo pip install --upgrade pip

pip install --user setuptools pyserial click cryptography future pyparsing pyelftools

Можно дальше по инструкции клонировать репозиторий и запустить сборку. Скачивание всех зависимостей и сборка занимают примерно час.

А потом результаты сборки можете ... удалить, потому что версии самого билдера и всех используемых библиотек отличаются и использовать их в PlatformIO не получится.

И засуньте себе это в зад

Нам нужны конкретные версии конкретных пакетов, билдер из коробки такой возможности не предоставляет, поэтому придется ему помочь. Актуальные версии пакетов, которые используются в PlatformIO, можно посмотреть в ~/.platformio/packages/framework-arduinoespressif32/tools/sdk/version.txt, у меня файл выглядит так:

esp-idf: v4.4.7 38eeba213a
arduino: idf-38eeba213a d75795f5
esp-dl: master 0632d24
esp-rainmaker: master d8e9345
esp32-camera: master f0bb429
esp_littlefs: master 41873c2
espressif__esp-dsp: master 9b4a8b4
tinyusb: master a0e5626bc

Каким-то чудом по хешу коммита версии одной из библиотек в PlatformIO удалось найти статью на японском (!), которая описывает, что действительно нужно сделать для пересборки библиотеки. Билдер мы ставили не зря, но вот дальше начинаются приключения - каждую из этих библиотек придется установить вручную.

Для начала все же клонируем билдер и переключим версию:

git clone https://github.com/espressif/esp32-arduino-lib-builder
cd esp32-arduino-lib-builder
git switch release/v4.4

Далее необходимо зафиксировать каждую версию библиотеки, поэтому нужно закомментировать в билдере автоматическое обновление компонентов (build.sh:84-87):

# echo "* Installing/Updating ESP-IDF and all components..."
# update components from git
# ./tools/update-components.sh
# if [ $? -ne 0 ]; then exit 1; fi

Теперь придется вручную загрузить все компоненты, включая ESP-IDF и ядро Arduino для ESP32 .

TLDR установка всех зависимостей в одну строку
git clone -b v4.4.7 --recursive https://github.com/espressif/esp-idf.git && git -C ./esp-idf/ reset --hard  38eeba213a && git clone -b 2.0.17 --recursive https://github.com/espressif/arduino-esp32 ./components/arduino && git -C ./components/arduino reset --hard d75795f5 && git clone --recursive https://github.com/espressif/esp32-camera ./components/esp32-camera && git -C ./components/esp32-camera reset --hard f0bb429 && git clone --recursive https://github.com/espressif/esp-dl.git ./components/esp-dl && git -C ./components/esp-dl reset --hard 0632d24 && git clone --recursive https://github.com/joltwallet/esp_littlefs.git ./components/esp_littlefs && git -C ./components/esp_littlefs reset --hard 41873c2 && git -C ./components/esp_littlefs submodule update --init --recursive && git clone --recursive https://github.com/espressif/esp-rainmaker.git ./components/esp-rainmaker && git -C ./components/esp-rainmaker reset --hard d8e9345 && git -C ./components/esp-rainmaker submodule update --init --recursive && git clone --recursive https://github.com/espressif/esp-dsp.git ./components/espressif__esp-dsp && git -C ./components/espressif__esp-dsp reset --hard 9b4a8b4 && git clone --recursive https://github.com/hathach/tinyusb.git ./components/arduino_tinyusb/tinyusb && git -C ./components/arduino_tinyusb/tinyusb reset --hard a0e5626bc

Ниже разбивка по библиотекам и командам.

esp-idf

git clone -b v4.4.7 --recursive https://github.com/espressif/esp-idf.git
git -C ./esp-idf/ reset --hard  38eeba213a

arduino-esp32

git clone -b 2.0.17 --recursive https://github.com/espressif/arduino-esp32 ./components/arduino
git -C ./components/arduino reset --hard d75795f5

esp32-camera

git clone --recursive https://github.com/espressif/esp32-camera ./components/esp32-camera
git -C ./components/esp32-camera reset --hard f0bb429

esp-dl

git clone --recursive https://github.com/espressif/esp-dl.git ./components/esp-dl
git -C ./components/esp-dl reset --hard 0632d24

esp_littlefs

git clone --recursive https://github.com/joltwallet/esp_littlefs.git ./components/esp_littlefs
git -C ./components/esp_littlefs reset --hard 41873c2
git -C ./components/esp_littlefs submodule update --init --recursive

esp-rainmaker

git clone --recursive https://github.com/espressif/esp-rainmaker.git ./components/esp-rainmaker
git -C ./components/esp-rainmaker reset --hard d8e9345
git -C ./components/esp-rainmaker submodule update --init --recursive

espressif__esp-dsp

git clone --recursive https://github.com/espressif/esp-dsp.git ./components/espressif__esp-dsp
git -C ./components/espressif__esp-dsp reset --hard 9b4a8b4

tinyusb

git clone --recursive https://github.com/hathach/tinyusb.git ./components/arduino_tinyusb/tinyusb
git -C ./components/arduino_tinyusb/tinyusb reset --hard a0e5626bc

Сборка

Теперь можем запустить сборку для esp32 (если у вас другая ревизия платы - указывайте её):

./build.sh -t esp32

Сборка занимает продолжительное время, если по итогу создан каталог с именем «out» - операция прошла успешно.

$ ls out
package_esp32_index.template.json  platform.txt  tools

Sdkconfig

Если хотите, можете посмотреть текущие настройки sdkconfig:

. ./esp-idf/export.sh
idf.py menuconfig

Можно использовать menuconfig только для просмотра настроек сборки, редактировать здесь настройки не выйдет.

интерфейс menuconfig
интерфейс menuconfig

Нужная мне опция находится в Component config ---> FreeRTOS ---> Enable FreeRTOS to collect run time stats. Как видим, по умолчанию флаг сброшен:

меню freertos
меню freertos

Нужно внести изменения относительно стандартного sdkconfig. Для esp32 нужно отредактировать configs/defconfig.esp32. Для esp32c2 и esp32c3 результирующее имя файла — defconfig.esp32c2 и defconfig.esp32c3 соответственно (рядом можете найти и другие ревизии).

CONFIG_BTDM_CTRL_MODE_BTDM=y
CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE=20
CONFIG_BT_BTC_TASK_STACK_SIZE=8192
CONFIG_BT_BTU_TASK_STACK_SIZE=8192
CONFIG_BT_CLASSIC_ENABLED=y
CONFIG_BT_A2DP_ENABLE=y
CONFIG_BT_SPP_ENABLED=y
CONFIG_BT_HFP_ENABLE=y
CONFIG_BT_STACK_NO_LOG=y
CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y
CONFIG_ESP32_SPIRAM_SUPPORT=y
CONFIG_SPIRAM_OCCUPY_HSPI_HOST=y
CONFIG_ESP32_ULP_COPROC_ENABLED=y
CONFIG_ESP32_XTAL_FREQ_AUTO=y
# CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 is not set
CONFIG_FREERTOS_FPU_IN_ISR=y
# CONFIG_USE_WAKENET is not set
# CONFIG_USE_MULTINET is not set
CONFIG_TWAI_ERRATA_FIX_BUS_OFF_REC=y
CONFIG_TWAI_ERRATA_FIX_TX_INTR_LOST=y
CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID=y
CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT=y
CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y
CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y

Я добавил последнюю строку для включения функций сбора статистики. Все прочие уже были в файле.

Собираем все заново:

./build.sh -t esp32

После завершения сборки проверяем конфиг сборки (каждый раз нужно делать экспорт):

. ./esp-idf/export.sh
idf.py menuconfig

Если нужный флаг установлен - мы все сделали правильно.

меню freertos с измененным флагом
меню freertos с измененным флагом

PlatformIO

Осталось дело за малым, скопировать нашу библиотеку в PlatformIO.

Предварительно соxраняем исходную библиотеку и копируем собранную в PlatformIO:

mv -r ~/.platformio/packages/framework-arduinoespressif32/tools/sdk/ ./platformio-sdk-backup/
cp -r ./out/tools/sdk ~/.platformio/packages/framework-arduinoespressif32/tools

Можно переходить в PlatformIO и попробовать собрать прошивку, функции должны быть доступны.

Вот такой минимальный код можно использовать для проверки:

#include <Arduino.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

void TaskLog(void *pvParameters) {
    static const int statsBufferSize = 1024;
    static char statsBuffer[statsBufferSize];

    static const int listBufferSize = 1024;
    static char listBuffer[listBufferSize];

    while (true) {
        Serial.println("\n============ Task Stats ============");

        // Get runtime stats for CPU usage
        // This requires configGENERATE_RUN_TIME_STATS to be enabled
        vTaskGetRunTimeStats(statsBuffer);
        Serial.println("Run Time Stats:");
        Serial.println(statsBuffer);

        // Get task list with state, priority, stack, and task number
        // Note: vTaskList output depends on configuration and may not include core affinities by default
        vTaskList(listBuffer);
        Serial.println("Task List:");
        Serial.println(listBuffer);

        Serial.println("=====================================");

        vTaskDelay(5000 / portTICK_PERIOD_MS);
    }
} 

void setup() {
    // Инициализация последовательного порта
    Serial.begin(115200);
    Serial.println("ESP32 example with stats");

    // Создание задачи для вывода логов на ядре 1
    xTaskCreatePinnedToCore(
        TaskLog,     // Функция задачи
        "Log",       // Имя задачи
        2048,        // Увеличили размер стека для доп. вычислений
        NULL,        // Параметры задачи
        1,           // Приоритет задачи
        NULL,        // Дескриптор задачи
        1            // Ядро, на котором будет выполняться задача
    );
}

void loop() {
    delay(1000);
}

Каждые 5 секунд в консоль выводится статистика по загрузке CPU каждой задачей, а также список задач:

============ Task Stats ============
Run Time Stats:
Log             11614           <1%
IDLE0           20176378                97%
IDLE1           20618561                99%
loopTask        1060            <1%
esp_timer       24              <1%
Tmr Svc         22              <1%
ipc1            47571           <1%
ipc0            32460           <1%

Task List:
Log             X       1       624     10
IDLE0           R       0       552     5
IDLE1           R       0       548     6
loopTask        B       1       7292    8
Tmr Svc         B       1       1584    7
ipc1            B       24      484     2
ipc0            B       24      508     1
esp_timer       S       22      4096    3

=====================================

Вот таким замысловатым способом вы можете менять параметры библиотеки esp32-arduino для использования в PlatformIO.

Список параметров значительно шире, чем включение функций получения статистики, жаль что IDE не предоставляют более удобный способ конфигурирования основных библиотек.

UPD

Сообщество PlatformIO также предложило использовать pioarduino — форк платформы platform-espressif32, — чтобы включить поддержку последней версии Espressif32 Arduino 3.x в PlatformIO. Эта версия включает встроенную поддержку статистических функций. PlatformIO пока официально не поддерживает Arduino 3.x. Кроме того, между этими версиями есть довольно значительные различия.

UPD 2

Если вы используете Arduino IDE - можно использовать библиотеку esp32 3.* от espressiv systems вместо ардуиновской, там эти функции включены по умолчанию. В остальном описанный алгоритм остается актуальным для изменения других параметров sdkconfig для обеих IDE. Спасибо @shadrapза помощь.

Комментарии (7)


  1. shadrap
    02.02.2025 08:43

    Наверное я вас не понял , а просто им единички вместо 0 поставить в FreeRTOSConfig.h :

    #ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
    #define configGENERATE_RUN_TIME_STATS 1 /* Used by vTaskGetRunTimeStats() / #endif / CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS / #ifdef CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS #define configUSE_STATS_FORMATTING_FUNCTIONS 1 / Used by vTaskList() / #endif / CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS */

    не достаточно ?


    1. positroid Автор
      02.02.2025 08:43

      Увы, platformio использует уже скомпилированные библиотеки так называемого esp32 arduino core и конфигурация FreeRTOS через константы невозможна. Если я правильно понял - то с Arduino IDE ситуация та же, если вдруг ошибаюсь - напишите кто-нибудь, скорректирую статью.

      Добавил упоминание Platformio / Arduino IDE в начало статьи, чтобы было понятнее, до ката это указано. Если все собирать полностью из исходников - такой проблемы быть не должно.

      В UPD добавил вариант попроще с заменой платформы на кастомную, но там тоже готовая сборка библиотек


      1. shadrap
        02.02.2025 08:43

        Не буду фантазировать , давно не брал в руки platformio , как то хватает Arduino, может быть я и ошибаюсь , но раньше можно было использовать как пре-компилед библиотеки так и нет. В Arduino он лежит в инклудниках RTOS , в последних билдах отчеты включены по умолчанию.


        1. positroid Автор
          02.02.2025 08:43

          Сходу не вышло подтвердить вашу гипотезу, код из статьи не собирается в Arduino IDE по причине отсутствия указанных функций, define ситуацию не спасает, а для подмены библиотеки по описанной в статье схеме нужно пересобирать esp32-arduino уже с совсем другими версиями пакетов.

          Возможно, я что-то упускаю и можно в Arduino IDE использовать другой подход, нужно изучить детальнее


          1. positroid Автор
            02.02.2025 08:43

            Разобрались в личке, добавил UPD 2 и скорректировал статью - действительно в Arduino IDE можно использовать эти функции, если подключить 3.* версию библиотеки esp32 от espressiv systems взамен ардуиновской.


  1. 4chemist
    02.02.2025 08:43

    Статья сподвигла глянуть что да как с загрузкой CPU. Благо у меня чистый ESP-IDF, так что включил без приседаний. Всё казалось, что там серьезная нагрузка.

    А оказалось...

    Скрытый текст

    twaiCtrlTask 711 <1%
    IDLE1 301186298 99%
    IDLE0 296722385 98%
    telnet 685233 <1%
    tiT 492071 <1%
    ledTask 6394 <1%
    fp2CheckAliveAv 2691 <1%
    main 449385 <1%
    relayTask 1285 <1%
    twaiTxTask 12283 <1%
    powerMeterTask 10 <1%
    logToFileTask 294137 <1%
    mdns 60982 <1%
    ipc1 463250 <1%
    ipc0 220077 <1%
    sys_evt 15305 <1%
    httpd 883169 <1%
    wifi 2719499 <1%
    twaiRxTask 103842 <1%
    esp_timer 315391 <1%
    Tmr Svc 13 <1%


    1. positroid Автор
      02.02.2025 08:43

      Я в отсутствие этих функций пытался написать свою статистику через micros(), но потерпел фиаско на http-сервере, который с таким подходом показывал 50% загрузки в простое (очевидно задача ожидания http-запроса выполняется не последовательно и замера через micros в начале и конце задачи недостаточно).

      Поэтому решил все же добить тему получения статистики и увидел те же <1% у http сервера)

      Меня это все интересует прежде всего в рамках esp32-cam и потоковой передачи видео, пока кажется, что она должна неплохо нагружать контроллер, но до реализации пока не добрался.