Turn-key PCB assembly services in prototype quantities or low-volume to mid-volume production runs

Using FreeRTOS kernel in AVR projects

FreeRTOS is known as Real-Time Operating System. Probably it would be too dare call it real-time-os, preferably a real-time scheduler where applications can be split into independent tasks that share full processor resources by switching them rapidly it looks like all functions are executed in parallel. This feature is called multitasking.

There are lots of debates on using RTOS on AVR microcontrollers as they are arguably too small for the running scheduler. The main limitation is a small amount of ram and increased power usage. If you are going to use lots of tasks in the application, probably you will run out of RAM that is used for saving context when switching between tasks. Consider FreeRTOS only if you use larger scale AVRs like Atmega128 or Atmega256. Surely you can find smaller schedulers that are specially designed for smaller microcontrollers even tiny series. In another hand, if you master FreeRTOS, it can be used with multiple types of microcontrollers like ARM, Cortex, PIC and various compilers including IAR, GCC, Keil, Rowley, Attolic. And the main reason to keep an eye on it – it is free.

Probably it would take lots of time and space to go through RTOS theory. Some great information can be found on the FreeRTOS website itself. In this series of posts, we are going to focus on the practical side of using RTOS on AVR microcontroller. We will go through several steps from a single task application to more complex solutions.

Things needed to start with FreeRTOS

To begin using FreeRTOS, we need to download it from https://www.freertos.org/. While writing this post latest version was FreeRTOSV7.0.1. In the downloaded package, you’ll find FreeRTOS source code files, ports to specific microcontrollers, and lots of example programs for various microcontrollers and compilers. We are going to use old good Piconomic Atmega128L development board with external memory expansion board that adds additional 8K of SRAM. You can choose any Atmega128 development board as far as it can blink LEDs, read buttons, and use USART. Programs will work fine on any of them. As a programming environment, we are going to use AVRStudio5, which is still entirely new and capricious. If you want to learn how to start working with AVRStudio5, check out this short tutorial.

Preparing AVRStudio5 project

First of all, we create a new project in AVRStudio5. For this, we select File->New Project and select the AVR GCC C Executable Project. Enter the proper location where your project will be stored.

Click OK. Then select DeviceAtmega128” from device list:

Click OK, and you are set up with the first project with the main program file that contains some initial code. As FreeRTOS package includes lots of files that we don’t need for our project we are going to copy necessary files to our folder. To make it easier to update FreeRTOS files with upcoming releases, we are going to maintain folder structure close to the original. To do so in our project tree, we are going to create a Source folder. To do so, click the right mouse button on the project folder and select Add->New Folder and type in Source. Now import following files to Source folder from downloaded FreeRTOS package Source folder:

Add all files that are in Source directory (including readme.txt). Adding files is simple – click right mouse button of Source folder and select Add->Existing Item and in file browser select necessary files (multiple select is possible!).

We have added only kernel C files. Now we have to take care of headers. For this, we need to create include folder inside the Source folder. Then add all files to it from FreeRTOS package include folder.

Now that we’ve taken care of FreeRTOS kernel we need port files. As you may know, port files are to support specific microcontroller hardware. Port files contain information on how to run SysTick timer and how to save and restore context to and from the task. Porting is an essential part if we need to support one or another microcontroller. FreeRTOS package already has lots of port options, and most likely you may find one that will support your selected MCU. In another case, you’ll have to write port on your own. As we are using Atmega128L microcontroller seems that included Atmega323 port works fine so we are going to use it for now. To include port files properly let’s create a folder named portable inside the Source folder. And then in the portable folder, we create a GCC folder. And in GCC we create a folder named ATMega323. Then import porting files port.c and portmacro.h to this folder from FreeRTOS package. Still, this isn’t finished with files. We also need memory management file heap_1.c, which takes care of allocating and freeing memory for tasks and queues. To add this file to the project, create MemMang folder in a portable folder and add a file from the same folder in the downloaded package. And lastly, FreeRTOS needs FreeRTOSConfig.h configuration file that keeps all freeRTOS related settings. Just import it from FreeRTOS\Demo\AVR_ATMega323_WinAVR.

To make things neat, let us create another folder Drivers in the project root directory. This will be used to store microcontroller peripheral drivers like USART, I2C, ADC, button, LED, and so on.

Before we are going to write some code, the project has to be configured. To start configuration go to menu Project->Properties. First, goto the Build tab.

This time we are going to configure the project as a release. Select Configuration as Release. So we need to generate .hex file (.map, .lss and .eep). These can be selected in the Build Artifact group.

In the Toolchain tab and Optimization select -Os optimization. And in Directories, you will need to include all directories containing .h files in your project(I only managed to get working only with absolute paths). Add GCC_MEGA_AVR in Defined Symbols to tell core that we are going to use GCC for AVR microcontroller.

FreeRTOS Configuration

FreeRTOS has several options that allow configuring applications for various needs. All predefined parameters are placed in FreeRTOSConfig.h file. Depending on what functions are you going to use some of them may be omitted. AVR microcontroller is too small to use all features of RTOS because of limited RAM. For instance, using the trace facility probably would be killing. So for our basic example, we are using the following settings:

#define configUSE_PREEMPTION        1
#define configUSE_IDLE_HOOK         0
#define configUSE_TICK_HOOK         0
#define configCPU_CLOCK_HZ          ( ( unsigned long ) 7372800 )
#define configTICK_RATE_HZ          ( ( portTickType )1000 )
#define configMAX_PRIORITIES        ( ( unsigned portBASE_TYPE ) 1 )
#define configMINIMAL_STACK_SIZE    ( ( unsigned short ) 85 )
#define configTOTAL_HEAP_SIZE       ( (size_t ) ( 3500 ) )
#define configMAX_TASK_NAME_LEN     ( 8 )
#define configUSE_TRACE_FACILITY    0
#define configUSE_16_BIT_TICKS      1
#define configIDLE_SHOULD_YIELD     1
#define configQUEUE_REGISTRY_SIZE   0
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES       0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet        0
#define INCLUDE_uxTaskPriorityGet       0
#define INCLUDE_vTaskDelete             0
#define INCLUDE_vTaskCleanUpResources   0
#define INCLUDE_vTaskSuspend            0
#define INCLUDE_vTaskDelayUntil         1
#define INCLUDE_vTaskDelay              0

We are going to use preemptive kernel engine where kernel timer tick ISR determines which task should run next according to task priorities. Preemptive multitasking is similar to OS like Linux or Windows. The preemptive kernel uses more RAM but is more flexible. Also, we aren’t going to use an idle hook for now – so disable it too and make idle task yield immediately once it is run. We won’t be changing task priorities during program flow so we disable this functionality too. We are going to use task delay utilities so leave them ON.

Each functionality that isn’t used frees some amount of memory. For low memory devices is very important to select these carefully.

After all project properties are set, we can start coding our first application. Why not start with a single task – LED blink. To make code modular, we will begin with writing LED library. So we need to write these routines and put in separate .c and .h files.

LED freeRTOS driver

We created a Drivers folder in our project root directory. Simply create LED.c and LED.h files by pressing the right mouse button on Drivers folder and selecting Add->New Item. AVRStudio5 will generate .c and .h templates where we can start writing our code.

We are going to control one LED connected to pin D6 in our test project. The writing driver is easy. First, we need to initialize the LED pin as output with a simple function:

void vLEDInit(void)
// Set LED_O as output pin
    DDR_LED_O |= (1<<BIT_LED_O);

and then write the LED toggle function that will be called by the task.

void vLEDToggle(void)
   //Toggle LED
   PORT_LED_O ^= (1<<BIT_LED_O);

that’s it.

Creating a task

Later we are going to add more tasks so let’s put them all in one separate source file. I created mytasks.c file along with mytasks.h. Let’s create simple tasks which will toggle LED every second. We already have LED toggling driver ready. The only thing left is managing proper delay so LED would toggle every second. FreeRTOS has a handy function that allows setting tasks delays when tasks should run. This is called vTaskDelayUntil(). It takes two parameters – previous wake time and ticks to wait. Now its a tricky part of all this. If you look back in FreeRTOSConfig.c file you’ll find a line:

#define configTICK_RATE_HZ          ( ( portTickType )1000 )

which means that kernel timer ticks every 1ms. To get the 1s delay, we need to wait for 1000 ticks. All we need is to set this number as the second parameter.

void vLEDFlashTask( void *pvParameters )
portTickType xLastWakeTime;
const portTickType xFrequency = 1000;
    for( ;; )

Function xTaskGetTickCount() returns current number of ticks calculated form program start. So we need to pass this number to our delay function as the first parameter. We are doing LED initialize before endless for(;;) loop. And task application goes inside an endless loop. Here goes our vLEDToggle() function and vTaskDelayUntil() function. vtaskDelayUntil function ensures that the task remains in the blocked state until the delay ends. So this means that blocked task isn’t scheduled until proper event unblocks it (in our case delay exceeds). If we would use idle task hook function for setting MCU to power save mode, our application would require less energy as your task is run only every 1s.

Running freeRTOS task

Once the task is created, consider the most significant job is done. Now what is left is to create this task in the main routine and start scheduler. Before we start, we must decide what priority task should be assigned. As we are going to use one task (plus idle) we can use idle priority:

#define mainLED_TASK_PRIORITY           ( tskIDLE_PRIORITY )

To create a task, we are going to use one handy function xTaskCreate(). It needs several parameters. First one is a task function name that has to be run. Second is a task name that can be freely chosen. Third parameter is stack size. Our application is very simple so minimal stack can be used. For more complex tasks select this parameter carefully. Then follows the pointer to parameters that have to be passed to tasks. If there is no parameters to pass use NULL. Following setting is task priority. And the last parameter is used to pass back a handle by reference so task could be addressed. Pass NULL as we aren’t going to use it. Our created task should look as follows:

xTaskCreate( vLEDFlashTask, ( signed char * ) "LED", configMINIMAL_STACK_SIZE, NULL, mainLED_TASK_PRIORITY, NULL );

And lastly, we must start scheduler which is our RTOS kernel. This is done by calling vTaskStartScheduler().

The compiled project occupies about 6K of Flash memory and uses 3,6K(88.5%) of RAM. So RAM is a limiting factor on how many tasks are you going to run and what complexity they are. If no preemption is required as alternative co-routines can be used as they can share a stack.

You can download the full project here: M128RTOS[~200K]


  1. Pingback: Running multiple FreeRTOS tasks on AVR | Scientific, embedded, biomedical, electronics contents.

  2. Pingback: Free RTOS on AVR Atmega128 tutorial | Embedded projects from around the web

  3. Hi,
    your instructions are nearly perfect for new commers like me.
    I wanted to ask you for a little optimisation in the following points.
    1) Ad some screenshots of the folder structure when you finished adding all the headerfiles from freeRTOS, just to be on the safe side.
    2) In the last paragraph before talking about the freertosConfig.h file, you talked about “including all directories containing .h files”. From where? FreeRTOS? If so, which ones. This also could be solved if you would add a small screenshot of the files that you are talking about.
    3) Add “GCC_MEGA_AVR” into “Defined Symbols”? A little elaboration with one or 2 screenshots would be great.

    Again those are my own humble recommendations, and I would appreciate it if you can find some time

  4. Thank you for suggestions. I’ll try to make these more clear when I find time. For now if you stuck at some point don’t hesitate to ask. And of course you can always download project archive to analyze it. It’s at the end of post.

    • Thank you for your answer.
      I’am stuck at these 3 points that where mentioned in my frist post.
      Where should the freertosCONFIG.h file located, if you consider that “./ ” represents the root if the project folder.

      “GCC_MEGA_AVR” into “Defined Symbols” What is meant by that?

  5. Thank you a lot for this lesson, actually i fellow all your steps, but an error has been appeared .

    undefined reference to ‘vApplicationIdleHook’ ..???!!

    What’s that? when i put comments mark before this function in tasks.c file, this error disappeared so i think something i missed in the initialization and declaration of RTOS files.
    I’ll be grateful if u could help me to fix this error

  6. at EreeRTOSconfig.h
    change this line #define configUSE_IDLE_HOOK 1
    to #define configUSE_IDLE_HOOK 0
    (that’s a guess )

    Good luck

  7. Hello

    When am I debugging the program and it comes to this line of code:

    /* The wake time has not overflowed, so we can use the current block list. */
    vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );

    The simulation stopped

  8. How do you debugging this project to AVR Debugger?

  9. Hello,
    I’m unable to import the FreeRTOSConfig.h file, the error says, cannot read such file, can some one pl help me.
    Thanks in advance.

  10. i guess there are few things worth noting here for the newbies like me:
    first, if you are downloading the project here then put it in D:\Elektronika\Projects\M128RTOS , or you can change the path from toolchain directories otherwise you will get can’t find the directory for some files.
    Second, you will need to change some outdated symbol
    and it will build successfully, then you can open proteus and just get atmega128 ,adjust the freq to external medium and in advanced properties remove default to 7372800Hz, and it will work perfectly!
    also i would like to thank Scienceprog for this amazing tutorial, it’s way better than that on the official freertos site.

  11. where can I find this file ? thanks
    Error 1 FreeRTOS.h: No such file or directory C:\Users\antonius\Documents\Atmel Studio\6.1\M128RTOS\freertosm128\freertosm128.c 9 22 freertosm128

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.