Tuesday, April 19, 2016

ATMega323 port

This post will talk about the portable part of FreeRTOS. As the Windows port is not exactly a port (the FreeRTOS actually runs on top of another operating system, which incurs in a few anomalies when the was made), I'll examine the Atmega323 for WinAVR port files, located under FreeRTOS\Source\portable\GCC\ATMega323. First of all, a quick review on the source file structure.

FreeRTOS Source Files Organization

When you download and extract the zip file containing the FreeRTOS [1], you'll see two directories: FreeRTOS-Plus and FreeRTOS. The first one comprises the FreeRTOS+ ecosystem [2] and the second, the FreeRTOS source code itself (I'll focus on that). Under FreeRTOS directory, there are 3 folders: License (only has the license itself), Demo (all the different official ports and demo applications available) and Source (the real time kernel source). The core RTOS kernel, contained under the Source folder, is comprised of basically three files: tasks.c, queue.c and list.c. The others (croutine.c for co-routine implementation, timers.c for software timers and event_groups.c) are optional.

Each ported processor will require some specific code (mainly the files port.c and portmacro.h), which, for the official ports, is located under FreeRTOS/Source/Portable/[compiler]/[architecture]. For instance, the ATMega323 port we'll check later can be found in FreeRTOS\Source\portable\GCC\ATMega323, as AVR-GCC (WinAVR [3]) is the compiler and ATMega323 is the architecture. The Windows port files we've been using can be found under FreeRTOS\Source\portable\MSVC-MingW.

As the memory management (heap) routines are also needed, the samples we discussed earlier are also provided in the portable layer/folder structure under FreeRTOS\Source\portable\MemMang. There you'll find the 5 sample heap implementations, but you can also write your own and place it there.

Under the Demo folder is where you'll find the specific demo applications source code, along with the common demo implementation code for several functionalities (queues, semaphores, timers, etc) I talked a few times about (here and here). Each official demo application has its own folder, named to indicate the port to which they relate, under FreeRTOS/Demo/ (this is where the FreeRTOSConfig.h is located, for example) as well as an official webpage [4]. Under FreeRTOS/Demo/Common/Minimal/, you'll find the basic implementation for the functionalities that is shared between several applications. The Windows port uses the file under FreeRTOS/Demo/Common/Full/, but that should be avoided, as those are deprecated.
The basic structure of the Windows port demo application can be seen below:

FreeRTOS/
 +- Demo/
 |   +- Common/Minimal/
 |   +- WIN32-MingW/
 +- Source/
     +- *.c
     +- include/
     +- portable/
         +- MemMang/
         +- MSVC-MingW/


Creating a new application

To create a new application from an existing port, the quickest path is to use a Demo application and modify it to fit your needs. Compile and run the standard demo project and, when it runs as expected, you can add and/or remove whatever you may want.

Official Porting Guide

Here, I'll give you a little resume on the official porting guide provided by FreeRTOS [5]. Later on, we'll check the ATMega323 port files.

So the first thing you should do is to familiarize yourself with the source files organization (done that!) and create a folder under FreeRTOS/Source/portable/[compiler]/[processor]. Copy an empty port.c and portmacro.h there (you can use complete files from other ports, just remember clean all functions and macro bodies and only leave the stubs). Create a directory for the demo project for the new port under FreeRTOS/Demo/[architecture_compiler] and add a copy of FreeRTOSConfig.h and main.c (remember to only leave the stubs and modify some of the options from the config file that are hardware dependent, such as the tick rate, heap size, etc - check my other post about that). Now create a new folder under [architecture_compiler] called ParTest and copy some version of ParTest.c with just the stubs inside. This file will have a few LED tests that should run when your port is working fine: setup a few GPIOs to be used as LED outputs, turn on, off or toggle specific LEDs (remember what I said in some earlier post? blinking LEDs is the hello world of the embedded applications).

Now that everything is in place, you can create a project (makefile) that will successfully compile (not run, as there are a lot of stubs to implement) everything:
  • The basic kernel: Source/tasks.c, queue.c and list.c
  • The portable bits: Source/portable/[compiler]/[processor]/port.c
  • Memory management: Source/MemMang/heap_?.c (choose one of them)
  • Application specifics: Demo/[architecture_compiler]/main.c and ParTest/ParTest.c
And the hard part: implementing the stubs. The official guide suggests to start from the pxPortInitializeStack(), as it's very architecture dependent.

ATMega323 port.c

The windows port is not really a conventional port, since the FreeRTOS runs over another operating system that is not real time, and there surely might be a few things to learn by examining it, but as not to waste any time, I'll examine the Atmega323 port for the WinAVR (AVR-GCC) compiler, since it'll be much closer to our goal of porting to an Atmega2560. The port files can be found under FreeRTOS\Source\portable\GCC\ATMega323/ and the demo project under FreeRTOS\Demo\AVR_ATMega323_WinAVR/. You can make an Eclipse project with the files (it's not ready, as was the Windows port project), but as this is for studies purposes, there is no need. I should just warn you of one thing:


Starting with the pxPortInitialiseStack() in port.c, as the official guide says. This function is responsible for initializing the stack of a task as if it has already been there, so that the context change runs as smoothly as possible. This means some data must be stored in a certain order so that it can be retrieved in the right order later.

StackType_t *pxPortInitialiseStack( 
                    StackType_t *pxTopOfStack, 
                    TaskFunction_t pxCode, 
                    void *pvParameters )

First the types:

  • StackType_t, is defined in portmacro.h as a portSTACK_TYPE, which is defined as a uint8_t. This represents the type of the data that will be stored in the stack (in this case, 1 byte-wide).
  • TaskFunction_t, is the return type that has to be used by the tasks. It's defined, in projdefs.h (Source/include/projdefs.h) as a pointer to a void-type function.
The parameters are: a pointer to the current top of the stack, a pointer to the start of the tasks code and a pointer to a set of parameters. This set of parameters is the same you define when creating the task with xTaskCreate(). 

Now to the code, you'll see the first thing it does is to insert a few values to the start of the stack (0x11, 0x22 and 0x33). I haven't actually found much about it, but since this demo was written a long time ago, I presume it was used before any stack overflow detection mechanism was implemented (a few other Demo projects I checked don't have this). Ok, so after each value is added to the stack, the pxTopOfStack pointer is updated to the next position.

Next, the address to the start of the code (pxCode) is added to the stack (as the address is 16-bit wide, it has to be added in two steps, LSB first). Next, the 32 CPU registers (ATMega323 has 32 general purpose registers, where the last 6 are actually 3 16-bit registers called X, Y and Z [6] page 11) are stored with a few singularities: the global interrupt flag is inserted just after register 0 (see ATMega323's SREG) and the address to the parameters is placed just before the X register (also in two steps, as the pxCode address). In the end, the new pxTopOfStack is returned.

Now let's check the context saving and restoring. Context saving means to save all internal registers of the microcontroller in order to, when a task goes back to running mode, it seems like nothing is changed. For instance, if the task stops in the middle of some calculations, a few values will be stored in the registers and those should be saved so that the calculations can go on. Context restoring means to get all the stored values and put them back to the correspondent register. Those functions (portSAVE_CONTEXT() and portRESTORE_CONTEXT()) are written in assembly and are responsible for saving the registers I described earlier. These two and the pxPortInitialiseStack() must be absolutely synchronized, otherwise the value of one register can end up in another and the tasks will most likely fail.

portSAVE_CONTEXT() uses the following assembly instructions (you can check ATMega323 datasheet page 233 [6] for that):
  • push r?: pushes the value in a register into the stack (the stack pointer is already in the right position)
  • in r?,<REG>: loads the value of an I/O Space Register (<REG>) to a Rx register
    • ps.: addresses 0x3D and 0x3E correspond to the Stack Pointer register addresses
  • cli: disables the global interrupts
  • clr r?: clears the register
  • lds r?,<variable>: load direct from RAM (the value in the <variable> is stored in r?)
  • st x+,r?: store indirect and post increment (the value in the address pointed by the X register is updated with the value in the r? register, then the value of X is incremented)
portRESTORE_CONTEXT():
  • ld r?,x+: that's the opposite from "st x+,r?", so the value addressed by the X register is stored in r?, then the value of X is incremented
  • out <REG>,r?: the opposite of "in r?,<REG>" (this time, the Stack Pointer registers are referenced by its names __SP_L__ and __SP_H__)
  • pop r?: pops a value from the stack to the register.
Ok, but when are these functions used? One time is when the task yields manually (i.e. calls vPortYield(), that, if you follow the defines, is the implementation of taskYIELD()). When the task is manually yielded, it has its context saved (a call to portSAVE_CONTEXT()), then the context is changed to the next task to run (you can check the vTaskSwitchContext() in tasks.c) and then the context of the new task is restored (a call to portSAVE_CONTEXT()). Another place those functions are used is when a Tick occurs and another task must take place (vPortYieldFromTick(): the process is the same I described, with the difference that the Tick count is incremented).

Another port function is configuring the timer to generate the tick (prvSetupTimerInterrupt()). This is very architecture specific, since the internal registers should be configured such as an event occurs at the Tick Rate. For ATMega323, the Timer 1 is used in Output Compare mode, the counter is reset after an interrupt and the prescaler is set to 64. In the end, the interrupt is enabled (it will actually only be enabled when the global interrupt flag is set). The interrupt routine is also defined in port.c and has two options: when the scheduler is preemptive (the scheduler stops the current task to other take place), vPortYieldFromTick() is called; when the scheduler is set to cooperative (each task has to yield itself), only the Tick Count is incremented.

Last, but not least, the xPortStartScheduler() function, as the name says, will start the scheduler. First, it calls the prvSetupTimerInterrupt() described above, then, restores the context (portRESTORE_CONTEXT()), which will configure the microcontroller to run the task pointed by pxCurrentTCB. In the end, there is a asm call to "RET", which is a subroutine return and all it does is put the next data in the Stack in the Program Counter (PC), which, if you remember from the pxPortInitialiseStack(), was the pxCode parameter, which is the address where the task code starts (it is added before any register is added to the stack, as it would happen when the Tick Interrupt happens - the point where the code stopped is saved to the stack, then the context is saved, starting from register r0).

As a final observation in this file, I just talk a little about the attributes signal and naked, that we see in some function definitions (at least I didn't know they even exist), such as interruptions. These are directives to the compiler change the way it builds its output. The signal attribute ensures that the compiler inserts code that will save and restore every register that has been used in the interruption code and that the return will be done by a "RETI" instruction instead of the original "RET", as the first will re-enable the interruptions on exit [7]. The naked attribute ensures that the compiler won't add any code to the start and end of the interrupt function, which means nothing will be saved nor restored and this will all be user's responsibility. This is specially useful when the Tick interrupt with preemptive scheduler occurs, since the context switch is done there. Without the attribute, a few registers would be saved to the stack, then the current context saved (causing the registers to be saved twice in the stack), the task context is changed, the new task's context is restored and finally the code produced by the compiler would restore the registers saved, losing the tasks context. Also, when naked is used, the return method ("RETI") must be explicitly declared.

ATMega323 portmacro.h

The portmacro.h contains a few definitions of variable types that are highly architecture dependent such as the portLONG, portSHORT, portSTACK_TYPE, portBASE_TYPE, etc. A few macros are also defined here, such as those for critical code management (you need to disable interruptions): portENTER_CRITICAL() first saves the Status Register, then disables the global interruption flag (even if it was already disabled) and pushes the saved Status Register to the stack; the portEXIT_CRITICAL() pops the saved Status Register from the stack and restores it (there is no need to re-enable the global interruption flag, since it is part of the Status Register). The portSTACK_GROWTH is defined according to the datasheet [6], page 22, where it says
"The Stack Pointer is decremented by one when data is pushed onto the Stack with the PUSH instruction (...)"
thus the portSTACK_GROWTH is defined as -1.



[1] http://www.freertos.org/a00104.html
[2] http://www.freertos.org/FreeRTOS-Plus/
[3] http://winavr.sourceforge.net/
[4] http://www.freertos.org/a00090.html
[5] http://www.freertos.org/FreeRTOS-porting-guide.html
[6] http://www.atmel.com/Images/doc1457.pdf
[7] http://www.freertos.org/implementation/a00012.html

Thursday, April 7, 2016

Memory Management - Heap? Stack Overflow?

Memory Management

Every new task created will require some RAM memory to be allocated by the RTOS kernel (both for the task control and for the task's stack) in a heap (basically an area in the memory known by kernel where everything is stored). The same happens to every queue, mutex, semaphore, etc. When some of those are deleted, the memory should (must?) be freed. In a common OS, with no time restrictions, this is performed by using malloc() and free(). The problem is that these commands are usually non deterministic (the time spent can vary), may take a lot of unnecessary code space, are not thread safe and can just not be available in the system. To solve these problems, the memory management algorithm is allowed to be written by the user, which means this is located rather than in the core code of the FreeRTOS, but in the portable layer. Instead of calling malloc() and free(), the kernel will call pvPortMalloc() and pvPortFree().


Nevertheless, FreeRTOS includes 5 sample implementations of the memory management unit that can be used. These are called "heap_*" and each has its own source file located in Source/Portable/MemMang (the Full Demo only uses the heap_5.c). Other implementations may be added and used, but one of those samples must be included in your project (the RTOS kernel will use it, even though the application uses another one). The 5 sample implementations are describe below.
  • heap_1.c: this is the simplest one and doesn't permit memory to be freed. This is used a lot, as lots of applications creates and initializes all the tasks, queues, semaphores, etc, at system boot and never delete them. The implementation simply divides an array as RAM is requested (the size of this "array", which is actually the size of the heap, is defined in FreeRTOSConfig.h as configTOTAL_HEAP_SIZE). The API function xPortGetFreeHeapSize() may be used to optimize this value. [1]
  • heap_2.c: this is similar to heap_1, but allow freeing memory. To keep it simple, there is no de-fragmentation algorithm, which means that adjacent free blocks aren't combined in one larger block (this is done in heap_4, it's called coalescence algorithm). This implementation should be used if the amount of memory freed and "malloced" are always the same, i.e., the tasks's stacks are always the same size or the amount of queue storage is always the same, otherwise, the memory may become fragmented into small blocks and future allocations may fail. configTOTAL_HEAP_SIZE controls the size of the heap. [2]
  • heap_3.c: just implements a wrapper so that the compiler library's free() and malloc() implementation are used. It just makes those functions thread safe. Beware that this implementation is not deterministic and will probably increase the kernel code size. configTOTAL_HEAP_SIZE has no effect. [3]
  • heap_4.c: works similar to heap_2, but implements a coalescence algorithm (combines adjacent free memory blocks into one larger block). This is quite useful when the application needs to allocate memory by itself (by the use of pvPortMalloc() and pvPortFree()), instead of using an API for that. If necessary, the heap can be located in a specific location (address) by setting the option configAPPLICATION_ALLOCATED_HEAP in FreeRTOSConfig.h and explicitly declaring the ucHeap[ configTOTAL_HEAP_SIZE  ] array (more details on [4]).
  • heap_5.c: implements all that heap_4 does, plus allows heap to be formed by several different sized blocks in RAM, instead of one contiguous huge block (i.e., one block starts at address A, with size X, the next starts at address B, with size Y, and so on). The heap is initialized by calling vPortDefineHeapRegions(), which takes as parameter a structure that describes it. Nothing can use the heap before this functions is executed. As Full Demo uses the heap_5, it has to call the function (you can check under prvInitialiseHeap() in main.c). More details can be seen in the official webpage [5].
A few tricks can be used when talking about the heap management. In systems where there is an external, slower, RAM, using two implementations at once allows task stacks and other RTOS objects to be placed in the fast internal RAM, while application data can be placed in the external one.

Stack Usage - Stack Overflow

The task stack is managed by the task itself, which has to be kept within the size determined at creation time (when xTaskCreate() is called). Sometimes, the task tries to use more memory than is available, which causes a popular problem, a common reason for the system's instability: a Stack Overflow.
To ease the debugging of this problem, FreeRTOS offers two mechanisms to check for stack overflow and call a function (hook) if that happens. The configCHECK_FOR_STACK_OVERFLOW, in FreeRTOSConfig.h, chooses between the two methods and, if one of the methods is chosen, a hook function must be provided (vApplicationStackOverflowHook()).

  • Method 1 (configCHECK_FOR_STACK_OVERFLOW set to 1): the stack pointer is checked whenever the task is swept out of the running state. If the pointer is out of boundaries, the hook is called.
  • Method 1 and 2 (configCHECK_FOR_STACK_OVERFLOW set to 2): the task's stack is filled with known values when the task is first created. Whenever the task is swept out of the running state, the last 16 bytes are check and, if any of those are not as predicted, the hook is called. This method can only be used in conjunction to the method 1.


[1] http://www.freertos.org/a00111.html#heap_1
[2] http://www.freertos.org/a00111.html#heap_2
[3] http://www.freertos.org/a00111.html#heap_3
[4] http://www.freertos.org/a00111.html#heap_4
[5] http://www.freertos.org/a00111.html#heap_5

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

Tuesday, February 23, 2016

Full demo - part 2

Well, a few things left unsaid. 


The Check Task

This is there to ensure everything is going as expected. It will run every 2.5 seconds asking each and every set of tasks described in the last post whether they're working fine and will print a "OK" message if so (that's the OK message you saw the first time you run the main_full program).
Each set of tasks has a "xAre*********TasksStillRunning()", which is implemented close to the tasks code and will return a value informing whether or not the functionality tested is ok. You'll notice the order of the tasks is different here from the part 1, but that's how it was implemented.
  • Timer Demo Tasks: xAreTimerDemoTasksStillRunning(), as each successful test of the Software Timer increments a counter, this function tests whether this value has changed, thus all is running fine.
  • Notify Task: xAreTaskNotificationTasksStillRunning(), as the functions and tasks increment counters whenever a notification is taken and given, this test will check whether the counting is changing and if every notification given is taken.
  • Interrupt Semaphores Tasks: xAreInterruptSemaphoreTasksStillRunning(), checks whether the counting semaphores are still working and the master is still running.
  • Event Group Tasks: xAreEventGroupTasksStillRunning(), checks whether the master and slave are still running and the ISR calls are ok.
  • Integer Math Tasks: xAreIntegerMathsTaskStillRunning(), checks whether the answer from the calculations keep being correct all the time.
  • Generic Queue Tasks: xAreGenericQueueTasksStillRunning(), check if the queues and mutexes keep on going well.
  • Queue Peek Tasks: xAreQueuePeekTasksStillRunning(), checks if the queue keeps on being peeked.
  • Blocking Queue Tasks: xAreBlockingQueuesStillRunning(), checks whether all the consumers and producers keep on consuming and producing.
  • Semaphore Tasks: xAreSemaphoreTasksStillRunning(), check if the sempahores are being taken and given.
  • Polled Queue TasksxArePollingQueuesStillRunning(), checks if the producer keeps producing and the consumer keeps consuming to and from the queue.
  • Math Tasks: xAreMathsTaskStillRunning(), same as integer math tasks, but this time there are more tasks testing the floating point operations.
  • Recursive Mutex Tasks: xAreRecursiveMutexTasksStillRunning(), checks if the controlling, blocking and polling tasks keep on running.
  • Counting Semaphore Tasks: xAreCountingSemaphoreTasksStillRunning(), checks if the semaphores keep on being incremented and decremented.
  • Suicidal Tasks: xIsCreateTaskStillRunning(), checks if the creator is still alive and creating and if no more than 4 extra tasks (besides all the other tasks that were created in this project) are created.
  • Dynamic Priority Tasks: xAreDynamicPriorityTasksStillRunning(), checks if everything is still running.
  • Queue Set Tasks: xAreQueueSetTasksStillRunning(), checks if all tasks are still running, if all queues are being used and if the ISR function is still sending values to the queues.
  • Queue Overwrite Tasks: xIsQueueOverwriteTaskStillRunning(), checks if the task and the ISR function are still working.
  • Queue Space Task: (not tested).

Idle Task/Hook

The Idle Hook is a function that runs every time the Idle Task runs, if configUSE_IDLE_HOOK is set to 1. The function, in this case, is defined in main.c (vApplicationIdleHook()) and only has a call to vFullDemoIdleFunction() (defined in main_full.c). It is used to demonstrate how one can use the Idle Hook to do something. 
The first thing it does is to sleep (15ms) just to allow any task that could have been terminated by the idle task to actually terminate. 
Then there are a few demonstrations (prvDemonstrateTaskStateAndHandleGetFunctions()), such as get the idle task handle (should be equal to the idle hook's handle) and the timer daemon handle. It also creates a test task (prvTestTask(), it doesn't actually do anything) to show what could be done with its handle (get its state, suspend, delete). This only happens once while the application is running.
Then there is a demonstration of pending a function call (prvDemonstratePendingFunctionCall()), that is, having the RTOS daemon task (timer service task) call some function (xTimerPendFunctionCall()).
Then, a mutex, created in main_full() function just to this purpose, is deleted to demonstrate the usage of  vSemaphoreDelete().
In the end, a test to heap_5.c is performed, by malloc'ing a random size void variable and freeing it.


Tick Task/Hook

Similar to the Idle Hook, the Tick Hook is a piece of code called whenever a Tick happens (defined in configTICK_RATE_HZ, in FreeRTOSConfig.h), if configUSE_IDLE_HOOK is set to 1. The function is defined in main.c (vApplicationTickHook()) and only performs the call to vFullDemoTickHookFunction(), defined in main_full.c. This is where most (maybe all?) the ISR functions described in part 1 are called, such as vTimerPeriodicISRTests(), from Timer Demo Tasks, xNotifyTaskFromISR() and vQueueSetAccessQueueSetFromISR().

Other Hooks

There are two other hooks defined: vApplicationMallocFailedHook(), which runs if configUSE_MALLOC_FAILED_HOOK is set to 1 and when a malloc (pvPortMalloc()) fails, and vApplicationStackOverflowHook(), which runs if configCHECK_FOR_STACK_OVERFLOW is set to 1 or 2 (which is not) and when (can you guess?) a stack overflow is detected.

On the next post, I'll talk about the FreeRTOSConfig.h, which I mentioned a few times here and there, but never gone further. See you soon!

Friday, February 19, 2016

Moving on: Full demo - part 1

Now that we understand the simple Blinky project, let's check a more complete demo project: the full main. Back in Eclipse, search for the string mainCREATE_SIMPLE_BLINKY_DEMO_ONLY in main.c (line 112) and change it back to 0. Compile (Ctrl + B) and Run (F11). A new string will appear in console every 2.5 seconds. First of all we must know that the main_full is a more comprehensive test and demo application. It has no particular function, but to show how everything works and relates, and also to be a starting point when creating your own project.



The main_full follows the standard FreeRTOS demo project [1] and as such, implements a task commonly called "Check" (prvCheckTask()), whose function is to check, from time to time (every 2.5 seconds in this case) whether all the other tasks are working correctly (I think I'll go further on this on the next post). It's this task which is posting the OK messages on console. The standard tasks created are (check on main_full() function; if you don't know it yet, Ctrl + Click on the name of the function will lead you to its definition):


  • Notify Task (vStartTaskNotifyTask(), implementation on the file FreeRTOS\Demo\Common\Minimal\TaskNotify.c or Standard_Demo_Tasks\TaskNotify.c under project explorer in Eclipse). This task is created with the Idle Task priority and its objective is to test the behavior of direct task notifications. It's important to say that the TaskNotify.c doesn't implement the direct task notification itself, but an API for that. The direct task notification implementation can be found on task.c (directory FreeRTOS\Source or under "FreeRTOS Source") and task.h (directory FreeRTOS\Source\include or under "FreeRTOS Source\include") [2]. The notifications are given at random moments by a software timer (prvNotifyingTimer(), http://www.freertos.org/RTOS-software-timer.html), created by the task, and by an ISR (xNotifyTaskFromISR()) and taken 4 times by the task itself (it tests several options, like clearing or not the notifications, bocking or not, etc).
  • Blocking Queue Tasks (vStartBlockingQueueTasks(), implementation on FreeRTOS\Demo\Common\Minimal\BlockQ.c or Standard_Demo_Tasks\BlockQ.c). This actually creates 3 sets of 2 tasks, each set working on its queue in a Consumer/Producer fashion [3]:
    • Set 1: The queue has only one position filled by the Producer (vBlockingQueueProducer) with an incrementing value and no blocking time. The Consumer (vBlockingQueueConsumer) will receive the value and compare it with the expected value, making use of the blocking time defined on the Queue function (remember from the "Understanding Blinky part 1"?). As the Consumer has a higher priority than the Producer (sent as parameter on main_full's call to vStartBlockingQueueTasks), it will always leave the blocking state as soon as the queue is filled, so there will always be room for the value when the Producer tries to send it.
    • Set 2: This is similar to Set 1, but this time the Producer can be blocked while waiting to fill the one position queue. It also has a higher priority, meaning the Consumer will always be blocked as soon as it reads the value from the queue.
    • Set 3: This time, both the tasks have the same priority, but the queue is longer and they both can block if there is no position to be written or value to be read. This means the queue can be read or written either when the queue is empty (the consumer blocks) or full (the producer blocks) or when a context switch happens.
    • An observation about this sets of tasks: they all use the same functions to create the task for the Producer and Consumer (vBlockingQueueProducer and vBlockingQueueConsumer) and the only difference are the parameters used for each. When the task is created, each will have its own stack with its own variables, but the code size will always be the same for 3 sets or 20. Also, the blocking time, when used, is always 1000 ms.
  • Semaphore Tasks (vStartSemaphoreTasks(), implementation on FreeRTOS\Demo\Common\Minimal\semtest.c or Standard_Demo_Tasks\semtest.c). Two sets of two tasks each are created in order to show how binary semaphores are used. Each set has a common variable whose access is protected by a semaphore. One set uses polling on the semaphore to check whether it's available (the task Yields if the semaphore is already taken - to Yield means the task goes to Ready state, allowing other tasks to run) and the other uses a blocking time (as on the Blocking Queue Tasks, it uses the blocking time defined on the Semaphore functions). When the tasks can use the common variable, they clear it and count it back up to a predefined value, in order to make use of some processing time and be sure that their processing time will end. This ensures the semaphore blockage is working correctly. 
    • A few observations: all the tasks use the same function prvSemaphoreTest(), which receives as parameters, among others, the blocking time, if there is one, and a pointer to the common variable; also, the blocking time, when used, is 100 ms. The tasks priority is set on the main_full call to vStartSemaphoreTasks().
  • Polled Queue Tasks (vStartPolledQueueTasks(), implementation on FreeRTOS\Demo\Common\Minimal\PollQ.c or Standard_Demo_Tasks\PollQ.c). The aim of this is to show how to use the queue without blocking any task, but using the polling method. Two tasks (one Consumer and one Producer) and a queue with 10 positions are created. The producer will fill the queue with 3 consecutive values and sleep (block) for 200 ms. The consumer will check if there are any values stored in the queue by using the function uxQueueMessagesWaiting() and, if there are, it will read all the available values, emptying the queue, so that whenever the Producer runs, there is always free position to be filled. In the end, it will also sleep for 200 ms.
  • Integer Math Tasks (vStartIntegerMathTasks(), implementation on FreeRTOS\Demo\Common\Minimal\integer.c or Standard_Demo_Tasks\integer.c). This is a good test to the context switching of the RTOS. It creates a single task that performs a calculation between 'long' variables with a known result. If the result calculated is as predicted, then the context switching is working fine, otherwise something is wrong (registers may not be saved correctly, maybe something with the stack, etc).
  • Generic Queue Tasks (vStartGenericQueueTasks(), implementation on FreeRTOS\Demo\Common\Minimal\GenQTest.c or Standard_Demo_Tasks\GenQTest.c). Performs a few other tests regarding the usage of queues. Four tasks, one queue and one mutex are created:
    • prvSendFrontAndBackTest(): tests the functions xQueueSendToFront() and xQueueSendToBack() by filling the queue with this functions, then reading and comparing whether all was added correctly.
    • prvLowPriorityMutexTask()prvMediumPriorityMutexTask() and prvHighPriorityMutexTask(): they test the usage of the mutual exclusion (MutEx) mechanism [4]. The mutex is basically a binary semaphore with priority inheritance, which means that when a higher priority task asks for a mutex that is held by a lower priority task, the priority of the second is raised to the first's in order to ensure the higher priority task will remain in blocked state for a minimal amount of time.
  • Queue Peek Tasks (vStartQueuePeekTasks(), implementation on FreeRTOS\Demo\Common\Minimal\QPeek.c or Standard_Demo_Tasks\QPeek.c). Performs the operation Peek on a Queue. Peeking means the value will be read from the queue, but not deleted, so that other tasks can read it too. A total of 4 tasks are created, each with a different priority, in order to show how tasks wake while peeking and reading the queue.
  • Math Tasks (vStartMathTasks(), implementation on FreeRTOS\Demo\Common\Minimal\flop.c or Standard_Demo_Tasks\flop.c). Very similar to Integer Math Tasks, but using floating point calculations. Four different tasks are created all with the same priority as the Idle Function, which makes them a good test to the scheduler (all should run once in a while) and the context switching mechanism (the results are known prior to execution).
  • Recursive Mutex Tasks (vStartRecursiveMutexTasks(), implementation on FreeRTOS\Demo\WIN32-MingW\recmutex.c or DemosModifiedForLowTickRate/recmutex.c). Shows how the recursive mutex can be used. A recursive mutex is a type of mutex that can be taken several times by the same task, but also has to be given (returned) the same amount of times before another task takes it. Also, the priority inheritance explained earlier also apply. Three tasks are created: controlling, blocking and polling, with descending priorities. The first will take the mutex twice, with a delay in between, making the blocking task block and the polling one to keep polling, then it will give back twice, allowing the blocking task to wake up and take the mutex, and then suspends. The blocking task, after taking the mutex, will give it back and suspend, allowing the polling task to take it. When the polling task takes the mutex, it resumes the other tasks, which will try to take the mutex (held by the polling task) and block, making the polling task priority to be risen until it gives the mutex back, which it does and all the cycle repeats.
  • Counting Semaphore Tasks (vStartCountingSemaphoreTasks(), implementation on FreeRTOS\Demo\Common\Minimal\countsem.c or Standard_Demo_Tasks\countsem.c). Shows a simple usage of counting semaphores. Those are semaphores that can be taken and given several times (taking decrements and giving increments, from 0 to a maximum value defined when the semaphore is created). This can be used to signalize the occurrence of an event several times (several keystrokes, for instance), where the interrupt service of the event will give the semaphore and the handler will take it. Two tasks and semaphores are created: one whose semaphore starts with the max value and one that start with zero. Both give and take the semaphore endlessly, making it run from 0 to max and back to 0.
  • Dynamic Priority Tasks (vStartDynamicPriorityTasks(), implementation on FreeRTOS\Demo\Common\Minimal\dynamic.c or Standard_Demo_Tasks\dynamic.c). Creates two sets of tasks, one with three tasks and one with two tasks. The first set tests the access to a shared variable with the manipulation of its own priorities (vTaskPrioritySet()) and suspending the scheduler (vTaskSuspendAll() and xTaskResumeAll()). The other set tests the access to a queue also suspending the scheduler.
  • Queue Set Tasks (vStartQueueSetTasks(), implementation on FreeRTOS\Demo\Common\Minimal\QueueSet.c or Standard_Demo_Tasks\QueueSet.c). Tests the usage of Queue Sets [5]. Imagine a task receives messages of different types from several other tasks (one sends only a signal - a semaphore -, other sends one byte of data, one sends a stream, etc) and each must be processed differently. Usually, a struct is created as the data type of the queue, where the type and data can be indicated. The Queue Set is used for that, as you can add to the set several different queues and/or semaphores and the Receiver Task can block waiting for a message in any of those queues and semaphores with only one function call. In this case, two tasks are created (a receiver and a sender) and used along with a call for a function on the Tick Hook (that's the function that runs at every tick, thus running from an interrupt), also a queue set of size 9 is created (prvSetupTest()), meaning a max of 9 events can be stored, so 3 queues of 3 positions are added to the set. The Receiver Task (prvQueueSetReceivingTask()) always blocks waiting for a message from any of the elements on the set, then receives and tests it and start over. The Sender Task (prvQueueSetSendingTask()) only writes messages to a random queue on the queue set. The function called from the ISR (Interrupt Service Routine) first tries to read from the queue set (if there is a message waiting), then writes to one of the queue, like the sender (as it runs every tick, there is a counter to ensure that the queue set code only runs once every 100 ticks).
  • Queue Overwrite Tasks (vStartQueueOverwriteTask(), implementation on FreeRTOS\Demo\Common\Minimal\QueueOverwrite.c or Standard_Demo_Tasks\QueueOverwrite.c). Tests the usage of Queue Overwrite both from a task (prvQueueOverwriteTask()) and from an ISR (vQueueOverwritePeriodicISRDemo(), from the Tick Hook), each with its own queue. The overwrite function only works on queues with size 1 and is used to overwrite the value stored on queue (if there is any, otherwise, the new value is just added to the queue).
  • Queue Space Task (prvDemoQueueSpaceFunctions(), implementation on main_full.c itself). Tests a few other queue related functions, such as uxQueueSpacesAvailable(), which return the number of positions still available on the queue and xQueueReset(), which clears the queue.
  • Event Group Tasks (vStartEventGroupTasks(), implementation on FreeRTOS\Demo\Common\Minimal\EventsGroupDemo.c or Standard_Demo_Tasks\EventsGroupDemo.c). Event group is a set of event bits (or flags) that can be set, get, cleared or waited to be set (the whole group of flags or just part of it). Event groups can also be used as a synchronization (also called rendezvous) device. Four tasks are created (Master, Slave and two Synchronization Tasks) and a call from an ISR is made (vPeriodicEventGroupsProcessing()). The master first tests the blockage of tasks (the Sync Tasks) by the event group (each will wait for one of the flags on the event group in blocked mode and, when unblocked, will suspend), by using prvSelectiveBitsTestMasterFunction() (from the master) and prvSelectiveBitsTestSlaveFunction() (from the sync tasks). The second part starts by testing the blockage of a single task (the slave) from a single flag or a group of flags (the flags can be cleared by the blocked task after it unblocks) (see prvBitCombinationTestMasterFunction() and the slave task itself - prvTestSlaveTask()). Finally, it performs a few sync tests by itself and by using the other 3 tasks (the slave and the two sync tasks) (prvPerformTaskSyncTests()).
  • Interrupt Semaphores Tasks (vStartInterruptSemaphoreTasks(), implementation on FreeRTOS\Demo\Common\Minimal\IntSemTest.c or Standard_Demo_Tasks\IntSemTest.c). This tests the usage of semaphore, mutex and counting semaphore with interrupts, including the priority inheritance mechanism. Three tasks are created: a master (vInterruptMutexMasterTask(), which takes the mutex given from the ISR) and slave (vInterruptMutexSlaveTask(), which tests the inheritance mechanism) and a counting semaphore task (vInterruptCountingSemaphoreTask(), it waits until the ISR function has incremented the semaphore, then takes all the semaphores). The ISR function runs from the Tick Hook (vInterruptSemaphorePeriodicTest()).
  • Timer Demo Tasks (vStartTimerDemoTask(), implementation on FreeRTOS\Demo\Common\Minimal\TimerDemo.c or Standard_Demo_Tasks\TimerDemo.c). Creates and starts the maximum number of software timers the API can handle before they're started by the OS (20, defined in FreeRTOSConfig.h as configTIMER_QUEUE_LENGTH)  with timing multiple of 2.5 seconds, which only increments each its own variable by the end of the specified time (prvAutoReloadTimerCallback()). Then creates the timers used on the interrupt routines(prvISRAutoReloadTimerCallback() and prvISROneShotTimerCallback()), which also just increment its variables. A task for managing the timers is also created (prvTimerTestTask()), it tests several functions from the Software Timer API. There are also a few tests made from a function called from an interrupt (vTimerPeriodicISRTests()).
  • Suicidal Tasks (vCreateSuicidalTasks(), implementation on FreeRTOS\Demo\Common\Minimal\death.c or Standard_Demo_Tasks\death.c). This creates one task (the Creator) that creates 2 other tasks every 1 second. One of the created tasks will kill the other (vTaskDelete(xTaskToKill)) and then kill itself (vTaskDelete( NULL )).
Phew. That was a lot (and took me a lot to gather all this info). My suggestion: read this a few times, read the code of each of these tasks and functions and understand what is happening. Play around with the code, write a few printf's and this will get you more familiar with the OS. See you soon!

[1] http://www.freertos.org/a00102.html
[2] http://www.freertos.org/RTOS-task-notifications.html
[3] http://www.freertos.org/a00013.html
[4] http://www.freertos.org/Real-time-embedded-RTOS-mutexes.html
[5] http://www.freertos.org/Pend-on-multiple-rtos-objects.html