Internals Overview#

Internal Tasks#

Timer Task#

The timer task is used to implement all software-based timers in the Micrium OS Kernel. You must create these timers, and they can be either one-shot or periodic timers. If software timers are not needed in your application, this task can be disabled (through OS_CFG_TMR_EN) to save memory.

When a timer expires, your application can receive a callback from the timer. Note that this callback must not make any pend calls. It is also important to note that this callback is made from the timer task’s stack, so the timer’s stack must be sized appropriately if the callback function is rather long.

The rate at which the timer task runs, its priority, and its stack size are all configurable. To change the default values, call the following function before the OSInit() call in main():

void  OS_ConfigureTmrTask (OS_TASK_CFG  *p_tmr_task_cfg)

Statistics Task#

The statistics task is used keep track of all the kernel objects in use in Micrium OS Kernel so they can be reported via uC/Probe, Micrium Kernel-Awareness plugins or user logs. This task runs at a fixed interval (typically 10Hz) and the rate is configurable. If the statistics task is not needed, it can be disabled to save space.

The statistics task also provides a hook to allow user code after the statistics task has run. This can be useful if a user wishes to log certain statistics. The hook is called via OSStatTaskHook().

The rate at which the statistics task runs, its priority and its stack size are all configurable. To change the default values, call the following function before the OSInit() call in main():

void  OS_ConfigureStatTask  (OS_TASK_CFG  *p_stat_task_cfg)

Interrupt Stack#

The Cortex-M architecture allows for a separate interrupt stack, which makes it easier to write applications for a real-time operating system. Without an extra interrupt stack, you would be required to always have enough room at the end of every task’s stack to handle the stack elements of the interrupt. With the Cortex-M architecture, a separate ISR stack is defined and used during an interrupt context. The default size of the interrupt stack (256 stack units/1024 bytes) is typically enough for most Micrium OS applications. All interrupts should ideally be very short, so there should not be a need for a large stack.

If it does become necessary to have a larger interrupt stack, the size of the stack can be adjusted by making the following call before the OSInit() call in main():

void  OS_ConfigureISRStk (CPU_STK       *p_stk_base_ptr,
                          CPU_STK_SIZE   stk_size)

Micrium Heap#

Micrium OS makes use of a heap-like area to allocate certain OS objects. By default, the heap will be used for the following items: the internal tasks’ TCB and stack (assuming any are enabled), the interrupt task stack, and data related to any kernel objects created. In other stacks such as Network or USB, the heap is used for service tasks related to the stack, as well as any internal data structures that must be created. Unfortunately, because everything is so configurable, it is not possible at compile time to determine the exact size of the heap that is needed before runtime. This means it is imperative that all return values from any Micrium OS call are checked.

The size of the heap is configured in common_cfg.h. To change the size of the heap, locate the following line:

#define  LIB_MEM_CFG_HEAP_SIZE  XXXXuL

If an assert is hit with the error RTOS_ERR_SEG_OVF, this means the heap size is too small and needs to be made larger.

Note that this heap is provided by the Common module of Micrium OS, and is not the general-purpose C heap that would be used with the standard malloc-type functions. That general-purpose heap is configured through the linker file and is outside the scope of Micrium OS, which does not use the standard malloc(). Micrium OS applications should never use the malloc functions.

This heap is one of an indefinite number of memory segments (see Mem_SegCreate()). When a Micrium OS module, or the application, allocates space on a memory segment (see Mem_SegAlloc()), it specifies a pointer to the memory segment to use. Passing the value DEF_NULL will result in allocating the memory on the heap. By default, all Micrium OS modules will get their required memory from the heap. This, however, is configurable for each module, by calling the function <module>_ConfigureMemSeg() before initializing the module with <module>_Init(). Each module can therefore use isolated memory sections, either onboard the MCU or in external RAM.

Error Handling#

The last parameter of any Micrium OS function is reserved for the error pointer. The error pointer is always an RTOS_ERR structure. The error structure is defined as:

typedef  struct  rtos_err {
    RTOS_ERR_CODE     Code;         /**< Err code enum val.                         */
#if (RTOS_ERR_CFG_EXT_EN == DEF_ENABLED)
#if (RTOS_ERR_CFG_STR_EN == DEF_ENABLED)
    CPU_CHAR const   *CodeText;     /**< Err code in string fmt.                    */
    CPU_CHAR const   *DescText;     /**< Err desc string.                           */
#endif
    CPU_CHAR         *FileName;     /**< File name where error occurred.            */
    CPU_INT32U        LineNbr;      /**< Line nbr  where error occurred.            */
#ifdef PP_C_STD_VERSION_C99_PRESENT /* Only present if C99 enabled.                 */
    const  CPU_CHAR  *FnctName;     /**< Fnct name where err occurred.              */
#endif

After every Micrium OS API call, you should always check the return value of RTOS_ERR. Since the error return is a struct, Micrium OS provides a set of macros to access parts of the struct to future-proof code from any possible changes to RTOS_ERR in the future. These macros are:

  • RTOS_ERR_CODE_GET(err_val)

  • RTOS_ERR_STR_GET(err_code)

  • RTOS_ERR_DESC_STR_GET(err_code)

  • RTOS_ERR_SET(err_var, err_code)

  • RTOS_ERR_COPY(err_dst, err_src)

As shown in the declaration of RTOS_ERR, you can enable or disable all of the fields except the code variable. This is accomplished using the following defines in rtos_err_cfg.h .

#define

Result

RTOS_ERR_CFG_EXT_EN

DEF_ENABLED: use and populate the extended error fields for file name, line number, and – if C99 is enabled – the function name, where the error occurred.

RTOS_ERR_CFG_STR_EN

DEF_ENABLED: allow for the error’s string-name and descriptive text to be saved in RTOS_ERR. This is useful if you want to log the errors to a file and review it at a later time. Requires RTOS_ERR_CFG_EXT_EN to be enabled.

Assertions#

Micrium OS has four assertion macros that can be used to check error conditions:

  • RTOS_ASSERT_CRITICAL(expr, err_code, ret_val)

  • RTOS_ASSERT_DBG(expr, err_code, ret_val)

  • APP_RTOS_ASSERT_CRITICAL(expr, err_code, ret_val)

  • APP_RTOS_ASSERT_DBG(expr, err_code, ret_val)

The first two macros are used only for internal Micrium OS code. The second two macros are provided for you to use in your application if you wish.

The critical asserts are used to check for an irrecoverable error. These can typically occur when incidences such as a stack overflow have occurred and made unexpected changes to kernel objects or stacks. The internal and application critical asserts map to another macro called CPU_SW_EXCEPTION() which will lock the system. Due to this, you should always have a watchdog enabled so it can properly restart the system if an error occurs.

The debug asserts typically check for conditions that are caused by invalid parameters or invalid configurations. They are used to notify you that something is not correct with the way the code is being used. These asserts can and should be disabled once development is completed. To disable the debug asserts, set RTOS_CFG_ASSERT_DBG_ARG_CHK_EXT_MASK in rtos_cfg.h to RTOS_CFG_MODULE_NONE.