Index
In FreeRTOS, each task has its own stack, which is used to store local variables, function calls, and the task’s execution context (such as register values). Effective stack management is crucial because tasks with too little stack may overflow, causing unpredictable behavior, while too much stack allocation wastes precious memory on embedded systems.
Key Concepts
- Task Stack: The amount of memory assigned to a task to handle its function calls, local variables, and context. This stack is allocated when the task is created and remains fixed throughout the task’s lifetime.
- Stack Overflow: Occurs when a task’s stack usage exceeds its allocated memory. FreeRTOS provides mechanisms to detect stack overflow, which can trigger an error or a reset if enabled.
- Optimization: Proper stack allocation minimizes memory usage. Stack sizes should be adjusted according to the task’s needs, balancing between sufficient stack space and minimal memory use.
Example: Task Stack Management and Stack Overflow Detection
In this example, we will:
- Create two tasks with different stack sizes.
- Use a function to check the amount of remaining stack memory.
- Implement FreeRTOS’s stack overflow detection mechanism.
Step 1: Enable Stack Overflow Detection
To detect stack overflow, FreeRTOS provides two methods:
configCHECK_FOR_STACK_OVERFLOW
: Set this to1
or2
inFreeRTOSConfig.h
to enable stack overflow checking.vApplicationStackOverflowHook()
: Implement this hook function to handle stack overflow events.
Open the FreeRTOSConfig.h
file in your project and add the following settings if they are not already present:
#define configCHECK_FOR_STACK_OVERFLOW 2 // Enables stack overflow checking
#define configUSE_MALLOC_FAILED_HOOK 1 // Enables memory allocation failure hook
Add the vApplicationStackOverflowHook()
function to handle stack overflow:
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) {
printf("Stack overflow in task: %s\n", pcTaskName);
// Handle the overflow here (e.g., reset the system)
abort();
}
Step 2: Write the Code
Here’s an example that creates two tasks with different stack sizes. One task has sufficient stack space, while the other has an intentionally small stack size to demonstrate stack overflow handling.
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#define SMALL_STACK_SIZE 100 // Small stack size for overflow demonstration
#define NORMAL_STACK_SIZE 2048 // Normal stack size
// Function to monitor the remaining stack space for a task
void monitor_task_stack(TaskHandle_t taskHandle, const char *taskName) {
UBaseType_t remainingStack = uxTaskGetStackHighWaterMark(taskHandle);
printf("Remaining stack for %s: %d bytes\n", taskName, remainingStack);
}
// Task with normal stack usage
void normal_task(void *pvParameter) {
int localVar = 0;
while (1) {
localVar++;
printf("Normal Task - Running, LocalVar: %d\n", localVar);
vTaskDelay(1000 / portTICK_PERIOD_MS); // Delay to simulate work
}
}
// Task with intentionally small stack to trigger overflow
void small_stack_task(void *pvParameter) {
char largeArray[200]; // Allocate a large array to cause stack overflow
for (int i = 0; i < 200; i++) {
largeArray[i] = i; // Fill the array
}
while (1) {
printf("Small Stack Task - Running\n");
vTaskDelay(500 / portTICK_PERIOD_MS); // Delay to simulate work
}
}
void app_main(void) {
TaskHandle_t normalTaskHandle, smallStackTaskHandle;
// Create a task with a normal stack size
xTaskCreate(normal_task, "Normal Task", NORMAL_STACK_SIZE, NULL, 1, &normalTaskHandle);
// Create a task with a small stack size to demonstrate stack overflow
xTaskCreate(small_stack_task, "Small Stack Task", SMALL_STACK_SIZE, NULL, 1, &smallStackTaskHandle);
// Monitor the stack usage of each task every 2 seconds
while (1) {
monitor_task_stack(normalTaskHandle, "Normal Task");
monitor_task_stack(smallStackTaskHandle, "Small Stack Task");
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
}
Explanation of the Code
- Stack Overflow Detection Setup:
- We set
configCHECK_FOR_STACK_OVERFLOW
to2
inFreeRTOSConfig.h
to enable stack overflow detection. - We define
vApplicationStackOverflowHook()
to print an error message if a stack overflow occurs and terminate the application withabort()
.
- We set
- Monitor Stack Usage:
- The
monitor_task_stack()
function usesuxTaskGetStackHighWaterMark()
to monitor the remaining stack for each task. - This function reports the stack usage in bytes and helps identify potential memory usage issues.
- The
- Tasks:
normal_task
: This task has enough stack memory, so it should run without any overflow issues.small_stack_task
: This task is allocated a small stack (100 bytes). We attempt to use more stack space than allocated, which should trigger a stack overflow.
- Main Function (
app_main
):- The main function creates both tasks.
- A loop monitors stack usage periodically, printing out the remaining stack for each task every 2 seconds.
Step 3: Build and Flash the Project
- Build the project:
idf.py build
2. Flash the project to the ESP32:
idf.py -p /dev/ttyUSB0 flash
Output Explanation
When you run the project, you should see output similar to this:
Normal Task - Running, LocalVar: 1
Small Stack Task - Running
Remaining stack for Normal Task: 2048 bytes
Remaining stack for Small Stack Task: 92 bytes
...
Stack overflow in task: Small Stack Task
- The output will show the
Normal Task
running without issues and the remaining stack size. - The
Small Stack Task
will likely run initially, but the large array allocation (char largeArray[200]
) will cause a stack overflow, triggeringvApplicationStackOverflowHook()
and printing “Stack overflow in task: Small Stack Task.”
Summary
This example demonstrates:
- Creating tasks with different stack sizes and monitoring their stack usage with
uxTaskGetStackHighWaterMark()
. - Detecting stack overflow using FreeRTOS’s built-in overflow detection mechanism.
- Handling stack overflow with
vApplicationStackOverflowHook()
to prevent unpredictable behavior.
Stack management is essential to optimize memory usage and prevent runtime errors. By adjusting stack sizes to fit task requirements and enabling stack overflow checks, you can build more robust FreeRTOS applications on ESP32.