Узнаем количество используемой памяти для каждой задачи в системе FreeRTOS на базе платы Arduino Nano в среде программирования Arduino IDE.

В данном уроке мы с Вами посмотрим сколько памяти занимают наши задачи. Учитывая, что под каждую задачу выделяется память, а она в микроконтроллерах не бесконечна,  — знать сколько памяти потребляют наши задачи очень актуально. Если Вы выделили больше памяти чем Вам нужно, программа будет работать но память будет не рационально использоваться. Тут все зависит от компилятора и  версии системы FreeRTOS: возможны варианты когда свободная (не используемая часть памяти) будет возвращена в общую «таблицу» свободной памяти и ее можно будет использовать, или не используемая память так и останется не используемая. Лучше не полагаться на умный компилятор и версию системы и самостоятельно следить за выделением памяти.  Если же память под задачу выделяется динамически — так же полезно знать сколько система выделяет под нее места, что бы в один момент у Вас не закончилась память. Если же память под задачу будет выделена меньше чем ей необходимо — микроконтроллер просто зависнет или перестанет адекватно работать.
Сегодня мы рассмотрим  пример для статической памяти и увидим сколько нужно памяти для обычной задачи поморгать светодиодом.
Функции которые мы будем использовать:

UBaseType_t uxTaskGetStackHighWaterMark ( TaskHandle_t xTask );

Данная функция возвращает количество оставшейся свободной памяти, где аргументом является дескриптор запрашиваемой задачи. При этом задача может запросить свою собственную максимальную отметку, передав NULL в качестве параметра xTask.

Так же воспользуемся следующими функциями:
xTaskGetTickCount() — возвращает количество тиков с момента вызова vTaskStartScheduler.

uxTaskGetNumberOfTasks() — возвращает количество задач, которыми в настоящее время управляет ядро ​​RTOS. Сюда входят все готовые, заблокированные и приостановленные задачи. Задача, которая была удалена, но еще не освобождена, также будет включена в подсчет. 

char * pcTaskGetName(TaskHandle_t xTaskToQuery) — Возвращает указатель на имя данной задачи, которое представляет собой стандартную строку с нулевым завершением.

void vTaskDelete( TaskHandle_t xTask ) — Удаляет выбранную задачу, NULL приведет к удалению вызывающей задачи. При этом важно понимать, что  память, выделенная кодом задачи, не освобождается автоматически и должна быть освобождена перед удалением задачи.

TaskHandle_t — Тип, на который ссылаются задачи. Например, вызов xTaskCreate возвращает (через параметр-указатель) переменную TaskHandle_t, которую затем можно использовать в качестве параметра vTaskDelete для удаления задачи.

#include <Arduino_FreeRTOS.h>

TaskHandle_t taskBlinkHandle;
TaskHandle_t taskDeletedHandle;
TaskHandle_t taskBlockedHandle;

void setup() {
xTaskCreate(TaskBlink, // Task function
"Blink", // Task name
45, // Stack size
NULL,
0, // Priority
&taskBlinkHandle); // Task handler

xTaskCreate(TaskSerial,
"Serial",
128,
NULL,
2,
NULL);

xTaskCreate(TaskDeleted,
"Deleted",
64,
NULL,
1,
&taskDeletedHandle);

xTaskCreate(TaskBlocked,
"Blocked",
64,
NULL,
1,
&taskBlockedHandle);

}

void loop() {}

void TaskSerial(void *pvParameters)
{
(void) pvParameters;
Serial.begin(9600);
for (;;)
{
Serial.println("======== Tasks status ========");
Serial.print("Tick count: ");
Serial.print(xTaskGetTickCount());
Serial.print(", Task count: ");
Serial.print(uxTaskGetNumberOfTasks());
Serial.println();
Serial.println();
// Serial task status
Serial.print("- TASK ");
Serial.print(pcTaskGetName(NULL));
Serial.print(", High Watermark: ");
Serial.print(uxTaskGetStackHighWaterMark(NULL));

TaskHandle_t taskSerialHandle = xTaskGetCurrentTaskHandle();
Serial.println();

Serial.print("- TASK ");
Serial.print(pcTaskGetName(taskBlinkHandle)); // Get task name with handler
Serial.print(", High Watermark: ");
Serial.print(uxTaskGetStackHighWaterMark(taskBlinkHandle));
Serial.println();

Serial.print("- TASK ");
Serial.print(pcTaskGetName(taskDeletedHandle));
Serial.print(", High Watermark: ");
Serial.print(uxTaskGetStackHighWaterMark(taskDeletedHandle));
Serial.println();

Serial.print("- TASK ");
Serial.print(pcTaskGetName(taskBlockedHandle));
Serial.print(", High Watermark: ");
Serial.print(uxTaskGetStackHighWaterMark(taskBlockedHandle));
Serial.println();

Serial.println();

vTaskDelay( 5000 / portTICK_PERIOD_MS );
}
}

void TaskBlocked(void *pvParameters) {
(void) pvParameters;
for (;;)
{
vTaskDelay( 900000 / portTICK_PERIOD_MS );
}
}

void TaskDeleted(void *pvParameters) {
(void) pvParameters;

vTaskDelete(NULL);
}

void TaskBlink(void *pvParameters)
{
(void) pvParameters;
pinMode(LED_BUILTIN, OUTPUT);
for (;;)
{
digitalWrite(LED_BUILTIN, HIGH);
vTaskDelay( 250 / portTICK_PERIOD_MS );
digitalWrite(LED_BUILTIN, LOW);
vTaskDelay( 250 / portTICK_PERIOD_MS );
}
}

Результатом данной программы у Вас будет следующая информация: