Index
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
- 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.).
- Heap Management: FreeRTOS provides its own memory management system that is separate from the standard C library’s
malloc()
andfree()
. It is designed to work with the real-time requirements of embedded systems. - 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
- Dynamic Memory Allocation:
- The function
allocate_array()
usespvPortMalloc()
to allocate memory for an array of integers. The size of the array is defined byARRAY_SIZE
. - The allocated array is initialized with values (1, 2, 3, etc.) before being returned.
- The function
- 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()
.
- 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.
- Main Function (
app_main
):- The
producer_task
andconsumer_task
are created usingxTaskCreate()
.
- The
Step 4: 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:
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.