Extra 5% OFF Use Code: OL05
Free Shipping over ₹999

Stack Management in FreeRTOS

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

  1. 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.
  2. 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.
  3. 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:

  1. configCHECK_FOR_STACK_OVERFLOW: Set this to 1 or 2 in FreeRTOSConfig.h to enable stack overflow checking.
  2. 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

  1. Stack Overflow Detection Setup:
    • We set configCHECK_FOR_STACK_OVERFLOW to 2 in FreeRTOSConfig.h to enable stack overflow detection.
    • We define vApplicationStackOverflowHook() to print an error message if a stack overflow occurs and terminate the application with abort().
  2. Monitor Stack Usage:
    • The monitor_task_stack() function uses uxTaskGetStackHighWaterMark() to monitor the remaining stack for each task.
    • This function reports the stack usage in bytes and helps identify potential memory usage issues.
  3. 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.
  4. 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

  1. 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, triggering vApplicationStackOverflowHook() 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.

    Leave a Reply

    Your email address will not be published.

    Need Help?