Position: Index > Unclassified >

Using FreeRTOS kernel in AVR projects

2017-11-25 15:07  
Declaration:We aim to transmit more information by carrying articles . We will delete it soon, if we are involved in the problems of article content ,copyright or other problems.

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

There are lots of debates on using RTOS on AVR microcontrollers as they are arguable too small for running scheduler. The main limitation is small amount of ram and increased power usage. If you are gonna use lots tasks in 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 other hand if you master FreeRTOS it can be used with multiple types of microcontrollers like ARM, Cortex, PIC and multiple compilers including IAR, GCC, Keil, Rowley, Attolic. And main reason to keep eye on it – its free.

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

Things needed to start with FreeRTOS

To start using FreeRTOS we need to download it from http://www.freertos.org/. While writing this post latest version was FreeRTOSV7.0.1. In 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 chose 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 programming environment we are going to use AVRStudio5 which is still quite 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 new project in AVRStudio5. For this we simplyFile->New Projectand select AVR GCC C Executable Project. Enter proper location where your project will be stored.

ClickOK. Then selectDeviceAtmega128” from device list:

ClickOKand yo are set up with basic project with main program file that contains some initial code. As FreeRTOS package contains 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 original. To do so in out project tree we are going to createSourcefolder. To do so just click right mouse button on project folder and selectAdd->New Folderand type inSource. Now import following files toSourcefolder from downloaded FreeRTOS package Sourcefolder:

add all files that are in Source directory (including readme.txt). Adding files is simple – just click right mouse button ofSourcefolder and selectAdd->ExistingItem 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 createincludefolder insideSourcefolder. 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 task. Porting is essential part if wee need to support one or another microcontroller. FreeRTOS package already has lots of port options and mos likely you may find one that will support your selected MCU. In other case you’ll have to write port by 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 lest create folder namedportableinsideSourcefolder. And then inportablefolder we createGCCfolder. And in GCC we create folder namedATMega323. Then import porting filesport.candportmacro.hto this folder from FreeRTOS package. Still this isn’t finished with files. We also need memory management fileheap_1.c, which takes care of allocating and freeing memory for tasks and queues. To add this file to project createMemMangfolder inportablefolder and add file from same folder in downloaded package. And lastly FreeRTOS needsFreeRTOSConfig.hconfiguration file that keeps all freeRTOS related settings. Just import it fromFreeRTOS\Demo\AVR_ATMega323_WinAVR.

To make things neat lets create another folder Driversin 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, project has to be configured. To start configuration just go to menuProject->Properties. First go toBuildtab.

This time we are going to configure project as release. SelectConfigurationasRelease. So wee need to generate .hex file (.map, .lss and .eep). These can be selected inBuild Artifactgroup.

InToolchaintab andOptimizationselect-Osoptimization. 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 to configure applications for various needs. All predefined parameters are placed in FreeRTOSConfig.h file. Depending on what functions are you gonna 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 trace facility probably would be killing. So for our basic example we are using 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. Preemptive kernel uses more RAM but is more flexible. Also we aren’t going to use 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 uses 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 to start with single task – LED blink. To make code modular we will start with writing LED library. So we need to write these routines and put in separate .c and .h files.

 

LED freeRTOS driver

We created aDriversfolder in our project rood directory. Simply create LED.c and LED.h files by pressing right mouse button onDriversfolder and selectingAdd->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. Writing driver is easy. First we need to initialize LED pin as output with simple function:

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

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

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

that’s it.

Creating 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. Lets create simple tasks which will toggle LED every one second. We already have LED toggling driver ready. The only thing left is managing proper delay so LED would toggle every second. FreeRTOS has handy function that allows to set 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. In order to get 1s delay we need to wait 1000 ticks. All we need is to set this number as second parameter.

void vLEDFlashTask( void *pvParameters )
{
vLEDInit();
portTickType xLastWakeTime;
const portTickType xFrequency = 1000;
xLastWakeTime=xTaskGetTickCount();
	for( ;; )
	{
		vLEDToggle();
		vTaskDelayUntil(&xLastWakeTime,xFrequency);
	}

}

Function xTaskGetTickCount() returns current number of ticks calculated form program start. So we need to pass this number to our delay function as first parameter. We are doing LED initialize before endless for(;;) loop. And task application goes inside endless loop. Here goes our vLEDToggle() function and vTaskDelayUntil() function. vtaskDelayUntil function ensures that task remains in blocked state until 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 task is create consider biggest job is done. Now what is left is to create this task in main routine and start scheduler. Before we start we must decide what priority task should be assigned with. As we are going to use one task (plus idle) we can use idle priority:

#define mainLED_TASK_PRIORITY			( tskIDLE_PRIORITY )

To create task we are gonna use one handy function xTaskCreate(). It needs several parameters. First one is 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 pointer to parameters that has to be passed to tasks. If there is no parameters to pass use NULL. Following parameter is task priority. And 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().

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

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


Reprinted Url Of This Article:
http://www.scienceprog.com/using-freertos-kernel-in-avr-projects/