1# FreeRTOS adaptation layer 2 3Introduction 4------------ 5Welcome to the FreeRTOS adaptation layer for ThreadX documentation. This document will go over configuration, initialization and usage of the adaptation layer as well as important guidelines and limitations. 6 7Files 8----- 9The adaptation layer is comprised of the following files: 10- tx_freertos.c 11- FreeRTOS.h 12- event_groups.h 13- queue.h 14- semphr.h 15- task.h 16- timers.h 17 18The main source file for the adaptation layer is “tx_freertos.c” as well as “FreeRTOS.h” the other headers are provided for compatibility with FreeRTOS. 19In addition, the following configuration file must be available within the project. A template of the configuration file is provided in the source distribution. 20- FreeRTOSConfig.h 21 22ThreadX Configuration 23--------------------- 24A few ThreadX configurations should be looked at prior to using the adaptation layer. Please note that if a configuration is changed within `tx_user.h` the preprocessor definition `TX_INCLUDE_USER_DEFINE_FILE` should be defined at the compiler command line. This is to ensure that `tx_user.h` is properly included from `tx_port.h`. 25 26## Thread Extension: 27The adaptation layer requires a custom field within the `TX_THREAD` data structure to store a reference to the adaptation layer thread-related data. The following preprocessor definitions should be added to `tx_user.h`. Failure to add this configuration will result in a compilation error. 28 29`#define TX_THREAD_USER_EXTENSION VOID *txfr_thread_ptr;` 30 31## Timer Processing Task: 32To better emulate the FreeRTOS timer behaviour it is recommended, but not necessary, to enable processing of ThreadX timers within a task instead of within an ISR. To do so the `TX_TIMER_PROCESS_IN_ISR` preprocessor definition should NOT be defined within `tx_user.h` or `tx_port.h` It is also recommended, but not required to have the timer task priority set at priority 0, which is the highest priority within ThreadX, like this: 33 34`#define TX_TIMER_THREAD_PRIORITY 0` 35 36If desired to reduce resource usage, timer processing can be done within the timer tick ISR by defining `TX_TIMER_PROCESS_IN_ISR` within `tx_user.h`. This won’t have any negative side effect but may change the sequencing of timer firing compared to FreeRTOS. 37 38Adaptation Layer Setup and Configuration 39---------------------------------------- 40To include the adaptation layer in a ThreadX project it is sufficient to add to the makefile or project the `tx_freertos.c` source file as well as create or copy the `FreeRTOSConfig.h` configuration file. The configuration can be taken from an existing project but care should be taken to ensure that it contains no extraneous declarations and definitions that may cause compilation errors. A template of the configuration file can be found within the config_template directory. Every uncommented definitions within the template configuration file are understood by the adaptation layer while every other configuration definitions are ignored. The various FreeRTOS headers can be found at the root of the adaptation layer source directory. 41For simplicity only a selected set of the usual configuration defines are supported by the adaptation layer. All other configurations not explicitly listed are ignored. In addition a few additional definitions can be added to `FreeRTOSConfig.h` to tune the behaviour of the adaptation layer. 42 43| Name | Default Value | Description | 44|------|---------------|-------------| 45| configUSE_16_BIT_TICKS | 0 | Set to 1 to use 16-bit tick | 46| configSTACK_DEPTH_TYPE | uint16_t | Use to override the type used to specify stack depth | 47| configTICK_RATE_HZ | - | Set the kernel tick rate, used by the pdMS_TO_TICKS() macro | 48| configMAX_PRIORITIES | - | Maximum number of priorities. Must be less than or equal to the configured number of ThreadX priorities. | 49| configMINIMAL_STACK_SIZE | 512u | Minimum stack size, used as the stack size of the idle task if `TX_FREERTOS_IDLE_STACK` is not defined. 50| configTOTAL_HEAP_SIZE | - | Amount of internal memory allocated to the adaptation layer when creating FreeRTOS objects. Can be set to 0 to disable dynamic allocation. | 51| INCLUDE_vTaskDelete | 1 | Set to 0 to disable the task delete API. When disabled the adaptation layer will not create the idle task to save resources. | 52| TX_FREERTOS_IDLE_STACK | 512u | Stack size of the idle task. | 53| TX_FREERTOS_ASSERT_FAIL | | Define to a macro invoked on internal assertion failures from within the adaptation layer | 54| configASSERT | | Define to a macro invoked for invalid arguments | 55 56## Initialization 57Unless auto-initialization is used, see below, early initialization should proceed as is usual for any ThreadX application. The adaptation layer should be initialized upon reaching `tx_application_define()` by calling `tx_freertos_init()`. Internally `tx_freertos_init()` will initialize a ThreadX byte pool that will be used by the adaptation layer to allocate and free kernel objects. 58FreeRTOS tasks and objects can be created from within `tx_application_define()`. Usually, at least the initial application task should be created. 59 60Here’s an example of a minimal initialization of the adaptation layer. 61 62```cpp 63VOID tx_application_define(VOID * first_unused_memory) 64{ 65 BaseType_t error; 66 TaskHandle_t task_handle; 67 68 tx_freertos_init(); 69 70 error = xTaskCreate(first_thread_entry, "Initial Task", STACK_SIZE, NULL, 10, &task_handle); 71 if(error != pdPASS) { 72 // Handle error. 73 } 74} 75``` 76It is also possible to initialize the FreeRTOS adaptation layer later once ThreadX is started as long as `tx_freertos_init()` is called before attempting to create any FreeRTOS kernel objects or tasks. 77 78## Auto-initialization 79The default method of initializing the adaptation layer requires some modifications to the application to initialize ThreadX and the adaptation layer prior to using the FreeRTOS API. An alternative method is available when modifications to the application isn't desirable. To do so the following configuration should be added and set to one in FreeRTOSConfig.h: 80 81`#define TX_FREERTOS_AUTO_INIT 1` 82 83Additionally the following preprocessor definition should be added to `tx_user.h`: 84 85`#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION return;` 86 87When both of those configurations are done, the adaptation layer will be initialized automatically by the first call to an object create function, no other call is allowed prior to starting the kernel by calling `vTaskStartScheduler()`. 88 89## Port Macros 90Four port macros to manipulate ISRs are required by the adaptation layer. Default implementations are provided for IAR. They can be defined in `FreeRTOSConfig.h` if needed. 91 92`taskENTER_CRITICAL_FROM_ISR()` 93 94`taskEXIT_CRITICAL_FROM_ISR` 95 96`portDISABLE_INTERRUPTS` 97 98`portENABLE_INTERRUPTS` 99 100Usage Guidelines and Limitations 101-------------------------------- 102While the adaptation layer attempts to emulate the behaviour and feature set of FreeRTOS it must be understood that some limitations and deviations exist. Every application developer using the adaptation layer should review this document, especially the exhaustive list of supported API presented later in this document along with important deviations in behaviour from FreeRTOS. In addition, the following general guidelines should be followed. 103 104## Usage of FreeRTOS API Calls Within a Native ThreadX Thread 105The scenario of using FreeRTOS calls within a thread created using `tx_thread_create()` is not supported. While it is not explicitly disallowed by the adaptation layer some FreeRTOS API may function erratically when they are called from outside a FreeRTOS task. 106 107## Usage of ThreadX Native API Calls Within a FreeRTOS Task 108Similarly to the above scenario, usage of native ThreadX calls from within a task created using `xTaskCreate()` or `xTaskCreateStatic()` is not recommended, with exceptions. It is possible to use any of the ThreadX synchronizations objects, such as Semaphore, Mutexes, Queues and event flags directly from within a FreeRTOS task. It is not supported to use any of the ThreadX thread manipulation functions, however. 109 110## Mix of ThreadX Threads and FreeRTOS Tasks 111It is possible to mix native ThreadX threads and FreeRTOS threads in the same applications assuming that previous two guidelines are followed. 112 113## Idle Task and Idle Priority 114ThreadX by its design does not have an idle task. FreeRTOS, however, does have an idle task, and it is responsible for performing the final cleanup and freeing of memory when deleting a task. The adaptation layer creates, during initialization, an idle task to perform the same duty. The idle task has the lowest possible priority allowed by ThreadX namely `TX_MAX_PRIORITIES – 1`. The idle task will only run if there is a deleted thread to cleanup, otherwise it will be waiting on an internal semaphore posted from the adaptation layer `vTaskDelete()` function. 115 116## Task Yielding and Preemption From ISR 117When returning from an ISR, ThreadX will automatically switch to the highest priority task ready to run. As such the `taskYIELD_FROM_ISR()` macro has no effect and yielding will always occur if a higher priority task was made ready to run within and ISR. `taskYIELD()` however works as expected yielding control to the next ready-to-run task with the same priority as the current task. 118 119## Task Deletion and the Idle Task 120FreeRTOS uses the Idle task, which is created during initialization, to cleanup deleted threads. The Threadx adaptation layer mimics this behaviour by deleting and freeing any resources allocated to a task within an internal idle task. If the `vTaskDelete()` call is disabled by setting `INCLUDE_vTaskDelete` to 0, the idle task will not be created and the task delete functionality won’t be available. 121 122## Returning From a Task 123FreeRTOS does not allow simply returning from a task while this behaviour is permitted within ThreadX. The adaptation layer allows returning from a task when `vTaskDelete()` is available although for portability it is recommended to always explicitly delete tasks. When `vTaskDelete()` is disabled by setting `INCLUDE_vTaskDelete` to 0, returning from a task will cause an assertion failure. 124 125## Memory Management and Heap Configuration 126The total memory size available to the adaptation layer when creating FreeRTOS kernel objects dynamically is configurable through the `configTOTAL_HEAP_SIZE` definition located in `FreeRTOSConfig.h` configuration file. An area of memory of the specified size is created internally and managed using a ThreadX byte pool. Setting `configTOTAL_HEAP_SIZE` to 0 will effectively disable dynamic allocation of kernel objects. 127 128## Tickless Mode 129Tickless mode, which can be selected using `configUSE_TICKLESS_IDLE` is not supported by the adaptation layer or ThreadX. 130 131API Support by Category 132----------------------- 133This release of the FreeRTOS adaptation layer for ThreadX broadly supports the following API groups: 134- Task creation, control and utilities 135- Semaphores and Mutexes 136- Queues 137- Queue Sets 138- Direct to Task Notifications 139- Software Timers 140- Event Groups 141 142The tables that follow list the individual along with any notable limitations or deviations from the FreeRTOS behaviour of each API or API group. 143 144## Task 145The task API represents the core of the adaptation layer enabling creation and control of FreeRTOS tasks using underlying ThreadX threads. FreeRTOS priorities are transparently mapped to ThreadX priorities in reverse orders since under FreeRTOS increasing priority values means an increasing task priority which is the reverse of the ThreadX convention. 146 147### Macros 148| Name | Notes | 149|------|-------| 150| taskSCHEDULER_SUSPENDED 151| taskSCHEDULER_NOT_STARTED 152| taskSCHEDULER_RUNNING 153| taskENTER_CRITICAL() 154| taskEXIT_CRITICAL() 155| taskENTER_CRITICAL_FROM_ISR() 156| taskEXIT_CRITICAL_FROM_ISR() 157| taskDISABLE_INTERRUPTS() 158| taskENABLE_INTERRUPTS() 159| tskIDLE_PRIORITY 160| taskYIELD() 161| taskYIELD_FROM_ISR() | Has no effect, ThreadX will automatically pre-empt when a higher priority task is available to run upon returning from an ISR. | 162 163### Functions 164| Names | Notes | 165|-------|-------| 166| vTaskStartScheduler() | Has no effect if `TX_FREERTOS_AUTO_INIT` is undefined or set to 0, scheduler is started automatically when returning from `tx_application_define().` Otherwise this call will start the scheduler for the first time. | 167| xTaskGetSchedulerState() 168| vTaskSuspendAll() 169| xTaskResumeAll() | Always return pdFALSE since pre-emption is handled automatically by ThreadX. | 170| xTaskCreateStatic() 171| xTaskCreate() 172| uxTaskGetNumberOfTasks() | Only returns the number of task created by either `xTaskCreate()` or `xTaskcreateStatic()`. Task created internally by ThreadX or by the application using `tx_thread_create()` are not counted. | 173| vTaskDelete() 174| vTaskDelay() 175| vTaskDelayUntil() | The implementation of `vTaskDelayUntil()` cannot perform a wait in an atomic fashion. As such there might be additional jitter when using this function with the adaptation layer. The implementation will, however, not accumulate any drift. | 176| xTaskGetCurrentTaskHandle() | This will only work when called from a task created by either `xTaskCreate()` or `xTaskcreateStatic()`. | 177| vTaskSuspend() 178| vTaskResume() 179| xTaskResumeFromISR() 180| xTaskAbortDelay() 181| uxTaskPriorityGet() 182| uxTaskPriorityGetFromISR() 183| vTaskPrioritySet() 184| pcTaskGetName() 185| eTaskGetState() 186| uxTaskGetStackHighWaterMark() | Not implemented. | 187| uxTaskGetStackHighWaterMark2() | Not implemented. | 188| xTaskCallApplicationTaskHook() | Not implemented. | 189| xTaskGetIdleTaskHandle() | Not implemented since the idle task is not a FreeRTOS task. | 190| uxTaskGetSystemState() | Not implemented. | 191| vTaskList() | Not implemented. | 192| vTaskGetRunTimeStats() | Not implemented. | 193| xTaskGetIdleRunTimeCounter() | Not implemented since the idle task is not free-running but waiting for delete events. | 194 195## Task Notification 196Task notifications are fully implemented. 197 198| Name | Notes | 199|------|-------| 200| xTaskNotifyGive() 201| vTaskNotifyGiveFromISR() 202| ulTaskNotifyTake() 203| xTaskNotifyWait() 204| xTaskNotify() 205| xTaskNotifyFromISR() 206| xTaskNotifyAndQuery() 207| xTaskGenericNotify() 208| xTaskNotifyAndQueryFromISR() 209| xTaskGenericNotifyFromISR() 210| xTaskNotifyStateClear() 211| ulTaskNotifyValueClear() 212 213## Semaphore and Mutex 214Semaphores, either counting or binary as well as Mutexes are fully implemented. Mutexes under the adaptation layer cannot be taken or given from an ISR as this is not allowed in ThreadX as well as recent version of FreeRTOS. Due to differences between ThreadX and FreeRTOS it is possible that the ordering task wakeup may slightly differ. 215 216| Name | Notes | 217|------|-------| 218| xSemaphoreCreateCounting() 219| xSemaphoreCreateCountingStatic() 220| xSemaphoreCreateBinary() 221| xSemaphoreCreateBinaryStatic() 222| xSemaphoreCreateMutex() 223| xSemaphoreCreateMutexStatic() 224| xSemaphoreCreateRecursiveMutex() 225| xSemaphoreCreateRecursiveMutexStatic() 226| vSemaphoreDelete() 227| xSemaphoreTake() 228| xSemaphoreTakeFromISR() | It’s not possible to take a mutex from an ISR. | 229| xSemaphoreTakeRecursive() 230| xSemaphoreGive() 231| xSemaphoreGiveFromISR() 232| xSemaphoreGiveRecursive() | It’s not possible to give a mutex from an ISR. | 233| uxSemaphoreGetCount() 234| xSemaphoreGetMutexHolder() 235| xSemaphoreGetMutexHolderFromISR() 236| vSemaphoreCreateBinary() | Not implemented since it’s marked as deprecated in the FreeRTOS documentation. | 237 238## Queue 239The FreeRTOS queue API is implemented with the help of ThreadX semaphores and is designed to mimic the behaviour of FreeRTOS queues. Due to differences between ThreadX and FreeRTOS it is possible that the ordering task wakeup may slightly differ. 240 241| Name | Notes | 242|------|-------| 243| xQueueCreate() | 244| xQueueCreateStatic() | 245| vQueueDelete() 246| xQueueSend() 247| xQueueSendFromISR() 248| xQueueSendToBack() 249| xQueueSendToBackFromISR() 250| xQueueSendToFront() | 251| xQueueSendToFrontFromISR() | 252| xQueueReceive() 253| xQueueReceiveFromISR() 254| xQueuePeek() | 255| xQueuePeekFromISR() | 256| uxQueueMessagesWaiting() | 257| uxQueueMessagesWaitingFromISR() | 258| uxQueueSpacesAvailable() | 259| xQueueIsQueueEmptyFromISR() 260| xQueueIsQueueFullFromISR() 261| xQueueReset() 262| xQueueOverwrite() | 263| xQueueOverwriteFromISR() | 264| pcQueueGetName() | Not implemented. | 265 266## Queue Sets 267Queue sets are implemented with support for adding queues, semaphores and mutexes to a set. Due to the way ThreadX deliver messages, it is possible that the order of events returned by `xQueueSelectFromSet()` and `xQueueSelectFromSetFromISR()` differs from the order they would be returned by FreeRTOS. 268 269| Name | Notes | 270|------|-------| 271| xQueueCreateSet() 272| xQueueAddToSet() 273| xQueueRemoveFromSet() 274| xQueueSelectFromSet() 275| xQueueSelectFromSetFromISR() 276 277## Event Group 278Event groups are implemented using ThreadX’s event flags. It is important to note however that `xEventGroupSync()` is not atomic. 279 280| Name | Notes| 281|------|-------| 282| xEventGroupCreate() 283| xEventGroupCreateStatic() 284| vEventGroupDelete() 285| xEventGroupWaitBits() 286| xEventGroupSetBits() 287| xEventGroupSetBitsFromISR() 288| xEventGroupClearBits() 289| xEventGroupClearBitsFromISR() 290| xEventGroupGetBits() 291| xEventGroupGetBitsFromISR() 292| xEventGroupSync() | Not atomic. | 293 294## Timer 295The timer API is fully implemented except for the pend function all functionality provided by `xTimerPendFunctionCall()` and `xTimerPendFunctionCallFromISR()`. Also since the timer handling thread is not a FreeRTOS task, `xTimerGetTimerDaemonTaskHandle()` is not supported as well. 296 297| Name | Notes | 298|------|-------| 299| xTimerCreate() 300| xTimerCreateStatic() 301| xTimerDelete() 302| xTimerIsTimerActive() 303| xTimerStart() 304| xTimerStop() 305| xTimerChangePeriod() 306| xTimerReset() 307| xTimerStartFromISR() 308| xTimerStopFromISR() 309| xTimerChangePeriodFromISR() 310| xTimerResetFromISR() 311| pvTimerGetTimerID() 312| vTimerSetTimerID() 313| vTimerSetReloadMode() 314| pcTimerGetName() 315| xTimerGetPeriod() 316| xTimerGetExpiryTime() 317| uxTimerGetReloadMode() 318| xTimerPendFunctionCall() | Not implemented. | 319| xTimerPendFunctionCallFromISR() | Not implemented. | 320| xTimerGetTimerDaemonTaskHandle() | Not implemented. | 321 322Document Revision History 323------------------------- 324 325| Version | Release | Notes | 326|---------|---------|-------| 327| 1 | 2020-09-30 | - Initial release. | 328