DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Mastering Concurrency: An In-Depth Guide to Java's ExecutorService
  • What Are SpeedUp and ScaleUp in DBMS?
  • How To REST With Rails and ActiveResource: Part Three
  • Troubleshooting Memory Leaks With Heap Profilers

Trending

  • Start Coding With Google Cloud Workstations
  • Artificial Intelligence, Real Consequences: Balancing Good vs Evil AI [Infographic]
  • Issue and Present Verifiable Credentials With Spring Boot and Android
  • Automatic Code Transformation With OpenRewrite

FreeRTOS v9.0.0 With Static Memory Allocation

This week a new FreeRTOS Version 9 was released which does not need any dynamic memory allocation anymore. It is possible now to build completely statically allocated systems with FreeRTOS.

By 
Erich Styger user avatar
Erich Styger
·
Jun. 02, 16 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
6.4K Views

Join the DZone community and get the full member experience.

Join For Free

I’m using FreeRTOS in most of my applications. There were only a few exceptions where an RTOS has to be used in safety-critical systems: there usually it is not permitted to use any dynamic memory allocation because this adds the risk that a memory allocation could fail at runtime because of memory fragmentation or memory leak. And FreeRTOS uses a dynamic memory (heap) for the task stacks and the RTOS resources including semaphores, mutexes, and queues.

This is now a thing of the past. This week a new FreeRTOS Version 9 was released which does not need dynamic memory allocation anymore. It is possible now to build completely statically allocated systems with FreeRTOS.

Dynamic and Static Memory Allocation in FreeRTOS V9.0.0 

FreeRTOSConfig.h: Static or Dynamic?

Besides avoiding an ‘out of memory’ at application runtime, static allocation for the RTOS resources has another benefit: if using the heap, I always have to make sure it is large enough. That means that usually it needs to be somewhat larger than really needed. That way some RAM is wasted which is a problem for small embedded systems. So having things statically allocated is a better approach to me. But using static memory allocation in FreeRTOS does not mean that I cannot use dynamic memory anymore: actually I can have both if I want.

To configure how the memory is used, FreeRTOSConfig.h has two more defines:

#define configSUPPORT_DYNAMIC_ALLOCATION 1 /* 1: make dynamic allocation functions for RTOS available. 0: only static functions are allowed */
#define configSUPPORT_STATIC_ALLOCATION 0 /* 1: make static allocation functions for RTOS available. 0: only dynamic functions are allowed */

Either one or both can be turned on (set to 1). So it is possible to mix static and dynamic allocation in the same application.

The Processor Expert component has settings for the two defines:

Dynamic and Static Memory Allocation in FreeRTOS V9.0.0

Static FreeRTOS API Functions

With

configSUPPORT_STATIC_ALLOCATION

the following added FreeRTOS API functions are available which all are using static memory:

  • xTaskCreateStatic()
  • xQueueCreateStatic()
  • xEventGroupCreateStatic()
  • xTimerCreateStatic()
  • xSemaphoreCreateBinaryStatic()
  • xSemaphoreCreateCountingStatic()
  • xSemaphoreCreateMutexStatic()
  • xSemaphoreCreateRecursiveMutexStatic()

The above functions are versions of their ‘dynamic’ counterparts. Each of the ‘static’ API functions needs to have at least one additional pointer to the persistent (not on the dynamic stack!!) allocated buffer memory. For the task API, an additional data pointer is needed for the TCB (Task Control Block) memory. I’m showing in the next sections examples of how the API is used. I’m using macros from the FreeRTOSConfig.h to make things portable between ‘static’ and ‘dynamic’ implementations.

Application Functions for Idle and Timer Tasks

When turning on static memory allocation (configSUPPORT_STATIC_ALLOCATION), the IDLE task will be allocated in a static way. In that case I have to provide the memory for the IDLE task with the following code:

#if configSUPPORT_STATIC_ALLOCATION
/* static memory allocation for the IDLE task */
static StaticTask_t xIdleTaskTCBBuffer;
static StackType_t xIdleStack[IDLE_TASK_SIZE];

void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize) {
  *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer;
  *ppxIdleTaskStackBuffer = &xIdleStack[0];
  *pulIdleTaskStackSize = IDLE_TASK_SIZE;
}
#endif

In a similar way, if software timers are enabled with configSUPPORT_STATIC_ALLOCATION enabled, an application provided function needs to be provided:

#if configSUPPORT_STATIC_ALLOCATION && configUSE_TIMERS
static StaticTask_t xTimerTaskTCBBuffer;
static StackType_t xTimerStack[configTIMER_TASK_STACK_DEPTH];

/* If static allocation is supported then the application must provide the
   following callback function - which enables the application to optionally
   provide the memory that will be used by the timer task as the task's stack
   and TCB. */
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize) {
  *ppxTimerTaskTCBBuffer = &xTimerTaskTCBBuffer;
  *ppxTimerTaskStackBuffer = &xTimerStack[0];
  *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}
#endif

The Processor Expert FreeRTOS component has two settings to add these two functions automatically to the application code:

Default Memory Functions

Static Task

The static version of task creation API requires two additional pointers: one for the TCB (Task Control Block) and one for the task stack itself.

The example below shows both the dynamic and static allocation version of creating a task.

#define SHELL_TASK_SIZE   configMINIMAL_STACK_SIZE+100
#if configSUPPORT_STATIC_ALLOCATION
  #if configUSE_HEAP_SECTION_NAME
    #define SECTION __attribute__((section (configHEAP_SECTION_NAME_STRING)))
  #else
    #define SECTION /* empty */
  #endif
  static StaticTask_t SECTION xTaskTCBBuffer;
  static StackType_t SECTION xStack[SHELL_TASK_SIZE];
#endif

void SHELL_Init(void) {
#if configSUPPORT_STATIC_ALLOCATION
  if (xTaskCreateStatic(ShellTask, "Shell", SHELL_TASK_SIZE, NULL, tskIDLE_PRIORITY+1, &xStack[0], &xTaskTCBBuffer)==NULL) {
    for(;;){} /* task creation failed */
  }
#else /* configSUPPORT_DYNAMIC_ALLOCATION */
  if (xTaskCreate(ShellTask, "Shell", SHELL_TASK_SIZE, NULL, tskIDLE_PRIORITY+1, NULL) != pdPASS) {
    for(;;){} /* error, maybe out of heap memory? */
  }
#endif
}

In the above example with GNU gcc for ARM I have the ability to allocate the static memory in a special linker segment. Note that xTaskCreateStatic() now directly returns the task handle.

Static Semaphore and Mutex

Similar to static task creation, the following shows both the static and dynamic version of a binary semaphore creation:

static xSemaphoreHandle sem;
#if configSUPPORT_STATIC_ALLOCATION
static StaticSemaphore_t xSemaphoreBufferSem;
#endif

#if configSUPPORT_STATIC_ALLOCATION
 sem = xSemaphoreCreateBinaryStatic(&xSemaphoreBufferSem);
#else /* configSUPPORT_DYNAMIC_ALLOCATION */
 sem = xSemaphoreCreateBinary();
#endif

It works the same way for mutexes:

static xSemaphoreHandle mutex;
#if configSUPPORT_STATIC_ALLOCATION
static StaticSemaphore_t xMutexBuffer;
#endif

#if configSUPPORT_STATIC_ALLOCATION
 mutex = xSemaphoreCreateMutexStatic(&xMutexBuffer);
#else /* configSUPPORT_DYNAMIC_ALLOCATION */
 mutex = xSemaphoreCreateMutex();
#endif

Static Timer

The code below shows the static and dynamic way of creating a software timer:

static TimerHandle_t handle;
#if configSUPPORT_STATIC_ALLOCATION
  static StaticTimer_t xTimerBuffer;
#endif

#if configSUPPORT_STATIC_ALLOCATION
  handle = xTimerCreateStatic(
      "swtimer", /* debug name of task */
      pdMS_TO_TICKS(500), /* period */
      pdTRUE, /* auto-reload */
      NULL, /* no timer ID */
      vTimerCallback, /* callback */
      &xTimerBuffer
      );
#else /* configSUPPORT_DYNAMIC_ALLOCATION */
  handle = xTimerCreate(
      "swtimer", /* debug name of task */
      pdMS_TO_TICKS(500), /* period */
      pdTRUE, /* auto-reload */
      NULL, /* no timer ID */
      vTimerCallback /* callback */
      );
#endif

Static Queues

The code below shows both the static and dynamic version to create a queue:

#define QUEUE_LENGTH 16 /* items in queue */
#define QUEUE_ITEM_SIZE sizeof(char*) /* each item is a char pointer to a string, allocated in the heap */
#if configSUPPORT_STATIC_ALLOCATION
 /* xQueueBuffer will hold the queue structure. */
 static StaticQueue_t xQueueBuffer;

 /* ucQueueStorage will hold the items posted to the queue. Must be at least
 [(queue length)*(queue item size)] bytes long. */
 static uint8_t ucQueueStorage[QUEUE_LENGTH*QUEUE_ITEM_SIZE];
#endif

#if configSUPPORT_STATIC_ALLOCATION
 SQUEUE_Queue = xQueueCreateStatic(QUEUE_LENGTH, QUEUE_ITEM_SIZE, &ucQueueStorage[0], &xQueueBuffer);
#else /* configSUPPORT_DYNAMIC_ALLOCATION */
 SQUEUE_Queue = xQueueCreate(QUEUE_LENGTH, QUEUE_ITEM_SIZE);
#endif

NXP Kinetis SDK

I have successfully ported the RTOS for the NXP Kinetis SDK V2.0, and the port and example project for the FRDM-K22F board is located here: https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/FRDM-K22F/FRDM-K22F_USB_Mouse_Kybd_SDK_v2.0

FreeRTOS running on a NXP FRDM-K22F Board 

Currently not everything in the SDK allows for static allocation. For example, the USB stack in the SDK is still using dynamic allocation methods. I assume this will be updated in a future release. Otherwise you can see in the above example how I have made some of the allocation static.

Other Changes in FreeRTOS V9.0.0

Beside of static memory allocation, there are other good extensions in version 9 (see http://www.freertos.org/FreeRTOS-V9.html):

  • New function xTaskAbortDelay() to force a task out of the blocked state by another task.
  • If a task gets deleted by another task with vTaskDelete(), the task stack and TCB (Task Control Block) was freed by the Idle task. Now it the memory is released right away except the task deletes itself, then still the Idle task does the release.
  • New hook vApplicationDaemonTaskStartupHook() which executes when the RTOS timer task starts.
  • Tickless idle mode can now be used with cooperative multitasking mode (configUSE_PREEMPTION set to 0).
  • All the heap memory types support now configAPPLICATION_ALLOCATED_HEAP which can be used for custom heap allocation.
  • New vTaskGetInfo() function to retrieve the status of a single task.
  • New uxSemaphoreGetCount() function to get the counter of the semaphore, e.g for a counting semaphore or the binary status of a normal (binary) semaphore.

FreeRTOS Trace

I had to update the Segger SystemView and Percepio Tracealizer libraries for a few API changes in FreeRTOS V9.0.0. The changes were rather minimal, and both are running now with V9 of FreeRTOS.

Segger SystemView with FreeRTOS V9.0.0 

Segger SystemView with FreeRTOS V9.0.0

Tracealizer with FreeRTOS V9.0.0 

Tracealizer with FreeRTOS V9.0.0

For the Percepio Tracealizer with Segger RTT I have extended the library to support static TrcCtrl task creation.

Summary

The avoidance of any dynamic memory allocation in FreeRTOS greatly extends the usage of this already very popular RTOS especially into safety critical systems or any other critical systems. For example we have now migrated a space project at the university from a different RTOS to FreeRTOS as now it fulfills our requirements for running a payload system on a satellite. I have migrated a few robotics project from FreeRTOS V8.x.x to the V9.0.0 version without any issues.

An update of the Processor Expert components is planned for today.

Happy Static’ing!

FreeRTOS Task (computing) Memory (storage engine) application

Published at DZone with permission of Erich Styger, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Mastering Concurrency: An In-Depth Guide to Java's ExecutorService
  • What Are SpeedUp and ScaleUp in DBMS?
  • How To REST With Rails and ActiveResource: Part Three
  • Troubleshooting Memory Leaks With Heap Profilers

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!