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

Dynamic Memory Allocation in FreeRTOS

Dynamic memory allocation in FreeRTOS is managed using pvPortMalloc() and vPortFree(). These functions allow you to allocate and free memory dynamically from the heap at runtime. This can be useful when the size of the data structures you need to use is not known at compile time.

Key Concepts

  1. Dynamic Memory Allocation: The process of allocating memory at runtime, as opposed to static or stack allocation. This allows for more flexible data structures (like linked lists, queues, etc.).
  2. Heap Management: FreeRTOS provides its own memory management system that is separate from the standard C library’s malloc() and free(). It is designed to work with the real-time requirements of embedded systems.
  3. Fragmentation: Over time, as memory is allocated and freed, small chunks of free memory can become scattered throughout the heap. This can lead to memory fragmentation, which may prevent larger blocks from being allocated even if there is enough total free memory.

Example: Using pvPortMalloc() and vPortFree()

In this example, we’ll create two tasks that dynamically allocate and free an array of integers. One task will allocate memory and fill it with data, while the other task will read from that data and free the memory once done.

Step 1: Set Up the Environment

Ensure you have ESP-IDF installed and your environment set up:

. $HOME/esp/esp-idf/export.sh

Step 2: Create a New Project

Create a new folder for your project and initialize it.

Step 3: Write the Code

Here’s a simple FreeRTOS application using dynamic memory allocation:

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"

#define ARRAY_SIZE 5

// Function to allocate and initialize an array
int* allocate_array(void) {
    int* array = (int*)pvPortMalloc(ARRAY_SIZE * sizeof(int)); // Allocate memory for an array of integers
    if (array != NULL) {
        for (int i = 0; i < ARRAY_SIZE; i++) {
            array[i] = i + 1; // Initialize the array
        }
    }
    return array; // Return pointer to the allocated memory
}

// Task that allocates memory and fills the array
void producer_task(void *pvParameter) {
    for (int i = 0; i < 3; i++) { // Run 3 times for demonstration
        int* array = allocate_array(); // Allocate the array
        if (array != NULL) {
            printf("Producer: Allocated array: ");
            for (int j = 0; j < ARRAY_SIZE; j++) {
                printf("%d ", array[j]); // Print the contents of the array
            }
            printf("\n");
        } else {
            printf("Producer: Memory allocation failed\n");
        }
        vTaskDelay(500 / portTICK_PERIOD_MS); // Simulate some delay
        vPortFree(array); // Free the allocated memory
        printf("Producer: Freed allocated memory\n");
    }
}

// Task that reads the array and frees memory
void consumer_task(void *pvParameter) {
    // The consumer task does not allocate memory in this example but can be extended as needed.
    vTaskDelay(1000 / portTICK_PERIOD_MS); // Delay to wait for producer task
    printf("Consumer: Waiting for producer task to finish...\n");
}

// Main application entry point
void app_main(void) {
    // Create the producer and consumer tasks
    xTaskCreate(producer_task, "Producer Task", 2048, NULL, 1, NULL);
    xTaskCreate(consumer_task, "Consumer Task", 2048, NULL, 1, NULL);
}

Explanation of the Code

  1. Dynamic Memory Allocation:
    • The function allocate_array() uses pvPortMalloc() to allocate memory for an array of integers. The size of the array is defined by ARRAY_SIZE.
    • The allocated array is initialized with values (1, 2, 3, etc.) before being returned.
  2. Producer Task (producer_task):
    • This task allocates an array three times in a loop.
    • After allocation, it prints the contents of the array.
    • It then simulates some work with a delay.
    • After finishing its work, it frees the allocated memory using vPortFree().
  3. Consumer Task (consumer_task):
    • This task currently only waits for the producer task to complete. It can be extended to read data or perform operations if necessary.
  4. Main Function (app_main):
    • The producer_task and consumer_task are created using xTaskCreate().

Step 4: 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:

Producer: Allocated array: 1 2 3 4 5 
Producer: Freed allocated memory
Producer: Allocated array: 1 2 3 4 5 
Producer: Freed allocated memory
Producer: Allocated array: 1 2 3 4 5 
Producer: Freed allocated memory
Consumer: Waiting for producer task to finish...

The output confirms that the producer task successfully allocated, initialized, printed, and freed the memory multiple times.

Summary

In this example, we demonstrated how to use dynamic memory allocation in FreeRTOS with pvPortMalloc() and vPortFree(). We showed how to allocate memory for a shared resource (an array), utilize it in tasks, and free it after use. Proper management of dynamic memory is crucial in embedded systems to prevent memory leaks and fragmentation, ensuring that the system runs efficiently and reliably.

    Leave a Reply

    Your email address will not be published.

    Need Help?