/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \mainpage The CMSIS-RTOS API Version 2 (CMSIS-RTOS2) is a generic RTOS interface for ARM® Cortex®-M processor-based devices. It provides a standardized API for software components that require RTOS functionality and gives therefore serious benefits to the users and the software industry: - CMSIS-RTOS2 provides basic features that are required in many applications. - The unified feature set of the CMSIS-RTOS2 reduces learning efforts and simplifies sharing of software components. - Middleware components that use the CMSIS-RTOS2 are RTOS agnostic and are easier to adapt. - Standard project templates of the CMSIS-RTOS2 may be shipped with freely available CMSIS-RTOS2 implementations. \note The CMSIS-RTOS API Version 2 defines a minimum feature set. Implementations with extended features may be provided by the RTOS vendors. The CMSIS-RTOS2 manages the resources of the microcontroller system and implements the concept of parallel threads that run concurrently. Applications frequently require several concurrent activities. CMSIS-RTOS2 can manage multiple concurrent activities at the time when they are needed. Each activity gets a separate thread which executes a specific task and this simplifies the overall program structure. The CMSIS-RTOS2 system is scalable and additional threads can be added easily at a later time. Threads have a priority allowing faster execution of time-critical parts of a user application. The CMSIS-RTOS2 offers services needed in many real-time applications, for example, periodical activation of timer functions, memory management, and message exchange between threads with time limits. The CMSIS-RTOS2 addresses the following new requirements: - Dynamic object creation no longer requires static memory, static memory buffers are now optional. - Support for ARMv8-M architecture that provides a secure and non-secure state of code execution. - Provisions for message passing in multi-core systems. - Full support of C++ run-time environments. - C interface which is binary compatible across ABI compatible compilers. As a consequence of these requirements the CMSIS-RTOS2 has the following fundamental modifications: - The functions osXxxxNew replace osXxxxCreate functions; osXxxxNew and osXxxxDelete create and destroy objects. - The C function \c main is no longer started as a thread (this was an optional feature in CMSIS-RTOS v1). - Functions that return osEvent have been replaced. CMSIS-RTOS2 provides an translation layer for the CMSIS-RTOS API v1. It is possible to intermix CMSIS-RTOS API Version 2 and CMSIS-RTOS API Version 1 within the same application. Over time, you may migrate to the new API as explained in \ref os2Migration. CMSIS-RTOS2 is not POSIX compliant, but has provisions to enable a C++11/C++14 interface. The following sections provide further details about CMSIS-RTOS2 and the RTX reference implementation. - \subpage rtos_revisionHistory documents changes made in each version for CMSIS-RTOS API v2 and RTX v5. - \subpage genRTOS2IF provides an overview about the CMSIS-RTOS API v2. - \subpage functionOverview lists the CMSIS-RTOS2 API functions and the header file cmsis_os2.h. - \subpage rtosValidation describes the validation suite that is publicly available. - \subpage os2Migration shows how to use CMSIS-RTOS2 in existing projects and lists function differences to CMSIS-RTOS v1. - \subpage rtx5_impl provides general information about the operation and usage of RTX v5.
CMSIS-RTOS2 in ARM::CMSIS Pack ----------------------------- The following files relevant to CMSIS-RTOS2 are present in the ARM::CMSIS Pack directories: File/Folder | Content -----------------------------|------------------------------------------------------------------------ \b CMSIS/Documentation/RTOS2 | This documentation \b CMSIS/RTOS2/Include | \ref cmsis_os2_h \b CMSIS/RTOS2/RTX | CMSIS-RTOS v2 reference implementation based on RTX version 5 \b CMSIS/RTOS2/Template | Compatibility layer to CMSIS-RTOS v1 */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \page rtos_revisionHistory Revision History \section GenRTOS2Rev CMSIS-RTOS API Version 2 fv
Version Description
V2.1.2 Additional functions allowed to be called from Interrupt Service Routines: - \ref osKernelGetInfo, \ref osKernelGetState
V2.1.1 Additional functions allowed to be called from Interrupt Service Routines: - \ref osKernelGetTickCount, \ref osKernelGetTickFreq Changed Kernel Tick type to uint32_t: - updated: \ref osKernelGetTickCount, \ref osDelayUntil
V2.1.0 Support for critical and uncritical sections (nesting safe): - updated: \ref osKernelLock, \ref osKernelUnlock - added: \ref osKernelRestoreLock Updated \ref CMSIS_RTOS_ThreadFlagsMgmt "Thread Flags" and \ref CMSIS_RTOS_EventFlags "Event Flags": - changed flags parameter and return type from int32_t to uint32_t
V2.0.0 New API Version 2.0 available. - See \ref rtos_api2 for a detailed function reference. - See \ref os2Migration for details on the migration process from API Version 1.
V1.02 - only documentation changes Added: Overview of the \ref rtosValidation "CMSIS-RTOS Validation" Software Pack.\n Clarified: Behavior of \ref CMSIS_RTOS_TimeOutValue.
V1.02 Added: New control functions for short timeouts in microsecond resolution \b osKernelSysTick, \b osKernelSysTickFrequency, \b osKernelSysTickMicroSec.\n Removed: osSignalGet.
V1.01 Added capabilities for C++, kernel initialization and object deletion.\n Prepared for C++ class interface. In this context to \em const attribute has been moved from osXxxxDef_t typedefs to the osXxxxDef macros.\n Added: \ref osTimerDelete, \ref osMutexDelete, \ref osSemaphoreDelete.\n Added: \ref osKernelInitialize that prepares the kernel for object creation.\n
V1.00 First official Release.\n Added: \ref osKernelStart; starting 'main' as a thread is now an optional feature.\n Semaphores have now the standard behavior.\n \b osTimerCreate does no longer start the timer. Added: \ref osTimerStart (replaces osTimerRestart).\n Changed: osThreadPass is renamed to \ref osThreadYield.
V0.02 Preview Release.
\section RTX5RevisionHistory CMSIS-RTOS RTX Version 5
Version Description
V5.2.3 - Based on CMSIS-RTOS API V2.1.2. - Added TrustZone Module Identifier configuration for Idle and Timer Thread. - Moved SVC/PendSV handler priority setup from osKernelInitialize to osKernelStart (User Priority Grouping can be updated after osKernelInitialize but before osKernelStart). - Corrected SysTick and PendSV handlers for ARMv8-M Baseline. - Corrected memory allocation for stack and data when "Object specific Memory allocation" configuration is used. - Added support for ARMv8-M IAR compiler.
V5.2.2 - Corrected IRQ and SVC exception handlers for Cortex-A.
V5.2.1 - Corrected SysTick and SVC Interrupt Priority for Cortex-M.
V5.2.0 - Based on CMSIS-RTOS API V2.1.1. - Added support for for Cortex-A. - Using OS Tick API for RTX Kernel Timer Tick. - Fixed potential corruption of terminated threads list. - Corrected MessageQueue to use actual message length (before padding). - Corrected parameters for ThreadEnumerate and MessageQueueInserted events. - Timer Thread creation moved to osKernelStart.
V5.1.0 - Based on CMSIS-RTOS API V2.1.0. - Added support for Event recording. - Added support for IAR compiler. - Updated configuration files: RTX_Config.h for the configuration settings and RTX_config.c for implementing the \ref rtx5_specific. - osRtx name-space for RTX specific symbols.
V5.0.0 Initial release compliant to CMSIS-RTOS2.\n
*/ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \page genRTOS2IF Generic RTOS Interface CMSIS-RTOS2 is a generic API that is agnostic of the underlying RTOS kernel. Application programmers call CMSIS-RTOS2 API functions in the user code to ensure maximum portability from one RTOS to another. Middleware using CMSIS-RTOS2 API takes advantages of this approach by avoiding unnecessary porting efforts. \image html "API_Structure.png" "CMSIS-RTOS API Structure" A typical CMSIS-RTOS2 API implementation interfaces to an existing real-time kernel. The CMSIS-RTOS2 API provides the following attributes and functionalities: - Function names, identifiers, and parameters are descriptive and easy to understand. The functions are powerful and flexible which reduces the number of functions exposed to the user. - \ref CMSIS_RTOS_ThreadMgmt allows you to define, create, and control threads. - Interrupt Service Routines (ISR) can \ref CMSIS_RTOS_ISR_Calls "call some CMSIS-RTOS functions". When a CMSIS-RTOS function cannot be called from an ISR context, it rejects the invocation and returns an error code. - Three different event types support communication between multiple threads and/or ISR: - \ref CMSIS_RTOS_ThreadFlagsMgmt "Thread Flags": may be used to indicate specific conditions to a thread. - \ref CMSIS_RTOS_EventFlags "Event Flags": may be used to indicate events to a thread or ISR. - \ref CMSIS_RTOS_Message "Messages": can be sent to a thread or an ISR. Messages are buffered in a queue. - \ref CMSIS_RTOS_MutexMgmt and \ref CMSIS_RTOS_SemaphoreMgmt are incorporated. - CPU time can be scheduled with the following functionalities: - A \a timeout parameter is incorporated in many CMSIS-RTOS functions to avoid system lockup. When a timeout is specified, the system waits until a resource is available or an event occurs. While waiting, other threads are scheduled. - The \ref osDelay and \ref osDelayUntil functions put a thread into the \b WAITING state for a specified period of time. - The \ref osThreadYield provides co-operative thread switching and passes execution to another thread of the same priority. - \ref CMSIS_RTOS_TimerMgmt functions are used to trigger the execution of functions. The CMSIS-RTOS2 API is designed to optionally incorporate multi-processor systems and/or access protection via the Cortex-M Memory Protection Unit (MPU). In some RTOS implementations threads may execute on different processors, thus \b message queues may reside in shared memory resources. The CMSIS-RTOS2 API encourages the software industry to evolve existing RTOS implementations. RTOS implementations can be different and optimized in various aspects towards the Cortex-M processors. Optional features may be for example - Support of the Cortex-M Memory Protection Unit (MPU). - Support of multi-processor systems. - Support of a DMA controller. - Deterministic context switching. - Round-robin context switching. - Deadlock avoidance, for example with priority inversion. - Zero interrupt latency by using ARMv7-M instructions LDREX and STREX. \section usingOS2 Using a CMSIS-RTOS2 Implementation A CMSIS-RTOS2 implementation is typically provided as a library. To add the RTOS functionality to an existing CMSIS-based application, the RTOS library (and typically one or more configuration files) needs to be added. There is a single new header file %cmsis_os2.h available. This is the only header file required for a completely portable application. In such a case, user provided memory for control blocks, objects data and thread stack cannot be used. Alternatively, you can include an implementation specific header file (for example rtx_os.h) which provides definitions also for resource allocation (such as size of control blocks, required memory for object data and thread stack). This is optional and implies that the application code is not completely portable. \image html "CMSIS_RTOS_Files.png" "CMSIS-RTOS File Structure" Once the files are added to a project, the user can start working with the CMSIS-RTOS functions. A code example is provided below: Code Example \code /*---------------------------------------------------------------------------- * CMSIS-RTOS 'main' function template *---------------------------------------------------------------------------*/ #include "RTE_Components.h" #include CMSIS_device_header #include "cmsis_os2.h" /*---------------------------------------------------------------------------- * Application main thread *---------------------------------------------------------------------------*/ void app_main (void *argument) { // ... for (;;) {} } int main (void) { // System Initialization SystemCoreClockUpdate(); #ifdef RTE_Compiler_EventRecorder // Initialize and start Event Recorder EventRecorderInitialize(EventRecordError, 1U); #endif // ... osKernelInitialize(); // Initialize CMSIS-RTOS osThreadNew(app_main, NULL, NULL); // Create application main thread osKernelStart(); // Start thread execution for (;;) {} } \endcode \section cmsis_os2_h cmsis_os2.h header file The file \b cmsis_os2.h is a standard header file that interfaces to every CMSIS-RTOS2 compliant real-time operating systems (RTOS). Each implementation is provided the same \b cmsis_os2.h which defines the interface to the \ref rtos_api2. Using the \b cmsis_os2.h along with dynamic object allocation allows to create source code or libraries that require no modifications when using on a different CMSIS-RTOS2 implementation. Header file %cmsis_os2.h \include cmsis_os2.h */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \page rtx5_impl RTX v5 Implementation Keil RTX version 5 (RTX5) implements the CMSIS-RTOS2 as a native RTOS interface for ARM Cortex-M processor-based devices. A translation layer to CMSIS-RTOS API v1 is provided. Therefore, RTX5 can be used in applications that where previously based on RTX version 4 and CMSIS-RTOS version 1 with minimal effort. The following sections provide further details: - \subpage cre_rtx_proj explains how to setup an RTX v5 project in Keil MDK. - \subpage theory_of_operation provides general information about the operation of CMSIS-RTOS RTX v5. - \subpage config_rtx5 describes configuration parameters of CMSIS-RTOS RTX v5. - \subpage creating_RTX5_LIB explains how to build your own CMSIS-RTOS RTX v5 library. - \subpage dirstructfiles5 explains the directories and files that are supplied as part of CMSIS-RTOS RTX v5. - \subpage technicalData5 lists microcontroller hardware requirements and limitations such as number of concurrent threads. - \subpage misraCompliance5 describes the violations to the MISRA standard. */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \page cre_rtx_proj Create an RTX5 Project The steps to create a microcontroller application using RTX5 are: - Create a new project and select a microcontroller device. - In the Manage Run-Time Environment window, select CMSIS\::CORE and CMSIS\::RTOS2 (API)\::Keil RTX5. You can choose to either add RTX as a library (Variant: \b Library) or to add the full source code (Variant: \b Source - required if using the Event Recorder): \image html manage_rte_output.png - If the Validation Output requires other components to be present, try to use the \b Resolve button. - Click \b OK. In the \b Project window, you will see the files that have been automatically added to you project, such as \b %RTX_Config.h, \b %RTX_Config.c, the library or the source code files, as well as the system and startup files: \image html project_window.png - If using the Variant: \b Source as statet above, you have to assure to use at least C99 compiler mode (Project Options -> C/C++ -> C99 Mode). - You can add template files to the project by right-clicking on Source Group 1 and selecting Add New Item to 'Source Group 1'. In the new window, click on User Code Template. On the right-hand side you will see all available template files for CMSIS-RTOS RTX: \image html add_item.png - \ref config_rtx5 "Configure" RTX5 to the application's needs using the \b %RTX_Config.h file. \section cre_rtx_cortexa Additional requirements for RTX on Cortex-A Cortex-A based microcontrollers are less unified with respect to the interrupt and timer implementations used compared to M-class devices. Thus RTX requires additional components when an A-class device is used, namely IRQ Controller (API) and \ref CMSIS_RTOS_TickAPI "OS Tick (API)" implementations. \image html manage_rte_cortex-a.png The default implementations provided along with CMSIS are - ARM Generic Interrupt Controller (GIC) - ARM Cortex-A5, Cortex-A9 Private Timer (PTIM) - ARM Cortex-A7 Generic Physical Timer (GTIM) For devices not implementing GIC, PTIM nor GTIM please refer to the according device family pack and select the proper implementations. \section cre_rtx_proj_specifics Add support for RTX specific functions If you require some of the \ref rtx5_specific "RTX specific functions" in your application code, \#include the \ref rtx_os_h "header file rtx_os.h". This enables \ref lowPower "low-power" and \ref TickLess "tick-less" operation modes. \section cre_rtx_proj_er Add Event Recorder Visibility - To use the Event Recorder together with RTX5, select the software component Compiler:Event Recorder. - Select the \b Source variant of the software component CMSIS:RTOS2 (API):Keil RTX5. \image html event_recorder_rte.png "Component selection for Event Recorder" - Call the function EventRecorderInitialize() in your application code (ideally in \c main()). - Build the application code and download it to the debug hardware. Once the target application generates event information, it can be viewed in the µVision debugger using the \b Event \b Recorder. */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \page theory_of_operation Theory of Operation Many aspects of the kernel are configurable and the configuration options are mentioned where applicable. \section SystemStartup System Startup Since main is no longer a thread RTX5 does not interfere with the system startup until main is reached. Once the execution reaches \c main() there is a recommended order to initialize the hardware and start the kernel. This is also reflected in the user code template file "CMSIS-RTOS2 'main' function" supplied with the RTX5 component. Your application's \c main() should implement at least the following in the given order: -# Initialization and configuration of hardware including peripherals, memory, pins, clocks and the interrupt system. -# Update the system core clock using the respective CMSIS-Core (Cortex-M) or CMSIS-Core (Cortex-A) function. -# Initialize the CMSIS-RTOS kernel using \ref osKernelInitialize. -# Optionally, create a new thread \c app_main, which is used as a main thread using \ref osThreadNew. Alternatively, threads can be created in \c main() directly. -# Start the RTOS scheduler using \ref osKernelStart. This function does not return in case of successful execution. Any application code after \b osKernelStart will not be executed unless \b osKernelStart fails. \note Interrupts (like SVC for example) used by the kernel are initialized in \ref osKernelInitialize. In case priorities and groupings in the NVIC are altered by the application after the above sequence it might be necessary to call \ref osKernelInitialize again. You might observe weird misbehaviour possibly catched by \ref osRtxErrorNotify or causing a hard fault. \note The tick timer is configured during \ref osKernelStart. The tick interval is calculated based on the \c SystemCoreClock variable. \section Scheduler RTX5 implements a low-latency preemtive scheduler. Major parts of RTX5 are executed in handler mode such as - \ref SysTick_Handler used for time-based scheduling. - \ref SVC_Handler used for lock-based scheduling. - \ref PendSV_Handler used for interrupt-based scheduling. In order to be low-latency with respect to ISR execution those system exceptions are configured to use the lowest priority groups available. The priorities are configured such that no preemption happens between them. Thus no interrupt critical sections (i.e. interrupt locks) are needed to protect the scheduler. \image html scheduling.png "Thread scheduling and interrupt execution" The scheduler combines priority and round-robin based context switches. The example depicted in the image above contains four threads (1, 2, 3, and 4). Threads 1 and 2 share the same priority, thread 3 has a higher one and thread 4 the highest (\ref osThreadAttr_t::priority). As long as threads 3 and 4 are blocked the scheduler switches between thread 1 and 2 on a time-slice basis (round-robin). The time-slice for round-robin scheduling can be configured, see Round-Robin Timeout in \ref systemConfig. Thread 2 unblocks thread 3 by an arbitrary RTOS-call (executed in SVC handler mode) at time index 2. The scheduler switches to thread 3 immidiately because thread 3 has the highest priority. Thread 4 is still blocked. At time index 4 an interrupt (ISR) occurs and preempts the SysTick_Handler. RTX does not add any latency to the interrupt service execution. The ISR routine uses an RTOS-call that unblocks thread 4. Instead of switching to thread 4 immediately the PendSV flag is set to defer the context switching. The PendSV_Handler is executed right after the SysTick_Handler returns and the defered context switch to thread 4 is carried out. As soon as highest priority thread 4 blocks again by using a blocking RTOS-call execution is switched back to thread 3 immidiately during time index 5. At time index 5 thread 3 uses a blocking RTOS-call as well. Thus the scheduler switches back to thread 2 for time index 6. At time index 7 the scheduler uses the round-robin mechanism to switch to thread 1 and so on. \section MemoryAllocation Memory Allocation RTX5 objects (thread, mutex, semaphore, timer, message queue, thread and event flags, as well as memory pool) require dedicated RAM memory. Objects can be created using osObjectNew() calls and deleted using osObjectDelete() calls. The related object memory needs to be available during the lifetime of the object. RTX5 offers three different memory allocation methods for objects: - \ref GlobalMemoryPool uses a single global memory pool for all objects. It is easy to configure, but may have the disadvantage for memory fragmentation when objects with different sizes are created and destroyed. - \ref ObjectMemoryPool uses a fixed-size memory pool for each object type. The method is time deterministic and avoids memory fragmentation. - \ref StaticObjectMemory reserves memory during compile time and completely avoids that a system can be out of memory. This is typically a required for some safety critical systems. It possible to intermix all the memory allocation methods in the same application. \subsection GlobalMemoryPool Global Memory Pool The global memory pool allocates all objects from a memory area. This method of memory allocation is the default configuration setting of RTX5. \image html MemAllocGlob.png "Global Memory Pool for all objects" When the memory pool does not provide sufficient memory, the creation of the object fails and the related osObjectNew() function returns \token{NULL}. Enabled in \ref systemConfig. \subsection ObjectMemoryPool Object-specific Memory Pools Object-specific memory pools avoids memory fragmentation with a dedicated fixed-size memory management for each object type. This type of memory pools are fully time deterministic, which means that object creation and destruction takes always the same fixed amount of time. As a fixed-size memory pool is specific to an object type, the handling of out-of-memory situations is simplified. \image html MemAllocSpec.png "One memory pool per object type" Object-specific memory pools are selectively enabled for each object type, e.g: mutex or thread using the RTX configuration file: - Enabled in \ref threadConfig for thread objects. - Enabled in \ref timerConfig for timer objects. - Enabled in \ref eventFlagsConfig for event objects. - Enabled in \ref mutexConfig for mutex objects. - Enabled in \ref semaphoreConfig for semaphore. - Enabled in \ref memPoolConfig for memory pools. - Enabled in \ref msgQueueConfig for message objects. When the memory pool does not provide sufficient memory, the creation of the object fails and the related osObjectNew() function returns \token{NULL}. \subsection StaticObjectMemory Static Object Memory In contrast to the dynamic memory allocations, the static memory allocation requires compile-time allocation of object memory. \image html MemAllocStat.png "Statically allocated memory for all objects" The following code example shows how to create an OS object using static memory. Code Example: \code{.c} /*---------------------------------------------------------------------------- * CMSIS-RTOS 'main' function template *---------------------------------------------------------------------------*/ #include "RTE_Components.h" #include CMSIS_device_header #include "cmsis_os2.h" //include rtx_os.h for types of RTX objects #include "rtx_os.h" //The thread function instanced in this example void worker(void *arg) { while(1) { //work osDelay(10000); } } // Define objects that are statically allocated for worker thread 1 osRtxThread_t worker_thread_tcb_1; // Reserve two areas for the stacks of worker thread 1 // uint64_t makes sure the memory alignment is 8 uint64_t worker_thread_stk_1[64]; // Define the attributes which are used for thread creation // Optional const saves RAM memory and includes the values in periodic ROM tests const osThreadAttr_t worker_attr_1 = { "wrk1", osThreadJoinable, &worker_thread_tcb_1, sizeof(worker_thread_tcb_1), &worker_thread_stk_1[0], sizeof(worker_thread_stk_1), osPriorityAboveNormal, 0 }; // Define ID object for thread osThreadId_t th1; /*---------------------------------------------------------------------------- * Application main thread *---------------------------------------------------------------------------*/ void app_main (void *argument) { uint32_t param = NULL; // Create an instance of the worker thread with static resources (TCB and stack) th1 = osThreadNew(worker, ¶m, &worker_attr_1); for (;;) {} } int main (void) { // System Initialization SystemCoreClockUpdate(); // ... osKernelInitialize(); // Initialize CMSIS-RTOS osThreadNew(app_main, NULL, NULL); // Create application main thread osKernelStart(); // Start thread execution for (;;) {} } \endcode \section ThreadStack Thread Stack Management For Cortex-M processors without floating point unit the thread context requires 64 bytes on the local stack. \note For Cortex-M4/M7 with FP the thread context requires 200 bytes on the local stack. For these devices the default stack space should be increased to a minimum of 300 bytes. Each thread is provided with a separate stack that holds the thread context and stack space for automatic variables and return addresses for function call nesting. The stack sizes of RTX threads are flexibly configurable as explained in the section \ref threadConfig. RTX offers a configurable checking for stack overflows and stack utilization. \section lowPower Low-Power Operation The system thread \b osRtxIdleThread can be use to switch the system into a low-power mode. The easiest form to enter a low-power mode is the execution of the \c __WFE function that puts the processor into a sleep mode where it waits for an event. Code Example: \code #include "RTE_Components.h" #include CMSIS_device_header /* Device definitions */ void osRtxIdleThread (void) { /* The idle demon is a system thread, running when no other thread is */ /* ready to run. */ for (;;) { __WFE(); /* Enter sleep mode */ } } \endcode \note \c __WFE() is not available in every Cortex-M implementation. Check device manuals for availability. \section kernelTimer RTX Kernel Timer Tick RTX uses the generic \ref CMSIS_RTOS_TickAPI to configure and control its periodic Kernel Tick. To use an alternative timer as the Kernel Tick Timer one simply needs to implement a custom version of the \ref CMSIS_RTOS_TickAPI. \note The OS Tick implementation provided must asure that the used timer interrupt uses the same (low) priority group as the service interrupts, i.e. interrupts used by RTX must not preempt each other. Refer to the \ref Scheduler section for more details. \subsection TickLess Tick-less Low-Power Operation RTX5 provides extension for tick-less operation which is useful for applications that use extensively low-power modes where the SysTick timer is also disabled. To provide a time-tick in such power-saving modes, a wake-up timer is used to derive timer intervals. The CMSIS-RTOS2 functions \ref osKernelSuspend and \ref osKernelResume control the tick-less operation. Using this functions allows the RTX5 thread scheduler to stop the periodic kernel tick interrupt. When all active threads are suspended, the system enters power-down and calculates how long it can stay in this power-down mode. In the power-down mode the processor and peripherals can be switched off. Only a wake-up timer must remain powered, because this timer is responsible to wake-up the system after the power-down period expires. The tick-less operation is controlled from the \b osRtxIdleThread thread. The wake-up timeout value is set before the system enters the power-down mode. The function \ref osKernelSuspend calculates the wake-up timeout measured in RTX Timer Ticks; this value is used to setup the wake-up timer that runs during the power-down mode of the system. Once the system resumes operation (either by a wake-up time out or other interrupts) the RTX5 thread scheduler is started with the function \ref osKernelResume. The parameter \a sleep_time specifies the time (in RTX Timer Ticks) that the system was in power-down mode. Code Example: \code #include "msp.h" // Device header /*---------------------------------------------------------------------------- * MSP432 Low-Power Extension Functions *---------------------------------------------------------------------------*/ static void MSP432_LP_Entry(void) { /* Enable PCM rude mode, which allows to device to enter LPM3 without waiting for peripherals */ PCM->CTL1 = PCM_CTL1_KEY_VAL | PCM_CTL1_FORCE_LPM_ENTRY; /* Enable all SRAM bank retentions prior to going to LPM3 */ SYSCTL->SRAM_BANKRET |= SYSCTL_SRAM_BANKRET_BNK7_RET; __enable_interrupt(); NVIC_EnableIRQ(RTC_C_IRQn); /* Do not wake up on exit from ISR */ SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk; /* Setting the sleep deep bit */ SCB->SCR |= (SCB_SCR_SLEEPDEEP_Msk); } static volatile unsigned int tc; static volatile unsigned int tc_wakeup; void RTC_C_IRQHandler(void) { if (tc++ > tc_wakeup) { SCB->SCR &= ~SCB_SCR_SLEEPONEXIT_Msk; NVIC_DisableIRQ(RTC_C_IRQn); NVIC_ClearPendingIRQ(RTC_C_IRQn); return; } if (RTC_C->PS0CTL & RTC_C_PS0CTL_RT0PSIFG) { RTC_C->CTL0 = RTC_C_KEY_VAL; // Unlock RTC key protected registers RTC_C->PS0CTL &= ~RTC_C_PS0CTL_RT0PSIFG; RTC_C->CTL0 = 0; SCB->SCR |= (SCB_SCR_SLEEPDEEP_Msk); } } uint32_t g_enable_sleep = 0; void osRtxIdleThread (void) { for (;;) { tc_wakeup = osKernelSuspend(); /* Is there some time to sleep? */ if (tc_wakeup > 0) { tc = 0; /* Enter the low power state */ MSP432_LP_Entry(); __WFE(); } /* Adjust the kernel ticks with the amount of ticks slept */ osKernelResume (tc); } } \endcode \note \c __WFE() is not available in every ARM Cortex-M implementation. Check device manuals for availability. The alternative using \c __WFI() has other issues, please take note of http://www.keil.com/support/docs/3591.htm as well. \section rtx_os_h RTX5 Header File Every implementation of the CMSIS-RTOS2 API can bring its own additional features. RTX5 adds a couple of \ref rtx5_specific "functions" for the idle more, for error notifications, and special system timer functions. It also is using macros for control block and memory sizes. If you require some of the RTX specific functions in your application code, \#include the header file \b %rtx_os.h: \include rtx_os.h \section CMSIS_RTOS_TimeOutValue Timeout Value Timeout values are an argument to several \b osXxx functions to allow time for resolving a request. A timeout value of \b 0 means that the RTOS does not wait and the function returns instantly, even when no resource is available. A timeout value of \ref osWaitForever means that the RTOS waits infinitely until a resource becomes available. Or one forces the thread to resume using \ref osThreadResume which is discouraged. The timeout value specifies the number of timer ticks until the time delay elapses. The value is an upper bound and depends on the actual time elapsed since the last timer tick. Examples: - timeout value \b 0 : the system does not wait, even when no resource is available the RTOS function returns instantly. - timeout value \b 1 : the system waits until the next timer tick occurs; depending on the previous timer tick, it may be a very short wait time. - timeout value \b 2 : actual wait time is between 1 and 2 timer ticks. - timeout value \ref osWaitForever : system waits infinite until a resource becomes available. \image html TimerValues.png "Example of timeout using osDelay()" \section CMSIS_RTOS_ISR_Calls Calls from Interrupt Service Routines The following CMSIS-RTOS2 functions can be called from threads and Interrupt Service Routines (ISR): - \ref osKernelGetInfo, \ref osKernelGetState, \ref osKernelGetTickCount, \ref osKernelGetTickFreq, \ref osKernelGetSysTimerCount, \ref osKernelGetSysTimerFreq - \ref osThreadFlagsSet - \ref osEventFlagsSet, \ref osEventFlagsClear, \ref osEventFlagsGet, \ref osEventFlagsWait - \ref osSemaphoreAcquire, \ref osSemaphoreRelease, \ref osSemaphoreGetCount - \ref osMemoryPoolAlloc, \ref osMemoryPoolFree, \ref osMemoryPoolGetCapacity, \ref osMemoryPoolGetBlockSize, \ref osMemoryPoolGetCount, \ref osMemoryPoolGetSpace - \ref osMessageQueuePut, \ref osMessageQueueGet, \ref osMessageQueueGetCapacity, \ref osMessageQueueGetMsgSize, \ref osMessageQueueGetCount, \ref osMessageQueueGetSpace Functions that cannot be called from an ISR are verifying the interrupt status and return the status code \b osErrorISR, in case they are called from an ISR context. In some implementations, this condition might be caught using the HARD_FAULT vector. */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \page config_rtx5 Configure RTX v5 The file "RTX_Config.h" defines the configuration parameters of CMSIS-RTOS RTX and must be part of every project that is using the CMSIS-RTOS RTX kernel. The configuration options are explained in detail in the following sections: - \ref systemConfig covers system-wide settings for the global memory pool, tick frequency, ISR event buffer and round-robin thread switching. - \ref threadConfig provides several parameters to configure the \ref CMSIS_RTOS_ThreadMgmt functions. - \ref timerConfig provides several parameters to configure the \ref CMSIS_RTOS_TimerMgmt functions. - \ref eventFlagsConfig provides several parameters to configure the \ref CMSIS_RTOS_EventFlags functions. - \ref mutexConfig provides several parameters to configure the \ref CMSIS_RTOS_MutexMgmt functions. - \ref semaphoreConfig provides several parameters to configure the \ref CMSIS_RTOS_SemaphoreMgmt functions. - \ref memPoolConfig provides several parameters to configure the \ref CMSIS_RTOS_PoolMgmt functions. - \ref msgQueueConfig provides several parameters to configure the \ref CMSIS_RTOS_Message functions. The file "RTX_Config.c" contains default implementations of the functions \ref osRtxIdleThread and \ref osRtxErrorNotify. Both functions can simply be overwritten with a custimized behavior by redefining them as part of the user code. The configuration file uses Configuration Wizard Annotations. Refer to Pack - Configuration Wizard Annotations for details. Depending on the development tool, the annotations might lead to a more user-friendly graphical representation of the settings. The screenshot below is a screenshot from the µVision \b Configuration \b Wizard view: \image html config_wizard.png "RTX_Config.h in Configuration Wizard View" Alternatively one can provide configuration options using the compiler command line. For example one can customize the used tick frequency to 100us by (overwriting) the configuration using \code cc -DOS_TICK_FREQ=100 \endcode \section systemConfig System Configuration The system configuration covers system-wide settings for the global memory pool, tick frequency, ISR event buffer and round-robin thread switching. System Configuration Options \image html config_wizard_system.png "RTX_Config.h: System Configuration" Name | \#define | Description ---------------------------------------|--------------------------|---------------------------------------------------------------- Global Dynamic Memory size [bytes] | \c OS_DYNAMIC_MEM_SIZE | Defines the combined global dynamic memory size for the \ref GlobalMemoryPool. Default value is \token{4096}. Value range is \token{[0-1073741824]} bytes, in multiples of \token{8} bytes. Kernel Tick Frequency (Hz) | \c OS_TICK_FREQ | Defines base time unit for delays and timeouts in Hz. Default: 1000Hz = 1ms period. Round-Robin Thread switching | \c OS_ROBIN_ENABLE | Enables Round-Robin Thread switching. Round-Robin Timeout | \c OS_ROBIN_TIMEOUT | Defines how long a thread will execute before a thread switch. Default value is \token{5}. Value range is \token{[1-1000]}. ISR FIFO Queue | \c OS_ISR_FIFO_QUEUE | RTOS Functions called from ISR store requests to this buffer. Default value is \token{16 entries}. Value range is \token{[4-256]} entries in multiples of \token{4}. \subsection systemConfig_glob_mem Global dynamic memory Refer to \ref GlobalMemoryPool. \subsection systemConfig_rr Round-Robin Thread Switching RTX5 may be configured to use round-robin multitasking thread switching. Round-robin allows quasi-parallel execution of several threads of the \a same priority. Threads are not really executed concurrently, but are scheduled where the available CPU time is divided into time slices and RTX5 assigns a time slice to each thread. Because the time slice is typically short (only a few milliseconds), it appears as though threads execute simultaneously. Round-robin thread switching functions as follows: - the tick is preloaded with the timeout value when a thread switch occurs - the tick is decremented (if not already zero) each system tick if the same thread is still executing - when the tick reaches 0 it indicates that a timeout has occurred. If there is another thread ready with the \a same priority, then the system switches to that thread and the tick is preloaded with timeout again. In other words, threads execute for the duration of their time slice (unless a thread's time slice is given up). Then, RTX switches to the next thread that is in \b READY state and has the same priority. If no other thread with the same priority is ready to run, the current running thread resumes it execution. \note When switching to higher priority threads, the round-robin timeout value is reset. Round-Robin multitasking is controlled with the \#define OS_ROBIN_ENABLE. The time slice period is configured (in RTX timer ticks) with the \#define OS_ROBIN_TIMEOUT. \subsection systemConfig_isr_fifo ISR FIFO Queue The RTX functions (\ref CMSIS_RTOS_ISR_Calls), when called from and interrupt handler, store the request type and optional parameter to the ISR FIFO queue buffer to be processed later, after the interrupt handler exits. The scheduler is activated immediately after the IRQ handler has finished its execution to process the requests stored to the FIFO queue buffer. The required size of this buffer depends on the number of functions that are called within the interrupt handler. An insufficient queue size will be caught by \b osRtxErrorNotify with error code \b osRtxErrorISRQueueOverflow. \section threadConfig Thread Configuration The RTX5 provides several parameters to configure the \ref CMSIS_RTOS_ThreadMgmt functions. Thread Configuration Options \image html config_wizard_threads.png "RTX_Config.h: Thread Configuration"
Option | \#define | Description :--------------------------------------------------------|:-----------------------|:--------------------------------------------------------------- Object specific Memory allocation | \c OS_THREAD_OBJ_MEM | Enables object specific memory allocation. See \ref ObjectMemoryPool. Number of user Threads | \c OS_THREAD_NUM | Defines maximum number of user threads that can be active at the same time. Applies to user threads with system provided memory for control blocks. Default value is \token{1}. Value range is \token{[1-1000]}. Number of user Threads with default Stack size | \c OS_THREAD_DEF_STACK_NUM | Defines maximum number of user threads with default stack size and applies to user threads with \token{0} stack size specified. Value range is \token{[0-1000]}. Total Stack size [bytes] for user Threads with user-provided Stack size | \c OS_THREAD_USER_STACK_SIZE | Defines the combined stack size for user threads with user-provided stack size. Default value is \token{0}. Value range is \token{[0-1073741824]} Bytes, in multiples of \token{8}. Default Thread Stack size [bytes] | \c OS_STACK_SIZE | Defines stack size for threads with zero stack size specified. Default value is \token{200}. Value range is \token{[96-1073741824]} Bytes, in multiples of \token{8}. Idle Thread Stack size [bytes] | \c OS_IDLE_THREAD_STACK_SIZE | Defines stack size for Idle thread. Default value is \token{200}. Value range is \token{[72-1073741824]} bytes, in multiples of \token{8}. Stack overrun checking | \c OS_STACK_CHECK | Enable stack overrun checks at thread switch. Stack usage watermark | \c OS_STACK_WATERMARK | Initialize thread stack with watermark pattern for analyzing stack usage. Enabling this option increases significantly the execution time of thread creation. Processor mode for Thread execution | \c OS_PRIVILEGE_MODE | Controls the processor mode. Default value is \token{Privileged} mode. Value range is \token{[0=Unprivileged; 1=Privileged]} mode. \subsection threadConfig_countstack Configuration of Thread Count and Stack Space The RTX5 kernel uses a separate stack space for each thread and provides two methods for defining the stack requirements: - Static allocation: when \ref osThreadAttr_t::stack_mem and \ref osThreadAttr_t::stack_size specify a memory area which is used for the thread stack. \b Attention: The stack memory provided must be 64-bit aligned, i.e. by using uint64_t for declaration. - Dynamic allocation: when \ref osThreadAttr_t is NULL or \ref osThreadAttr_t::stack_mem is NULL, the system allocates the stack memory from: - Object-specific Memory Pool (default Stack size) when "Object specific Memory allocation" is enabled and "Number of user Threads with default Stack size" is not \token{0} and \ref osThreadAttr_t::stack_size is \token{0} (or \ref osThreadAttr_t is NULL). - Object-specific Memory Pool (user-provided Stack size) when "Object specific Memory allocation" is enabled and "Total Stack size for user..." is not \token{0} and \ref osThreadAttr_t::stack_size is not \token{0}. - Global Memory Pool when "Object specific Memory allocation" is disabled or (\ref osThreadAttr_t::stack_size is not \token{0} and "Total Stack size for user..." is \token{0}) or (\ref osThreadAttr_t::stack_size is \token{0} and "Number of user Threads with default Stack size" is \token{0}). \ref osThreadAttr_t is a parameter of the function \ref osThreadNew. \note Before the RTX kernel is started by the \ref osKernelStart() function, the main stack defined in startup_device.s is used. The main stack is also used for: - user application calls to RTX functions in \b thread \b mode using SVC calls - interrupt/exception handlers. \subsection threadConfig_ovfcheck Stack Overflow Checking RTX5 implements a software stack overflow checking that traps stack overruns. Stack is used for return addresses and automatic variables. Extensive usage or incorrect stack configuration may cause a stack overflow. Software stack overflow checking is controlled with the define \c OS_STACK_CHECK. If a stack overflow is detected, the function \b osRtxErrorNotify with error code \b osRtxErrorStackUnderflow is called. By default, this function is implemented as an endless loop and will practically stop code execution. \subsection threadConfig_watermark Stack Usage Watermark RTX5 initializes thread stack with a watermark pattern (0xCC) when a thread is created. This allows the debugger to determine the maximum stack usage for each thread. It is typically used during development but removed from the final application. Stack usage watermark is controlled with the define \c OS_STACK_WATERMARK. Enabling this option significantly increases the execution time of \ref osThreadNew (depends on thread stack size). \subsection threadConfig_procmode Processor Mode for Thread Execution RTX5 allows to execute threads in unprivileged or privileged processor mode. The processor mode is controlled with the define \c OS_PRIVILEGE_MODE. In \b unprivileged processor mode, the application software: - has limited access to the MSR and MRS instructions, and cannot use the CPS instruction. - cannot access the system timer, NVIC, or system control block. - might have restricted access to memory or peripherals. In \b privileged processor mode, the application software can use all the instructions and has access to all resources. \section timerConfig Timer Configuration RTX5 provides several parameters to configure the \ref CMSIS_RTOS_TimerMgmt functions. Timer Configuration Options \image html config_wizard_timer.png "RTX_Config.h: Timer Configuration" Name | \#define | Description ---------------------------------------|--------------------------|---------------------------------------------------------------- Object specific Memory allocation | \c OS_TIMER_OBJ_MEM | Enables object specific memory allocation. Number of Timer objects | \c OS_TIMER_NUM | Defines maximum number of objects that can be active at the same time. Applies to objects with system provided memory for control blocks. Value range is \token{[1-1000]}. Timer Thread Priority | \c OS_TIMER_THREAD_PRIO | Defines priority for timer thread. Default value is \token{40}. Value range is \token{[8-48]}, in multiples of \token{8}. The numbers have the following priority correlation: \token{8=Low}; \token{16=Below Normal}; \token{24=Normal}; \token{32=Above Normal}; \token{40=High}; \token{48=Realtime} Timer Thread Stack size [bytes] | \c OS_TIMER_THREAD_STACK_SIZE | Defines stack size for Timer thread. May be set to 0 when timers are not used. Default value is \token{200}. Value range is \token{[0-1073741824]}, in multiples of \token{8}. Timer Callback Queue entries | \c OS_TIMER_CB_QUEUE | Number of concurrent active timer callback functions. May be set to 0 when timers are not used. Default value is \token{4}. Value range is \token{[0-256]}. \subsection timerConfig_obj Object-specific memory allocation See \ref ObjectMemoryPool. \subsection timerConfig_user User Timer Thread The RTX5 function \b osRtxTimerThread executes callback functions when a time period expires. The priority of the timer subsystem within the complete RTOS system is inherited from the priority of the \b osRtxTimerThread. This is configured by \c OS_TIMER_THREAD_PRIO. Stack for callback functions is supplied by \b osRtxTimerThread. \c OS_TIMER_THREAD_STACK_SIZE must satisfy the stack requirements of the callback function with the highest stack usage. \section eventFlagsConfig Event Flags Configuration RTX5 provides several parameters to configure the \ref CMSIS_RTOS_EventFlags functions. Event Configuration Options \image html config_wizard_eventFlags.png "RTX_Config.h: Event Flags Configuration" Name | \#define | Description ---------------------------------------|--------------------------|---------------------------------------------------------------- Object specific Memory allocation | \c OS_EVFLAGS_OBJ_MEM | Enables object specific memory allocation. See \ref ObjectMemoryPool. Number of Event Flags objects | \c OS_EVFLAGS_NUM | Defines maximum number of objects that can be active at the same time. Applies to objects with system provided memory for control blocks. Value range is \token{[1-1000]}. \subsection eventFlagsConfig_obj Object-specific memory allocation When object-specific memory is used, the pool size for all Event objects is specified by \c OS_EVFLAGS_NUM. Refer to \ref ObjectMemoryPool. \section mutexConfig Mutex Configuration RTX5 provides several parameters to configure the \ref CMSIS_RTOS_MutexMgmt functions. Mutex Configuration Options \image html config_wizard_mutex.png "RTX_Config.h: Mutex Configuration" Name | \#define | Description ---------------------------------------|--------------------------|---------------------------------------------------------------- Object specific Memory allocation | \c OS_MUTEX_OBJ_MEM | Enables object specific memory allocation. See \ref ObjectMemoryPool. Number of Mutex objects | \c OS_MUTEX_NUM | Defines maximum number of objects that can be active at the same time. Applies to objects with system provided memory for control blocks. Value range is \token{[1-1000]}. \subsection mutexConfig_obj Object-specific Memory Allocation When object-specific memory is used, the pool size for all Mutex objects is specified by \c OS_MUTEX_NUM. Refer to \ref ObjectMemoryPool. \section semaphoreConfig Semaphore Configuration RTX5 provides several parameters to configure the \ref CMSIS_RTOS_SemaphoreMgmt functions. Semaphore Configuration Options \image html config_wizard_semaphore.png "RTX_Config.h: Semaphore Configuration" Name | \#define | Description ---------------------------------------|--------------------------|---------------------------------------------------------------- Object specific Memory allocation | \c OS_SEMAPHORE_OBJ_MEM | Enables object specific memory allocation. See \ref ObjectMemoryPool. Number of Semaphore objects | \c OS_SEMAPHORE_NUM | Defines maximum number of objects that can be active at the same time. Applies to objects with system provided memory for control blocks. Value range is \token{[1-1000]}. \subsection semaphoreConfig_obj Object-specific memory allocation When Object-specific Memory is used, the pool size for all Semaphore objects is specified by \c OS_SEMAPHORE_NUM. Refer to \ref ObjectMemoryPool. \section memPoolConfig Memory Pool Configuration RTX5 provides several parameters to configure the \ref CMSIS_RTOS_PoolMgmt functions. Memory Pool Configuration Options \image html config_wizard_memPool.png "RTX_Config.h: Memory Pool Configuration" Name | \#define | Description ---------------------------------------|--------------------------|---------------------------------------------------------------- Object specific Memory allocation | \c OS_MEMPOOL_OBJ_MEM | Enables object specific memory allocation. See \ref ObjectMemoryPool. Number of Memory Pool objects | \c OS_MEMPOOL_NUM | Defines maximum number of objects that can be active at the same time. Applies to objects with system provided memory for control blocks. Value range is \token{[1-1000]}. Data Storage Memory size [bytes] | \c OS_MEMPOOL_DATA_SIZE | Defines the combined data storage memory size. Applies to objects with system provided memory for data storage. Default value is \token{0}. Value range is \token{[0-1073741824]}, in multiples of \token{8}. \subsection memPoolConfig_obj Object-specific memory allocation When object-specific memory is used, the number of pools for all MemoryPool objects is specified by \c OS_MEMPOOL_NUM. The total storage size reserved for all pools is configured in \c OS_MEMPOOL_DATA_SIZE. Refer to \ref ObjectMemoryPool. \section msgQueueConfig Message Queue Configuration RTX5 provides several parameters to configure the \ref CMSIS_RTOS_Message functions. MessageQueue Configuration Options \image html config_wizard_msgQueue.png "RTX_Config.h: Message Queue Configuration" Name | \#define | Description ---------------------------------------|--------------------------|---------------------------------------------------------------- Object specific Memory allocation | \c OS_MSGQUEUE_OBJ_MEM | Enables object specific memory allocation. See \ref ObjectMemoryPool. Number of Message Queue objects | \c OS_MSGQUEUE_NUM | Defines maximum number of objects that can be active at the same time. Applies to objects with system provided memory for control blocks. Value range is \token{[1-1000]}. Data Storage Memory size [bytes] | \c OS_MSGQUEUE_DATA_SIZE | Defines the combined data storage memory size. Applies to objects with system provided memory for data storage. Default value is \token{0}. Value range is \token{[0-1073741824]}, in multiples of \token{8}. \subsection msgQueueConfig_obj Object-specific memory allocation When Object-specific Memory is used, the number of queues for all Message Queue objects is specified by \c OS_MSGQUEUE_NUM. The total storage size reserved for all queues is configured in \c OS_MSGQUEUE_DATA_SIZE. Refer to \ref ObjectMemoryPool. */ /* ========================================================================================================================== */ /** \page creating_RTX5_LIB Building the RTX5 Library The CMSIS Pack contains a µVision project for building the complete set of RTX5 libraries. This project can also be used as a reference for building the RTX5 libraries using a tool-chain of your choice. -# Open the project \b RTX_CM.uvprojx from the pack folder CMSIS/RTOS2/RTX/Library/ARM/MDK in µVision. -# Select the project target that matches your device's processor core. \n The project provides target configuration for all supported Cortex-M targets supported by RTX5. -# You can find out about the required preprocessor defines in the dialogs Options for Target - C/C++ and Options for Target - Asm. Note the need to use at least the C99 compiler mode when building RTX from source. -# From the Project window you find the list of source files required for a complete library build. -# Build the library of your choice using \b Project - \b Build \b Target (or press F7). \image html own_lib_projwin.png "Project with files for ARMv8-M Mainline" */ /* ========================================================================================================================== */ /** \page dirstructfiles5 Directory Structure and File Overview The following section provides an overview of the directory structure and the files that are relevant for the user's for CMSIS-RTOS RTX v5. The following directory references start below the CMSIS pack installation path, for example ARM/CMSIS/version/CMSIS/RTOS2. \section Folders RTX v5 Directory Structure The CMSIS-RTOS RTX v5 is delivered in source code and several examples are provided.
Directory Content
Include The include file for CMSIS-RTOS API v2. cmsis_os2.h is the central include file for user applications.
Template CMSIS-RTOS API template source and header file.
RTX Directory with RTX specific files and folders. Also contains the component viewer description file.
RTX/Config CMSIS-RTOS RTX configuration files %RTX_Config.h and %RTX_Config.c.
RTX/Examples Example projects that can be directly used in development tools.
RTX/Include RTX v5 specific include files.
RTX/Include1 CMSIS-RTOS v1 API header file.
RTX/Library Pre-built libraries (see next table for details).
RTX/Source Source code that can be used with ARMCC and GCC.
RTX/Template User code templates for creating application projects with CMSIS-RTOS RTX v5.
\section libFiles RTX v5 Library Files The CMSIS-RTOS RTX Library is available pre-compiled for ARMCC and GCC compilers and supports all Cortex-M processor variants in every configuration, including ARM Cortex-M23 and Cortex-M33.
Library File Processor Configuration
Library/ARM/RTX_CM0.lib CMSIS-RTOS RTX Library for ARMCC Compiler, Cortex-M0 and M1, little-endian.
Library/ARM/RTX_CM3.lib CMSIS-RTOS RTX Library for ARMCC Compiler, Cortex-M3, M4, and M7 without FPU, little-endian.
Library/ARM/RTX_CM4F.lib CMSIS-RTOS RTX Library for ARMCC Compiler, Cortex-M4 and M7 with FPU, little-endian.
Library/ARM/RTX_V8MB.lib CMSIS-RTOS RTX Library for ARMCC Compiler, ARMv8-M baseline.
Library/ARM/RTX_V8MBN.lib CMSIS-RTOS RTX Library for ARMCC Compiler, ARMv8-M baseline, non-secure.
Library/ARM/RTX_V8MM.lib CMSIS-RTOS RTX Library for ARMCC Compiler, ARMv8-M mainline.
Library/ARM/RTX_V8MMF.lib CMSIS-RTOS RTX Library for ARMCC Compiler, ARMv8-M mainline with FPU.
Library/ARM/RTX_V8MMFN.lib CMSIS-RTOS RTX Library for ARMCC Compiler, ARMv8-M mainline with FPU, non-secure.
Library/ARM/RTX_V8MMN.lib CMSIS-RTOS RTX Library for ARMCC Compiler, ARMv8-M mainline, non-secure.
Library/GCC/libRTX_CM0.a CMSIS-RTOS libRTX Library for GCC Compiler, Cortex-M0 and M1, little-endian.
Library/GCC/libRTX_CM3.a CMSIS-RTOS libRTX Library for GCC Compiler, Cortex-M3, M4, and M7 without FPU, little-endian.
Library/GCC/libRTX_CM4F.a CMSIS-RTOS libRTX Library for GCC Compiler, Cortex-M4 and M7 with FPU, little-endian.
Library/GCC/libRTX_V8MB.a CMSIS-RTOS libRTX Library for GCC Compiler, ARMv8-M baseline.
Library/GCC/libRTX_V8MBN.a CMSIS-RTOS libRTX Library for GCC Compiler, ARMv8-M baseline, non-secure.
Library/GCC/libRTX_V8MM.a CMSIS-RTOS libRTX Library for GCC Compiler, ARMv8-M mainline.
Library/GCC/libRTX_V8MMF.a CMSIS-RTOS libRTX Library for GCC Compiler, ARMv8-M mainline with FPU.
Library/GCC/libRTX_V8MMFN.a CMSIS-RTOS libRTX Library for GCC Compiler, ARMv8-M mainline with FPU, non-secure.
Library/GCC/libRTX_V8MMN.a CMSIS-RTOS libRTX Library for GCC Compiler, ARMv8-M mainline, non-secure.
*/ /* ========================================================================================================================== */ /** \page technicalData5 Technical Data \section technicalData_Toolchains Supported Toolchains Keil RTX5 is developed and tested using the common toolchains and development environments. \subsection technicalData_Toolchain_ARM ARM Compiler (ARM/Keil MDK, uVision5) Major parts of RTX5 are developed and optimized using ARM Compiler and ARM/Keil MDK. The current release is tested with the following versions: \subsection technicalData_Toolchain_IAR IAR Embedded Workbench RTX5 has been ported to fully support IAR Embedded Workbench. The following releases are known to work: \subsection technicalData_Toolchain_GCC GNU Compiler Collection RTX5 has also been ported to support GCC, maintenance mainly relays on community contribution. Active development is currently tested with: \section technicalData5_ControlBlockSizes Control Block Sizes Keil RTX5 specific control block definitions (including sizes) as well as memory pool and message queue memory requirements are defined in the RTX5 header file: \code /// Control Block sizes #define osRtxThreadCbSize sizeof(osRtxThread_t) #define osRtxTimerCbSize sizeof(osRtxTimer_t) #define osRtxEventFlagsCbSize sizeof(osRtxEventFlags_t) #define osRtxMutexCbSize sizeof(osRtxMutex_t) #define osRtxSemaphoreCbSize sizeof(osRtxSemaphore_t) #define osRtxMemoryPoolCbSize sizeof(osRtxMemoryPool_t) #define osRtxMessageQueueCbSize sizeof(osRtxMessageQueue_t) /// Memory size in bytes for Memory Pool storage. /// \param block_count maximum number of memory blocks in memory pool. /// \param block_size memory block size in bytes. #define osRtxMemoryPoolMemSize(block_count, block_size) \ (4*(block_count)*(((block_size)+3)/4)) /// Memory size in bytes for Message Queue storage. /// \param msg_count maximum number of messages in queue. /// \param msg_size maximum message size in bytes. #define osRtxMessageQueueMemSize(msg_count, msg_size) \ (4*(msg_count)*(3+(((msg_size)+3)/4))) \endcode If you are using a \ref GlobalMemoryPool to allocate memory for the RTOS objects, you need to know the size that is required for each object in case of errors. Currently, the control block sizes are as follows (subject to change without notification): Type | Control block size in bytes | --------------|:---------------------------:| Thread | 68 | Timer | 32 | Event Flags | 16 | Mutex | 28 | Semaphore | 16 | Memory Pool | 36 | Message Queue | 52 | The size of the memory that is required for memory pool and message queue data storage can be determined from the macros stated above. */ /* ========================================================================================================================== */ /** \page misraCompliance5 MISRA-C Compliance Exceptions CMSIS-RTOS RTX tries to be MISRA-C compliant as much as possible. However, there are some violations in order to simplify the overall code logic and to generate more efficient code. This page will list the MISRA-C compliance exceptions. Work in progress. */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \page rtosValidation RTOS Validation ARM offers a Software Pack for the CMSIS-RTOS Validation. The ARM::CMSIS-RTOS_Validation Pack contains the following: - Source code of a CMSIS-RTOS Validation Suite along with configuration file. - Documentation of the CMSIS-RTOS Validation Suite. - Example that shows the usage of the CMSIS-RTOS Validation Suite using simulation. \note Currently, a public version of the test suite is available only for CMSIS-RTOS v1 API. The CMSIS-RTOS Validation Suite performs generic validation of various RTOS features. The test cases verify the functional behavior, test invalid parameters and call management functions from ISR. The following CMSIS-RTOS features can be tested with the current release: - Thread : Create multiple threads, terminate, restart, yield, change priority - Timer : Create periodic and one-shot timers - GenWait : Call generic wait functions (osDelay and osWait) - WaitFunc : Measure wait ticks (delay, mail, message, mutex, semaphore, signal) Moreover the following inter-thread communication functions can be tested: - Signal : Verify signal events - Memory Pool : Verify memory allocation - Message Queue : Exchange messages between threads - Mail Queue : Exchange data between threads - Mutex : Synchronize resource access - Semaphore : Access shared resources The RTOS Validation output can be printed to a console, output via ITM printf, or output to a memory buffer. \section test_output Sample Test Output \verbatim CMSIS-RTOS Test Suite Oct 21 2015 16:39:16 TEST 01: TC_ThreadCreate PASSED TEST 02: TC_ThreadMultiInstance PASSED TEST 03: TC_ThreadTerminate PASSED : : TEST 08: TC_ThreadChainedCreate PASSED TEST 09: TC_ThreadYield NOT EXECUTED TEST 10: TC_ThreadParam PASSED : : TEST 60: TC_MailFromISRToThread PASSED Test Summary: 60 Tests, 59 Executed, 59 Passed, 0 Failed, 0 Warnings. Test Result: PASSED \endverbatim */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \page functionOverview Function Overview CMSIS-RTOS v2 provides multiple API interfaces: - \subpage rtos_api2 is the new C function API that supports dynamic object creation and ARMv8-M (ARM Cortex-M23 and Cortex-M33). - CMSIS-RTOS C API v1 is a C function API that is backward compatible with CMSIS-RTOS v1. - \subpage rtos_apicpp is a C++ class function API. It is possible to intermix the different API variants in the same application and even in the same C/C++ source module. However, the functions of the C API Version 1 may be deprecated in future versions of CMSIS-RTOS. \section rtos_api2 CMSIS-RTOS2 Overview of all CMSIS-RTOS C API v2 functions that are implemented in the \subpage cmsis_os2_h. - \ref CMSIS_RTOS_KernelCtrl - \ref osKernelGetInfo : \copybrief osKernelGetInfo - \ref osKernelGetState : \copybrief osKernelGetState - \ref osKernelGetSysTimerCount : \copybrief osKernelGetSysTimerCount - \ref osKernelGetSysTimerFreq : \copybrief osKernelGetSysTimerFreq - \ref osKernelInitialize : \copybrief osKernelInitialize - \ref osKernelLock : \copybrief osKernelLock - \ref osKernelUnlock : \copybrief osKernelUnlock - \ref osKernelRestoreLock : \copybrief osKernelRestoreLock - \ref osKernelResume : \copybrief osKernelResume - \ref osKernelStart : \copybrief osKernelStart - \ref osKernelSuspend : \copybrief osKernelSuspend - \ref osKernelGetTickCount : \copybrief osKernelGetTickCount - \ref osKernelGetTickFreq : \copybrief osKernelGetTickFreq - \ref CMSIS_RTOS_ThreadMgmt - \ref osThreadDetach : \copybrief osThreadDetach - \ref osThreadEnumerate : \copybrief osThreadEnumerate - \ref osThreadExit : \copybrief osThreadExit - \ref osThreadGetCount : \copybrief osThreadGetCount - \ref osThreadGetId : \copybrief osThreadGetId - \ref osThreadGetName : \copybrief osThreadGetName - \ref osThreadGetPriority : \copybrief osThreadGetPriority - \ref osThreadGetStackSize : \copybrief osThreadGetStackSize - \ref osThreadGetStackSpace : \copybrief osThreadGetStackSpace - \ref osThreadGetState : \copybrief osThreadGetState - \ref osThreadJoin : \copybrief osThreadJoin - \ref osThreadNew : \copybrief osThreadNew - \ref osThreadResume : \copybrief osThreadResume - \ref osThreadSetPriority : \copybrief osThreadSetPriority - \ref osThreadSuspend : \copybrief osThreadSuspend - \ref osThreadTerminate : \copybrief osThreadTerminate - \ref osThreadYield : \copybrief osThreadYield - \ref CMSIS_RTOS_ThreadFlagsMgmt - \ref osThreadFlagsSet : \copybrief osThreadFlagsSet - \ref osThreadFlagsClear : \copybrief osThreadFlagsClear - \ref osThreadFlagsGet : \copybrief osThreadFlagsGet - \ref osThreadFlagsWait : \copybrief osThreadFlagsWait - \ref CMSIS_RTOS_EventFlags - \ref osEventFlagsGetName : \copybrief osEventFlagsGetName - \ref osEventFlagsNew : \copybrief osEventFlagsNew - \ref osEventFlagsDelete : \copybrief osEventFlagsDelete - \ref osEventFlagsSet : \copybrief osEventFlagsSet - \ref osEventFlagsClear : \copybrief osEventFlagsClear - \ref osEventFlagsGet : \copybrief osEventFlagsGet - \ref osEventFlagsWait : \copybrief osEventFlagsWait - \ref CMSIS_RTOS_Wait - \ref osDelay : \copybrief osDelay - \ref osDelayUntil : \copybrief osDelayUntil - \ref CMSIS_RTOS_TimerMgmt - \ref osTimerDelete : \copybrief osTimerDelete - \ref osTimerGetName : \copybrief osTimerGetName - \ref osTimerIsRunning : \copybrief osTimerIsRunning - \ref osTimerNew : \copybrief osTimerNew - \ref osTimerStart : \copybrief osTimerStart - \ref osTimerStop : \copybrief osTimerStop - \ref CMSIS_RTOS_MutexMgmt - \ref osMutexAcquire : \copybrief osMutexAcquire - \ref osMutexDelete : \copybrief osMutexDelete - \ref osMutexGetName : \copybrief osMutexGetName - \ref osMutexGetOwner : \copybrief osMutexGetOwner - \ref osMutexNew : \copybrief osMutexNew - \ref osMutexRelease : \copybrief osMutexRelease - \ref CMSIS_RTOS_SemaphoreMgmt - \ref osSemaphoreAcquire : \copybrief osSemaphoreAcquire - \ref osSemaphoreDelete : \copybrief osSemaphoreDelete - \ref osSemaphoreGetCount : \copybrief osSemaphoreGetCount - \ref osSemaphoreGetName : \copybrief osSemaphoreGetName - \ref osSemaphoreNew : \copybrief osSemaphoreNew - \ref osSemaphoreRelease : \copybrief osSemaphoreRelease - \ref CMSIS_RTOS_PoolMgmt - \ref osMemoryPoolAlloc : \copybrief osMemoryPoolAlloc - \ref osMemoryPoolDelete : \copybrief osMemoryPoolDelete - \ref osMemoryPoolFree : \copybrief osMemoryPoolFree - \ref osMemoryPoolGetBlockSize : \copybrief osMemoryPoolGetBlockSize - \ref osMemoryPoolGetCapacity : \copybrief osMemoryPoolGetCapacity - \ref osMemoryPoolGetCount : \copybrief osMemoryPoolGetCount - \ref osMemoryPoolGetName : \copybrief osMemoryPoolGetName - \ref osMemoryPoolGetSpace : \copybrief osMemoryPoolGetSpace - \ref osMemoryPoolNew : \copybrief osMemoryPoolNew - \ref CMSIS_RTOS_Message - \ref osMessageQueueDelete : \copybrief osMessageQueueDelete - \ref osMessageQueueGet : \copybrief osMessageQueueGet - \ref osMessageQueueGetCapacity : \copybrief osMessageQueueGetCapacity - \ref osMessageQueueGetCount : \copybrief osMessageQueueGetCount - \ref osMessageQueueGetMsgSize : \copybrief osMessageQueueGetMsgSize - \ref osMessageQueueGetName : \copybrief osMessageQueueGetName - \ref osMessageQueueGetSpace : \copybrief osMessageQueueGetSpace - \ref osMessageQueueNew : \copybrief osMessageQueueNew - \ref osMessageQueuePut : \copybrief osMessageQueuePut - \ref osMessageQueueReset : \copybrief osMessageQueueReset - \ref CMSIS_RTOS_TickAPI - \ref OS_Tick_Setup : \copybrief OS_Tick_Setup - \ref OS_Tick_Enable : \copybrief OS_Tick_Enable - \ref OS_Tick_Disable : \copybrief OS_Tick_Disable - \ref OS_Tick_AcknowledgeIRQ : \copybrief OS_Tick_AcknowledgeIRQ - \ref OS_Tick_GetIRQn : \copybrief OS_Tick_GetIRQn - \ref OS_Tick_GetClock : \copybrief OS_Tick_GetClock - \ref OS_Tick_GetInterval : \copybrief OS_Tick_GetInterval - \ref OS_Tick_GetCount : \copybrief OS_Tick_GetCount - \ref OS_Tick_GetOverflow : \copybrief OS_Tick_GetOverflow - \ref rtx5_specific - \ref osRtxErrorNotify : \copybrief osRtxErrorNotify - \ref osRtxIdleThread : \copybrief osRtxIdleThread The following CMSIS-RTOS2 functions can be called from threads and \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines" (ISR): - \ref osKernelGetInfo, \ref osKernelGetState, \ref osKernelGetTickCount, \ref osKernelGetTickFreq, \ref osKernelGetSysTimerCount, \ref osKernelGetSysTimerFreq - \ref osThreadFlagsSet - \ref osEventFlagsSet, \ref osEventFlagsClear, \ref osEventFlagsGet, \ref osEventFlagsWait - \ref osSemaphoreAcquire, \ref osSemaphoreRelease, \ref osSemaphoreGetCount - \ref osMemoryPoolAlloc, \ref osMemoryPoolFree, \ref osMemoryPoolGetCapacity, \ref osMemoryPoolGetBlockSize, \ref osMemoryPoolGetCount, \ref osMemoryPoolGetSpace - \ref osMessageQueuePut, \ref osMessageQueueGet, \ref osMessageQueueGetCapacity, \ref osMessageQueueGetMsgSize, \ref osMessageQueueGetCount, \ref osMessageQueueGetSpace */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \page rtos_apicpp CMSIS-RTOS C++ API A C++11/C++14 interface is planned for the future. */ /* ======================================================================================================================== */ // Group creation for Reference /* \addtogroup CMSIS_RTOS1 CMSIS-RTOS API v1 \brief This section describes the CMSIS-RTOS API v1. \details The CMSIS-RTOS is a generic API layer that interfaces to an existing RTOS kernel. CMSIS-RTOS API v2 provides an translation layer for the CMSIS-RTOS API v1 that simplifies migration. Refer to the Reference guide of the CMSIS-RTOS API v1 for details. */ // Group creation for Reference /** \addtogroup CMSIS_RTOS CMSIS-RTOS2 API \brief Describes the C function interface of CMSIS-RTOS API v2. \details The CMSIS-RTOS2 is a generic API layer that interfaces to an RTOS kernel. The complete API interface is defined in the \ref cmsis_os2_h. When using dynamic memory allocation for objects, source code or libraries require no modifications when using on a different CMSIS-RTOS2 implementation. */ /** \addtogroup rtx5_specific RTX5 Specific API \brief This section describes CMSIS-RTOS RTX5 specifics. \details The RTX5 kernel can be customized for different application requirements: - If you are depending on the \ref lowPower "lowest power consumption" possible, you need to adapt the function \ref osRtxIdleThread to send the system to sleep mode as often as possible. In addition, use the \ref TickLess "tick-less low power" functions \ref osKernelSuspend and \ref osKernelResume to suspend the scheduler and to stop the SysTick timer. - If you try to find a \b runtime \b error, use the function \ref osRtxErrorNotify to debug the error. RTX5 interfaces to the Event Recorder to provide event information which helps you to understand and analyze the operation. Refer to \ref rtx_evr for more information. @{ */ /** \defgroup rtx5_specific_defines Macros \brief RTX5 macros \details @{ */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \def osRtxThreadCbSize */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \def osRtxTimerCbSize */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \def osRtxEventFlagsCbSize */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \def osRtxMutexCbSize */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \def osRtxSemaphoreCbSize */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \def osRtxMemoryPoolCbSize */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \def osRtxMessageQueueCbSize */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \def osRtxMemoryPoolMemSize */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \def osRtxMessageQueueMemSize */ /** @} */ /** \defgroup rtx5_specific_structs Structs \brief RTX5 structs \details @{ */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \struct osRtxThread_t */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \struct osRtxTimerFinfo_t */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \struct osRtxTimer_t */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \struct osRtxEventFlags_t */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \struct osRtxMutex_t */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \struct osRtxSemaphore_t */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \struct osRtxMemoryPool_t */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \struct osRtxMessageQueue_t */ /** @} */ /** \defgroup rtx5_specific_functions Functions \brief RTX5 functions \details @{ */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ /** \fn uint32_t osRtxErrorNotify (uint32_t code, void *object_id); \details Some system error conditions can be detected during runtime. If the RTX kernel detects a runtime error, it calls the runtime error function \b osRtxErrorNotify for an object specified by parameter \a object_id. The parameter \a code passes the actual error code to this function: | Error Code | Description | |------------------------------|-----------------------------------------------------------------------------------| | osRtxErrorStackUnderflow | Stack underflow detected for thread (thread_id=object_id) | | osRtxErrorISRQueueOverflow | ISR Queue overflow detected when inserting object (object_id) | | osRtxErrorTimerQueueOverflow | User Timer Callback Queue overflow detected for timer (timer_id=object_id) | | osRtxErrorClibSpace | Standard C/C++ library libspace not available: increase \c OS_THREAD_LIBSPACE_NUM | | osRtxErrorClibMutex | Standard C/C++ library mutex initialization failed | The function \b osRtxErrorNotify must contain an infinite loop to prevent further program execution. You can use an emulator to step over the infinite loop and trace into the code introducing a runtime error. For the overflow errors this means you need to increase the size of the object causing an overflow. \note Cannot be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines". Code Example \code #include "rtx_os.h" uint32_t osRtxErrorNotify (uint32_t code, void *object_id) { (void)object_id; switch (code) { case osRtxErrorStackUnderflow: // Stack underflow detected for thread (thread_id=object_id) break; case osRtxErrorISRQueueOverflow: // ISR Queue overflow detected when inserting object (object_id) break; case osRtxErrorTimerQueueOverflow: // User Timer Callback Queue overflow detected for timer (timer_id=object_id) break; case osRtxErrorClibSpace: // Standard C/C++ library libspace not available: increase OS_THREAD_LIBSPACE_NUM break; case osRtxErrorClibMutex: // Standard C/C++ library mutex initialization failed break; default: break; } for (;;) {} //return 0U; } \endcode */ /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ osRtxErrorClibMutex /** \fn void osRtxIdleThread (void *argument); \details The function \b osRtxIdleThread is executed by the RTX kernel, when no other threads are ready to run. By default, this thread is an empty end-less loop that does nothing. It only waits until another task becomes ready to run. You may change the code of the \b osRtxIdleThread function to put the CPU into a power-saving or idle mode, see \ref TickLess. The default stack size for this thread is defined in the file RTX_Config.h. Refer to \ref threadConfig. \note Cannot be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines". Code Example \code #include "rtx_os.h" __NO_RETURN void osRtxIdleThread (void *argument) { (void)argument; for (;;) {} } \endcode */ /** @} */ /// @}