Define CMSIS RTOS2 APIs for your Platform#
This section explains how to define a CMSIS-RTOS2 API function using FreeRTOS library as an example. This guide focuses to explain the CMSIS-RTOS2 API implementation only for those CMSIS-RTOS2 API functions that are used in the SDK v3.x.
For EFR32xG24 (hereafter referred to as EFR32) project, the CMSIS-FreeRTOS implementation is present in cmsis_os2.c file present at path: <application project>/gecko_sdk/util/third_party/freertos/cmsis/Source
For STM32 project, the CMSIS-FreeRTOS implementation is present in cmsis_os2.c file present at path: \<STM32 project\>/Middlewares/FreeRTOS/Source/CMSIS_RTOS_V2
Note: For getting the description, parameters and return values of each function, refer here.
FreeRTOS Preprocessor Macros#
Define the following preprocessor macros if using FreeRTOS.
SL_CATALOG_FREERTOS_KERNEL_PRESENT
configNUM_USER_THREAD_LOCAL_STORAGE_POINTERS=0
configNUM_SDK_THREAD_LOCAL_STORAGE_POINTERS=2
configUSE_POSIX_ERRNO =1
In the FreeRTOS.h
file present at \<STM32 project\>/Middlewares/Third_Party/FreeRTOS/Source/include
, define the following macro as shown below:
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS (configNUM_USER_THREAD_LOCAL_STORAGE_POINTERS \
+ configNUM_SDK_THREAD_LOCAL_STORAGE_POINTERS)
Sample FreeRTOS API Implementations#
The following sections contain sample FreeRTOS implementations of CMSIS RTOS2 APIs.
The following functions are described in these sections. These are listed here in alphabetical order:
osDelay | osEventFlagsClear | osEventFlagsDelete | osEventFlagsNew | osEventFlagsSet | osEventFlagsWait | osKernelGetTickCount | osKernelInitialize | osKernelStart | osMutexAcquire | osMutexDelete | osMutexNew | osMutexRelease | osSemaphoreAcquire | osSemaphoreDelete | osSemaphoreNew | osSemaphoreRelease | osThreadNew
Kernel Management Functions#
The following functions are covered in this section. These are mentioned in the sequence in which occur in the flow of an application: osKernelInitialize | osKernelStart | osKernelGetTickCount
osKernelInitialize#
The following example is a FreeRTOS implementation.
osStatus_t osKernelInitialize (void) {
osStatus_t stat;
if (IS_IRQ()) {
stat = osErrorISR;
}
else {
if (KernelState == osKernelInactive) {
#if defined(USE_TRACE_EVENT_RECORDER)
EvrFreeRTOSSetup(0U);
#endif
#if defined(USE_FreeRTOS_HEAP_5) && (HEAP_5_REGION_SETUP == 1)
vPortDefineHeapRegions (configHEAP_5_REGIONS);
#endif
KernelState = osKernelReady;
stat = osOK;
} else {
stat = osError;
}
}
return (stat);
}
osKernelStart#
The following example is a FreeRTOS implementation.
osStatus_t sl_kernel_start(void) {
osStatus_t stat;
if (IS_IRQ()) {
stat = osErrorISR;
}
else {
if (KernelState == osKernelReady) {
/* Ensure SVC priority is at the reset value */
SVC_Setup();
/* Change state to enable IRQ masking check */
KernelState = osKernelRunning;
/* Start the kernel scheduler */
vTaskStartScheduler();
stat = osOK;
} else {
stat = osError;
}
}
return (stat);
}
osKernelGetTickCount#
uint32_t osKernelGetTickCount (void) {
TickType_t ticks;
if (IS_IRQ()) {
ticks = xTaskGetTickCountFromISR();
} else {
ticks = xTaskGetTickCount();
}
return (ticks);
}
Thread Management Functions#
osThreadNew#
osThreadId_t osThreadNew (osThreadFunc_t func, void *argument, const osThreadAttr_t *attr) {
const char *name;
uint32_t stack;
TaskHandle_t hTask;
UBaseType_t prio;
int32_t mem;
hTask = NULL;
if (!IS_IRQ() && (func != NULL)) {
stack = configMINIMAL_STACK_SIZE;
prio = (UBaseType_t)osPriorityNormal;
name = NULL;
mem = -1;
if (attr != NULL) {
if (attr->name != NULL) {
name = attr->name;
}
if (attr->priority != osPriorityNone) {
prio = (UBaseType_t)attr->priority;
}
if ((prio < osPriorityIdle) || (prio > osPriorityISR) || ((attr->attr_bits & osThreadJoina-ble) == osThreadJoinable)) {
return (NULL);
}
if (attr->stack_size > 0U) {
/* In FreeRTOS stack is not in bytes, but in sizeof(StackType_t) which is 4 on ARM ports. */
/* Stack size should be therefore 4 byte aligned in order to avoid division caused side effects */
stack = attr->stack_size / sizeof(StackType_t);
}
if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticTask_t)) &&
(attr->stack_mem != NULL) && (attr->stack_size > 0U)) {
mem = 1;
}
else {
if ((attr->cb_mem == NULL) && (attr->cb_size == 0U) && (attr->stack_mem == NULL)) {
mem = 0;
}
}
}
else {
mem = 0;
}
if (mem == 1) {
#if (configSUPPORT_STATIC_ALLOCATION == 1)
hTask = xTaskCreateStatic ((TaskFunction_t)func, name, stack, argument, prio, (Stack-Type_t *)attr->stack_mem,
(StaticTask_t *)attr->cb_mem);
#endif
}
else {
if (mem == 0) {
#if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
if (xTaskCreate ((TaskFunction_t)func, name, (uint16_t)stack, argument, prio, &hTask) != pdPASS) {
hTask = NULL;
}
#endif
}
}
}
return ((osThreadId_t)hTask);
}
Generic Wait functions#
osDelay#
osStatus_t osDelay (uint32_t ticks) {
osStatus_t stat;
if (IS_IRQ()) {
stat = osErrorISR;
}
else {
stat = osOK;
if (ticks != 0U) {
vTaskDelay(ticks);
}
}
return (stat);
}
Event Flags Management Functions#
The following functions are covered in this section. These are mentioned in the sequence in which occur in the flow of an application: osEventFlagsNew | osEventFlagsSet | osEventFlagsClear | osEventFlagsWait | osEventFlagsDelete
osEventFlagsNew#
osEventFlagsId_t osEventFlagsNew (const osEventFlagsAttr_t *attr) {
EventGroupHandle_t hEventGroup;
int32_t mem;
hEventGroup = NULL;
if (!IS_IRQ()) {
mem = -1;
if (attr != NULL) {
if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticEventGroup_t))) {
mem = 1;
}
else {
if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) {
mem = 0;
}
}
}
else {
mem = 0;
}
if (mem == 1) {
#if (configSUPPORT_STATIC_ALLOCATION == 1)
hEventGroup = xEventGroupCreateStatic (attr->cb_mem);
#endif
}
else {
if (mem == 0) {
#if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
hEventGroup = xEventGroupCreate();
#endif
}
}
}
return ((osEventFlagsId_t)hEventGroup);
}
osEventFlagsSet#
uint32_t osEventFlagsSet (osEventFlagsId_t ef_id, uint32_t flags) {
EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
uint32_t rflags;
BaseType_t yield;
if ((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) {
rflags = (uint32_t)osErrorParameter;
}
else if (IS_IRQ()) {
#if (configUSE_OS2_EVENTFLAGS_FROM_ISR == 0)
(void)yield;
/* Enable timers and xTimerPendFunctionCall function to support osEventFlagsSet from ISR */
rflags = (uint32_t)osErrorResource;
#else
yield = pdFALSE;
if (xEventGroupSetBitsFromISR (hEventGroup, (EventBits_t)flags, &yield) == pdFAIL) {
rflags = (uint32_t)osErrorResource;
} else {
rflags = flags;
portYIELD_FROM_ISR (yield);
}
#endif
}
else {
rflags = xEventGroupSetBits (hEventGroup, (EventBits_t)flags);
}
return (rflags);
}
osEventFlagsClear#
uint32_t osEventFlagsClear (osEventFlagsId_t ef_id, uint32_t flags) {
EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
uint32_t rflags;
if ((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) {
rflags = (uint32_t)osErrorParameter;
}
else if (IS_IRQ()) {
#if (configUSE_OS2_EVENTFLAGS_FROM_ISR == 0)
/* Enable timers and xTimerPendFunctionCall function to support osEventFlagsSet from ISR */
rflags = (uint32_t)osErrorResource;
#else
rflags = xEventGroupGetBitsFromISR (hEventGroup);
if (xEventGroupClearBitsFromISR (hEventGroup, (EventBits_t)flags) == pdFAIL) {
rflags = (uint32_t)osErrorResource;
}
#endif
}
else {
rflags = xEventGroupClearBits (hEventGroup, (EventBits_t)flags);
}
return (rflags);
}
osEventFlagsWait#
uint32_t osEventFlagsWait (osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout) {
EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
BaseType_t wait_all;
BaseType_t exit_clr;
uint32_t rflags;
if ((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) {
rflags = (uint32_t)osErrorParameter;
}
else if (IS_IRQ()) {
rflags = (uint32_t)osErrorISR;
}
else {
if (options & osFlagsWaitAll) {
wait_all = pdTRUE;
} else {
wait_all = pdFAIL;
}
if (options & osFlagsNoClear) {
exit_clr = pdFAIL;
} else {
exit_clr = pdTRUE;
}
rflags = xEventGroupWaitBits (hEventGroup, (EventBits_t)flags, exit_clr, wait_all, (Tick-Type_t)timeout);
if (options & osFlagsWaitAll) {
if ((flags & rflags) != flags) {
if (timeout > 0U) {
rflags = (uint32_t)osErrorTimeout;
} else {
rflags = (uint32_t)osErrorResource;
}
}
}
else {
if ((flags & rflags) == 0U) {
if (timeout > 0U) {
rflags = (uint32_t)osErrorTimeout;
} else {
rflags = (uint32_t)osErrorResource;
}
}
}
}
return (rflags);
}
osEventFlagsDelete#
osStatus_t osEventFlagsDelete (osEventFlagsId_t ef_id) {
EventGroupHandle_t hEventGroup = (EventGroupHandle_t)ef_id;
osStatus_t stat;
#ifndef USE_FreeRTOS_HEAP_1
if (IS_IRQ()) {
stat = osErrorISR;
}
else if (hEventGroup == NULL) {
stat = osErrorParameter;
}
else {
stat = osOK;
vEventGroupDelete (hEventGroup);
}
#else
stat = osError;
#endif
return (stat);
}
Mutex Management Functions#
The following functions are covered in this section. These are mentioned in the sequence in which occur in the flow of an application: osMutexNew | osMutexAcquire | osMutexRelease | osMutexDelete
osMutexNew#
osMutexId_t osMutexNew (const osMutexAttr_t *attr) {
SemaphoreHandle_t hMutex;
uint32_t type;
uint32_t rmtx;
int32_t mem;
#if (configQUEUE_REGISTRY_SIZE > 0)
const char *name;
#endif
hMutex = NULL;
if (!IS_IRQ()) {
if (attr != NULL) {
type = attr->attr_bits;
} else {
type = 0U;
}
if ((type & osMutexRecursive) == osMutexRecursive) {
rmtx = 1U;
} else {
rmtx = 0U;
}
if ((type & osMutexRobust) != osMutexRobust) {
mem = -1;
if (attr != NULL) {
if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticSemaphore_t))) {
mem = 1;
}
else {
if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) {
mem = 0;
}
}
}
else {
mem = 0;
}
if (mem == 1) {
#if (configSUPPORT_STATIC_ALLOCATION == 1)
if (rmtx != 0U) {
#if (configUSE_RECURSIVE_MUTEXES == 1)
hMutex = xSemaphoreCreateRecursiveMutexStatic (attr->cb_mem);
#endif
}
else {
hMutex = xSemaphoreCreateMutexStatic (attr->cb_mem);
}
#endif
}
else {
if (mem == 0) {
#if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
if (rmtx != 0U) {
#if (configUSE_RECURSIVE_MUTEXES == 1)
hMutex = xSemaphoreCreateRecursiveMutex ();
#endif
} else {
hMutex = xSemaphoreCreateMutex ();
}
#endif
}
}
#if (configQUEUE_REGISTRY_SIZE > 0)
if (hMutex != NULL) {
if (attr != NULL) {
name = attr->name;
} else {
name = NULL;
}
vQueueAddToRegistry (hMutex, name);
}
#endif
if ((hMutex != NULL) && (rmtx != 0U)) {
hMutex = (SemaphoreHandle_t)((uint32_t)hMutex | 1U);
}
}
}
return ((osMutexId_t)hMutex);
}
osMutexAcquire#
osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout) {
SemaphoreHandle_t hMutex;
osStatus_t stat;
uint32_t rmtx;
hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
rmtx = (uint32_t)mutex_id & 1U;
stat = osOK;
if (IS_IRQ()) {
stat = osErrorISR;
}
else if (hMutex == NULL) {
stat = osErrorParameter;
}
else {
if (rmtx != 0U) {
#if (configUSE_RECURSIVE_MUTEXES == 1)
if (xSemaphoreTakeRecursive (hMutex, timeout) != pdPASS) {
if (timeout != 0U) {
stat = osErrorTimeout;
} else {
stat = osErrorResource;
}
}
#endif
}
else {
if (xSemaphoreTake (hMutex, timeout) != pdPASS) {
if (timeout != 0U) {
stat = osErrorTimeout;
} else {
stat = osErrorResource;
}
}
}
}
return (stat);
}
osMutexRelease#
osStatus_t osMutexRelease (osMutexId_t mutex_id) {
SemaphoreHandle_t hMutex;
osStatus_t stat;
uint32_t rmtx;
hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
rmtx = (uint32_t)mutex_id & 1U;
stat = osOK;
if (IS_IRQ()) {
stat = osErrorISR;
}
else if (hMutex == NULL) {
stat = osErrorParameter;
}
else {
if (rmtx != 0U) {
#if (configUSE_RECURSIVE_MUTEXES == 1)
if (xSemaphoreGiveRecursive (hMutex) != pdPASS) {
stat = osErrorResource;
}
#endif
}
else {
if (xSemaphoreGive (hMutex) != pdPASS) {
stat = osErrorResource;
}
}
}
return (stat);
}
osMutexDelete#
osStatus_t osMutexDelete (osMutexId_t mutex_id) {
osStatus_t stat;
#ifndef USE_FreeRTOS_HEAP_1
SemaphoreHandle_t hMutex;
hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
if (IS_IRQ()) {
stat = osErrorISR;
}
else if (hMutex == NULL) {
stat = osErrorParameter;
}
else {
#if (configQUEUE_REGISTRY_SIZE > 0)
vQueueUnregisterQueue (hMutex);
#endif
stat = osOK;
vSemaphoreDelete (hMutex);
}
#else
stat = osError;
#endif
return (stat);
}
Semaphore Management Functions#
The following functions are covered in this section. These are mentioned in the sequence in which occur in the flow of an application: osSemaphoreNew | osSemaphoreAcquire | osSemaphoreRelease | osSemaphoreDelete
osSemaphoreNew#
osSemaphoreId_t osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr) {
SemaphoreHandle_t hSemaphore;
int32_t mem;
#if (configQUEUE_REGISTRY_SIZE > 0)
const char *name;
#endif
hSemaphore = NULL;
if (!IS_IRQ() && (max_count > 0U) && (initial_count <= max_count)) {
mem = -1;
if (attr != NULL) {
if ((attr->cb_mem != NULL) && (attr->cb_size >= sizeof(StaticSemaphore_t))) {
mem = 1;
}
else {
if ((attr->cb_mem == NULL) && (attr->cb_size == 0U)) {
mem = 0;
}
}
}
else {
mem = 0;
}
if (mem != -1) {
if (max_count == 1U) {
if (mem == 1) {
#if (configSUPPORT_STATIC_ALLOCATION == 1)
hSemaphore = xSemaphoreCreateBinaryStatic ((StaticSemaphore_t *)attr->cb_mem);
#endif
}
else {
#if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
hSemaphore = xSemaphoreCreateBinary();
#endif
}
if ((hSemaphore != NULL) && (initial_count != 0U)) {
if (xSemaphoreGive (hSemaphore) != pdPASS) {
vSemaphoreDelete (hSemaphore);
hSemaphore = NULL;
}
}
}
else {
if (mem == 1) {
#if (configSUPPORT_STATIC_ALLOCATION == 1)
hSemaphore = xSemaphoreCreateCountingStatic (max_count, initial_count, (StaticSemaphore_t *)attr->cb_mem);
#endif
}
else {
#if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
hSemaphore = xSemaphoreCreateCounting (max_count, initial_count);
#endif
}
}
#if (configQUEUE_REGISTRY_SIZE > 0)
if (hSemaphore != NULL) {
if (attr != NULL) {
name = attr->name;
} else {
name = NULL;
}
vQueueAddToRegistry (hSemaphore, name);
}
#endif
}
}
return ((osSemaphoreId_t)hSemaphore);
}
osSemaphoreAcquire#
osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout) {
SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id;
osStatus_t stat;
BaseType_t yield;
stat = osOK;
if (hSemaphore == NULL) {
stat = osErrorParameter;
}
else if (IS_IRQ()) {
if (timeout != 0U) {
stat = osErrorParameter;
}
else {
yield = pdFALSE;
if (xSemaphoreTakeFromISR (hSemaphore, &yield) != pdPASS) {
stat = osErrorResource;
} else {
portYIELD_FROM_ISR (yield);
}
}
}
else {
if (xSemaphoreTake (hSemaphore, (TickType_t)timeout) != pdPASS) {
if (timeout != 0U) {
stat = osErrorTimeout;
} else {
stat = osErrorResource;
}
}
}
return (stat);
}
osSemaphoreRelease#
osStatus_t osSemaphoreRelease (osSemaphoreId_t semaphore_id) {
SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id;
osStatus_t stat;
BaseType_t yield;
stat = osOK;
if (hSemaphore == NULL) {
stat = osErrorParameter;
}
else if (IS_IRQ()) {
yield = pdFALSE;
if (xSemaphoreGiveFromISR (hSemaphore, &yield) != pdTRUE) {
stat = osErrorResource;
} else {
portYIELD_FROM_ISR (yield);
}
}
else {
if (xSemaphoreGive (hSemaphore) != pdPASS) {
stat = osErrorResource;
}
}
return (stat);
}
osSemaphoreDelete#
osStatus_t osSemaphoreDelete (osSemaphoreId_t semaphore_id) {
SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)semaphore_id;
osStatus_t stat;
#ifndef USE_FreeRTOS_HEAP_1
if (IS_IRQ()) {
stat = osErrorISR;
}
else if (hSemaphore == NULL) {
stat = osErrorParameter;
}
else {
#if (configQUEUE_REGISTRY_SIZE > 0)
vQueueUnregisterQueue (hSemaphore);
#endif
stat = osOK;
vSemaphoreDelete (hSemaphore);
}
#else
stat = osError;
#endif
return (stat);
}