Guide to FreeRTOS

Introduction To FreeRTOS

Demo Application

Content

1.Documentation

2.The source code

2.1MCU dependent files

3.Basic Task Switching

3.1Summary

3.2Cooperative (Round Robin) scheduling

3.3Preemptive scheduling

4.The RTA Demo

4.1Demo Tasks

4.2Demo configuration – FreeRTOS_Config.h

5.Tips, Debugging

Revision Record

1.Documentation

FreeRTOS is a free, preemptive, Real Time Operating System (RTOS) for microcontrollers, It is rather well documented at

Since FreeRTOS has plenty of documentation online. This document will only attempt to:

  1. Give some basic info on task switching.
  2. Briefly explain the Renesas demo project.The RTA demo project will serve as your reference material to this document.
  3. Give some tips on debugging. The latter should be added to with increasing experience!

If you want to use FreeRTOS on a Renesas MCU for which a HEW project is not currently not available,see“Adapting_FreeRTOS_to_H8S2378”. That document describes how FreeRTOS was adapted to aRenesas H8S/2378, what had to be changed and as a resource for future similar attempts.

2.The source code

Copy the workspace folder to your own local workspace folder and open the HEW project from there by double clicking on the .hws-file.

2.1MCU dependent files

2.1.1The FreeRTOSSource\portable directory

The directory ..\FreeRTOSSource\portable\ contains MCU specific files.

(1)Port.c and Portmacro.h

Port.c and Portmacro.h are common to all H8S and H8SX devices. Add Port.c to your project source files, and Portmacro.h traditionally is put in the..\FreeRTOSSource\include directory. That directory should be included in your include path.

(2)FreeRTOSPort.h

FreeRTOSPort.h is a file added by RTA for keeping MCU variant items apart from all other code.

For example, if you are using the H8SX/1582, put FreeRTOSPort(H8S2378TMR).h in your project directory and rename it FreeRTOSPort.h

The timer tick configuration for different MCUs reside in this file. Here are the different macros and what they do. You can change these macros to better suit your projects needs.

TMR_VECT Define which interrupt is the timer tick interrupt vector. The scheduler is clocked by this interrupt.
TMR_INT_PRIORITY() Define what interrupt level the timer tick interrupt should have.
CLR_TMR_INT() Define how the timer tick interrupt flag is cleared.
CONFIG_TMR() Defines which timer will cause the timer tick interrupt, and how this timer is set up.
TRAP_VECTDefine which interrupt you want to be executed if the trap instruction is called, this is used for the portYield (taskYield) function as we don’t want to call the same interrupt as for the tick interrupt since the tick increment should not be incremented for portYield.

3.Basic Task Switching

3.1Summary

Use this simple philosophy to get started with your project.

Cooperative:Have each task call taskYIELD once per loop. The tasks will be time sliced one after the other in a round robin manner. The only alteration to a round robin scheduling will be if you have a higher priority task and you use vTaskDelayUntil. Note: If preemptive scheduling is turned on, the tasks will be run consecutively at the timer tick and by calls to taskYIELD. (This could be confusing)
Preemptive:Tasks will be time sliced at the timer tick and when any OS-call is made. Tasks with higher priority will interleave tasks of lower priority (at interrupts and at timer ticks).

3.2Cooperative (Round Robin) scheduling

Context switches only occur if a task blocks with an OS-call or simply calls taskYIELD.This will cause task switching to be

Time sliced
Tasks will be switched only where you have placed an OS-call.

This may be preferred over having ‘unpredictable’switches at times and places of your codeif preemption were used.

Cooperative scheduling is achieved by setting

configUSE_PREEMPTION = 0

in FreeRTOSconfig.h.

It is important to realize that a task is always placed in its priority task wait list as soon as it makes any OS-call.

(1)taskYIELD

This OS-call is necessary to do in order to switch tasks when not using preemption. (Again; FreeRTOS will not time slice at e.g. the timer tick without using preeemption.)Use taskYIELDfor example once per task loop giving a round robin scheduling for tasks of equal priority.

(2)vTaskDelay/ vTaskDelayUntil

Put a task to rest for a specified time. This will cause the task to start participating in the time slicing again after the delay specified. These functions can be used by cyclical tasks to givea constant execution frequency, though not as exactly as can be achieved with preemptive scheduling.When the task is scheduled for run after the specified number of kernel ticks, a call to taskYield mustfirst have been called to by another task. If the task that called vTaskDelayUntil has a higher priority, it should be scheduled next.

3.3Preemptive scheduling

Always runs the highest available task. Tasks of identical priority share CPU time (fully pre-emptive with round robin time slicing).
Preemptive scheduling is achieved by instead setting

configUSE_PREEMPTION = 1

Preemptive scheduling can use the same OS-calls as above, but each timer tick, or when any OS-call is made, the tasks are rescheduled according to their priorities. The round robin mechanism among tasks of equal priority may then be temporarily disrupted by a higher priority task.

(1)taskYIELD

This simple OS-call can always be done to switch tasks when using preemption but when a round robin fashion is desired among tasks of equal priority. Use taskYIELDfor example once per task loop.

(2)vTaskDelay/ vTaskDelayUntil

This works the same as for a non-preemptive kernel except that the task will start running at the specified timer tick unless a higher priority task has become ready. This means it will not have to wait for another task to call taskYIELD.

(3)TaskResume

A key issue in preemptive scheduling is to be able to have an event(e.g. interrupt) force a certain task to immediately resume execution. The task will resume and later at a logical place put itself to sleep by calling the OS with for example taskYIELD.

(4)TaskSuspend

This call can suspend any task. TaskSuspend(0)suspends the calling task itself. When suspended a task will never get any microcontroller processing time, no matter what its priority, until TaskResume(taskhandlenr) is issued by another task.

4.The RTA Demo

The sample project demonstrates the following.

Creation of tasks When a task is created, the 4th argument void *pvParameters must point to any argument, or in data, needed by the task function. This argument may also be a structure if more than one parameter needs to be passed. This is typically the address of a certain queue, the address to a semaphore structure etc. If no arguments are needed, just pass NULL as the 4th argument.
Scheduling using the calls as per above. The demo can be run with or without preemption using the compiler switch

#define configUSE_PREEMPTION1

Semaphores
Queues
Mailboxes
Lists

4.1Demo Tasks

main()is not a task, but calls all sub tests below and then starts the scheduler. It also creates the vErrorCheckstask which checks that all tasks are running. The vErrorChecks task also periodically creates and deletes the vMemCheckTask to test that the heap is intact; that we have not run out of memory.

4.1.1vStartIntegerMathTasks

vStartIntegerMathTasks() creates a selectable number of vCompeteingIntMathTasks thatcrunch numbers and compete for CPU power in a round robin manner by using the same priority level and taskYIELD once per task loop. It also creates xAreIntegerMathsTaskStillRunningto check that all the created tasks are still running.

4.1.2vStartLEDFlashTasks

vStartLEDFlashTasks( )creates a selectable number of vLEDFlashTasksthat flash the board LEDS. Each taskgains CPU-time by using vTaskDelayUntil and demonstrates how to run a task at a fixed frequency (as ‘fixed’ as the RTOS can achieve.)

4.1.3vStartMsgQueueTasks

This part shows how to set up and use a mailbox.vStartMsgQueueTasks()creates two tasks that communicate over a single queue. One task acts as a producer, the other a consumer. The producer loops NR_TEST_MSGS times, posting messages of this type onto the queue:

static struct renesas_mailbox_s
{
unsigned char message_nr;
unsigned char message[NR_MSG_BYTES+1];
};
static struct renesas_mailbox_s send_msg;
static struct renesas_mailbox_s rec_msg;

These messages are posted cyclically by the producer task in order:

0, "RENESAS_A\0"
1, "RENESAS_B\0"
2, "RENESAS_C\0"
3, "RENESAS_D\0"
4, "RENESAS_E\0”

The producer then delays for a fixed period before doing the same over again.

The consumer receives, or consumes, the messages. The receive call is blocking, meaning that task stops at the OS-call until there is a message available. The task is thus put to rest while waiting for messages allowing other tasks to execute. One could as an alternative poll for any new messages (non blocking) and add a delay in the loop, but this should be considered a less effective use of the OS.

If one task were to send messages back to the other task, another queue would have to be created with

xPolledQueue2 = xQueueCreate(QUEUE_SIZE, … sizeof( struct renesas_mailbox_s ));

and a structure containing both queues would have to be created and passed to the task functions at task creation.

4.1.4vStartMathTasks

vStartMathTasks()creates eight tasks, each of which loops continuously performing an emulated (with library subroutines) floating point calculation. All the tasks run at the idle, lowest, priority and yield once per loop if non preemptive scheduling is used. If preemptive scheduling is used they never block or yield. This causes all eight tasks to time slice with the idle task. This means that these tasks will get pre-empted any time another task is ready to run or a time slice occurs. The pre-emption will most often occur mid calculation being a good test of the scheduler’s context switch.

4.1.5vStartSemaphoreTasks

This function creates two sets of two tasks. The tasks within a set share a variable, access to which is guarded by a semaphore. Each task attempts to obtain the semaphore. On obtaining a semaphore a check is done to ensure that the guarded variable has an expected value. The variable is then cleared before incrementing it back up to the expected value. Between each increment the variable is checked to ensure that it contains the value to which it was just set to make sure it has not been tampered with. When the starting value is again reached, the task releases the semaphore giving the other task a chance to do exactly the same thing.

4.1.6vStartDynamicPriorityTasks

This demo has an importance in showing the usage of vTaskSuspend and vTaskResume; the ability of a task to stop another task or itself and to resume execution of another task.Illustratedis also the usage of xTaskResumeAll, vTaskSuspendAll, and vTaskPrioritySet.

Three tasks are created; one continuous counter task (let’s call it CounterC), one ‘limited’ counting task(let’s call it CounterL) and one controller task (let’s call it Controller). A "count" variable is shared between all three tasks. The two counter tasks are never to be in a ready state at the same time. CounterL has the highest priority, and Controller and CounterC have equal priority.

CounterL(Limited counting task): Increments the shared count variable on each iteration of it's loop until the count has reached a limit of 0xFF where it suspends itself. It will not start a new loop until Controller has made it "ready" again by calling vTaskResume. Since CounterL operates at a higher priority than Controller so it does not need to worry about mutual exclusion of the count variable.

CounterC(Continuous counting task): Runs indefinitely incrementing the shared count variable on each iteration. To ensure it has exclusive access to the variable itraises it's priority above that of Controllerbefore each increment, then lowers it again.

Controller has two sections. The first controls and monitors CounterC’s continuous counting during which CounterLis suspended. Controller sleeps for a fixed period while CounterC increments the shared variable. When Controller wakes it checks that the continuous count task has executed by checking the shared variable. To ensure mutual exclusion, (and for demonstration purpose) vTaskSuspendAll is called. After a fixed number of iterations Controller suspends CounterC and sets the shared variable to zero.

The 2ndsection controls and monitors CounterL; when it is operational,CounterC is suspended. CounterL is woken from it's suspension by Controller with vTaskResume. As this counter task operates at a higher priority than Controller, CounterL will run until it suspends itself with vTaskSuspend(0). The next line after Controller’svTaskResumeof CounterL is therefore a check that the shared variable was indeed incremented to 0xFF by CounterL.

4.2Demo configuration – FreeRTOS_Config.h

The RTA demo is configured as follows:

/*------

* Application specific definitions.

*

* These definitions should be adjusted for your particular hardware and

* application requirements.

*

* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE

* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.

*------*/

#define configUSE_PREEMPTION1//Set to zero to run RTA demo w/o preemption.

#define configUSE_IDLE_HOOK0

#define configUSE_TICK_HOOK0

#define configCPU_CLOCK_HZ( ( unsigned portLONG ) 8000000 )

#define configTICK_RATE_HZ( ( portTickType ) 10 )

#define configMAX_PRIORITIES( ( unsigned portBASE_TYPE ) 4 )

#define configMINIMAL_STACK_SIZE( ( unsigned portSHORT ) 200 )

#define configTOTAL_HEAP_SIZE( ( size_t ) ( 20 * 1024 ) )

#define configMAX_TASK_NAME_LEN( 8 )

#define configUSE_TRACE_FACILITY0

#define configUSE_16_BIT_TICKS1

#define configIDLE_SHOULD_YIELD1

/* Added Renesas */

#define configKERNEL_INTERRUPT_PRIORITY 1

/* 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_vTaskPrioritySet1

#define INCLUDE_uxTaskPriorityGet1

#define INCLUDE_vTaskDelete1

#define INCLUDE_vTaskCleanUpResources0

#define INCLUDE_vTaskSuspend1

#define INCLUDE_vTaskDelayUntil1

#define INCLUDE_vTaskDelay1

#endif /* FREERTOS_CONFIG_H */

Go to and click on API then on Configuration for an explanation for each item.

Please refer to the project source code comments for further info on the demo. Use the Release debug session, as that was used to create the demo.

5.Tips, Debugging

This can be added to!

When you start to debug your code, take a note of all tasks’ Task Control Block addresses and preferably also their beginning stack addresses by setting a breakpoint right after

pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pvTaskCode, pvParameters );

To do this, note the addresses of pxNewTCB, and pxTopOfStack. This is so that if you run into crashes you can study that the TCB looks OK by checking that memory area. To aid in making sure you are reading the right TCB in RAM you will find the ASCII name of the task in the TCB.

To study the Task’s Control Block, the task must unfortunately be the current task. (Perhaps this could be improved in the future by adding a setting to the watch window to decipher a certain item as a TCB struct.)Study the current task by adding pxCurrentTCB to the Watch window. The TCB gives the following information:

1.Name of current task.

2.The priority of the task. This will tell you which xList pxReadyTasksListto look at. See below.

3.The start of the tasks stack, and the location of the last item placed on the task’s stack. (Useful to see if memory was corrupted.)

vTaskList can be used during code development to check the state of all tasks at a certain place in your code. This command will write task information to a buffer. The buffer is passed to vTaskList and the information entered lists in order:

1.Name - is the name given to the task when it was created. Note that the demo application creates more than one instance of some tasks.

2.State - shows the state of a task. This can be either 'B'locked, 'R'eady, 'S'uspended or 'D'eleted.

3.Priority - is the priority given to the task when it was created.

4.Stack - shows the high water mark of the task stack. This is the minimum amount of free stack that has been available during the lifetime of the task.

5.Num - is the number automatically allocated to the task.

You can study the state of other tasks without vTasklist if you add pxReadyTasksLists[] or xDelayedTaskList1to your watch window. You must first however step into the first OS-call as you must be in the scope of tasks.c. To see which tasks are pending, have the TCB pointers to your tasks at hand as described in previous bullet.Again, it is unfortunately not possible to study the TCB content for any task by looking at this list. If a task you are looking for is not in pxReadyTasksListsthe list, it is simply not ready to run at the moment.

Figure 1 AddxListpxReadyTasksLists[] to your watch window if you need to see the state of tasks at a breakpoint. Ready tasks are in this list, and the only value of interest for each item is really the TCB pointer. Note that xItemValue is not used other than to determine the end of the list,whenit is then FF instead of 0.

Tracing task execution.You can check task execution order by taking a trace. You need the tool tracecon_big_endian_untested.exe Here is how to do this.

1.Add the following to your code

a.FreeRTOSconfig.h

i.#define configUSE_TRACE_FACILITY1

b.e.g. main.c

i.signed portCHAR taskCheckWriteBuffer[400];

ii.In file you want to add start and stop trace:

iii.extern signed portCHAR taskCheckWriteBuffer[400];vTaskStartTrace( taskCheckWriteBuffer, 400 );…ulTaskEndTrace();

2.In HEW

a.Open up a watch window

b.Add taskCheckWriteBuffer. Check that trace data is there.

c.Open memory window to address of taskCheckWriteBuffer.

d.Right-click in mem window.

e.Select Save

f.Format=Binary, Enter Start & Stop address, Filename = trace.bin.

3.Go to DOS-prompt and run

i.C:\WorkSpace\RTOS\FreeRTOS>tracecon_big_endian_untested.exe

ii.This will create file TRACE.TXT.

iii.Open and view task execution order.

Revision Record

Rev. / Date / Description
Page / Summary
0.90 / Mar 20 ‘08 / — / First edition.
1.0 / Apr3 ‘08 / — / After Review FP.
1.03 / June 9 ‘08 / 1 / Added section “Source code” with Portable directory structure description.

Guide_to_FreeRTOS_v1.05.docJune 2008Page 1 of 9