Monday, August 1, 2016

ArduinoMEGA on Eclipse without Arduino SDK

More than being quite limited, the Arduino IDE comes with its own SDK, which means we can't have our own main() function. I chose Eclipse because it's free and easy to use and there are a few tutorials around on how to use an Arduino board with Eclipse IDE. So, I read lots of them and came up with my own step by step:

  1. On Windows:
    1. Download and install Eclipse IDE for C/C++ Developers (today, the latest is Mars 2)
    2. Download and install WinAVR (today, the latest is 20100110)
    3. Open Eclipse, go to Help > Install New Software.... Add the following to the "Work with" section: http://avr-eclipse.sourceforge.net/updatesite and install the plugin.
    4. Done!
  2. On Linux (Ubuntu in my case):
    1. Install Eclipse
      1. sudo apt-get install eclipse
    2. Install AVR compiler
      1. sudo apt-get install avrdude binutils-avr gcc-avr avr-libc gdb-avr
    3. Open Eclipse, go to Help > Install New Software.... Add the following to the "Work with" section: http://avr-eclipse.sourceforge.net/updatesite and install the plugin.
    4. Add your user to the dialout group, then logout and login again (this is in order to your user have permission to access the serial port).
      1. sudo usermod -a -G dialout <username>
    5. Done!


Wait, what? This is it? Yep! Unless you didn't install WinAVR on its default location (C:/WinAVR-20100110). In that case, you'll need to adjust the paths in the AVR Eclipse plugin (on Eclipse, go to Window > Preference > AVR > Paths):
  • AVR-GCC: <WinAVR path>\bin
  • GNU make: <WinAVR path>\utils\bin
  • AVR Header Files: <WinAVR path>\avr\include
  • AVRDude: <WinAVR path>\bin

Yes, this screen is from Ubuntu.

Now let's create a first project just to check whether it works. Can you guess? A Blink project! This time, we won't use any of the easy Arduino stuff. Instead, let's open the microcontroller datasheet and start configuring the registers. In Eclipse, go to File > New > C++ Project (in Linux, you'll go to File > New > Project and choose C++ Project under C/C++ Folder).
  1. Choose the Empty Project under the folder "AVR Cross Target Application"


  2. Pick a name (Blink) and a location
  3. Click Next
  4. Click Next again
  5. Choose the MCU (ATmega2560) and Frequency (16000000 - that's 16 followed by 6 zeroes, 16MHz)
  6. Click Finish
  7. Go to the project properties (click with the left button on the project and go to Properties)
  8. Under AVR > Target Hardware you can check if the MCU and frequency were correctly chosen

  9. Under AVR > AVRDude, in the box Programmer Configuration, click New....
  10. Choose the bootloader version (Atmel STK500 Version 2.x firmware), choose a name for the configuration, choose the correct COM port in "Override default port" (use the Device Manager in Windows -i.e. COM18 -, or, in Linux, the command line "dmesg | grep tty" and remember to put "/dev/" before the port name - i.e. /dev/ttyUSB0), and override default baudrate with 115200  and click OK.
  11. Still on the Project Properties, go to C/C++ Build > Settings. On the tab Tool Settings:
    1. Additional Tools in Toolchain, check "Generate HEX file for Flash memory"
    2. AVR Compiler > Optimization, Optimization Levels: Size Optimization (-Os), uncheck Pack Structs and Short Enums
    3. AVR Compiler > Language Standard, uncheck "char is unsigned" and "bitfields are unsigned"
    4. Do the same to AVR C++ Compiler
  12. Now for the source code files, click with the left button on the project folder (in Project Explorer) and go to New > Folder, choose the project and the name ("src") and click Finish. Again in the Project Explorer, left click on new folder and New > Source File, choose the name ("blink.cpp") and Finish.
  13. Copy the following source code to your file.
    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    int main(void)
    {
     //Setup the clock (timer 1, 62.5kHz (16MHz / 256 = 62.5kHz), CTC mode, interrupt on)
     cli(); //Disable global interrupts
     TCCR1A = 0b00000000; //no physical outputs (COM1Ax, COM1Bx and COM1Cx == 0b00), WGM10 and WGM11 = 0.
     TCCR1B = 0b00001000; //input capture off, WGM13 = 0, WGM12 = 1, prescaler 1/256 (CS1x = 0b100 - off by now, thus 0b000)
     TCCR1C = 0b00000000; //writing a 1 to any of the 3 most significative bits forces a compare match
     TCNT1 = 0x0000; //resets the timer counter
     OCR1A = 62499; //Count 62500 cycles for 1 second interrupt
     OCR1B = 0x0000; //output compare register B is not used
     OCR1C = 0x0000; //output compare register C is not used
     ICR1 = 0x0000; //input capture not used
     TIMSK1 = 0b00000010; //input capture interrupt off, output compare B and C interrupts off, output compare A interrupt on, overflow interrupt off
     TIFR1 = 0x00; //resets the interrupt flags
     TCCR1B |= 0b00000100; //turn on the timer (CS1x = 0b100)
     sei(); //Enable global interrupts
    
     //Setup the I/O for the LED (digital pin 13, or PB7, according to the Arduino pin mapping)
     DDRB = 0b10000000; //PB7 is digital pin 13 (LED), configured as an output
     PORTB |= 0b10000000; //Set PB7 high to turn on LED
    
     while(1) { } //Loop forever, interrupts do the rest
    }
    
    ISR(TIMER1_COMPA_vect) //Interrupt Service Routine - flag is cleared automatically
    {
      PORTB ^= (1<<PB7); //Use xor to toggle the LED
    }
  14. Build it (Ctrl+B)
    1. Edit: If you're using Windows 10 (or other versions) and encountered this error: make: *** [src/blink.o] Error -1073741502, follow the steps on this post.
  15. To transfer to the board, there's a little catch (in Windows): seems like Arduino IDE uses a modified version of AVRDude that resets the board before attempting to upload the HEX file (this is needed in order to the Arduino enter the bootloader). So, if you get this timeout message, just hold the reset button on your board and release when you click the Upload button (that's the AVR button with an arrow pointing downwards, or CTRL+ALT+U).
    avrdude: stk500_2_Receive_Message(): timeout
  16. Now modify the OCR1A to 6249, compile and upload again: The timer will run 10 times faster, thus the LED must blink faster, if it doesn't, well...find out what's wrong and tell me in the comments box :)

Right now you should have a working hardware, with a working IDE and burner (close enough).
The project is available on GitHub.

On the next post, let's talk business and start porting the FreeRTOS.

Wednesday, June 1, 2016

Arduino's guts

After a long period of FreeRTOS posts, it's time to go back to Arduino to check some peculiarities. One of the great things that comes with an Arduino, besides the hardware ready to use out-of-the-box, is the Bootloader already burned in it. This means there is no need for the user to buy an expensive AVR programmer to work with it, you just have to plug it in an USB port and Download your application.

This bootloader uses a communication protocol originally developed by Atmel for the STK500 starterkit [http://www.atmel.com/Images/doc2525.pdf], which is why the protocol has this name. I believe there is no need to understand exactly how the protocol works, but a few remarks should be done. The bootloader will occupy some space in memory and that space mustn't be erased/overwritten, otherwise the bootloader is lost and we'll have to burn it again [https://www.arduino.cc/en/Hacking/Bootloader?from=Tutorial.Bootloader]. This can be prevented by correctly configuring the linker to only use addresses far from the bootloader and to place the main() function on the correct address that will be called.

So, let's check those information. First of all, we need to find the version of the bootloader that runs in our Arduino, so there goes a nice tip: send the string "!!!" to the Arduino just after it resets (you can use a serial terminal application, such as RealTerm [http://realterm.sourceforge.net/]). This will send us to the "Arduino Explorer" (a kind of terminal with a few commands we can send to the bootloader). So, press "H" to show the available commands: one of them should be "?=CPU stats" that will show which version is used. Step by step:

  1. Connect Arduino Board to your computer
  2. Open RealTerm and select the COM Port and Speed (115200), connect to COM Port
  3. Preset the string to be sent: "!!!" (3 exclamation points)
  4. Quickly, press the reset button on Arduino and send the String (this should be done within 1 or 2 seconds)
  5. Send "H" to check the available commands
  6. Send "?" to check the CPU Stats

In my case, the bootloader is the STK500v2 compiled in September 9th 2010 running on a ATmega2560. If you already installed the Arduino IDE, it's possible to analyze the code, under C:\Arduino\hardware\arduino\avr\bootloaders\stk500v2 (you can open the Programmer's Notepad project file STK500V2.pnproj).

Let's check some of the information we need to configure the linker in our port. First open the makefile of the bootloader and locate the part where the config variables for your board are. In my case, it's a mega2560, thus around line 337. One of the configurations is the BOOTLOADER_ADDRESS, set to 3E000 (hexadecimal), which means that the bootloader uses the last 8KB of read only memory (atmega2560 has 256KB of ROM, 0x3E000 == 248KB, 256 - 248 = 8KB).

Ok. From the paragraphs, please only remember the protocol your board uses (STK500v2) and that the maximum size of your program will have to be 248KB, which is a lot. I was writing and studying the subjects at the same time and just realized we won't have to configure much on the linker. If we were using an on board programmer, such as an ISP or JTAG, that doesn't communicate with the bootloader, than yes, we would have to take good care of the where the program would be programmed, but we're not. We'll actually use the bootloader through a serial connection and the bootloader will store our program in the ROM.

Enough with the bootloader, now: where is Arduino's main function? When you're using Arduino IDE, you have the setup() function, for configuring what you'll use, such as an analog output, a serial communication, etc, and the loop() function, which is basically what is in a while(1) loop. But what calls those functions? This is the job of the core library, which can be found under C:\Arduino\hardware\arduino\avr\cores\arduino. In the file main.cpp is defined the main() function, which initializes the microcontroller (function init()). Another few interesting functions are in wiring.c, such as the timer0 overflow interrupt, responsible for counting mili and microseconds (remember the delay() function?), and the init() itself. The wiring_analog.c has the analogRead() and analogWrite() definitions. pinMode(), digitalRead() and digitalWrite() are in wiring_digital.c.
int main(void)
{
    init();
    initVariant();

    #if defined(USBCON)
    USBDevice.attach();
    #endif

    setup();

    for (;;) {
        loop();
        if (serialEventRun) serialEventRun();
    }

    return 0;
}

FreeRTOS won't use any of this, as my intention is to have the RTOS running on the board as close to any other implementation as possible. This means that the main function will be the one defined in FreeRTOS' code and we won't have any loop() or setup() or digitalWrite() funcions. We're basically using the ArduinoMEGA as a development board that already comes with an easy to use bootloader and nothing more. The whole Arduino SDK will be nothing more than an application that we know it works and we can check for some configuration to use in our FreeRTOS port.

Next step will be to get Eclipse up and running with everything we need to upload our FreeRTOS.

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