Wednesday, March 30, 2016

Full demo - FreeRTOSConfig.h

This file is a big deal. Each application should have its own (application, not port) and that's where much of the customization is made. It is mostly comprised of definitions which turn ON or OFF some feature (usually a kernel's feature) that you need in your application. Remember those definitions started with "config", such as configUSE_IDLE_HOOK? In FreeRTOSConfig.h you will find, young Padawan. In this post I'll list and explain briefly all those you will find in the Full Demo for Windows. More detailed info can be found in FreeRTOS' website [1].

  • configUSE_PREEMPTION: this chooses the scheduler, whether preemptive or cooperative. Preemptive scheduling means the task will be stopped in order to other task take place on the processor. Cooperative scheduling will patiently wait until the task kindly leaves the processor (either if its execution finished or it went to sleep, etc).
  • configUSE_PORT_OPTIMISED_TASK_SELECTION: there is usually two kinds of task selection, a generic one, which was written in C and can be used in any port, or an optimized one, usually written in the port's specific assembly and optimized to the port. The generic doesn't have a limit in the amount of priorities for the task, while the optimized is usually limited to 32.
  • configUSE_IDLE_HOOK: this chooses whether the Idle Hook will be used or not.
  • configUSE_TICK_HOOK: this chooses whether the Tick Hook will be used or not.
  • configTICK_RATE_HZ: this is the frequency of the tick interrupt, when the task is stopped to make place to another one (or maybe not). Care must be taken when you choose this value, as the higher the frequency, the more the overhead caused by the context switching will matter. For all the demo projects, it's set to 1000 Hz, and that's a good starting number.
  • configMINIMAL_STACK_SIZE: this is the size of the stack used by the Idle Task and shoul not differ from the one specified on the demo project of the port you're using. It is specified in words, as in the xTaskCreate() function, thus, if your microcontroller/microprocessor uses a 32-bit (4 bytes) wide stack, a stack of 50 words will mean 200 bytes.
  • configTOTAL_HEAP_SIZE: total amount of RAM available to the RTOS kernel. This is only used in certain cases of memory management [2] and I'll discuss that soon.
  • configMAX_TASK_NAME_LEN: the maximum length of the task's descriptive name (the one you write on xTaskCreate()), including the ending NULL char.
  • configUSE_TRACE_FACILITY: enables a few more trace capabilities, in order to assist with execution visualization.
  • configUSE_16_BIT_TICKS: this specifies the size of the variable that counts the ticks. If the config is set, the type (TickType_t) will bean unsigned 16-bit, other wise, it will be 32-bit wide. With a tick rate of 1 kHz and a 16-bit counter, the max amount of time that can be counted is 65535 ticks or 65.535 seconds, instead of 2^32 (4294967296) ticks or around 1193 hours. 8 and 16-bit ports can benefit a lot when setting this option, since the overhead of treating a 32-bi variable can be high.
  • configIDLE_SHOULD_YIELD: if the preemption is being used and there are user tasks with Idle priority, this option tells the idle function to Yield whenever there is another task with the same priority ready to be executed. This means the Idle task will let another task take the remaining time it had (which will be less than one tick). This can lead to a task having less execution time than others with the same priority (imagine tasks A, B and C, where A is always executed when the idle task yields, while B and C take full Ticks), which can be prevented by increasing the other tasks priority.
  • configUSE_MUTEXES: enables Mutex capabilities (check Generic Queue Tasks).
  • configCHECK_FOR_STACK_OVERFLOW: chooses between not using a stack overflow control (set to 0) and two methods of checking (options 1 and 2). It will be discussed soon, but what you should know by now is that, if the config != 0, then you should have a Stack Overflow Hook.
  • configUSE_RECURSIVE_MUTEXES: enables Recursive Mutex capabilities (check Recursive Mutex Tasks).
  • configQUEUE_REGISTRY_SIZE: defines the maximum number of queues and semaphores that can be registered for easier debugging. It only makes sense when using a RTOS kernel aware debugger.
  • configUSE_MALLOC_FAILED_HOOK: enables the Malloc Failed Hook function (vApplicationMallocFailedHook()), which will be called whenever the pvPortMalloc() function returns NULL, which means there were not enough memory left on the heap for the allocation.
  • configUSE_APPLICATION_TASK_TAG: enables the function vTaskSetApplicationTaskTag(), which will allow a tag value (or function) to be assigned to a task. This functionality is used for tracing purposes and an example can be studied here.
  • configUSE_COUNTING_SEMAPHORES: enables Counting Semaphores capabilities (check Counting Semaphore Tasks).
  • configUSE_ALTERNATIVE_API: enables the alternative queue API described in queue.h header. Should not be used as is deprecated (although is set on the Full Demo).
  • configUSE_QUEUE_SETS: enables the Queue Sets functionality (check Queue Set Tasks).
  • configUSE_TASK_NOTIFICATIONS: enables the Direct to Task Notification API (each task will consume 8 more bytes). See Notify Task.
  • configUSE_TIMERS: enables the Software Timers. See Timer Demo Tasks.
  • configTIMER_TASK_PRIORITY: sets the priority of the software timer task. Maybe later I'll go more into that.
  • configTIMER_QUEUE_LENGTH: sets the length of the software timer command queue (the maximum number of unprocessed requests).
  • configTIMER_TASK_STACK_DEPTH: sets the size (in Words) of the stack of the software timer task. Depends highly on the timer callback functions, as the context where the calls are made is the timer service task.
  • configMAX_PRIORITIES: sets the number of priorities available. The higher this number, the higher the amount of RAM spent, so should be kept as low as needed.
  • ulGetRunTimeCounterValue( void ): this is the prototype for a Run Time statistics function. This one, as the name intends, will return the time since the application started.
  • vConfigureTimerForRunTimeStats( void ): initializes the Run Time Statistics.
  • configGENERATE_RUN_TIME_STATS: enables the Run Time Statistics. When this is enabled, the two next macros have to be defined.
  • portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(): this is a macro to a function (in this case, vConfigureTimerForRunTimeStats()) that will initialize a higher resolution (higher than the tick rate usually by 10 to 100 times) timer. The function is usually port specific (the Full Demo for Windows uses the Windows API for that, but a microcontroller may use a hardware timer).
  • portGET_RUN_TIME_COUNTER_VALUE(): this is a macro to a function (in this case, ulGetRunTimeCounterValue()) that will return the current time. The function is also usually port specific, as is the initialization described above.
  • configUSE_CO_ROUTINES: enables co-routine functionality. Even though it is set on the Full Demo, I couldn't find where these co-routines were used. Maybe I'll write another post explaining them, although it should be discontinued in FreeRTOS [3].
  • configMAX_CO_ROUTINE_PRIORITIES: the maximum number of co-routines priorities, similar to configMAX_PRIORITIES.
  • configUSE_STATS_FORMATTING_FUNCTIONS: enables some functions for trace capabilities. If this and configUSE_TRACE_FACILITY are set, vTaskList() and vTaskGetRunTimeStats() may be used.
  • INCLUDE_xxxxxx: these macros force the insertion (or not) of some functions, even though the unused are usually no inserted by the linker.
  • AssertCalled( unsigned long ulLine, const char * const pcFileName );: prototype of the function called by configASSERT(). Check configASSERT().
  • configASSERT( x ): macro that calls the function described above. Check configASSERT().
  • TRACE_ENTER_CRITICAL_SECTION() and TRACE_EXIT_CRITICAL_SECTION(): macros for the entering and existing critical sections, used in trace. The functions are port specific. Check the official FreeRTOS+ Trace docs [4].
  • "trcKernelPort.h": header file for the trace capabilities. Check the official FreeRTOS+ Trace docs [4].
Well, those are all of the options included on the FreeRTOSConfig.h in our Full Demo application. The FreeRTOS website brings a few more options that were left out:
  • configUSE_TICKLESS_IDLE: this is used to enhance the low power capabilities by allowing the application to disable the ticks interruptions and sleep, if there is nothing else to be done (all tasks are blocked or suspended). It can be set to 1, in order to use a port specific implementation of tickless idle, or to 2, to use the generic implementation. More information may be checked on the FreeRTOS specific web page [5].
  • configCPU_CLOCK_HZ: sets the frequency, in Hertz (Hz), of the internal clock of the peripheral that generates the Tick interrupts runs (usually the same as the CPU clock). This parameter is used to correctly configure the timer peripherals.
  • configUSE_TIME_SLICING: when set to 0, the scheduler will let tasks with the same period to run until it wants to stop (may be blocked or suspended). If not set (the default option) or set to 1, the scheduler will change the running task among others with the same priority every Tick.
  • configUSE_NEWLIB_REENTRANT: if set to 1, a newlib reent structure will be allocated for each task created. Any newlib functionalities are not maintained by the FreeRTOS crew. More about that on newlib's website [6].
  • configENABLE_BACKWARD_COMPATIBILITY: this enables the use of older (FreeRTOS pre 8.0.0) structure names.
  • configNUM_THREAD_LOCAL_STORAGE_POINTERS: this set the amount of Thread Local Storage (TLS) pointer. In a multi threaded application, TLS is used to substitute a global variable, as it will be stored inside the task's control block (imagine each task wanted to have an error number variable, commonly called "errno", available to every other task) [7].
  • configKERNEL_INTERRUPT_PRIORITYconfigMAX_SYSCALL_INTERRUPT_PRIORITY and configMAX_API_CALL_INTERRUPT_PRIORITY: those options are used to set some interrupts priorities. configMAX_SYSCALL* and configMAX_API_CALL* are equivalent (the later is the new name). Together, the two options can be set in order to some specific interrupt allow the kernel itself to be stoped (maybe some emergency interrupt that has to be processed as soon as it happens). Check the official documentation for more info [8].
  • configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS: this allows the user to create privileged functions (defined and implemented inside the application_defined_privileged_functions.h file). This means the task will be able to access anything in the application (even memory outside the task's context). Check the example in FreeRTOS specific page [9].
  • configAPPLICATION_ALLOCATED_HEAP: when set, allows the heap to be positioned in a specific location [10].

Uff, that was a lot. See you soon!


[1] http://www.freertos.org/a00110.html
[2] http://www.freertos.org/a00111.html
[3] http://www.freertos.org/taskandcr.html
[4] http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_Trace/RTOS_Trace_Instructions.shtml
[5] http://www.freertos.org/low-power-tickless-rtos.html
[6] http://sourceware.org/newlib/
[7] http://www.freertos.org/thread-local-storage-pointers.html
[8] http://www.freertos.org/a00110.html#kernel_priority
[9] http://www.freertos.org/a00110.html#configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS
[10] http://www.freertos.org/a00111.html#heap_4