FreeRTOS
Introduction To FreeRTOS
Demo Application
Content
1.
Documentation .................................................................................................................................. 1
2. The source code ............................................................................................................................... 2
2.1 MCU dependent files ........................................................................................................................ 2
3.
3.1
3.2
3.3
Basic Task Switching ........................................................................................................................ 2
Summary ........................................................................................................................................... 2
Cooperative (Round Robin) scheduling ............................................................................................ 3
Preemptive scheduling ...................................................................................................................... 3
4. The RTA Demo ................................................................................................................................. 4
4.1 Demo Tasks ...................................................................................................................................... 4
4.2 Demo configuration – FreeRTOS_Config.h ...................................................................................... 6
5.
Tips, Debugging ................................................................................................................................ 7
Revision Record ........................................................................................................................................ 9
1.
Documentation
FreeRTOS is a free, preemptive, Real Time Operating System (RTOS) for microcontrollers, It is rather well
documented at http://www.freertos.org/.
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 a Renesas H8S/2378,
what had to be changed and as a resource for future similar attempts.
81925530
June 2008
Page 1 of 9
Guide to FreeRTOS
The source code
2.
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.1
MCU dependent files
2.1.1
The 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
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_VECT
Define 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.
Define which interrupt is the timer tick interrupt vector . The scheduler is clocked
by this interrupt.
Basic Task Switching
3.
3.1
Summary
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).
81925530
June 2008
Page 2 of 9
Guide to FreeRTOS
3.2
Cooperative (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 code if 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 taskYIELD for 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 give a 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 must first have been called to by another task. If the task that called vTaskDelayUntil
has a higher priority, it should be scheduled next.
3.3
Preemptive 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 taskYIELD for 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)
81925530
TaskResume
June 2008
Page 3 of 9
Guide to FreeRTOS
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.
The RTA Demo
4.
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_PREEMPTION
Semaphores
Queues
Mailboxes
Lists
4.1
1
Demo Tasks
main() is not a task, but calls all sub tests below and then starts the scheduler. It also creates the vErrorChecks task
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.1
vStartIntegerMathTasks
vStartIntegerMathTasks() creates a selectable number of vCompeteingIntMathTasks that crunch 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 xAreIntegerMathsTaskStillRunning to check that all the created tasks are still running.
4.1.2
vStartLEDFlashTasks
vStartLEDFlashTasks( ) creates a selectable number of vLEDFlashTasks that flash the board LEDS. Each task gains
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.3
vStartMsgQueueTasks
81925530
June 2008
Page 4 of 9
Guide to FreeRTOS
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,
1,
2,
3,
4,
"RENESAS_A\0"
"RENESAS_B\0"
"RENESAS_C\0"
"RENESAS_D\0"
"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.4
vStartMathTasks
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.5
vStartSemaphoreTasks
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.6
vStartDynamicPriorityTasks
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. Illustrated is 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
81925530
June 2008
Page 5 of 9
Guide to FreeRTOS
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 it raises it's priority above that of Controller before each increment, then
lowers it again.
Controller has two sections. The first controls and monitors CounterC’s continuous counting during which CounterL
is 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 2nd section 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’s vTaskResume of
CounterL is therefore a check that the shared variable was indeed incremented to 0xFF by CounterL.
4.2
Demo 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_PREEMPTION
1 //Set to zero to run RTA demo w/o preemption.
#define configUSE_IDLE_HOOK
0
#define configUSE_TICK_HOOK
0
#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_FACILITY
0
#define configUSE_16_BIT_TICKS
1
#define configIDLE_SHOULD_YIELD
1
/* Added Renesas */
#define configKERNEL_INTERRUPT_PRIORITY
1
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES
#define configMAX_CO_ROUTINE_PRIORITIES
81925530
0
(2)
June 2008
Page 6 of 9
Guide to FreeRTOS
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet
1
#define INCLUDE_uxTaskPriorityGet
1
#define INCLUDE_vTaskDelete
1
#define INCLUDE_vTaskCleanUpResources
0
#define INCLUDE_vTaskSuspend
1
#define INCLUDE_vTaskDelayUntil
1
#define INCLUDE_vTaskDelay
1
#endif /* FREERTOS_CONFIG_H */
Go to http://www.freertos.org/ 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.
Tips, Debugging
5.
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 pxReadyTasksList to 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:
81925530
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.
June 2008
Page 7 of 9
Guide to FreeRTOS
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 xDelayedTaskList1
to 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 pxReadyTasksLists the list, it is simply not ready to run at the moment.
4 tasks of this
priority are ready
to execute
(points back to
beginning of list)
Nr 3 to be executed
Nr 2 to be executed
Next task of this priority
to be executed
End of list
4th and last to
be executed
Figure 1 Add xListpxReadyTasksLists[] 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, when it is then FF instead of 0.
81925530
June 2008
Page 8 of 9
Guide to FreeRTOS
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_FACILITY
b.
1
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.
3.
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.
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.
0.90
1.0
1.03
81925530
Date
Mar 20 ‘08
Apr 3 ‘08
June 9 ‘08
Description
Page
—
—
1
Summary
First edition.
After Review FP.
Added section “Source code” with Portable directory structure
description.
June 2008
Page 9 of 9
© Copyright 2026 Paperzz