SlideShare uma empresa Scribd logo
1 de 190
Baixar para ler offline
Maths is not everything

Embedded Systems
7 - Real-Time Operating System (FreeRTOS)

RMR©2012

Introduction
Task Management
Queue Management
Interrupts and Synchronization
Resource Management
Memory Management
Aditional Features
Maths is not everything

FreeRTOS
Introduction

RMR©2012
At the Beginning

Written by Richard Barry & FreeRTOS
Team
Huge number of users all over the world
6000 downloads per month

in March 2010, it came on the top of the
market study made by www.embedded.com.
A good starting point to experience realtime OS
Maths is not everything

RMR©2012

3

Simple but yet very powerful
FreeRTOS in Literature
An e-book is written to explain the internals.
“Using the FreeRTOS Real Time Kernel - a Practical Guide”
4 editions are available:
Standard edition
Microchip edition
Generic Cortex M3 edition
LPC17xx edition

FreeRTOS Reference Manual
API functions and configuration options
Maths is not everything

Online documentation
RMR©2012

4

www.freertos.org
FreeRTOS History
FreeRTOS
V1.0.1

FreeRTOS
V2.0.0

FreeRTOS V1.0.1
+
Scalability
+
New Task APIs

FreeRTOS
V6.0.0

Maths is not everything

2009
Backward Comp.
MPU Support
RMR©2012

5

FreeRTOS
V3.0.0

API Changes
+
Directory Names
Changed
+
Changes in Kernel

FreeRTOS
V4.0.0

FreeRTOS V3.0.0
+
Co-routines

FreeRTOS
V5.0.0

API Changes
FreeRTOS Features

Architecture
Source code
Portable
Scalable
Preemptive and co-operative scheduling
Multitasking
Services
Maths is not everything

RMR©2012

6

Interrupt management
Advanced features
Architecture

Application
Task 1

Maths is not everything

RMR©2012

7

Task 2

Task 3

Task 4
Source Code Organization

FreeRTOS
main kernel source directory

Source
include

kernel header files directory

Portable

kernel port

Compiler x
Compiler y

RMR©2012

8

compiler x port

MemMang
Maths is not everything

compiler x port
malloc/free implementation

Demo
Common

demo app common directory

Dir x

demo app of port x
demo app of port y

Dir y
Source Code Organization

Maths is not everything

RMR©2012

9

port.c and portmacro.h files within the HAL
Portability
Highly portable C
24 architectures supported
Assembly is kept minimum.
Ports are freely available in
source code.
Other contributions do exist.

Maths is not everything

RMR©2012

10
Scalable
Use the service you only need:
FreeRTOSConfig.h
Very few services / Complete services available
A group of #defines determines scalability.

Minimum footprint = 4 KB

Maths is not everything

RMR©2012

11
FreeRTOSConfig.h

Maths is not everything

RMR©2012

12

#define configUSE_PREEMPTION 1
#define configCPU_CLOCK_HZ 58982400
#define configTICK_RATE_HZ 250
#define configMAX_PRIORITIES 5
#define configMINIMAL_STACK_SIZE 128
#define configTOTAL_HEAP_SIZE 10240
#define configMAX_TASK_NAME_LEN 16
#define configUSE_MUTEXES 0
...
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_uxTaskGetStackHighWaterMark 0
#define INCLUDE_xTaskGetIdleTaskHandle 0
...
Preemptive and Cooperative Scheduling
Preemptive scheduling:
Fully preemptive
Always runs the highest priority task that is ready to run
Comparable with other preemptive kernels
Used in conjunction with tasks

Cooperative scheduling:
Context switch occurs if:
A task/co-routine blocks
Or a task/co-routine yields the CPU

Used in conjunction with tasks/co-routines

Maths is not everything

A hybrid of both scheduling can be used in your
application.
Application = Tasks

RMR©2012

13

Or Application = Tasks + Co-routines
Tasks have higher priority than Co-routines
Tasks vs Co-routines

Tasks

Co-routines

no restrictions

API calls have restrictions

totally prioritized

totally prioritized among coroutines but interruptible by
tasks when using hybrid mode

each task maintains its
own stack
re-entrance has to be
tackled carefully when
used with preemption

stack shared among them
re-entrance managed by
cooperation (less
problematic)

Maths is not everything

RMR©2012

14

cooperation only between coroutines
Multitasking

No software restriction on:
# of tasks that can be created
# of priorities that can be used
Priority assignment
More than one task can be assigned the same
priority.
RR with time slice = 1 RTOS tick
Maths is not everything

RMR©2012

15
Services

Queues
Semaphores
Binary and counting

Mutexes
With priority inheritance
Maths is not everything

RMR©2012

16

Support recursion
Interrupts

An interrupt can suspend a task
execution.
Interrupt mechanism is port dependent.
Nesting
Scheduling after interrupts
Preemptive or cooperative scheduler
Maths is not everything

RMR©2012

17
Advanced Features

Execution tracing
Run time statistics collection
Memory management
Memory protection support
Maths is not everything

RMR©2012

18

Stack overflow protection
Conventions: variables’ names

In FreeRTOS a prefix is used in the name
of the variables indicating its type
Chars start with a “c”
Shorts start with an “s”
Longs start with an “l”
other types start with an “x” (e.g. structures)
unsigned vars start with an “u”
pointers start with a “p”
Maths is not everything

RMR©2012

19
Conventions: functions’ names

private functions start with “prv”
API functions’ return are pre-fixed with the same
convention as variables
API functions start with the name of the source
archive where they were defined
e.g. xTaskCreate is defined in Task.c

Maths is not everything

RMR©2012

20
Licensing

Modified GPL (Real Time Engineers Ltd.)
Only FreeRTOS is GPL.
Open-source code, no royalties involved
May be used freely in commercial applications
Any modifications to the kernel need to be made
available as open-source code
Any app source code can be maintained as private
provided that no new functionalities at the kernel level
is involved
Maths is not everything

RMR©2012

21

FreeRTOS can’t be used in any comparisons without
the authors’ permission.
Other FreeRTOS Variants
OpenRTOS (High Integrity Systems)
= FreeRTOS + Commercial License
Tailored BSP, middle ware, applications …
no need to publish any kernel modification as open-source
Training, technical support, guaranties, ...
Platform preparation

SafeRTOS
= FreeRTOS + Commercial + IEC61508 SIL3 Certification
(critical apps)
Maths is not everything

Compliant with:
FDA510(k) Class III medical device standards

RMR©2012

22

EN62304
Maths is not everything

FreeRTOS
Kernel Structure - Tasks

RMR©2012
Task States
Running
task is executing owning the
CPU

Ready
task may run but is waiting
for the CPU to be available,

Blocked
task is delayed (timing / event)
or is waiting for another task
(synchronization)

Suspended
task may enter this state only
through specific calls
Maths is not everything

RMR©2012

24

there is no associated
timeout
not considered in scheduling
Global characteristic of a task

Every task behaves as an isolated
sequential program
has a single entry point
implemented usually as an infinite loop
normally, it never returns. If eventually it ends, it’s up
to the programmer to remove it (kill) from the
kernel’s list.

Task prototype
Maths is not everything

RMR©2012

25

void ATaskFunction(void *pvParameters);
Task skeleton
void ATaskFunction( void *pvParameters )
{
/* Variables can be declared just as per a normal function. Each instance of a task
created using this function will have its own copy of the iVariableExample variable.
This would not be true if the variable was declared static – in which case only one
copy of the variable would exist and this copy would be shared by each created
instance of the task. */
int iVariableExample = 0;
/* A task will normally be implemented as in infinite loop. */
for( ;; )
{
/* The code to implement the task functionality will go here. */
}
/* Should the task implementation ever break out of the above loop
then the task must be deleted before reaching the end of this function.
The NULL parameter passed to the vTaskDelete() function indicates that
the task to be deleted is the calling (this) task. */
vTaskDelete( NULL );

Maths is not everything

RMR©2012

26

}
Typical Application

Maths is not everything

RMR©2012

27
Task creation

portBASE_TYPE xTaskCreate(
pdTASK_CODE pvTaskCode,
const char * const pcName,
unsigned short usStackDepth,
void *pvParameters,
unsigned portBASE_TYPE uxPriority,
xTaskHandle *pvCreatedTask
);
pvTaskCode: a pointer to the function (actually just the name) where the task is implemented.
pcName: name given to the task. This is useless to FreeRTOS but is intended for debugging purposes (human
readable) only.
usStackDepth: length of the stack (each task has its own stack) for this task in words. Should be tailored to
task needs.
Maths is not everything

RMR©2012

28

pvParameters: a pointer to arguments given to the task. A good practice consists in creating a dedicated
structure, instantiate and fill it then give its pointer to the task.
uxPriority: priority given to the task, a number between 0 and MAX_PRIORITIES – 1.
pxCreatedTask: a pointer to an identifier that allows to handle the task. If the task does not have to be
handled in the future, this can be leaved NULL.
Task creation

portBASE_TYPE xTaskCreate(
pdTASK_CODE pvTaskCode,
const char * const pcName,
unsigned short usStackDepth,
void *pvParameters,
unsigned portBASE_TYPE uxPriority,
xTaskHandle *pvCreatedTask
);
Returned Value - there are two possible return values:
1. pdTrue: indicates that the task has been launched successfully.
Maths is not everything

2. errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY: indicates that the task

could not be created because there was insufficient heap memory available for FreeRTOS
to allocate RAM to hold the task data structures and stack.
RMR©2012

29
Example application that uses RTOS

v
v

v

v
Maths is not everything

RMR©2012

30
Example application: execution sequence (ARM)

Maths is not everything

RMR©2012

31
Task Control Block

Maths is not everything

RMR©2012

32
Example application: Data-structures maintained by RTOS

Initially

After TaskCreate(1)

currentTask

currentTask

Maths is not everything

RMR©2012

33

0

NULL

1

NULL

1

Task1

2

NULL

2

NULL

3

NULL

3

NULL

NULL

n-1

NULL

pxReadyTaskList

NULL

n-1

pxReadyTaskList

0
Example application: Data-structures maintained by RTOS

After TaskCreate(2)
currentTask

After TaskStartSchedule ()
currentTask

Task2

Maths is not everything

RMR©2012

34

0

idle

1

Task1

1

Task1

2

Task2

2

NULL

3

NULL

3

NULL

NULL

n-1

NULL

pxReadyTaskList

NULL

n-1

pxReadyTaskList

0
Ready and Blocked Lists

Maths is not everything

RMR©2012

35
Hypothetical DelayedTaskList

Maths is not everything

RMR©2012

36
Tasks within tasks
void vTask1( void *pvParameters )
{
const char *pcTaskName = "Task 1 is runningrn";
volatile unsigned long ul;
/* If this task is executing then the scheduler must already have
been started. Create the other task before entering the infinite
loop.*/
xTaskCreate( vTask2, "Task 2", 1000, NULL, 1, NULL );
for( ;; )
{
/* Print out the name of this task. */
vPrintString( pcTaskName );
/* Delay for a period. */
for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ )
{
/* This loop is just a very crude delay implementation. There
is nothing to do in here. There is a need for proper delay/
sleep function. */
}

Maths is not everything

}

RMR©2012

37

}
Using the task parameter
void vTaskFunction( void *pvParameters )
{
char *pcTaskName;
volatile unsigned long ul;
/* The string to print out is passed in via the parameter. Cast to a char ptr.*/
pcTaskName = ( char * ) pvParameters;
/* As per most tasks, this task is implemented in an infinite loop. */
for( ;; ) {
/* Print out the name of this task. */
vPrintString( pcTaskName );
/* Delay for a period. */
for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ )
{
/* This loop is just a very crude delay implementation. There is nothing to
do in here.*/
}
}
}

Maths is not everything

RMR©2012

38

/* Define the strings to be passed in as the task parameters. These are defined
const and not on the stack to ensure they remain valid when the tasks are
executing. */
static const char *pcTextForTask1 = “Task 1 is runningrn”;
static const char *pcTextForTask2 = “Task 2 is runningtn”;

int main( void )
{
/* Create one of the two tasks. */
xTaskCreate( vTaskFunction, "Task 1", 1000, (void*)pcTextForTask1, 1, NULL );
/* Create the other instance of the same task. */
xTaskCreate( vTaskFunction, "Task 2", 1000, (void*)pcTextForTask2, 2, NULL );
/* Start the scheduler so the tasks start executing. */
vTaskStartScheduler();
for( ;; );
}
Block State: the delay primitive
void vTaskDelay(portTickType xTicksToDelay);
Delays for xTicksToDelay kernel ticks, while allowing
other tasks to execute
portTickType is unsigned char
Argument is number of kernel ticks to delay
Upon completion of the delay task is returned to ready
state, resumes execution when possible
Maths is not everything

RMR©2012

39

Constants configTICK_RATE_MS and
configTICK_RATE_HZ usable to get desired time delay
Blocking: delaying a task for a period of time
void vTaskFunction( void *pvParameters )
{
char *pcTaskName;
/* The string to print out is passed in via the parameter */
pcTaskName = ( char * ) pvParameters;
/* As per most tasks, this task is implemented in an infinite loop. */
for( ;; ) {
/* Print out the name of this task. */
vPrintString( pcTaskName );
/* Delay for a period. Call to vTaskDelay() places the task into the Blocked
state until the delay period has expired. The delay period is specified in
'ticks', but the constant portTICK_RATE_MS can be used to convert this to a
value in milliseconds*/
vTaskDelay( 250 / portTICK_RATE_MS );
}
}

Maths is not everything

RMR©2012

40
Block State: the exact delay primitive
void vTaskDelayUntil(portTickType *pxPreviousWakeTime,
portTickType xTimeIncrement);

vTaskDelay() specifies the number of ticks between the call
and the same task once again transitioning out of the Block
state. But this amount of time is relative to the time at
which vTaskDelay() was called.
Delays for xTimeIncrement from last time called
Used for cyclic tasks, such as e.g. keypad scanning
First argument is variable with last time woken up
Second argument is number of ticks between wake-ups
Maths is not everything

The parameters specify the exact tick count value at which the calling task
should be moved from the Blocked state into the Ready state. The time at
which the calling task is unblocked is absolute, rather than relative to when the
function was called (as is the case with vTaskDelay())

RMR©2012

41
Blocking: delaying a task for the same EXACT period of time

void vTaskFunction( void *pvParameters )
{
char *pcTaskName;
portTickType xLastWakeTime;
/* The string to print out is passed in via the parameter. Cast this to a char
pointer. */
pcTaskName = ( char * ) pvParameters;
/* The xLastWakeTime variable needs to be initialized with the current tick
count. Note that this is the only time the variable is written to explicitly.
After this xLastWakeTime is updated automatically internally within
vTaskDelayUntil(). */
xLastWakeTime = xTaskGetTickCount();
/* As per most tasks, this task is implemented in an infinite loop. */
for( ;; ) {
/* Print out the name of this task. */
vPrintString( pcTaskName );
/* This task should execute exactly every 250 milliseconds. As per
the vTaskDelay() function, time is measured in ticks, and the
portTICK_RATE_MS constant is used to convert milliseconds into ticks.
xLastWakeTime is automatically updated within vTaskDelayUntil() so is not
explicitly updated by the task. */
vTaskDelayUntil( &xLastWakeTime, ( 250 / portTICK_RATE_MS ) );

Maths is not everything

RMR©2012

42

}
}
Priorities

Priorities range from 0 (lowest priority)
up to (configMAX_PRIORITIES – 1)
defined in FreeRTOSConfig.h.
the higher the MAX_PRIORITIES parameter is the
higher the RAM requirements will be.

Tasks will have priorities according to
their real-time characteristics
The scheduler will guarantee that the ready task with
the highest priority will be the one to be executed
Maths is not everything

RMR©2012

43

Tasks may have the same priority. In this case the
scheduler will execute them in a round-robin fashion.
Scheduler and Priorities
Task scheduling decides which “Ready” task has to be run
at a given time.
FreeRTOS uses priorities for this purpose. Priority is the only element the
scheduler takes into account to decide which task has to be switched in.
Every clock tick makes the scheduler to decide which task has to be waken up.

Maths is not everything

RMR©2012

44
Scheduler and Priorities
There is no automatic management of priorities
a task always keeps the same priority unless the programmer change it explicitly.
A low value means a low priority: priority 0 is the minimal priority a task could have
and this level should be strictly reserved for the idle task.

Task management allows an implementation of Rate Monotonic:
tasks with higher frequencies are given an higher priority whereas low frequencies
tasks deserve a low priority. Event­based or continuous tasks are preempted by
periodic tasks.

Maths is not everything

RMR©2012

45
Equally-priority tasks
Tasks created with an equal priority are treated equally by
the scheduler
If two of them are ready to run, the scheduler shares running time among all of
them
This configures a Round Robin implementation where quantum is the time
between each clock tick.
This value is available in TICK_RATE_HZ constant, in FreeRTOSConfig.h

Maths is not everything

RMR©2012

46
The idle task

When all tasks are either blocked or
suspended the
CPU needs to be executing
something
The Idle Task is then executed!
this task is automatically created when the scheduler is started ➱
vTaskStartScheduler().
this task has priority 0 (lowest possible).

Normally, the idle task does nothing (actually is when idle task
runs that the kernel does some housekeeping like purging
deleted tasks stuff)
Maths is not everything

RMR©2012

47

It is however possible to add application specific functionality
directly into the idle task through the use of an idle hook (or
call-back) function – a function that is automatically called by
the idle task once per iteration of the idle task loop.
Idle Task Hook

Common uses for the Idle task hook include:
Executing low priority, background or continuous processing.
	

Measuring the amount of spare processing capacity
measuring the amount of processing time allocated to the idle task
provides a clear indication of how much processing time is spare

Placing the processor into a low power mode
To run it ➱ configUSE_IDLE_HOOK must be set to 1 within FreeRTOSConfig.h
/* Declare a variable that will be incremented by the hook function. */
unsigned long ulIdleCycleCount = 0UL;

Maths is not everything

/* Idle hook functions MUST be called vApplicationIdleHook(), take no parameters,
and return void. */
void vApplicationIdleHook( void )
{

RMR©2012

48

/* This hook function does nothing but increment a counter. */
ulIdleCycleCount++;
}
Tick Interrupt Hook
It is possible to implement a callback function to
be called at every tick interrupt:
this function can be used to run a periodic routine like the one
needed to reset the watchdog timer;
as this routine runs in interrupt time, its processing effort should
be kept at a minimum, using short code and only a moderate
amount of stack space and not call any FreeRTOS API functions
whose name does not end with ‘FromISR()’.

To run it ➱ configUSE_TICK_HOOK must be set to 1 within
FreeRTOSConfig.h
Maths is not everything

RMR©2012

49

provide the implementation of the hook function using:
void vApplicationTickHook( void );
Suspended State

Tasks in the Suspended state are not
scheduled by the kernel
The only way to enter the Suspended State is by
invoking the vTaskSuspended() primitive
The only way to exit the Suspended State is by
invoking the vTaskResume() primitive
Maths is not everything

RMR©2012

50
Scheduler review

Each application comprises one or more tasks.
Each task is assigned a priority.
Each task can exist in one of several states.
(Running, Ready, Blocked, Suspended).
Only one task can exist in the Running state at any
one.

Maths is not everything

RMR©2012

51

The scheduler will always select the highest
priority Ready state task to enter the Running
state.
Task Management API

Maths is not everything

RMR©2012

52
Maths is not everything

FreeRTOS
Queues

RMR©2012
FreeRTOS Queues
Queue is a communication mechanism between tasks or between
tasks and interrupt handlers
Tasks: xQueueSend, xQueueReceive, uxQueueMessagesWaiting
ISRs: xQueueSendFromISR, xQueueReceiveFromISR
Tasks can wait for items to enter/exit the queue while allowing
other tasks to execute

Maths is not everything

RMR©2012

54
Queue’s characteristics
A queue doesn’t belong to a given task.
Many tasks and int. handlers may share the same queue, either
for reading or writing.
Each queue stores a finite number of data items (queue length).
Every item has a fixed sized (item size).
Both "queue length" and "item size" are set when the queue is
created.
FreeRTOS allocates heap space for storing the queue.
Queues hold data in order, First In First Out (FIFO)
Writing to a queue causes a byte for byte copy of the data to be
stored in the queue.
Maths is not everything

RMR©2012

55

Reading from a queue causes the copy of the data to be removed
from the queue.
for this reason, if the element size is too big is better to work with
pointers
Queue’s characteristics: reading from a queue
When a task attempts to read from a queue it may enter into
the Blocked state waiting for an item in there.
A task may define a reading timeout ➟ time it is kept in the
Blocked state waiting for data, should the queue is empty.
A task in the Blocked state waiting for data to become
available is automatically moved into the Ready state when:
An item is written into the queue.
The reading timeout expires.
Queues can have more than one task blocked on it waiting for
data, as queues can have multiple readers.

Maths is not everything

RMR©2012

56

only one task (the one waiting for data with the highest priority) will
be unblocked when data becomes available.
blocked tasks with equal priority ➟ the task that has been waiting
for data the longest will be unblocked.
Queue’s characteristics: writing to a queue
When a task attempts to write to a queue it may enter into
the Blocked state if the queue is full.
A task may define a writing timeout ➟ time it is kept in the
Blocked state waiting for space in the queue, should the queue
is full.
A task trying to write an item into a queue is automatically
moved into the Ready state when:
The item is successfully written into the queue.
The writing timeout expires.
Queues can have multiple writers; so, more than one task can
be blocked on it waiting for sending data.
Maths is not everything

RMR©2012

57

only one task (the one waiting for queue space with the highest
priority) will be unblocked when space becomes available.
blocked tasks with equal priority ➟ the task that has been waiting
for space the longest will be unblocked.
Queue read/write: example

Maths is not everything

RMR©2012

58
Queue read/write: example

Maths is not everything

RMR©2012

58
Queue read/write: example

Maths is not everything

RMR©2012

58
Queue Creation
Creates a queue for uxQueueLength items of size uxItemSize bytes per
item
Handle should be global variables if ISRs and tasks need to access it
After creation, check to see if not null before use

xQueueHandle xQueueCreate (unsigned portBASE_TYPE uxQueueLength,
unsigned portBASE_TYPE uxItemSize);
uxQueueLength - The maximum number of items that the queue being created can hold at any one time.
uxItemSize - The size in bytes of each data item that can be stored in the queue.
Return Value - If NULL is returned then the queue could not be created because there was insufficient heap
memory available for FreeRTOS to allocate the queue data structures and storage area.
A non-NULL value being returned indicates that the queue was created successfully. The returned value
should be stored as the handle to the created queue.

Maths is not everything

RMR©2012

59

xQueueHandle MyQueue;
int main( void )
{
...
MyQueue = xQueueCreate( 20, sizeof( unsigned char ) );
...
}
Queue System Calls: send to queue
portBASE_TYPE xQueueSendToFront (
xQueueHandle xQueue,
const void* pvItemToQueue,
portTickType xTicksToWait);
portBASE_TYPE xQueueSendToBack (
xQueueHandle xQueue,
const void* pvItemToQueue,
portTickType xTicksToWait);

Maths is not everything

RMR©2012

60
Queue System Calls: send to queue
portBASE_TYPE xQueueSendToFront (
xQueueHandle xQueue,
const void* pvItemToQueue,
portTickType xTicksToWait);
portBASE_TYPE xQueueSendToBack (
xQueueHandle xQueue,
const void* pvItemToQueue,
portTickType xTicksToWait);
xQueueSend() is equivalent to and exactly the same as xQueueSendToBack()

Maths is not everything

RMR©2012

60
Queue System Calls: send to queue
portBASE_TYPE xQueueSendToFront (
xQueueHandle xQueue,
const void* pvItemToQueue,
portTickType xTicksToWait);
portBASE_TYPE xQueueSendToBack (
xQueueHandle xQueue,
const void* pvItemToQueue,
portTickType xTicksToWait);
xQueueSend() is equivalent to and exactly the same as xQueueSendToBack()
pvItemToQueue - A pointer to the data that will be copied into the queue.
Maths is not everything

RMR©2012

60

xTicksToWait - The maximum amount of time the task should remain in the Blocked state,
should the queue already be full.
Both xQueueSendToFront() and xQueueSendToBack() will return immediately if xTicksToWait
is 0 and the queue is already full. Setting xTicksToWait to portMAX_DELAY will cause the task
to wait indefinitely (without timing out) provided INCLUDE_vTaskSuspend is set to 1 in
FreeRTOSConfig.h.
Queue System Calls: send to queue
pdPASS will only be
portBASE_TYPE xQueueSendToFront (
returned if data was
successfully sent to the
xQueueHandle xQueue,
queue.
const void* pvItemToQueue,
portTickType xTicksToWait);

portBASE_TYPE xQueueSendToBack (
xQueueHandle xQueue,
const void* pvItemToQueue,
portTickType xTicksToWait);
xQueueSend() is equivalent to and exactly the same as xQueueSendToBack()
pvItemToQueue - A pointer to the data that will be copied into the queue.
Maths is not everything

RMR©2012

60

xTicksToWait - The maximum amount of time the task should remain in the Blocked state,
should the queue already be full.
Both xQueueSendToFront() and xQueueSendToBack() will return immediately if xTicksToWait
is 0 and the queue is already full. Setting xTicksToWait to portMAX_DELAY will cause the task
to wait indefinitely (without timing out) provided INCLUDE_vTaskSuspend is set to 1 in
FreeRTOSConfig.h.
Queue System Calls: send to queue
pdPASS will only be
portBASE_TYPE xQueueSendToFront (
returned if data was
successfully sent to the
xQueueHandle xQueue,
queue.
const void* pvItemToQueue,
portTickType xTicksToWait);

portBASE_TYPE xQueueSendToBack (
xQueueHandle xQueue,
const void* pvItemToQueue,
portTickType xTicksToWait);

errQUEUE_FULL will
be returned if data
could not be written to
the queue because the
queue was already full.

xQueueSend() is equivalent to and exactly the same as xQueueSendToBack()
pvItemToQueue - A pointer to the data that will be copied into the queue.
Maths is not everything

RMR©2012

60

xTicksToWait - The maximum amount of time the task should remain in the Blocked state,
should the queue already be full.
Both xQueueSendToFront() and xQueueSendToBack() will return immediately if xTicksToWait
is 0 and the queue is already full. Setting xTicksToWait to portMAX_DELAY will cause the task
to wait indefinitely (without timing out) provided INCLUDE_vTaskSuspend is set to 1 in
FreeRTOSConfig.h.
Queue System Calls: receive from queue
portBASE_TYPE xQueueReceive (
xQueueHandle xQueue,
void *pvBuffer,
portTickType xTicksToWait);
portBASE_TYPE xQueuePeek (
xQueueHandle xQueue,
void *pvBuffer,
portTickType xTicksToWait);

Maths is not everything

RMR©2012

61
Queue System Calls: receive from queue
portBASE_TYPE xQueueReceive (
xQueueHandle xQueue,
void *pvBuffer,
portTickType xTicksToWait);
portBASE_TYPE xQueuePeek (
xQueueHandle xQueue,
void *pvBuffer,
portTickType xTicksToWait);
xQueuePeek() is used to receive an item from a queue without the item being removed from
the queue

Maths is not everything

RMR©2012

61
Queue System Calls: receive from queue
portBASE_TYPE xQueueReceive (
xQueueHandle xQueue,
void *pvBuffer,
portTickType xTicksToWait);
portBASE_TYPE xQueuePeek (
xQueueHandle xQueue,
void *pvBuffer,
portTickType xTicksToWait);
xQueuePeek() is used to receive an item from a queue without the item being removed from
the queue
pvBuffer - A pointer to the memory into which the received data will be copied.
Maths is not everything

RMR©2012

61

xTicksToWait - The maximum amount of time the task should remain in the Blocked state,
should the queue already be empty.
Both xQueueReceive() and xQueuePeek() will return immediately if xTicksToWait is 0 and the
queue is already empty. Setting xTicksToWait to portMAX_DELAY will cause the task to wait
indefinitely (without timing out) provided INCLUDE_vTaskSuspend is set to 1 in
FreeRTOSConfig.h.
Queue System Calls: receive from queue
pdPASS will only be
portBASE_TYPE xQueueReceive (
returned if data was
successfully read from
xQueueHandle xQueue,
the queue.
void *pvBuffer,
portTickType xTicksToWait);

portBASE_TYPE xQueuePeek (
xQueueHandle xQueue,
void *pvBuffer,
portTickType xTicksToWait);
xQueuePeek() is used to receive an item from a queue without the item being removed from
the queue
pvBuffer - A pointer to the memory into which the received data will be copied.
Maths is not everything

RMR©2012

61

xTicksToWait - The maximum amount of time the task should remain in the Blocked state,
should the queue already be empty.
Both xQueueReceive() and xQueuePeek() will return immediately if xTicksToWait is 0 and the
queue is already empty. Setting xTicksToWait to portMAX_DELAY will cause the task to wait
indefinitely (without timing out) provided INCLUDE_vTaskSuspend is set to 1 in
FreeRTOSConfig.h.
Queue System Calls: receive from queue
pdPASS will only be
portBASE_TYPE xQueueReceive (
returned if data was
successfully read from
xQueueHandle xQueue,
the queue.
void *pvBuffer,
portTickType xTicksToWait);

portBASE_TYPE xQueuePeek (
xQueueHandle xQueue,
void *pvBuffer,
portTickType xTicksToWait);

errQUEUE_EMPTY
will be returned if data
could not be read from
the queue because the
queue was already
empty.

xQueuePeek() is used to receive an item from a queue without the item being removed from
the queue
pvBuffer - A pointer to the memory into which the received data will be copied.
Maths is not everything

RMR©2012

61

xTicksToWait - The maximum amount of time the task should remain in the Blocked state,
should the queue already be empty.
Both xQueueReceive() and xQueuePeek() will return immediately if xTicksToWait is 0 and the
queue is already empty. Setting xTicksToWait to portMAX_DELAY will cause the task to wait
indefinitely (without timing out) provided INCLUDE_vTaskSuspend is set to 1 in
FreeRTOSConfig.h.
Queue System Calls: auxiliary

unsigned portBASE_TYPE uxQueueMessagesWaiting (
xQueueHandle xQueue);
uxQueueMessagesWaiting() is used to query the number of items
that are currently in a queue

Never call uxQueueMessagesWaiting() from an interrupt service
routine. The interrupt safe uxQueueMessagesWaitingFromISR()
should be used in its place
Maths is not everything

RMR©2012

62
Queue System Calls in Int. Handlers

Never use the previous SysCalls within
Int. Handlers!
In these handlers use the SysCalls ending
with“FromISR()”.
Examples:
XQueueSendToFrontFromISR().
XQueueSendToBackFromISR().
XQueueReceiveFromISR().
Maths is not everything

RMR©2012

63
Queue System Calls: examples

Maths is not everything

RMR©2012

64

/* To store the reference to the queue that is accessed by all three tasks. */
xQueueHandle xQueue;
int main( void )
{
/* queue is to hold a max of 5 values, each of type long. */
xQueue = xQueueCreate( 5, sizeof( long ) );
if( xQueue != NULL )
{
/* Create 2 instances of the task that will send to the queue. Task
par. is used to pass the value that the task will write to the queue;
only one task will continuously write 100 to the queue while the
other task will continuously write 200. Both tasks created w/ prio 1 */
xTaskCreate( vSenderTask, "Sender1", 1000, ( void * ) 100, 1, NULL );
xTaskCreate( vSenderTask, "Sender2", 1000, ( void * ) 200, 1, NULL );
/* Create the task that will read from the queue. The task is created
with priority 2, so above the priority of the sender tasks */
xTaskCreate( vReceiverTask, "Receiver", 1000, NULL, 2, NULL );
/* Start the scheduler so the created tasks start executing. */
vTaskStartScheduler();
}else {
/* The queue could not be created. */
}
/* If all is well then main() will never reach here as the scheduler will
now be running the tasks. Otherwise, it is likely that there was
insufficient heap memory available for the idle task to be created*/
for( ;; );
}
Queue System Calls: examples

Maths is not everything

RMR©2012

65

static void vSenderTask( void *pvParameters )
{
long lValueToSend;
portBASE_TYPE xStatus;
/* queue was created to hold ‘long’ values, so cast to the required type */
lValueToSend = ( long ) *pvParameters;
for( ;; )
{
/* Send the value to the queue. The queue was created before the
scheduler was started. The 2nd parameter -> address of the data to be
sent. The 3rd parameter -> time the task should wait for space in the
queue. In this case a block time is not specified because the queue
should never contain more than one item and therefore never be full */
xStatus = xQueueSendToBack( xQueue, &lValueToSend, 0 );
if( xStatus != pdPASS )
{
/* The send operation could not complete because the queue was
full - must be an error as the queue should never have more than
one item! */
vPrintString( "Could not send to the queue.rn" );
}
/* Allow the other sender task to execute. taskYIELD() informs the
scheduler that a switch should occur now rather than keeping this task
in the Running state until the end of the current time slice */
taskYIELD();
}
}
Queue System Calls: examples

Maths is not everything

RMR©2012

66

static void vReceiverTask( void *pvParameters )
{
long lReceivedValue;
portBASE_TYPE xStatus;
const portTickType xTicksToWait = 100 / portTICK_RATE_MS;
for( ;; ) {
/* call should always find the queue empty as this task will
immediately remove any data that is written to the queue */
if( uxQueueMessagesWaiting( xQueue ) != 0 )
{
vPrintString( "Queue should have been empty!rn" );
}
/* Receive data from the queue. 2nd par. -> the buffer that receives
data in queue. Buffer is an address of a var. with the required size
to hold the data. 3rd parameter -> time the task should wait for data
to be available, should the queue already be empty.*/
xStatus = xQueueReceive( xQueue, &lReceivedValue, xTicksToWait );
if( xStatus == pdPASS )
{/* Data successfully received from queue, printout the value */
vPrintStringAndNumber( "Received = ", lReceivedValue );
} else {
/* Data was not received from the queue even after waiting for 100ms.
Must be an error as the sending tasks are free running and will be
continuously writing to the queue. */
vPrintString( "Could not receive from the queue.rn" );
}
}
}
Queue System Calls: examples

Maths is not everything

RMR©2012

67
Queues: transferring compound types

Maths is not everything

RMR©2012

68
Queues: transferring compound types

/* Define the structure type that will be passed on the queue.
*/
typedef struct
{
unsigned char ucValue;
unsigned char ucSource;
} xData;
/* Declare two variables of type xData that will be passed on
the queue. */
static const xData xStructsToSend [ 2 ] =
{
{ 100, mainSENDER_1 }, /* Used by Sender1 */
{ 200, mainSENDER_2 } /* Used by Sender2 */
};
Maths is not everything

RMR©2012

69
Queues: transferring compound types

Maths is not everything

RMR©2012

70

/* To store the reference to the queue that is accessed by all three tasks. */
xQueueHandle xQueue;
int main( void )
{
/* queue is to hold a max of 3 values, each of structure of type xData */
xQueue = xQueueCreate( 3, sizeof( xData ) );
if( xQueue != NULL )
{
/* Create 2 instances of the task that will send to the queue. Task
par. is used to pass the struct that the task will write to the queue;
only one task will send xStructsToSend[0] to the queue while the
other task will xStructsToSend[1]. Both tasks created w/ prio 2 */
xTaskCreate(vSenderTask,"Sender1",1000,&(xStructsToSend[0],2,NULL );
xTaskCreate(vSenderTask,"Sender2",1000,&(xStructsToSend[1],2,NULL);
/* Create the task that will read from the queue. The task is created
with priority 1, so below the priority of the sender tasks */
xTaskCreate( vReceiverTask, "Receiver", 1000, NULL, 1, NULL );
/* Start the scheduler so the created tasks start executing. */
vTaskStartScheduler();
}else {
/* The queue could not be created. */
}
/* If all is well then main() will never reach here as the scheduler will
now be running the tasks. Otherwise, it is likely that there was
insufficient heap memory available for the idle task to be created*/
for( ;; );
}
Queues: transferring compound types
static void vSenderTask( void *pvParameters )
{
portBASE_TYPE xStatus;
const portTickType xTicksToWait = 100 / portTICK_RATE_MS;

Maths is not everything

RMR©2012

71

}

for( ;; )
{
/* Send to the queue. The queue was created before the scheduler was
started. 2nd parameter -> address of the structure being sent. The 3rd
parameter -> time the task should wait for space in the queue. A block
time is specified as the sending tasks have a higher priority than the
receiving task so the queue is expected to become full. The receiving
task will remove items from the queue when both sending tasks are
Blocked */
xStatus = xQueueSendToBack( xQueue, pvParameters, xTicksToWait );
if( xStatus != pdPASS )
{
/* The send operation could not complete even after waiting for
100ms - must be an error as the receiving task should make space
in the queue as soon as both sending tasks are in the Blocked
state */
vPrintString( "Could not send to the queue.rn" );
}
/* Allow the other sender task to execute. taskYIELD() informs the
scheduler that a switch should occur now rather than keeping this task
in the Running state until the end of the current time slice */
taskYIELD();
}
Queues: transferring compound types
static void vReceiverTask( void *pvParameters )
{
xData xReceivedStructure;
portBASE_TYPE xStatus;
const portTickType xTicksToWait = 100 / portTICK_RATE_MS;

Maths is not everything

RMR©2012

72

}

for( ;; )
{
/* always expects the queue to have 3 items */
if( uxQueueMessagesWaiting( xQueue ) != 3 ) {
vPrintString( "Queue should have been full!rn" );
}
/* Receive data from the queue. 2nd par. -> the buffer (address of a var)
with the required size to hold the data. 3rd parameter -> time the task
should wait for data to be available when queue is empty. It is not needed
as this task will only run when the queue is full.*/
xStatus = xQueueReceive( xQueue, &xReceivedStructure, 0 );
if( xStatus == pdPASS ) {
/* Data successfully received from queue, printout the value */
if( xReceivedStructure.ucSource == mainSENDER_1) {
vPrintStringAndNumber( "From Sender 1 = ",
xReceivedStructure.ucValue );
} else {
vPrintStringAndNumber( "From Sender 2 = ",
xReceivedStructure.ucValue );
}
} else {
/* Nothing was received from the queue. Must be an error as this tasks
should only runs when the queue is full */
vPrintString( "Could not receive from the queue.rn" );
}
}
Queues: transferring compound types

Maths is not everything

RMR©2012

73
Queues: handling big data
When the data being stored is large it is
preferable to use the queue to transfer pointers
rather than copy the data itself into and out of
the queue, byte by byte. However ...
The owner of the RAM being pointed to must be clearly defined
only the sending task should access the memory until a
pointer to the memory has been queued,
only the receiving task should access the memory after the
pointer has been received from the queue.

The RAM being pointed to remains valid

Maths is not everything

RMR©2012

74

If the memory being pointed to was allocated dynamically
then exactly one task should be responsible for freeing it. No
tasks should attempt to access the memory after it has been
freed.
A pointer should never be used to access data that has been
allocated on a task stack.
Queue Management API

Maths is not everything

RMR©2012

75
Maths is not everything

FreeRTOS
Interrupts and Synchronization

RMR©2012
Interrupt Handling

Embedded real-time systems have to take
actions in response to external events
a packet from a communication interface (event)
might require passing to a TCP/IP stack for processing
(action)

Usually, events are handled through
interrupts inside an ISR.
but how much processing should be done inside the
ISR?
Maths is not everything

RMR©2012

77

how can these events be communicated from a ISR to
the application tasks and this code can be structured
to best accommodate processing of potentially
asynchronous occurrences?
Interrupt Handling

Interrupt handling is critical for the app
performance ➟ the ISR should be short
and execute fast.
In FreeRTOS, an ISR should:
Acknowledge the interrupt
Collect data from the event
Defer the “hard work” to a “handler” task

Maths is not everything

RMR©2012

78

a context switch to the “handler” task
should occur
when it has a higher priority than the interrupted task
which is preempted
Interrupt Handling

Maths is not everything

RMR©2012

79
Communication between an IH and the Handler Task
An IH can defer the event heavy processing to a
Handler task through a synchronization
mechanism.
A simple way to do it is through a binary semaphore

Maths is not everything

RMR©2012

80
Communication between an IH and the Handler Task
An IH can defer the event heavy processing to a
Handler task through a synchronization
mechanism.
A simple way to do it is through a binary semaphore

Maths is not everything

RMR©2012

80
Communication between an IH and the Handler Task
An IH can defer the event heavy processing to a
Handler task through a synchronization
mechanism.
A simple way to do it is through a binary semaphore

Maths is not everything

RMR©2012

80
Communication between an IH and the Handler Task
An IH can defer the event heavy processing to a
Handler task through a synchronization
mechanism.
A simple way to do it is through a binary semaphore

Maths is not everything

RMR©2012

80
Communication between an IH and the Handler Task
An IH can defer the event heavy processing to a
Handler task through a synchronization
mechanism.
A simple way to do it is through a binary semaphore

Maths is not everything

RMR©2012

80
Communication between an IH and the Handler Task
An IH can defer the event heavy processing to a
Handler task through a synchronization
mechanism.
A simple way to do it is through a binary semaphore

Maths is not everything

RMR©2012

80
Synchronization mechanisms

FreeRTOS has the following
synchronization mechanisms:
Binary Semaphores
Counting Semaphores
Queues

Maths is not everything

RMR©2012

81

These mechanisms can be used in the
communication/synchronization between
tasks and between interrupt handlers and
tasks.
Binary Semaphores

Binary Semaphore Creation & Manipulation
void vSemaphoreCreateBinary (xSemaphoreHandle xSemaphore);
portBASE_TYPE xSemaphoreTake (xSemaphoreHandle xSemaphore,
portTickType xTicksToWait);
portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore);
portBASE_TYPE xSemaphoreGiveFromISR (
xSemaphoreHandle xSemaphore,
signed portBASE_TYPE *pxHigherPriorityTaskWoken);

Maths is not everything

RMR©2012

82
Binary Semaphores

Binary Semaphore Creation & Manipulation
void vSemaphoreCreateBinary (xSemaphoreHandle xSemaphore);
portBASE_TYPE xSemaphoreTake (xSemaphoreHandle xSemaphore,
portTickType xTicksToWait);
portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore);
portBASE_TYPE xSemaphoreGiveFromISR (
xSemaphoreHandle xSemaphore,
signed portBASE_TYPE *pxHigherPriorityTaskWoken);
xSemaphore - referenced by a variable and must be explicitly created before being used.

Maths is not everything

RMR©2012

82

xTicksToWait - The maximum amount of time the task should wait for the semaphore if it is
not already available. If xTicksToWait is 0 then xSemaphoreTake() will return immediately if the
semaphore is not available. Setting xTicksToWait to portMAX_DELAY will cause the task to
wait indefinitely (without timing out) provided INCLUDE_vTaskSuspend is set to 1 in
FreeRTOSConfig.h.
pxHigherPriorityTaskWoken - If xSemaphoreGiveFromISR() sets this value to pdTRUE then
a context switch should be performed before the interrupt is exited. This will ensure the
interrupt returns directly to the highest priority Ready state task.
Binary Semaphores

Binary Semaphore Creation & Manipulation
void vSemaphoreCreateBinary (xSemaphoreHandle xSemaphore);
portBASE_TYPE xSemaphoreTake (xSemaphoreHandle xSemaphore,
portTickType xTicksToWait);
portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore);
portBASE_TYPE xSemaphoreGiveFromISR (
pdPASS will only be xSemaphoreHandle xSemaphore,
returned if the call signed portBASE_TYPE *pxHigherPriorityTaskWoken);
was successful.
xSemaphore - referenced by a variable and must be explicitly created before being used.

Maths is not everything

RMR©2012

82

xTicksToWait - The maximum amount of time the task should wait for the semaphore if it is
not already available. If xTicksToWait is 0 then xSemaphoreTake() will return immediately if the
semaphore is not available. Setting xTicksToWait to portMAX_DELAY will cause the task to
wait indefinitely (without timing out) provided INCLUDE_vTaskSuspend is set to 1 in
FreeRTOSConfig.h.
pxHigherPriorityTaskWoken - If xSemaphoreGiveFromISR() sets this value to pdTRUE then
a context switch should be performed before the interrupt is exited. This will ensure the
interrupt returns directly to the highest priority Ready state task.
Binary Semaphores

Binary Semaphore Creation & Manipulation
void vSemaphoreCreateBinary (xSemaphoreHandle xSemaphore);
portBASE_TYPE xSemaphoreTake (xSemaphoreHandle xSemaphore,
portTickType xTicksToWait);
portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore);
portBASE_TYPE xSemaphoreGiveFromISR ( pdFALSE will be returned if
the semaphore was not
pdPASS will only be xSemaphoreHandle xSemaphore, available.
returned if the call signed portBASE_TYPE *pxHigherPriorityTaskWoken);
was successful.
xSemaphore - referenced by a variable and must be explicitly created before being used.

Maths is not everything

RMR©2012

82

xTicksToWait - The maximum amount of time the task should wait for the semaphore if it is
not already available. If xTicksToWait is 0 then xSemaphoreTake() will return immediately if the
semaphore is not available. Setting xTicksToWait to portMAX_DELAY will cause the task to
wait indefinitely (without timing out) provided INCLUDE_vTaskSuspend is set to 1 in
FreeRTOSConfig.h.
pxHigherPriorityTaskWoken - If xSemaphoreGiveFromISR() sets this value to pdTRUE then
a context switch should be performed before the interrupt is exited. This will ensure the
interrupt returns directly to the highest priority Ready state task.
Forcing a context switch in the IH

To force the context switching from an
ISR one should call:
void portEND_SWITCHING_ISR(portBASE_TYPE flag); // ARM port

void portSWITCH_CONTEXT(); // DOS port

The flag parameter should use the value
returned in the pxHigherPriorityTaskWoken
variable used by the primitives “FromISR”
called in the ISR.
Maths is not everything

RMR©2012

83
Communication between an IH and the Handler Task: example

Maths is not everything

RMR©2012

84

int main( void )
{
/*In this example a binary semaphore is created. */
vSemaphoreCreateBinary( xBinarySemaphore );
/* Install the interrupt handler. DOS emulation case*/
_dos_setvect( 0x82, vExampleInterruptHandler );
if( xBinarySemaphore != NULL ) /* Check if it was created successfully */
{
/* This is the task that will be synchronized with the interrupt. The
handler task is created with a high priority to ensure it runs
immediately after the interrupt exits */
xTaskCreate( vHandlerTask, "Handler", 1000, NULL, 3, NULL );
/* Create the task that will periodically generate a software
interrupt. This is created with a priority below the handler task to
ensure it will get pre-empted each time the handler task exits the
Blocked state */
xTaskCreate( vPeriodicTask, "Periodic", 1000, NULL, 1, NULL );
/* Start the scheduler so the created tasks start executing. */
vTaskStartScheduler();
}
/* If main() does reach here then it is likely that there was insufficient
heap memory available for the idle task or for the semaphore (data
structures) to be created with success*/
for( ;; );
}
Communication between an IH and the Handler Task: example

Maths is not everything

RMR©2012

85

static void vPeriodicTask( void *pvParameters )
{
for( ;; ) {
/* This task is just used to 'simulate' an interrupt by
generating a software interrupt every 500ms. */
vTaskDelay( 500 / portTICK_RATE_MS );
/* Generate the interrupt, printing a message both before and
after so the sequence of execution is evident from the output
produced when the example is executed. */
vPrintString( "Periodic task - About to generate an interrupt.r
n" );
__asm{ int 0x82 } /* generates the interrupt. */
vPrintString( "Periodic task - Interrupt generated.rnrnr
n" );
}
}
Communication between an IH and the Handler Task: example
static void vHandlerTask( void *pvParameters )
{
/* As per most tasks, this task is implemented within an infinite loop. */
for( ;; ) {
/* Use the semaphore to wait for an event. The task blocks indefinitely so
the call will only return once the semaphore has been successfully taken.
There is therefore no need to check the function return value. */
xSemaphoreTake( xBinarySemaphore, portMAX_DELAY );
/* To get here the event must have occurred. Process the event. In this case
processing is simply a matter of printing out a message. */
vPrintString( "Handler task - Processing event.rn" );
}
}

Maths is not everything

RMR©2012

86

static void __interrupt __far vExampleInterruptHandler( void )
{
static portBASE_TYPE xHigherPriorityTaskWoken;
xHigherPriorityTaskWoken = pdFALSE;
/* 'Give' the semaphore to unblock the task. */
xSemaphoreGiveFromISR( xBinarySemaphore, &xHigherPriorityTaskWoken );
if( xHigherPriorityTaskWoken == pdTRUE ) {
/* Giving the semaphore unblocked a task, and the priority of the unblocked task
is higher than the currently running task - force a context switch to ensure that
the interrupt returns directly to the unblocked (higher priority) task.
NOTE: The actual macro to use (context switch) from an ISR is dependent on the
port. This is the correct macro for the Open Watcom DOS port. Other ports may
require different syntax */
portSWITCH_CONTEXT(); // e.g.portEND_SWITCHING_ISR (xHigherPriorityTaskWoken);
}
}
Communication between an IH and the Handler Task: example

Maths is not everything

RMR©2012

87
Counting Semaphores

Binary semaphores are useful for low interrupt
rates.
However, when this rate increases,
failing to attend events is very likely to
happen.
a binary semaphore can latch at most one interrupt event; any
subsequent events occurring before the latched event has
been processed would be lost.

In such cases, counting semaphores can be
used instead of binary semaphores. Counting
semaphores can be used for:
Maths is not everything

RMR©2012

88

Handling events.
Managing the access to resources
Handling events with Counting Semaphores

Maths is not everything

RMR©2012

89
Handling events with Counting Semaphores

Maths is not everything

RMR©2012

89
Handling events with Counting Semaphores

Maths is not everything

RMR©2012

89
Handling events with Counting Semaphores

Maths is not everything

RMR©2012

89
Handling events with Counting Semaphores

Maths is not everything

RMR©2012

89
Handling events with Counting Semaphores

Maths is not everything

RMR©2012

89
Handling events with Counting Semaphores

Maths is not everything

RMR©2012

89
Counting Semaphores: creation and manipulation
xSemaphoreHandle xSemaphoreCreateCounting (unsigned
portBASE_TYPE uxMaxCount,
unsigned portBASE_TYPE uxInitialCount);
portBASE_TYPE xSemaphoreTake( xSemaphoreHandle xSemaphore,
portTickType xBlockTime);

portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore);
portBASE_TYPE xSemaphoreGiveFromISR (
xSemaphoreHandle xSemaphore,
signed portBASE_TYPE *pxHigherPriorityTaskWoken);

Maths is not everything

RMR©2012

90
Counting Semaphores: creation and manipulation
xSemaphoreHandle xSemaphoreCreateCounting (unsigned
portBASE_TYPE uxMaxCount,
unsigned portBASE_TYPE uxInitialCount);
portBASE_TYPE xSemaphoreTake( xSemaphoreHandle xSemaphore,
portTickType xBlockTime);

portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore);
portBASE_TYPE xSemaphoreGiveFromISR (
xSemaphoreHandle xSemaphore,
signed portBASE_TYPE *pxHigherPriorityTaskWoken);
uxMaxCount - The maximum value the semaphore will count to. When the semaphore is
used to count or latch events uxMaxCount is the maximum number of events that can be
latched. When the semaphore is used to manage access to a collection of resources
uxMaxCount should be set to the total number of resources that are available.
Maths is not everything

RMR©2012

90

uxInitialCount - The initial count value of the semaphore after it has been created. When the
semaphore is used to count or latch events uxInitialCount should be set to 0 – as presumably
when the semaphore is created no events have yet occurred. When the semaphore is used to
manage access to a collection of resources uxInitialCount should be set to equal uxMaxCount
– as presumably when the semaphore is created all the resources are available.
Counting Semaphores: example of use in an IH
int main( void )
{
/* In this example a counting semaphore is created. The semaphore is created to have a
maximum count value of 10, and an initial count value of 0 */
xCountingSemaphore = xSemaphoreCreateCounting( 10, 0 );

/* Install the interrupt handler. DOS emulation case*/
_dos_setvect( 0x82, vExampleInterruptHandler );
if( xBinarySemaphore != NULL ) /* Check if it was created successfully */
{
/* This is the task that will be synchronized with the interrupt. The
handler task is created with a high priority to ensure it runs
immediately after the interrupt exits */
xTaskCreate( vHandlerTask, "Handler", 1000, NULL, 3, NULL );
/* Create the task that will periodically generate a software
interrupt. This is created with a priority below the handler task to
ensure it will get pre-empted each time the handler task exits the
Blocked state */
xTaskCreate( vPeriodicTask, "Periodic", 1000, NULL, 1, NULL );
/* Start the scheduler so the created tasks start executing. */
vTaskStartScheduler();
}
/* If main() does reach here then it is likely that there was insufficient
heap memory available for the idle task or for the semaphore (data
structures) to be created with success*/
for( ;; );

Maths is not everything

RMR©2012

91

}
Counting Semaphores: example of use in an IH

Maths is not everything

RMR©2012

92

static void __interrupt __far vExampleInterruptHandler( void )
{
static portBASE_TYPE xHigherPriorityTaskWoken;
xHigherPriorityTaskWoken = pdFALSE;
/* 'Give' the semaphore multiple times. The first will unblock the handler
task, the following 'gives' are to demonstrate that the semaphore latches
the events to allow the handler task to process them in turn without any
events getting lost. This simulates multiple interrupts being taken by the
processor, even though in this case the events are simulated within a
single interrupt occurrence.*/
xSemaphoreGiveFromISR( xCountingSemaphore, &xHigherPriorityTaskWoken );
xSemaphoreGiveFromISR( xCountingSemaphore, &xHigherPriorityTaskWoken );
xSemaphoreGiveFromISR( xCountingSemaphore, &xHigherPriorityTaskWoken );
if( xHigherPriorityTaskWoken == pdTRUE ) {
/* Giving the semaphore unblocked a task, and the priority of the unblocked
task is higher than the currently running task - force a context switch to
ensure that the interrupt returns directly to the unblocked (higher
priority) task.
NOTE: The actual macro to use (context switch) from an ISR is dependent on
the port. This is the correct macro for the Open Watcom DOS port. Other
ports may require different syntax */
portSWITCH_CONTEXT(); // e.g.portEND_SWITCHING_ISR
(xHigherPriorityTaskWoken);
}
}
Semaphore Management API

Maths is not everything

RMR©2012

93
Synchronizing IH and Tasks with Queues

Semaphores are used to communicate
events.
Queues are used to both communicate
events and transfer data.

Maths is not everything

RMR©2012

94

xQueueSendToFrontFromISR(), xQueueSendToBackFromISR()
and xQueueReceiveFromISR() are versions of
xQueueSendToFront(), xQueueSendToBack() and
xQueueReceive() respectively that are safe to use within an
interrupt service routine.
Queue System Calls (from ISR): send to queue
portBASE_TYPE xQueueSendToFrontFromISR (
xQueueHandle xQueue,
const void* pvItemToQueue,
portBASE_TYPE *pxHigherPriorityTaskWoken);
portBASE_TYPE xQueueSendToBackFromISR (
xQueueHandle xQueue,
const void* pvItemToQueue,
portBASE_TYPE *pxHigherPriorityTaskWoken);

Maths is not everything

RMR©2012

95
Queue System Calls (from ISR): send to queue
portBASE_TYPE xQueueSendToFrontFromISR (
xQueueHandle xQueue,
const void* pvItemToQueue,
portBASE_TYPE *pxHigherPriorityTaskWoken);
portBASE_TYPE xQueueSendToBackFromISR (
xQueueHandle xQueue,
const void* pvItemToQueue,
portBASE_TYPE *pxHigherPriorityTaskWoken);
xQueueSendFromISR() is equivalent to xQueueSendToBackFromISR()

Maths is not everything

RMR©2012

95
Queue System Calls (from ISR): send to queue
portBASE_TYPE xQueueSendToFrontFromISR (
xQueueHandle xQueue,
const void* pvItemToQueue,
portBASE_TYPE *pxHigherPriorityTaskWoken);
portBASE_TYPE xQueueSendToBackFromISR (
xQueueHandle xQueue,
const void* pvItemToQueue,
portBASE_TYPE *pxHigherPriorityTaskWoken);
xQueueSendFromISR() is equivalent to xQueueSendToBackFromISR()
pvItemToQueue - A pointer to the data that will be copied into the queue.
Maths is not everything

RMR©2012

95

pxHigherPriorityTaskWoken - If calling the API function causes a task to leave the Blocked
state, and the unblocked task has a priority higher than the task that was interrupted, then the
API function will internally set *pxHigherPriorityTaskWoken to pdTRUE.
If xQueueSendToFrontFromISR() or xQueueSendToBackFromISR() sets this value to pdTRUE
then a context switch should be performed before the interrupt is exited. This ensure the
interrupt returns directly to the highest priority Ready state task.
Queue System Calls (from ISR): send to queue
portBASE_TYPE xQueueSendToFrontFromISR (
pdPASS will only be
returned if data was
xQueueHandle xQueue,
successfully sent to the
const void* pvItemToQueue,
queue.
portBASE_TYPE *pxHigherPriorityTaskWoken);
portBASE_TYPE xQueueSendToBackFromISR (
xQueueHandle xQueue,
const void* pvItemToQueue,
portBASE_TYPE *pxHigherPriorityTaskWoken);
xQueueSendFromISR() is equivalent to xQueueSendToBackFromISR()
pvItemToQueue - A pointer to the data that will be copied into the queue.
Maths is not everything

RMR©2012

95

pxHigherPriorityTaskWoken - If calling the API function causes a task to leave the Blocked
state, and the unblocked task has a priority higher than the task that was interrupted, then the
API function will internally set *pxHigherPriorityTaskWoken to pdTRUE.
If xQueueSendToFrontFromISR() or xQueueSendToBackFromISR() sets this value to pdTRUE
then a context switch should be performed before the interrupt is exited. This ensure the
interrupt returns directly to the highest priority Ready state task.
Queue System Calls (from ISR): send to queue
portBASE_TYPE xQueueSendToFrontFromISR (
pdPASS will only be
returned if data was
xQueueHandle xQueue,
successfully sent to the
const void* pvItemToQueue,
queue.
portBASE_TYPE *pxHigherPriorityTaskWoken);
errQUEUE_FULL will
be returned if data
could not be written to
the queue because the
queue was already full.

portBASE_TYPE xQueueSendToBackFromISR (
xQueueHandle xQueue,
const void* pvItemToQueue,
portBASE_TYPE *pxHigherPriorityTaskWoken);
xQueueSendFromISR() is equivalent to xQueueSendToBackFromISR()
pvItemToQueue - A pointer to the data that will be copied into the queue.
Maths is not everything

RMR©2012

95

pxHigherPriorityTaskWoken - If calling the API function causes a task to leave the Blocked
state, and the unblocked task has a priority higher than the task that was interrupted, then the
API function will internally set *pxHigherPriorityTaskWoken to pdTRUE.
If xQueueSendToFrontFromISR() or xQueueSendToBackFromISR() sets this value to pdTRUE
then a context switch should be performed before the interrupt is exited. This ensure the
interrupt returns directly to the highest priority Ready state task.
Queue System Calls: (from ISR) receive from queue

portBASE_TYPE xQueueReceiveFromISR (
xQueueHandle xQueue,
void *pvBuffer,
portBASE_TYPE *pxHigherPriorityTaskWoken);

Maths is not everything

RMR©2012

96
Queue System Calls: (from ISR) receive from queue

portBASE_TYPE xQueueReceiveFromISR (
xQueueHandle xQueue,
void *pvBuffer,
portBASE_TYPE *pxHigherPriorityTaskWoken);

pvBuffer - A pointer to the memory into which the received data will be copied.
Maths is not everything

RMR©2012

96

pxHigherPriorityTaskWoken - If calling the API function causes a task to leave the Blocked
state, and the unblocked task has a priority higher than the task that was interrupted, then the
API function will internally set *pxHigherPriorityTaskWoken to pdTRUE.
If xQueueSendToFrontFromISR() or xQueueSendToBackFromISR() sets this value to pdTRUE
then a context switch should be performed before the interrupt is exited. This ensure the
interrupt returns directly to the highest priority Ready state task.
Queue System Calls: (from ISR) receive from queue
pdPASS will only be
returned if data was
successfully read from
the queue.

portBASE_TYPE xQueueReceiveFromISR (
xQueueHandle xQueue,
void *pvBuffer,
portBASE_TYPE *pxHigherPriorityTaskWoken);

pvBuffer - A pointer to the memory into which the received data will be copied.
Maths is not everything

RMR©2012

96

pxHigherPriorityTaskWoken - If calling the API function causes a task to leave the Blocked
state, and the unblocked task has a priority higher than the task that was interrupted, then the
API function will internally set *pxHigherPriorityTaskWoken to pdTRUE.
If xQueueSendToFrontFromISR() or xQueueSendToBackFromISR() sets this value to pdTRUE
then a context switch should be performed before the interrupt is exited. This ensure the
interrupt returns directly to the highest priority Ready state task.
Queue System Calls: (from ISR) receive from queue
pdPASS will only be
returned if data was
successfully read from
the queue.

errQUEUE_EMPTY
will be returned if data
could not be read from
the queue because the
queue was already
empty.

portBASE_TYPE xQueueReceiveFromISR (
xQueueHandle xQueue,
void *pvBuffer,
portBASE_TYPE *pxHigherPriorityTaskWoken);

pvBuffer - A pointer to the memory into which the received data will be copied.
Maths is not everything

RMR©2012

96

pxHigherPriorityTaskWoken - If calling the API function causes a task to leave the Blocked
state, and the unblocked task has a priority higher than the task that was interrupted, then the
API function will internally set *pxHigherPriorityTaskWoken to pdTRUE.
If xQueueSendToFrontFromISR() or xQueueSendToBackFromISR() sets this value to pdTRUE
then a context switch should be performed before the interrupt is exited. This ensure the
interrupt returns directly to the highest priority Ready state task.
Interrupt Nesting
FreeRTOS ports allow interrupts to nest. These
ports require one or both of the following constants
to be defined within FreeRTOSConfig.h
configKERNEL_INTERRUPT_PRIORITY - Sets the interrupt
priority used by the tick interrupt (SysTick), normally configured with
the least possible priority.
configMAX_SYSCALL_INTERRUPT_PRIORITY - Sets the
highest interrupt priority from which interrupt safe FreeRTOS API
functions can be called.
when executing a critical section the kernel disables every
interrupt of equal or lower priority than the one defined by
this constant. This means that FreeRTOS doesn’t disable all
the interrupts even inside critical sections.
Maths is not everything

RMR©2012

97

If configMAX_SYSCALL_INTERRUPT_PRIORITY constant is not used
in the port, then any interrupt that uses the interrupt safe FreeRTOS API
functions must also execute at SysTick priority.
Interrupt Nesting: example

! •!

Interrupts w/ prio. 1 to 3 - prevented from executing while in a critical section, but they
can use the interrupt safe FreeRTOS API functions.

! •!

Interrupts w/ prio. ≥ 4 - not affected by critical sections (kernel cannot prevent these
ISR), within the limitations of the microcontroller itself. Applications requiring very strict
timing accuracy (e.g.motor control) would use a priority above 3 to ensure the scheduler
does not introduce jitter into the interrupts response time.

Maths is not everything

RMR©2012

98
Interrupt Nesting: example

as long as
they don’t use
FreeRTOS API

! •!

Interrupts w/ prio. 1 to 3 - prevented from executing while in a critical section, but they
can use the interrupt safe FreeRTOS API functions.

! •!

Interrupts w/ prio. ≥ 4 - not affected by critical sections (kernel cannot prevent these
ISR), within the limitations of the microcontroller itself. Applications requiring very strict
timing accuracy (e.g.motor control) would use a priority above 3 to ensure the scheduler
does not introduce jitter into the interrupts response time.

Maths is not everything

RMR©2012

98
Interrupt Nesting: example

cannot use
FreeRTOS API

as long as
they don’t use
FreeRTOS API

! •!

Interrupts w/ prio. 1 to 3 - prevented from executing while in a critical section, but they
can use the interrupt safe FreeRTOS API functions.

! •!

Interrupts w/ prio. ≥ 4 - not affected by critical sections (kernel cannot prevent these
ISR), within the limitations of the microcontroller itself. Applications requiring very strict
timing accuracy (e.g.motor control) would use a priority above 3 to ensure the scheduler
does not introduce jitter into the interrupts response time.

Maths is not everything

RMR©2012

98
Interrupt handlers: good practices

configKERNEL_INTERRUPT_PRIORITY must
be set with the lowest possible priority.
All ISR using the safe FreeRTOS API need to be
initialized with a priority level ≤
configMAX_SYSCALL_INTERRUPT_PRIORITY.
ISR extremely critical may have a higher priority
than
configMAX_SYSCALL_INTERRUPT_PRIORITY
but cannot use any FreeRTOS ISR primitive.
Maths is not everything

RMR©2012

99

Note: In some µP, high-priority relates with
high int. numbers, while in others (e.g.
ARM) higher int. numbers means lower
priority.
Maths is not everything

FreeRTOS
Resource Management

RMR©2012
Sharing resources in a multitask environment

In a multitasking system there is the
potential risk of a task to be interrupted
while accessing a resource without
completing it.
the task may leave the resource in an inconsistent
state which could result in data corruption if other
task or interrupt tries to access the same resource.
Examples of shared resources:
Global variables
Maths is not everything

Peripherals
Code

RMR©2012

101
Accessing global variables
Let’s assume the following C code:
	


	


	


GlobalC += 10;

In assembly we got:
1. LOAD R, [#1234]
2. SUM R, 10
3. STORE R, [#1234]
The C statement is not atomic. What are the
consequences? Suppose that:
Task A exec. Inst. 1 ➟ A preempted by B ➟ Task B changes
GlobalC and sleeps afterwards ➟ Task A resumes and exec. 2
and 3, using an old value of GlobalC
Maths is not everything

RMR©2012

102

When a global variable is accessed by more than 1 task, to
assure its consistency, one needs to control the access to
it!
Accessing peripherals

Consider the following scenario where two
tasks attempt to write to an LCD:
Task A executes and starts to write the string “Hello
world” to the LCD.
Task A is preempted by Task B after outputting just
the beginning of the string – “Hello w”.
Task B writes “Abort, Retry, Fail?” to the LCD before
entering the Blocked state.

Maths is not everything

RMR©2012

103

Task A continues from the point at which it was preempted and completes outputting the remaining
characters – “orld”.
The LCD will now be displaying the corrupted string
“Hello wAbort, Retry, Fail?orld”.
Function Reentrancy
A function is reentrant
when it’s safe to call the function from more than one task,
or from interrupts.
Each task maintains its own stack and a fresh set of
register values. If a function does not access any data other
than data that is allocated to the stack or held in a register
then the function is reentrant.

Maths is not everything

RMR©2012

104

/* A parameter is passed into the function. This will either be passed on the stack
or in a CPU register. Either way is safe as each task maintains its own stack and its
own set of register values. */
long lAddOneHundered( long lVar1 )
{
/* This function scope variable will also be allocated to the stack or a register,
depending on compiler and optimization level. Each task or interrupt that calls this
function will have its own copyof lVar2. */
long lVar2;
lVar2 = lVar1 + 100;
/* Most likely the return value will be placed in a CPU register, although it too
could be placed on the stack. */
return lVar2;
}
Function Reentrancy
A function not reentrant
when works with global variables (or static).
Even though each task works with its own stack and a
fresh set of register values, the function does access data
that is shared among all the tasks.

Maths is not everything

/* In this case lVar1 is a global variable so every task that calls the function will
be accessing the same single copy of the variable. */
long lVar1;
long lNonsenseFunction( void )
{
/* This variable is static so is not allocated on the stack. Each task that calls the
function will be accessing the same single copy of the variable. */
static long lState = 0;
long lReturn;
switch( lState )
{
case 0 : lReturn = lVar1 + 10;
lState = 1;
break;
case 1 :

RMR©2012

105

}
}

lReturn = lVar1 + 20;
lState = 0;
break;
Mutual Exclusion

Accessing resources shared between tasks
or between tasks and interrupts needs to be
managed using a ‘mutual exclusion’ technique.
to ensure that once a task starts accessing a shared
resource the same task has exclusive access until the
resource has been returned to a consistent state.
FreeRTOS provides several features for
implementing mutual exclusion
Maths is not everything

RMR©2012

106

but the best is to assure (if possible) that resources are not
shared and each resource is only accessed from a single
task.
Mutual Exclusion by implementing Critical Sections
Basic critical sections are regions of code that
are surrounded by calls to the macros:
taskENTER_CRITICAL()
taskEXIT_CRITICAL()
/* Ensure access to the PORTA register cannot be interrupted -> critical section */
taskENTER_CRITICAL();
/* A switch to another task cannot occur between the call to taskENTER_CRITICAL() and
to taskEXIT_CRITICAL(). Interrupts may still execute on FreeRTOS ports that allow
interrupt nesting, but only interrupts whose priority is above the value assigned to
the configMAX_SYSCALL_INTERRUPT_PRIORITY constant */
PORTA |= 0x01;
/* We have finished accessing PORTA so can safely leave the critical section */
taskEXIT_CRITICAL();

Maths is not everything

It’s a “brute force” method as:
disables all the int. up to configMAX_SYSCALL_INTERRUPT_PRIORITY

RMR©2012

107

preemption results from an interrupt, so taskENTER_CRITICAL()
assures that the task stays in Running until taskEXIT_CRITICAL()
Mutual Exclusion by implementing Critical Sections: example

void vPrintString( const portCHAR *pcString )
{
/* Write the string to stdout, using a critical section as a crude method
of mutual exclusion. */
taskENTER_CRITICAL();
{
printf( "%s", pcString );
fflush( stdout );
}
taskEXIT_CRITICAL();
}

Maths is not everything

RMR©2012

108

Critical sections must be kept very short
otherwise they will adversely affect
interrupt response times.
implementing Critical Sections by pausing the scheduler

Critical sections implemented by suspending
the scheduler only protects a region of code
from access by other tasks because interrupts
remain enabled
A critical section that is too long to be implemented by
disabling interrupts can instead be implemented by suspending
the scheduler
‘un-suspending’ the scheduler may be a relatively lengthy
operation.

Maths is not everything

RMR©2012

109

void vPrintString( const portCHAR *pcString )
{
/* Write the string to stdout, suspending the scheduler as a method of mutual
exclusion. */
vTaskSuspendScheduler();
{
printf( "%s", pcString );
fflush( stdout );
}
xTaskResumeScheduler();
}
Mutual Exclusion through the use of Mutexes
Mutex is a special type of binary semaphore used to
control accesses to a shared resource.
A mutex can be conceptually thought of as a token that
is associated with the resource being shared.
For a task to legitimately access the resource it must
first successfully ‘take’ the token (be the token holder).
When the token holder has finished with the resource
it must ‘give’ the token back (different from BinSem.)

Maths is not everything

RMR©2012

110

Only when the token has been returned can another
task successfully take the token and then safely access
the same shared resource.
A task is not permitted to access the shared resource
unless it holds the token.
Mutual Exclusion through the use of Mutexes: examples

Maths is not everything

RMR©2012

111
Mutual Exclusion through the use of Mutexes: examples

Maths is not everything

RMR©2012

111
Mutual Exclusion through the use of Mutexes: examples

Maths is not everything

RMR©2012

111
Mutual Exclusion through the use of Mutexes: examples

Maths is not everything

RMR©2012

111
Mutual Exclusion through the use of Mutexes: examples

Maths is not everything

RMR©2012

111
Mutual Exclusion through the use of Mutexes: examples

Maths is not everything

RMR©2012

111
Mutual Exclusion through the use of Mutexes: examples

Maths is not everything

RMR©2012

111
Mutual Exclusion through the use of Mutexes: examples

Maths is not everything

RMR©2012

111

The mechanism works purely through the discipline of the application writer. There
is no reason why a task cannot access the resource at any time, but each task
“agrees” not to unless they are first able to become the mutex holder.
Mutex Semaphores

MUTEX Creation & Manipulation
xSemaphoreHandle vSemaphoreCreateMutex(void);
portBASE_TYPE xSemaphoreTake (xSemaphoreHandle xSemaphore,
portTickType xTicksToWait);
portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore);

Maths is not everything

RMR©2012

112
Mutex Semaphores

MUTEX Creation & Manipulation
xSemaphoreHandle vSemaphoreCreateMutex(void);
portBASE_TYPE xSemaphoreTake (xSemaphoreHandle xSemaphore,
portTickType xTicksToWait);
portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore);

When to use

Maths is not everything

RMR©2012

112

When sharing a resource between a task and an ISR, the only option is to use a
critical section, disabling interrupts.
When sharing a resource between tasks the standard mechanism should be the
MUTEX.
Mutex Semaphores

MUTEX Creation & Manipulation
xSemaphoreHandle vSemaphoreCreateMutex(void);
portBASE_TYPE xSemaphoreTake (xSemaphoreHandle xSemaphore,
portTickType xTicksToWait);
portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore);
non-NULL will only be
returned if the MUTEX
was created successfully.

When to use

Maths is not everything

RMR©2012

112

When sharing a resource between a task and an ISR, the only option is to use a
critical section, disabling interrupts.
When sharing a resource between tasks the standard mechanism should be the
MUTEX.
Mutex Semaphores

MUTEX Creation & Manipulation
xSemaphoreHandle vSemaphoreCreateMutex(void);
portBASE_TYPE xSemaphoreTake (xSemaphoreHandle xSemaphore,
portTickType xTicksToWait);
portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore);
non-NULL will only be
returned if the MUTEX
was created successfully.

NULL will be returned if the
MUTEX could not be created.

When to use

Maths is not everything

RMR©2012

112

When sharing a resource between a task and an ISR, the only option is to use a
critical section, disabling interrupts.
When sharing a resource between tasks the standard mechanism should be the
MUTEX.
Using a Mutex

static void prvNewPrintString( const portCHAR *pcString )
{
/* The mutex already exists by the time this task first executes.
Attempt to take the mutex, blocking indefinitely to wait for the mutex
if it is not available straight away. */
/* The call to xSemaphoreTake() will only return when the mutex has
been successfully obtained so there is no need to check the function
return value. If any other delay period was used then the code must
check that xSemaphoreTake() returns pdTRUE before accessing the shared
resource (which in this case is standard out). */
xSemaphoreTake( xMutex, portMAX_DELAY );
{
/* The following line will only execute once the mutex has been
successfully obtained. Standard out can be accessed freely now as
only one task can have the mutex at any one time. */
printf( "%s", pcString );
fflush( stdout );
}
/* The mutex MUST be given back! */
xSemaphoreGive( xMutex );

Maths is not everything

RMR©2012

113

}
Using a Mutex

static void prvPrintTask( void *pvParameters )
{
char *pcStringToPrint;
/* Two instances of this task are created so the string the task will
send to prvNewPrintString() is passed into the task using the task
parameter */
pcStringToPrint = ( char * ) pvParameters;
for( ;; ) {
/* Print out the string using the newly defined function. */
prvNewPrintString( pcStringToPrint );
/* Wait a pseudo random time. Note that rand() is not necessarily
reentrant, but in this case it does not really matter as the code
does not care what value is returned. In a more secure application
a version of rand() that is known to be reentrant should be used,
or calls to rand() should be protected using a critical section.
*/
vTaskDelay( ( rand() & 0x1FF ) );
Maths is not everything

}
}

RMR©2012

114
Using a Mutex

Maths is not everything

RMR©2012

115

int main( void )
{
/* Before a semaphore is used it must be explicitly created */
xMutex = xSemaphoreCreateMutex();
/* Tasks will use a pseudo random delay -> seed the random number generator
*/
srand( 567 );
/* Check if the semaphore was created successfully before creating the
tasks*/
if( xMutex != NULL )
{
/* Create two instances of the tasks that write to stdout. The string they
write is passed in as the task parameter. Tasks are created at different
priorities so some preemption will occur */
xTaskCreate( prvPrintTask, "Print1", 1000,
"Task 1 ******************************************rn", 1, NULL );
xTaskCreate( prvPrintTask, "Print2", 1000,
"Task 2 ------------------------------------------rn", 2, NULL );
/* Start the scheduler to execute the created tasks */
vTaskStartScheduler();
}
/* If all is well then main() will never reach here as the scheduler will
now be
running the tasks. */
for( ;; );
}
Using a Mutex

Maths is not everything

RMR©2012

116

The possible sequence of execution depicted shows the
higher priority Task 2 having to wait for the lower priority
Task 1 to give up control of the mutex
Mutex Problems: Priority Inversion
A higher prio. task being delayed by a lower prio.task due to a
mutual exclusion issue is called ‘priority inversion’.
If a medium priority task started to execute while the high
priority task was waiting for the semaphore the result could
even be worse:
a high priority task waiting for a low priority task without the low
priority task even being able to execute

Maths is not everything

RMR©2012

117
Mutex Problems: Priority Inversion
A higher prio. task being delayed by a lower prio.task due to a
mutual exclusion issue is called ‘priority inversion’.
If a medium priority task started to execute while the high
priority task was waiting for the semaphore the result could
even be worse:
a high priority task waiting for a low priority task without the low
priority task even being able to execute

An interesting REAL example of priority inversion
Maths is not everything

RMR©2012

117

http://www.motherboardpoint.com/really-happened-mars-priority-inversion-and-marspathfinder-t169706.html
Priority Inheritance

it temporarily raises the mutex holder priority to that of the highest
priority task attempting to obtain the same mutex. ➟ LP task holding
the mutex ‘inherits’ the priority of the HP waiting task.
binary semaphores don’t have this feature

Maths is not everything

RMR©2012

118

assumes a task will only hold a single mutex at any one time.

FreeRTOS mutexes automatically provide a basic
‘priority inheritance’ mechanism.
Mutex Problems: deadlock
when two tasks cannot proceed because they are
both waiting for a resource that is held by the
other. Example:
Task A executes and successfully takes mutex X.
Task A is pre-empted by Task B.
Task B successfully takes mutex Y before attempting to also take
mutex X – but mutex X is held by Task A so is not available to
Task B. Task B opts to enter the Blocked state to wait for mutex
X to be released.
Task A continues executing. It attempts to take mutex Y – but
mutex Y is held by Task B so is not available to Task A. Task A opts
to enter the Blocked state to wait for mutex Y to be released.
Maths is not everything

RMR©2012

119

Task A is waiting for a mutex held by Task B, and Task B is waiting
for a mutex held by Task A.

Deadlocks are design errors of an application.
Gatekeepers

Gatekeeper tasks provide a clean method
of mutual exclusion without the worry of
priority inversion or deadlock.
A gatekeeper is a task that has sole ownership of a
resource.
Any other task needing to access the resource can
only do so indirectly by using the services of the
gatekeeper
Maths is not everything

RMR©2012

120

May ease the access to a resource from an interrupt
handler
Gatekeepers

Resource

Task 1

Task 2

Maths is not everything

RMR©2012

121

Queue
M
S
G
2

M
S
G
1

Gatekeeper
The Gatekeeper itself

Maths is not everything

RMR©2012

122

static void prvStdioGatekeeperTask( void *pvParameters )
{
char *pcMessageToPrint;
/* This is the only task that is allowed to write to the terminal output.
Any other task wanting to write a string to the output does not access the
terminal directly, but instead sends the string to this task. As only this
task accesses standard out there are no mutual exclusion or serialization
issues to consider within the implementation of the task itself. */
for( ;; ) {
/* Wait for a message to arrive. An indefinite block time is specified so
there is no need to check the return value – the function will only return
when a message has been successfully received. */
xQueueReceive( xPrintQueue, &pcMessageToPrint, portMAX_DELAY );
/* Output the received string. */
printf( "%s", pcMessageToPrint );
fflush( stdout );
/* Now simply go back to wait for the next message. */
}
}
The tasks that generate messages for the gatekeeper

static void prvPrintTask( void *pvParameters )
{
int iIndexToString;
/* Two instances of this task are created. The task parameter is used to
pass an index into an array of strings into the task */
iIndexToString = ( int ) pvParameters;
for( ;; ) {
/* Print out the string, not directly but instead by passing a pointer
to the string to the gatekeeper task via a queue. The queue is created
before the scheduler is started. A block time is not specified because
there should always be space in the queue. */
xQueueSendToBack( xPrintQueue, &( pcStringsToPrint[ iIndexToString ] ),
0 );
/* Wait a pseudo random time. Note that rand() is not necessarily
reentrant, but in this case it does not really matter as the code does
not care what value is returned. In a more secure application a version
of rand() that is known to be reentrant should be used - or calls to
rand() should be protected using a critical section. */
vTaskDelay( ( rand() & 0x1FF ) );

Maths is not everything

RMR©2012

123

}
}
Interrupt Hook using also the gatekeeper
void vApplicationTickHook( void )
{
static int iCount = 0;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
/* Print out a message every 200 ticks. The message is not written out
directly, but sent to the gatekeeper task. */
iCount++;
if( iCount >= 200 )
{
/* In this case the last parameter (xHigherPriorityTaskWoken) is not
actually used but must still be supplied. */
xQueueSendToFrontFromISR( xPrintQueue, &( pcStringsToPrint[ 2 ] ),
&xHigherPriorityTaskWoken );
/* Reset the count ready to print out the string again in 200 ticks
time. */
iCount = 0;
}
Maths is not everything

RMR©2012

124

}

void vApplicationTickHook( void );
!

Tick hook functions execute within the context of the tick interrupt so must
be kept very short, use only a moderate amount of stack space, and not call
any FreeRTOS API functions whose name does not end with ‘FromISR()’.
creating everything in the Main

Maths is not everything

RMR©2012

125

static char *pcStringsToPrint[] = {
"Task 1 ****************************************************rn",
"Task 2 ----------------------------------------------------rn",
"Message printed from the tick hook interrupt ##############rn"
};
/*-----------------------------------------------------------*/
/* Declare a variable of type xQueueHandle. This is used to send messages from the
print tasks and the tick interrupt to the gatekeeper task. */
xQueueHandle xPrintQueue;
/*-----------------------------------------------------------*/
int main( void )
{
/* Before a queue is used it must be explicitly created. The queue is created to
hold a maximum of 5 character pointers. */
xPrintQueue = xQueueCreate( 5, sizeof( char * ) );
/* The tasks are going to use a pseudo random delay, seed the random number
generator. */
srand( 567 );
/* Check the queue was created successfully. */
if( xPrintQueue != NULL ){
/* Create two instances of the tasks that send messages to the gatekeeper.The
index to the string the task uses is passed to the task via the task
parameter. The tasks are created at different priorities so the higher
priority task will occasionally preempt the lower priority task. */
xTaskCreate( prvPrintTask, "Print1", 1000, ( void * ) 0, 1, NULL );
xTaskCreate( prvPrintTask, "Print2", 1000, ( void * ) 1, 2, NULL )
/* Create the gatekeeper task. This is the only task that is permitted to
directly access standard out. */
xTaskCreate( prvStdioGatekeeperTask, "Gatekeeper", 1000, NULL, 0, NULL );
/* Start the scheduler so the created tasks start executing. */
vTaskStartScheduler();
}
Maths is not everything

FreeRTOS
Memory Management

RMR©2012
Managing memory dynamically

Every time a task, queue or semaphore is
created➟kernel has to allocate RAM.
The standard malloc() and free() library
functions can be used but can also suffer from
one or more of the following problems:
They are not always available on small embedded systems.
Their implementation can be relatively large so take up
valuable code space.
They are not deterministic. The amount of time taken to
execute the functions will differ from call to call.
Maths is not everything

RMR©2012

127

They can suffer from memory fragmentation.
Managing memory dynamically
Different embedded systems have varying RAM
allocation and timing requirements
FreeRTOS treats memory allocation as part of
the portable layer (as opposed to part of the
core code base).
This enables individual applications to provide their own specific
implementation when appropriate.
When the kernel requires RAM, instead of calling malloc()
directly it instead calls pvPortMalloc().
When RAM is being freed, instead of calling free() directly the
kernel instead calls vPortFree().
Maths is not everything

RMR©2012

128

These primitives have the same prototypes as the original
ones.

It’s up to the developer to provide an implementation for the
pvPortMalloc() e vPortFree() allocation memory functions.
Managing memory dynamically

FreeRTOS provides 4 different
implementations that are available in
"FreeRTOS/Source/portable/MemMang"
heap_1.c: just allocates memory.
heap_2.c: allocates and frees memory but does not
handle any fragmentation.
heap_3.c: uses the standard C lib malloc() and free()
implementation.

Maths is not everything

RMR©2012

129

heap_4.c: only available from FreeRTOS 7.2.0 allocates and frees memory, handles fragmentation and
is more efficient than the majority of C lib
implementations.
HEAP_1
Heap_1.c implements a very basic version of pvPortMalloc() and
does not implement vPortFree().
The allocation scheme simply subdivides a simple array into
smaller blocks as calls to pvPortMalloc() are made. The array is
the FreeRTOS heap.
The total size (in bytes) of the array is set by the definition
configTOTAL_HEAP_SIZE within FreeRTOSConfig.h.
Defining a large array in this manner can make the application appear to consume
a lot of RAM – even before any of the array has actually been assigned

Heap_1 is always deterministic.
Maths is not everything

RMR©2012

130

Useful in: any application that never
deletes a task, queue or semaphore.
HEAP_2
It uses a best fit algorithm to allocate memory and unlike heap_1
it does allow memory to be freed.
Heap_2.c also uses a simple array dimensioned by
configTOTAL_HEAP_SIZE..
Again the array is statically declared so it will make the application
appear to consume a lot of RAM.
The best fit algorithm ensures pvPortMalloc() uses the free
block of memory that is closest in size to the number of bytes
requested.
Heap_2 can suffer from fragmentation
Heap_2 is not deterministic.

Maths is not everything

RMR©2012

131

Useful in: applications that repeatedly
create and delete tasks provided the
size of the stack allocated to the
created tasks does not change.

size_t xPortGetFreeHeapSize(void);
HEAP_3
Heap_3.c simply uses the standard library malloc() and free()
function but in a thread safe way.
configTOTAL_HEAP_SIZE does not affect the size of the heap
and is instead defined by the linker configuration.
There is no statically allocated buffer in compilation time

Maths is not everything

RMR©2012

132

void *pvPortMalloc( size_t xWantedSize )
{
void *pvReturn;
vTaskSuspendAll();
{
pvReturn = malloc( xWantedSize );
}
xTaskResumeAll();
return pvReturn;
}
void vPortFree( void *pv )
{
if( pv != NULL )
Useful in: applications that repeatedly
{
vTaskSuspendAll();
allocate and free memory buffers of
{
different size.
free( pv );
}
xTaskResumeAll();
}
}
The Stack

Memory region used for local variables,
registers and parameters.
Each task has its own stack
If its size is under-dimensioned a stack overflow will
occur.
Some techniques do exist for monitoring the use of
the stack and the existence of overflow situations
FreeRTOS provides several features to assist trapping
and debugging stack related issues
Maths is not everything

RMR©2012

133
Stack Overflow - WaterMark
uxTaskGetStackHighWaterMark() is used to query how
near a task has come to overflowing the stack space
allocated to it. This value is called the stack 'high water
mark'.
unsigned portBASE_TYPE
uxTaskGetStackHighWaterMark(xTaskHandle xTask);

Maths is not everything

RMR©2012

134
Stack Overflow - WaterMark
uxTaskGetStackHighWaterMark() is used to query how
near a task has come to overflowing the stack space
allocated to it. This value is called the stack 'high water
mark'.
unsigned portBASE_TYPE
uxTaskGetStackHighWaterMark(xTaskHandle xTask);

xTask - The handle of the task whose stack high water mark is being queried. A task can
query its own stack high water mark by passing NULL in place of a valid task handle

Maths is not everything

RMR©2012

134

Returned value - The amount of stack the task is actually using will grow and shrink as the
task executes and interrupts are processed. uxTaskGetStackHighWaterMark() returns the
minimum amount of remaining stack space that was available since the task started executing.
This is the amount of stack that remained unused when the stack usage was at its greatest
(deepest) value. The closer the high water mark is to 0 the closer the task has come to
overflowing its stack.
Stack Overflow : Run Time Checking
FreeRTOS includes two optional run time stack
checking mechanisms.
controlled by the configCHECK_FOR_ST ACK_OVERFLOW
compile time configuration constant within
FreeRTOSConfig.h.

Both methods will increase the time it takes to
perform a context switch.
In any of these methods the kernel will monitor the
task stacks and execute a stack overflow hook (or
callback) function upon detecting an overflow.
Maths is not everything

RMR©2012

135

void vApplicationStackOverflowHook(
xTaskHandle *pxTask, signed char *pcTaskName);
Use this function to identify and correct stack problems during development.
The goal is simplify the debug and not to recover from a stack that has
overflown.
Stack Overflow : Run Time Checking
Run Time Stack Checking - Method 1
configCHECK_FOR_STACK_OVERFLOW= 1.

Kernel will check whether the stack pointer remains within the
valid stack space after the context has been saved.
The stack overflow hook is called if the stack pointer is found to be
outside of its valid range.
This method is quick to execute but can miss stack overflows that occur
between context saves.

Run Time Stack Checking - Method 2
configCHECK_FOR_STACK_OVERFLOW= 2.

Maths is not everything

RMR©2012

136

When a task is created its stack is filled with a known pattern.
This method walks the last valid 20 bytes of the task stack space
to check that this pattern has not been overwritten.
The stack overflow hook function is called if any of the 20 bytes have
changed from their expected value.
not as quick to execute as 1 but very likely to catch all stack overflows
Maths is not everything

FreeRTOS
Additional Features

RMR©2012
S emb t13-freertos
S emb t13-freertos
S emb t13-freertos
S emb t13-freertos
S emb t13-freertos
S emb t13-freertos
S emb t13-freertos

Mais conteúdo relacionado

Mais procurados

LLVM Instruction Selection
LLVM Instruction SelectionLLVM Instruction Selection
LLVM Instruction SelectionShiva Chen
 
PART-3 : Mastering RTOS FreeRTOS and STM32Fx with Debugging
PART-3 : Mastering RTOS FreeRTOS and STM32Fx with DebuggingPART-3 : Mastering RTOS FreeRTOS and STM32Fx with Debugging
PART-3 : Mastering RTOS FreeRTOS and STM32Fx with DebuggingFastBit Embedded Brain Academy
 
Understanding DPDK algorithmics
Understanding DPDK algorithmicsUnderstanding DPDK algorithmics
Understanding DPDK algorithmicsDenys Haryachyy
 
Intel DPDK Step by Step instructions
Intel DPDK Step by Step instructionsIntel DPDK Step by Step instructions
Intel DPDK Step by Step instructionsHisaki Ohara
 
Introduction to DPDK
Introduction to DPDKIntroduction to DPDK
Introduction to DPDKKernel TLV
 
Linux Preempt-RT Internals
Linux Preempt-RT InternalsLinux Preempt-RT Internals
Linux Preempt-RT Internals哲豪 康哲豪
 
Performance Comparison Between x86 and ARM Assembly
Performance Comparison Between x86 and ARM AssemblyPerformance Comparison Between x86 and ARM Assembly
Performance Comparison Between x86 and ARM AssemblyManasa K
 
The Linux Block Layer - Built for Fast Storage
The Linux Block Layer - Built for Fast StorageThe Linux Block Layer - Built for Fast Storage
The Linux Block Layer - Built for Fast StorageKernel TLV
 
OVS Hardware Offload with TC Flower
OVS Hardware Offload with TC FlowerOVS Hardware Offload with TC Flower
OVS Hardware Offload with TC FlowerNetronome
 
Linux Instrumentation
Linux InstrumentationLinux Instrumentation
Linux InstrumentationDarkStarSword
 
Capturing NIC and Kernel TX and RX Timestamps for Packets in Go
Capturing NIC and Kernel TX and RX Timestamps for Packets in GoCapturing NIC and Kernel TX and RX Timestamps for Packets in Go
Capturing NIC and Kernel TX and RX Timestamps for Packets in GoScyllaDB
 
Linux Interrupts
Linux InterruptsLinux Interrupts
Linux InterruptsKernel TLV
 
PostgreSQL on EXT4, XFS, BTRFS and ZFS
PostgreSQL on EXT4, XFS, BTRFS and ZFSPostgreSQL on EXT4, XFS, BTRFS and ZFS
PostgreSQL on EXT4, XFS, BTRFS and ZFSTomas Vondra
 
Effective Linux Development Using PetaLinux Tools 2017.4
Effective Linux Development Using PetaLinux Tools 2017.4Effective Linux Development Using PetaLinux Tools 2017.4
Effective Linux Development Using PetaLinux Tools 2017.4Zach Pfeffer
 

Mais procurados (20)

FreeRTOS Course - Queue Management
FreeRTOS Course - Queue ManagementFreeRTOS Course - Queue Management
FreeRTOS Course - Queue Management
 
LLVM Instruction Selection
LLVM Instruction SelectionLLVM Instruction Selection
LLVM Instruction Selection
 
PART-3 : Mastering RTOS FreeRTOS and STM32Fx with Debugging
PART-3 : Mastering RTOS FreeRTOS and STM32Fx with DebuggingPART-3 : Mastering RTOS FreeRTOS and STM32Fx with Debugging
PART-3 : Mastering RTOS FreeRTOS and STM32Fx with Debugging
 
Understanding DPDK algorithmics
Understanding DPDK algorithmicsUnderstanding DPDK algorithmics
Understanding DPDK algorithmics
 
C Programming - Refresher - Part III
C Programming - Refresher - Part IIIC Programming - Refresher - Part III
C Programming - Refresher - Part III
 
DPDK In Depth
DPDK In DepthDPDK In Depth
DPDK In Depth
 
FreeRTOS introduction
FreeRTOS introductionFreeRTOS introduction
FreeRTOS introduction
 
Embedded C - Day 2
Embedded C - Day 2Embedded C - Day 2
Embedded C - Day 2
 
Intel DPDK Step by Step instructions
Intel DPDK Step by Step instructionsIntel DPDK Step by Step instructions
Intel DPDK Step by Step instructions
 
Introduction to DPDK
Introduction to DPDKIntroduction to DPDK
Introduction to DPDK
 
Linux Preempt-RT Internals
Linux Preempt-RT InternalsLinux Preempt-RT Internals
Linux Preempt-RT Internals
 
Performance Comparison Between x86 and ARM Assembly
Performance Comparison Between x86 and ARM AssemblyPerformance Comparison Between x86 and ARM Assembly
Performance Comparison Between x86 and ARM Assembly
 
The Linux Block Layer - Built for Fast Storage
The Linux Block Layer - Built for Fast StorageThe Linux Block Layer - Built for Fast Storage
The Linux Block Layer - Built for Fast Storage
 
Advanced C - Part 2
Advanced C - Part 2Advanced C - Part 2
Advanced C - Part 2
 
OVS Hardware Offload with TC Flower
OVS Hardware Offload with TC FlowerOVS Hardware Offload with TC Flower
OVS Hardware Offload with TC Flower
 
Linux Instrumentation
Linux InstrumentationLinux Instrumentation
Linux Instrumentation
 
Capturing NIC and Kernel TX and RX Timestamps for Packets in Go
Capturing NIC and Kernel TX and RX Timestamps for Packets in GoCapturing NIC and Kernel TX and RX Timestamps for Packets in Go
Capturing NIC and Kernel TX and RX Timestamps for Packets in Go
 
Linux Interrupts
Linux InterruptsLinux Interrupts
Linux Interrupts
 
PostgreSQL on EXT4, XFS, BTRFS and ZFS
PostgreSQL on EXT4, XFS, BTRFS and ZFSPostgreSQL on EXT4, XFS, BTRFS and ZFS
PostgreSQL on EXT4, XFS, BTRFS and ZFS
 
Effective Linux Development Using PetaLinux Tools 2017.4
Effective Linux Development Using PetaLinux Tools 2017.4Effective Linux Development Using PetaLinux Tools 2017.4
Effective Linux Development Using PetaLinux Tools 2017.4
 

Destaque

FreeRTOS Xilinx Vivado: Hello World!
FreeRTOS Xilinx Vivado: Hello World!FreeRTOS Xilinx Vivado: Hello World!
FreeRTOS Xilinx Vivado: Hello World!Vincent Claes
 
Stm32f303 rest and Clock contol
Stm32f303 rest and Clock contolStm32f303 rest and Clock contol
Stm32f303 rest and Clock contolPrem Sanil
 
Tech Days 2015: SPARK 2014
Tech Days 2015: SPARK 2014Tech Days 2015: SPARK 2014
Tech Days 2015: SPARK 2014AdaCore
 
An3906 serial to eth freescale
An3906   serial to eth freescaleAn3906   serial to eth freescale
An3906 serial to eth freescaleFernando
 
Tech Days 2015: Multi-language Programming with GPRbuild
Tech Days 2015: Multi-language Programming with GPRbuildTech Days 2015: Multi-language Programming with GPRbuild
Tech Days 2015: Multi-language Programming with GPRbuildAdaCore
 
Bolt mld1717 11100975
Bolt mld1717 11100975Bolt mld1717 11100975
Bolt mld1717 11100975João Moreira
 
S emb t1-introduction
S emb t1-introductionS emb t1-introduction
S emb t1-introductionJoão Moreira
 
Introduction to the new MediaTek LinkIt™ Development Platform for RTOS
Introduction to the new MediaTek LinkIt™ Development Platform for RTOSIntroduction to the new MediaTek LinkIt™ Development Platform for RTOS
Introduction to the new MediaTek LinkIt™ Development Platform for RTOSMediaTek Labs
 
4th ARM Developer Day Presentation
4th ARM Developer Day Presentation4th ARM Developer Day Presentation
4th ARM Developer Day PresentationAntonio Mondragon
 
2013 ARM Student Design Competition @RIT
2013 ARM Student Design Competition @RIT 2013 ARM Student Design Competition @RIT
2013 ARM Student Design Competition @RIT Antonio Mondragon
 
4th ARM Developer Day Presenters info
4th ARM Developer Day Presenters info4th ARM Developer Day Presenters info
4th ARM Developer Day Presenters infoAntonio Mondragon
 
RIT 2nd ARM Developer Day - Texas Instruments Presentation
RIT 2nd ARM Developer Day - Texas Instruments PresentationRIT 2nd ARM Developer Day - Texas Instruments Presentation
RIT 2nd ARM Developer Day - Texas Instruments PresentationAntonio Mondragon
 
Windows Azure – Building & Deploying Cloud Services
Windows Azure – Building & Deploying Cloud Services Windows Azure – Building & Deploying Cloud Services
Windows Azure – Building & Deploying Cloud Services WinWire Technologies Inc
 
Andrew_Liu_ARDrone
Andrew_Liu_ARDroneAndrew_Liu_ARDrone
Andrew_Liu_ARDroneAndrew Liu
 
Sistema de monitoreo multipropósito
Sistema de monitoreo multipropósitoSistema de monitoreo multipropósito
Sistema de monitoreo multipropósitoAntonio Mondragon
 
Indy 500 - 4 years as an indie developer
Indy 500 - 4 years as an indie developerIndy 500 - 4 years as an indie developer
Indy 500 - 4 years as an indie developerDiogo Cardoso
 
Matthew Bailey IoT Keynote - Future of Wireless, Humanity and our Planet
Matthew Bailey IoT Keynote - Future of Wireless, Humanity and our PlanetMatthew Bailey IoT Keynote - Future of Wireless, Humanity and our Planet
Matthew Bailey IoT Keynote - Future of Wireless, Humanity and our PlanetMatthew Bailey
 

Destaque (20)

FreeRTOS Xilinx Vivado: Hello World!
FreeRTOS Xilinx Vivado: Hello World!FreeRTOS Xilinx Vivado: Hello World!
FreeRTOS Xilinx Vivado: Hello World!
 
Stm32f303 rest and Clock contol
Stm32f303 rest and Clock contolStm32f303 rest and Clock contol
Stm32f303 rest and Clock contol
 
Tech Days 2015: SPARK 2014
Tech Days 2015: SPARK 2014Tech Days 2015: SPARK 2014
Tech Days 2015: SPARK 2014
 
An3906 serial to eth freescale
An3906   serial to eth freescaleAn3906   serial to eth freescale
An3906 serial to eth freescale
 
Tech Days 2015: Multi-language Programming with GPRbuild
Tech Days 2015: Multi-language Programming with GPRbuildTech Days 2015: Multi-language Programming with GPRbuild
Tech Days 2015: Multi-language Programming with GPRbuild
 
Bolt mld1717 11100975
Bolt mld1717 11100975Bolt mld1717 11100975
Bolt mld1717 11100975
 
S emb t1-introduction
S emb t1-introductionS emb t1-introduction
S emb t1-introduction
 
Introduction to the new MediaTek LinkIt™ Development Platform for RTOS
Introduction to the new MediaTek LinkIt™ Development Platform for RTOSIntroduction to the new MediaTek LinkIt™ Development Platform for RTOS
Introduction to the new MediaTek LinkIt™ Development Platform for RTOS
 
Los jaliles pesados
Los jaliles pesadosLos jaliles pesados
Los jaliles pesados
 
Exp w21
Exp w21Exp w21
Exp w21
 
4th ARM Developer Day Presentation
4th ARM Developer Day Presentation4th ARM Developer Day Presentation
4th ARM Developer Day Presentation
 
2013 ARM Student Design Competition @RIT
2013 ARM Student Design Competition @RIT 2013 ARM Student Design Competition @RIT
2013 ARM Student Design Competition @RIT
 
4th ARM Developer Day Presenters info
4th ARM Developer Day Presenters info4th ARM Developer Day Presenters info
4th ARM Developer Day Presenters info
 
Arm rit design_comp 2014
Arm rit design_comp 2014Arm rit design_comp 2014
Arm rit design_comp 2014
 
RIT 2nd ARM Developer Day - Texas Instruments Presentation
RIT 2nd ARM Developer Day - Texas Instruments PresentationRIT 2nd ARM Developer Day - Texas Instruments Presentation
RIT 2nd ARM Developer Day - Texas Instruments Presentation
 
Windows Azure – Building & Deploying Cloud Services
Windows Azure – Building & Deploying Cloud Services Windows Azure – Building & Deploying Cloud Services
Windows Azure – Building & Deploying Cloud Services
 
Andrew_Liu_ARDrone
Andrew_Liu_ARDroneAndrew_Liu_ARDrone
Andrew_Liu_ARDrone
 
Sistema de monitoreo multipropósito
Sistema de monitoreo multipropósitoSistema de monitoreo multipropósito
Sistema de monitoreo multipropósito
 
Indy 500 - 4 years as an indie developer
Indy 500 - 4 years as an indie developerIndy 500 - 4 years as an indie developer
Indy 500 - 4 years as an indie developer
 
Matthew Bailey IoT Keynote - Future of Wireless, Humanity and our Planet
Matthew Bailey IoT Keynote - Future of Wireless, Humanity and our PlanetMatthew Bailey IoT Keynote - Future of Wireless, Humanity and our Planet
Matthew Bailey IoT Keynote - Future of Wireless, Humanity and our Planet
 

Semelhante a S emb t13-freertos

TWINS: OOP and FP - Warburton
TWINS: OOP and FP - WarburtonTWINS: OOP and FP - Warburton
TWINS: OOP and FP - WarburtonCodemotion
 
MarGotAspect - An AspectC++ code generator for the mARGOt framework
MarGotAspect - An AspectC++ code generator for the mARGOt frameworkMarGotAspect - An AspectC++ code generator for the mARGOt framework
MarGotAspect - An AspectC++ code generator for the mARGOt frameworkLeonardo Arcari
 
maXbox Starter 43 Work with Code Metrics ISO Standard
maXbox Starter 43 Work with Code Metrics ISO StandardmaXbox Starter 43 Work with Code Metrics ISO Standard
maXbox Starter 43 Work with Code Metrics ISO StandardMax Kleiner
 
Deep Dive into Futures and the Parallel Programming Library
Deep Dive into Futures and the Parallel Programming LibraryDeep Dive into Futures and the Parallel Programming Library
Deep Dive into Futures and the Parallel Programming LibraryJim McKeeth
 
Beyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic AnalysisBeyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic AnalysisFastly
 
379008-rc217-functionalprogramming
379008-rc217-functionalprogramming379008-rc217-functionalprogramming
379008-rc217-functionalprogrammingLuis Atencio
 
Buffer overflow tutorial
Buffer overflow tutorialBuffer overflow tutorial
Buffer overflow tutorialhughpearse
 
Unit 5 quesn b ans5
Unit 5 quesn b ans5Unit 5 quesn b ans5
Unit 5 quesn b ans5Sowri Rajan
 
Safe Clearing of Private Data
Safe Clearing of Private DataSafe Clearing of Private Data
Safe Clearing of Private DataPVS-Studio
 
Кирилл Толкачев. Микросервисы: огонь, вода и девопс
Кирилл Толкачев. Микросервисы: огонь, вода и девопсКирилл Толкачев. Микросервисы: огонь, вода и девопс
Кирилл Толкачев. Микросервисы: огонь, вода и девопсScrumTrek
 
Directive-based approach to Heterogeneous Computing
Directive-based approach to Heterogeneous ComputingDirective-based approach to Heterogeneous Computing
Directive-based approach to Heterogeneous ComputingRuymán Reyes
 
Toub parallelism tour_oct2009
Toub parallelism tour_oct2009Toub parallelism tour_oct2009
Toub parallelism tour_oct2009nkaluva
 
Distributed computing and hyper-parameter tuning with Ray
Distributed computing and hyper-parameter tuning with RayDistributed computing and hyper-parameter tuning with Ray
Distributed computing and hyper-parameter tuning with RayJan Margeta
 
Model Transformation Reuse
Model Transformation ReuseModel Transformation Reuse
Model Transformation Reusemiso_uam
 
maXbox Starter 45 Robotics
maXbox Starter 45 RoboticsmaXbox Starter 45 Robotics
maXbox Starter 45 RoboticsMax Kleiner
 
Twins: Object Oriented Programming and Functional Programming
Twins: Object Oriented Programming and Functional ProgrammingTwins: Object Oriented Programming and Functional Programming
Twins: Object Oriented Programming and Functional ProgrammingRichardWarburton
 
Suite Script 2.0 API Basics
Suite Script 2.0 API BasicsSuite Script 2.0 API Basics
Suite Script 2.0 API BasicsJimmy Butare
 

Semelhante a S emb t13-freertos (20)

TWINS: OOP and FP - Warburton
TWINS: OOP and FP - WarburtonTWINS: OOP and FP - Warburton
TWINS: OOP and FP - Warburton
 
Twins: OOP and FP
Twins: OOP and FPTwins: OOP and FP
Twins: OOP and FP
 
MarGotAspect - An AspectC++ code generator for the mARGOt framework
MarGotAspect - An AspectC++ code generator for the mARGOt frameworkMarGotAspect - An AspectC++ code generator for the mARGOt framework
MarGotAspect - An AspectC++ code generator for the mARGOt framework
 
maXbox Starter 43 Work with Code Metrics ISO Standard
maXbox Starter 43 Work with Code Metrics ISO StandardmaXbox Starter 43 Work with Code Metrics ISO Standard
maXbox Starter 43 Work with Code Metrics ISO Standard
 
Deep Dive into Futures and the Parallel Programming Library
Deep Dive into Futures and the Parallel Programming LibraryDeep Dive into Futures and the Parallel Programming Library
Deep Dive into Futures and the Parallel Programming Library
 
Beyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic AnalysisBeyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic Analysis
 
379008-rc217-functionalprogramming
379008-rc217-functionalprogramming379008-rc217-functionalprogramming
379008-rc217-functionalprogramming
 
Buffer overflow tutorial
Buffer overflow tutorialBuffer overflow tutorial
Buffer overflow tutorial
 
Oct.22nd.Presentation.Final
Oct.22nd.Presentation.FinalOct.22nd.Presentation.Final
Oct.22nd.Presentation.Final
 
Unit 5 quesn b ans5
Unit 5 quesn b ans5Unit 5 quesn b ans5
Unit 5 quesn b ans5
 
Safe Clearing of Private Data
Safe Clearing of Private DataSafe Clearing of Private Data
Safe Clearing of Private Data
 
Кирилл Толкачев. Микросервисы: огонь, вода и девопс
Кирилл Толкачев. Микросервисы: огонь, вода и девопсКирилл Толкачев. Микросервисы: огонь, вода и девопс
Кирилл Толкачев. Микросервисы: огонь, вода и девопс
 
Directive-based approach to Heterogeneous Computing
Directive-based approach to Heterogeneous ComputingDirective-based approach to Heterogeneous Computing
Directive-based approach to Heterogeneous Computing
 
Toub parallelism tour_oct2009
Toub parallelism tour_oct2009Toub parallelism tour_oct2009
Toub parallelism tour_oct2009
 
Distributed computing and hyper-parameter tuning with Ray
Distributed computing and hyper-parameter tuning with RayDistributed computing and hyper-parameter tuning with Ray
Distributed computing and hyper-parameter tuning with Ray
 
Model Transformation Reuse
Model Transformation ReuseModel Transformation Reuse
Model Transformation Reuse
 
Ns2leach
Ns2leachNs2leach
Ns2leach
 
maXbox Starter 45 Robotics
maXbox Starter 45 RoboticsmaXbox Starter 45 Robotics
maXbox Starter 45 Robotics
 
Twins: Object Oriented Programming and Functional Programming
Twins: Object Oriented Programming and Functional ProgrammingTwins: Object Oriented Programming and Functional Programming
Twins: Object Oriented Programming and Functional Programming
 
Suite Script 2.0 API Basics
Suite Script 2.0 API BasicsSuite Script 2.0 API Basics
Suite Script 2.0 API Basics
 

Mais de João Moreira

Mais de João Moreira (11)

S emb t12-os
S emb t12-osS emb t12-os
S emb t12-os
 
S emb t11-processes
S emb t11-processesS emb t11-processes
S emb t11-processes
 
S emb t10-development
S emb t10-developmentS emb t10-development
S emb t10-development
 
S emb t9-arch_power (1)
S emb t9-arch_power (1)S emb t9-arch_power (1)
S emb t9-arch_power (1)
 
S emb t9-arch_power
S emb t9-arch_powerS emb t9-arch_power
S emb t9-arch_power
 
S emb t8-arch_itfio
S emb t8-arch_itfioS emb t8-arch_itfio
S emb t8-arch_itfio
 
S emb t7-arch_bus
S emb t7-arch_busS emb t7-arch_bus
S emb t7-arch_bus
 
S emb t6-arch_mem
S emb t6-arch_memS emb t6-arch_mem
S emb t6-arch_mem
 
S emb t5-arch_io
S emb t5-arch_ioS emb t5-arch_io
S emb t5-arch_io
 
S emb t4-arch_cpu
S emb t4-arch_cpuS emb t4-arch_cpu
S emb t4-arch_cpu
 
S emb t2-definition
S emb t2-definitionS emb t2-definition
S emb t2-definition
 

Último

"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfMounikaPolabathina
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxBkGupta21
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 

Último (20)

"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdf
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptx
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 

S emb t13-freertos

  • 1. Maths is not everything Embedded Systems 7 - Real-Time Operating System (FreeRTOS) RMR©2012 Introduction Task Management Queue Management Interrupts and Synchronization Resource Management Memory Management Aditional Features
  • 2. Maths is not everything FreeRTOS Introduction RMR©2012
  • 3. At the Beginning Written by Richard Barry & FreeRTOS Team Huge number of users all over the world 6000 downloads per month in March 2010, it came on the top of the market study made by www.embedded.com. A good starting point to experience realtime OS Maths is not everything RMR©2012 3 Simple but yet very powerful
  • 4. FreeRTOS in Literature An e-book is written to explain the internals. “Using the FreeRTOS Real Time Kernel - a Practical Guide” 4 editions are available: Standard edition Microchip edition Generic Cortex M3 edition LPC17xx edition FreeRTOS Reference Manual API functions and configuration options Maths is not everything Online documentation RMR©2012 4 www.freertos.org
  • 5. FreeRTOS History FreeRTOS V1.0.1 FreeRTOS V2.0.0 FreeRTOS V1.0.1 + Scalability + New Task APIs FreeRTOS V6.0.0 Maths is not everything 2009 Backward Comp. MPU Support RMR©2012 5 FreeRTOS V3.0.0 API Changes + Directory Names Changed + Changes in Kernel FreeRTOS V4.0.0 FreeRTOS V3.0.0 + Co-routines FreeRTOS V5.0.0 API Changes
  • 6. FreeRTOS Features Architecture Source code Portable Scalable Preemptive and co-operative scheduling Multitasking Services Maths is not everything RMR©2012 6 Interrupt management Advanced features
  • 7. Architecture Application Task 1 Maths is not everything RMR©2012 7 Task 2 Task 3 Task 4
  • 8. Source Code Organization FreeRTOS main kernel source directory Source include kernel header files directory Portable kernel port Compiler x Compiler y RMR©2012 8 compiler x port MemMang Maths is not everything compiler x port malloc/free implementation Demo Common demo app common directory Dir x demo app of port x demo app of port y Dir y
  • 9. Source Code Organization Maths is not everything RMR©2012 9 port.c and portmacro.h files within the HAL
  • 10. Portability Highly portable C 24 architectures supported Assembly is kept minimum. Ports are freely available in source code. Other contributions do exist. Maths is not everything RMR©2012 10
  • 11. Scalable Use the service you only need: FreeRTOSConfig.h Very few services / Complete services available A group of #defines determines scalability. Minimum footprint = 4 KB Maths is not everything RMR©2012 11
  • 12. FreeRTOSConfig.h Maths is not everything RMR©2012 12 #define configUSE_PREEMPTION 1 #define configCPU_CLOCK_HZ 58982400 #define configTICK_RATE_HZ 250 #define configMAX_PRIORITIES 5 #define configMINIMAL_STACK_SIZE 128 #define configTOTAL_HEAP_SIZE 10240 #define configMAX_TASK_NAME_LEN 16 #define configUSE_MUTEXES 0 ... #define INCLUDE_vTaskDelete 1 #define INCLUDE_vTaskDelay 1 #define INCLUDE_xTaskGetCurrentTaskHandle 1 #define INCLUDE_uxTaskGetStackHighWaterMark 0 #define INCLUDE_xTaskGetIdleTaskHandle 0 ...
  • 13. Preemptive and Cooperative Scheduling Preemptive scheduling: Fully preemptive Always runs the highest priority task that is ready to run Comparable with other preemptive kernels Used in conjunction with tasks Cooperative scheduling: Context switch occurs if: A task/co-routine blocks Or a task/co-routine yields the CPU Used in conjunction with tasks/co-routines Maths is not everything A hybrid of both scheduling can be used in your application. Application = Tasks RMR©2012 13 Or Application = Tasks + Co-routines Tasks have higher priority than Co-routines
  • 14. Tasks vs Co-routines Tasks Co-routines no restrictions API calls have restrictions totally prioritized totally prioritized among coroutines but interruptible by tasks when using hybrid mode each task maintains its own stack re-entrance has to be tackled carefully when used with preemption stack shared among them re-entrance managed by cooperation (less problematic) Maths is not everything RMR©2012 14 cooperation only between coroutines
  • 15. Multitasking No software restriction on: # of tasks that can be created # of priorities that can be used Priority assignment More than one task can be assigned the same priority. RR with time slice = 1 RTOS tick Maths is not everything RMR©2012 15
  • 16. Services Queues Semaphores Binary and counting Mutexes With priority inheritance Maths is not everything RMR©2012 16 Support recursion
  • 17. Interrupts An interrupt can suspend a task execution. Interrupt mechanism is port dependent. Nesting Scheduling after interrupts Preemptive or cooperative scheduler Maths is not everything RMR©2012 17
  • 18. Advanced Features Execution tracing Run time statistics collection Memory management Memory protection support Maths is not everything RMR©2012 18 Stack overflow protection
  • 19. Conventions: variables’ names In FreeRTOS a prefix is used in the name of the variables indicating its type Chars start with a “c” Shorts start with an “s” Longs start with an “l” other types start with an “x” (e.g. structures) unsigned vars start with an “u” pointers start with a “p” Maths is not everything RMR©2012 19
  • 20. Conventions: functions’ names private functions start with “prv” API functions’ return are pre-fixed with the same convention as variables API functions start with the name of the source archive where they were defined e.g. xTaskCreate is defined in Task.c Maths is not everything RMR©2012 20
  • 21. Licensing Modified GPL (Real Time Engineers Ltd.) Only FreeRTOS is GPL. Open-source code, no royalties involved May be used freely in commercial applications Any modifications to the kernel need to be made available as open-source code Any app source code can be maintained as private provided that no new functionalities at the kernel level is involved Maths is not everything RMR©2012 21 FreeRTOS can’t be used in any comparisons without the authors’ permission.
  • 22. Other FreeRTOS Variants OpenRTOS (High Integrity Systems) = FreeRTOS + Commercial License Tailored BSP, middle ware, applications … no need to publish any kernel modification as open-source Training, technical support, guaranties, ... Platform preparation SafeRTOS = FreeRTOS + Commercial + IEC61508 SIL3 Certification (critical apps) Maths is not everything Compliant with: FDA510(k) Class III medical device standards RMR©2012 22 EN62304
  • 23. Maths is not everything FreeRTOS Kernel Structure - Tasks RMR©2012
  • 24. Task States Running task is executing owning the CPU Ready task may run but is waiting for the CPU to be available, Blocked task is delayed (timing / event) or is waiting for another task (synchronization) Suspended task may enter this state only through specific calls Maths is not everything RMR©2012 24 there is no associated timeout not considered in scheduling
  • 25. Global characteristic of a task Every task behaves as an isolated sequential program has a single entry point implemented usually as an infinite loop normally, it never returns. If eventually it ends, it’s up to the programmer to remove it (kill) from the kernel’s list. Task prototype Maths is not everything RMR©2012 25 void ATaskFunction(void *pvParameters);
  • 26. Task skeleton void ATaskFunction( void *pvParameters ) { /* Variables can be declared just as per a normal function. Each instance of a task created using this function will have its own copy of the iVariableExample variable. This would not be true if the variable was declared static – in which case only one copy of the variable would exist and this copy would be shared by each created instance of the task. */ int iVariableExample = 0; /* A task will normally be implemented as in infinite loop. */ for( ;; ) { /* The code to implement the task functionality will go here. */ } /* Should the task implementation ever break out of the above loop then the task must be deleted before reaching the end of this function. The NULL parameter passed to the vTaskDelete() function indicates that the task to be deleted is the calling (this) task. */ vTaskDelete( NULL ); Maths is not everything RMR©2012 26 }
  • 27. Typical Application Maths is not everything RMR©2012 27
  • 28. Task creation portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, const char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pvCreatedTask ); pvTaskCode: a pointer to the function (actually just the name) where the task is implemented. pcName: name given to the task. This is useless to FreeRTOS but is intended for debugging purposes (human readable) only. usStackDepth: length of the stack (each task has its own stack) for this task in words. Should be tailored to task needs. Maths is not everything RMR©2012 28 pvParameters: a pointer to arguments given to the task. A good practice consists in creating a dedicated structure, instantiate and fill it then give its pointer to the task. uxPriority: priority given to the task, a number between 0 and MAX_PRIORITIES – 1. pxCreatedTask: a pointer to an identifier that allows to handle the task. If the task does not have to be handled in the future, this can be leaved NULL.
  • 29. Task creation portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, const char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pvCreatedTask ); Returned Value - there are two possible return values: 1. pdTrue: indicates that the task has been launched successfully. Maths is not everything 2. errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY: indicates that the task could not be created because there was insufficient heap memory available for FreeRTOS to allocate RAM to hold the task data structures and stack. RMR©2012 29
  • 30. Example application that uses RTOS v v v v Maths is not everything RMR©2012 30
  • 31. Example application: execution sequence (ARM) Maths is not everything RMR©2012 31
  • 32. Task Control Block Maths is not everything RMR©2012 32
  • 33. Example application: Data-structures maintained by RTOS Initially After TaskCreate(1) currentTask currentTask Maths is not everything RMR©2012 33 0 NULL 1 NULL 1 Task1 2 NULL 2 NULL 3 NULL 3 NULL NULL n-1 NULL pxReadyTaskList NULL n-1 pxReadyTaskList 0
  • 34. Example application: Data-structures maintained by RTOS After TaskCreate(2) currentTask After TaskStartSchedule () currentTask Task2 Maths is not everything RMR©2012 34 0 idle 1 Task1 1 Task1 2 Task2 2 NULL 3 NULL 3 NULL NULL n-1 NULL pxReadyTaskList NULL n-1 pxReadyTaskList 0
  • 35. Ready and Blocked Lists Maths is not everything RMR©2012 35
  • 36. Hypothetical DelayedTaskList Maths is not everything RMR©2012 36
  • 37. Tasks within tasks void vTask1( void *pvParameters ) { const char *pcTaskName = "Task 1 is runningrn"; volatile unsigned long ul; /* If this task is executing then the scheduler must already have been started. Create the other task before entering the infinite loop.*/ xTaskCreate( vTask2, "Task 2", 1000, NULL, 1, NULL ); for( ;; ) { /* Print out the name of this task. */ vPrintString( pcTaskName ); /* Delay for a period. */ for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ ) { /* This loop is just a very crude delay implementation. There is nothing to do in here. There is a need for proper delay/ sleep function. */ } Maths is not everything } RMR©2012 37 }
  • 38. Using the task parameter void vTaskFunction( void *pvParameters ) { char *pcTaskName; volatile unsigned long ul; /* The string to print out is passed in via the parameter. Cast to a char ptr.*/ pcTaskName = ( char * ) pvParameters; /* As per most tasks, this task is implemented in an infinite loop. */ for( ;; ) { /* Print out the name of this task. */ vPrintString( pcTaskName ); /* Delay for a period. */ for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ ) { /* This loop is just a very crude delay implementation. There is nothing to do in here.*/ } } } Maths is not everything RMR©2012 38 /* Define the strings to be passed in as the task parameters. These are defined const and not on the stack to ensure they remain valid when the tasks are executing. */ static const char *pcTextForTask1 = “Task 1 is runningrn”; static const char *pcTextForTask2 = “Task 2 is runningtn”; int main( void ) { /* Create one of the two tasks. */ xTaskCreate( vTaskFunction, "Task 1", 1000, (void*)pcTextForTask1, 1, NULL ); /* Create the other instance of the same task. */ xTaskCreate( vTaskFunction, "Task 2", 1000, (void*)pcTextForTask2, 2, NULL ); /* Start the scheduler so the tasks start executing. */ vTaskStartScheduler(); for( ;; ); }
  • 39. Block State: the delay primitive void vTaskDelay(portTickType xTicksToDelay); Delays for xTicksToDelay kernel ticks, while allowing other tasks to execute portTickType is unsigned char Argument is number of kernel ticks to delay Upon completion of the delay task is returned to ready state, resumes execution when possible Maths is not everything RMR©2012 39 Constants configTICK_RATE_MS and configTICK_RATE_HZ usable to get desired time delay
  • 40. Blocking: delaying a task for a period of time void vTaskFunction( void *pvParameters ) { char *pcTaskName; /* The string to print out is passed in via the parameter */ pcTaskName = ( char * ) pvParameters; /* As per most tasks, this task is implemented in an infinite loop. */ for( ;; ) { /* Print out the name of this task. */ vPrintString( pcTaskName ); /* Delay for a period. Call to vTaskDelay() places the task into the Blocked state until the delay period has expired. The delay period is specified in 'ticks', but the constant portTICK_RATE_MS can be used to convert this to a value in milliseconds*/ vTaskDelay( 250 / portTICK_RATE_MS ); } } Maths is not everything RMR©2012 40
  • 41. Block State: the exact delay primitive void vTaskDelayUntil(portTickType *pxPreviousWakeTime, portTickType xTimeIncrement); vTaskDelay() specifies the number of ticks between the call and the same task once again transitioning out of the Block state. But this amount of time is relative to the time at which vTaskDelay() was called. Delays for xTimeIncrement from last time called Used for cyclic tasks, such as e.g. keypad scanning First argument is variable with last time woken up Second argument is number of ticks between wake-ups Maths is not everything The parameters specify the exact tick count value at which the calling task should be moved from the Blocked state into the Ready state. The time at which the calling task is unblocked is absolute, rather than relative to when the function was called (as is the case with vTaskDelay()) RMR©2012 41
  • 42. Blocking: delaying a task for the same EXACT period of time void vTaskFunction( void *pvParameters ) { char *pcTaskName; portTickType xLastWakeTime; /* The string to print out is passed in via the parameter. Cast this to a char pointer. */ pcTaskName = ( char * ) pvParameters; /* The xLastWakeTime variable needs to be initialized with the current tick count. Note that this is the only time the variable is written to explicitly. After this xLastWakeTime is updated automatically internally within vTaskDelayUntil(). */ xLastWakeTime = xTaskGetTickCount(); /* As per most tasks, this task is implemented in an infinite loop. */ for( ;; ) { /* Print out the name of this task. */ vPrintString( pcTaskName ); /* This task should execute exactly every 250 milliseconds. As per the vTaskDelay() function, time is measured in ticks, and the portTICK_RATE_MS constant is used to convert milliseconds into ticks. xLastWakeTime is automatically updated within vTaskDelayUntil() so is not explicitly updated by the task. */ vTaskDelayUntil( &xLastWakeTime, ( 250 / portTICK_RATE_MS ) ); Maths is not everything RMR©2012 42 } }
  • 43. Priorities Priorities range from 0 (lowest priority) up to (configMAX_PRIORITIES – 1) defined in FreeRTOSConfig.h. the higher the MAX_PRIORITIES parameter is the higher the RAM requirements will be. Tasks will have priorities according to their real-time characteristics The scheduler will guarantee that the ready task with the highest priority will be the one to be executed Maths is not everything RMR©2012 43 Tasks may have the same priority. In this case the scheduler will execute them in a round-robin fashion.
  • 44. Scheduler and Priorities Task scheduling decides which “Ready” task has to be run at a given time. FreeRTOS uses priorities for this purpose. Priority is the only element the scheduler takes into account to decide which task has to be switched in. Every clock tick makes the scheduler to decide which task has to be waken up. Maths is not everything RMR©2012 44
  • 45. Scheduler and Priorities There is no automatic management of priorities a task always keeps the same priority unless the programmer change it explicitly. A low value means a low priority: priority 0 is the minimal priority a task could have and this level should be strictly reserved for the idle task. Task management allows an implementation of Rate Monotonic: tasks with higher frequencies are given an higher priority whereas low frequencies tasks deserve a low priority. Event­based or continuous tasks are preempted by periodic tasks. Maths is not everything RMR©2012 45
  • 46. Equally-priority tasks Tasks created with an equal priority are treated equally by the scheduler If two of them are ready to run, the scheduler shares running time among all of them This configures a Round Robin implementation where quantum is the time between each clock tick. This value is available in TICK_RATE_HZ constant, in FreeRTOSConfig.h Maths is not everything RMR©2012 46
  • 47. The idle task When all tasks are either blocked or suspended the CPU needs to be executing something The Idle Task is then executed! this task is automatically created when the scheduler is started ➱ vTaskStartScheduler(). this task has priority 0 (lowest possible). Normally, the idle task does nothing (actually is when idle task runs that the kernel does some housekeeping like purging deleted tasks stuff) Maths is not everything RMR©2012 47 It is however possible to add application specific functionality directly into the idle task through the use of an idle hook (or call-back) function – a function that is automatically called by the idle task once per iteration of the idle task loop.
  • 48. Idle Task Hook Common uses for the Idle task hook include: Executing low priority, background or continuous processing. Measuring the amount of spare processing capacity measuring the amount of processing time allocated to the idle task provides a clear indication of how much processing time is spare Placing the processor into a low power mode To run it ➱ configUSE_IDLE_HOOK must be set to 1 within FreeRTOSConfig.h /* Declare a variable that will be incremented by the hook function. */ unsigned long ulIdleCycleCount = 0UL; Maths is not everything /* Idle hook functions MUST be called vApplicationIdleHook(), take no parameters, and return void. */ void vApplicationIdleHook( void ) { RMR©2012 48 /* This hook function does nothing but increment a counter. */ ulIdleCycleCount++; }
  • 49. Tick Interrupt Hook It is possible to implement a callback function to be called at every tick interrupt: this function can be used to run a periodic routine like the one needed to reset the watchdog timer; as this routine runs in interrupt time, its processing effort should be kept at a minimum, using short code and only a moderate amount of stack space and not call any FreeRTOS API functions whose name does not end with ‘FromISR()’. To run it ➱ configUSE_TICK_HOOK must be set to 1 within FreeRTOSConfig.h Maths is not everything RMR©2012 49 provide the implementation of the hook function using: void vApplicationTickHook( void );
  • 50. Suspended State Tasks in the Suspended state are not scheduled by the kernel The only way to enter the Suspended State is by invoking the vTaskSuspended() primitive The only way to exit the Suspended State is by invoking the vTaskResume() primitive Maths is not everything RMR©2012 50
  • 51. Scheduler review Each application comprises one or more tasks. Each task is assigned a priority. Each task can exist in one of several states. (Running, Ready, Blocked, Suspended). Only one task can exist in the Running state at any one. Maths is not everything RMR©2012 51 The scheduler will always select the highest priority Ready state task to enter the Running state.
  • 52. Task Management API Maths is not everything RMR©2012 52
  • 53. Maths is not everything FreeRTOS Queues RMR©2012
  • 54. FreeRTOS Queues Queue is a communication mechanism between tasks or between tasks and interrupt handlers Tasks: xQueueSend, xQueueReceive, uxQueueMessagesWaiting ISRs: xQueueSendFromISR, xQueueReceiveFromISR Tasks can wait for items to enter/exit the queue while allowing other tasks to execute Maths is not everything RMR©2012 54
  • 55. Queue’s characteristics A queue doesn’t belong to a given task. Many tasks and int. handlers may share the same queue, either for reading or writing. Each queue stores a finite number of data items (queue length). Every item has a fixed sized (item size). Both "queue length" and "item size" are set when the queue is created. FreeRTOS allocates heap space for storing the queue. Queues hold data in order, First In First Out (FIFO) Writing to a queue causes a byte for byte copy of the data to be stored in the queue. Maths is not everything RMR©2012 55 Reading from a queue causes the copy of the data to be removed from the queue. for this reason, if the element size is too big is better to work with pointers
  • 56. Queue’s characteristics: reading from a queue When a task attempts to read from a queue it may enter into the Blocked state waiting for an item in there. A task may define a reading timeout ➟ time it is kept in the Blocked state waiting for data, should the queue is empty. A task in the Blocked state waiting for data to become available is automatically moved into the Ready state when: An item is written into the queue. The reading timeout expires. Queues can have more than one task blocked on it waiting for data, as queues can have multiple readers. Maths is not everything RMR©2012 56 only one task (the one waiting for data with the highest priority) will be unblocked when data becomes available. blocked tasks with equal priority ➟ the task that has been waiting for data the longest will be unblocked.
  • 57. Queue’s characteristics: writing to a queue When a task attempts to write to a queue it may enter into the Blocked state if the queue is full. A task may define a writing timeout ➟ time it is kept in the Blocked state waiting for space in the queue, should the queue is full. A task trying to write an item into a queue is automatically moved into the Ready state when: The item is successfully written into the queue. The writing timeout expires. Queues can have multiple writers; so, more than one task can be blocked on it waiting for sending data. Maths is not everything RMR©2012 57 only one task (the one waiting for queue space with the highest priority) will be unblocked when space becomes available. blocked tasks with equal priority ➟ the task that has been waiting for space the longest will be unblocked.
  • 58. Queue read/write: example Maths is not everything RMR©2012 58
  • 59. Queue read/write: example Maths is not everything RMR©2012 58
  • 60. Queue read/write: example Maths is not everything RMR©2012 58
  • 61. Queue Creation Creates a queue for uxQueueLength items of size uxItemSize bytes per item Handle should be global variables if ISRs and tasks need to access it After creation, check to see if not null before use xQueueHandle xQueueCreate (unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize); uxQueueLength - The maximum number of items that the queue being created can hold at any one time. uxItemSize - The size in bytes of each data item that can be stored in the queue. Return Value - If NULL is returned then the queue could not be created because there was insufficient heap memory available for FreeRTOS to allocate the queue data structures and storage area. A non-NULL value being returned indicates that the queue was created successfully. The returned value should be stored as the handle to the created queue. Maths is not everything RMR©2012 59 xQueueHandle MyQueue; int main( void ) { ... MyQueue = xQueueCreate( 20, sizeof( unsigned char ) ); ... }
  • 62. Queue System Calls: send to queue portBASE_TYPE xQueueSendToFront ( xQueueHandle xQueue, const void* pvItemToQueue, portTickType xTicksToWait); portBASE_TYPE xQueueSendToBack ( xQueueHandle xQueue, const void* pvItemToQueue, portTickType xTicksToWait); Maths is not everything RMR©2012 60
  • 63. Queue System Calls: send to queue portBASE_TYPE xQueueSendToFront ( xQueueHandle xQueue, const void* pvItemToQueue, portTickType xTicksToWait); portBASE_TYPE xQueueSendToBack ( xQueueHandle xQueue, const void* pvItemToQueue, portTickType xTicksToWait); xQueueSend() is equivalent to and exactly the same as xQueueSendToBack() Maths is not everything RMR©2012 60
  • 64. Queue System Calls: send to queue portBASE_TYPE xQueueSendToFront ( xQueueHandle xQueue, const void* pvItemToQueue, portTickType xTicksToWait); portBASE_TYPE xQueueSendToBack ( xQueueHandle xQueue, const void* pvItemToQueue, portTickType xTicksToWait); xQueueSend() is equivalent to and exactly the same as xQueueSendToBack() pvItemToQueue - A pointer to the data that will be copied into the queue. Maths is not everything RMR©2012 60 xTicksToWait - The maximum amount of time the task should remain in the Blocked state, should the queue already be full. Both xQueueSendToFront() and xQueueSendToBack() will return immediately if xTicksToWait is 0 and the queue is already full. Setting xTicksToWait to portMAX_DELAY will cause the task to wait indefinitely (without timing out) provided INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h.
  • 65. Queue System Calls: send to queue pdPASS will only be portBASE_TYPE xQueueSendToFront ( returned if data was successfully sent to the xQueueHandle xQueue, queue. const void* pvItemToQueue, portTickType xTicksToWait); portBASE_TYPE xQueueSendToBack ( xQueueHandle xQueue, const void* pvItemToQueue, portTickType xTicksToWait); xQueueSend() is equivalent to and exactly the same as xQueueSendToBack() pvItemToQueue - A pointer to the data that will be copied into the queue. Maths is not everything RMR©2012 60 xTicksToWait - The maximum amount of time the task should remain in the Blocked state, should the queue already be full. Both xQueueSendToFront() and xQueueSendToBack() will return immediately if xTicksToWait is 0 and the queue is already full. Setting xTicksToWait to portMAX_DELAY will cause the task to wait indefinitely (without timing out) provided INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h.
  • 66. Queue System Calls: send to queue pdPASS will only be portBASE_TYPE xQueueSendToFront ( returned if data was successfully sent to the xQueueHandle xQueue, queue. const void* pvItemToQueue, portTickType xTicksToWait); portBASE_TYPE xQueueSendToBack ( xQueueHandle xQueue, const void* pvItemToQueue, portTickType xTicksToWait); errQUEUE_FULL will be returned if data could not be written to the queue because the queue was already full. xQueueSend() is equivalent to and exactly the same as xQueueSendToBack() pvItemToQueue - A pointer to the data that will be copied into the queue. Maths is not everything RMR©2012 60 xTicksToWait - The maximum amount of time the task should remain in the Blocked state, should the queue already be full. Both xQueueSendToFront() and xQueueSendToBack() will return immediately if xTicksToWait is 0 and the queue is already full. Setting xTicksToWait to portMAX_DELAY will cause the task to wait indefinitely (without timing out) provided INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h.
  • 67. Queue System Calls: receive from queue portBASE_TYPE xQueueReceive ( xQueueHandle xQueue, void *pvBuffer, portTickType xTicksToWait); portBASE_TYPE xQueuePeek ( xQueueHandle xQueue, void *pvBuffer, portTickType xTicksToWait); Maths is not everything RMR©2012 61
  • 68. Queue System Calls: receive from queue portBASE_TYPE xQueueReceive ( xQueueHandle xQueue, void *pvBuffer, portTickType xTicksToWait); portBASE_TYPE xQueuePeek ( xQueueHandle xQueue, void *pvBuffer, portTickType xTicksToWait); xQueuePeek() is used to receive an item from a queue without the item being removed from the queue Maths is not everything RMR©2012 61
  • 69. Queue System Calls: receive from queue portBASE_TYPE xQueueReceive ( xQueueHandle xQueue, void *pvBuffer, portTickType xTicksToWait); portBASE_TYPE xQueuePeek ( xQueueHandle xQueue, void *pvBuffer, portTickType xTicksToWait); xQueuePeek() is used to receive an item from a queue without the item being removed from the queue pvBuffer - A pointer to the memory into which the received data will be copied. Maths is not everything RMR©2012 61 xTicksToWait - The maximum amount of time the task should remain in the Blocked state, should the queue already be empty. Both xQueueReceive() and xQueuePeek() will return immediately if xTicksToWait is 0 and the queue is already empty. Setting xTicksToWait to portMAX_DELAY will cause the task to wait indefinitely (without timing out) provided INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h.
  • 70. Queue System Calls: receive from queue pdPASS will only be portBASE_TYPE xQueueReceive ( returned if data was successfully read from xQueueHandle xQueue, the queue. void *pvBuffer, portTickType xTicksToWait); portBASE_TYPE xQueuePeek ( xQueueHandle xQueue, void *pvBuffer, portTickType xTicksToWait); xQueuePeek() is used to receive an item from a queue without the item being removed from the queue pvBuffer - A pointer to the memory into which the received data will be copied. Maths is not everything RMR©2012 61 xTicksToWait - The maximum amount of time the task should remain in the Blocked state, should the queue already be empty. Both xQueueReceive() and xQueuePeek() will return immediately if xTicksToWait is 0 and the queue is already empty. Setting xTicksToWait to portMAX_DELAY will cause the task to wait indefinitely (without timing out) provided INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h.
  • 71. Queue System Calls: receive from queue pdPASS will only be portBASE_TYPE xQueueReceive ( returned if data was successfully read from xQueueHandle xQueue, the queue. void *pvBuffer, portTickType xTicksToWait); portBASE_TYPE xQueuePeek ( xQueueHandle xQueue, void *pvBuffer, portTickType xTicksToWait); errQUEUE_EMPTY will be returned if data could not be read from the queue because the queue was already empty. xQueuePeek() is used to receive an item from a queue without the item being removed from the queue pvBuffer - A pointer to the memory into which the received data will be copied. Maths is not everything RMR©2012 61 xTicksToWait - The maximum amount of time the task should remain in the Blocked state, should the queue already be empty. Both xQueueReceive() and xQueuePeek() will return immediately if xTicksToWait is 0 and the queue is already empty. Setting xTicksToWait to portMAX_DELAY will cause the task to wait indefinitely (without timing out) provided INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h.
  • 72. Queue System Calls: auxiliary unsigned portBASE_TYPE uxQueueMessagesWaiting ( xQueueHandle xQueue); uxQueueMessagesWaiting() is used to query the number of items that are currently in a queue Never call uxQueueMessagesWaiting() from an interrupt service routine. The interrupt safe uxQueueMessagesWaitingFromISR() should be used in its place Maths is not everything RMR©2012 62
  • 73. Queue System Calls in Int. Handlers Never use the previous SysCalls within Int. Handlers! In these handlers use the SysCalls ending with“FromISR()”. Examples: XQueueSendToFrontFromISR(). XQueueSendToBackFromISR(). XQueueReceiveFromISR(). Maths is not everything RMR©2012 63
  • 74. Queue System Calls: examples Maths is not everything RMR©2012 64 /* To store the reference to the queue that is accessed by all three tasks. */ xQueueHandle xQueue; int main( void ) { /* queue is to hold a max of 5 values, each of type long. */ xQueue = xQueueCreate( 5, sizeof( long ) ); if( xQueue != NULL ) { /* Create 2 instances of the task that will send to the queue. Task par. is used to pass the value that the task will write to the queue; only one task will continuously write 100 to the queue while the other task will continuously write 200. Both tasks created w/ prio 1 */ xTaskCreate( vSenderTask, "Sender1", 1000, ( void * ) 100, 1, NULL ); xTaskCreate( vSenderTask, "Sender2", 1000, ( void * ) 200, 1, NULL ); /* Create the task that will read from the queue. The task is created with priority 2, so above the priority of the sender tasks */ xTaskCreate( vReceiverTask, "Receiver", 1000, NULL, 2, NULL ); /* Start the scheduler so the created tasks start executing. */ vTaskStartScheduler(); }else { /* The queue could not be created. */ } /* If all is well then main() will never reach here as the scheduler will now be running the tasks. Otherwise, it is likely that there was insufficient heap memory available for the idle task to be created*/ for( ;; ); }
  • 75. Queue System Calls: examples Maths is not everything RMR©2012 65 static void vSenderTask( void *pvParameters ) { long lValueToSend; portBASE_TYPE xStatus; /* queue was created to hold ‘long’ values, so cast to the required type */ lValueToSend = ( long ) *pvParameters; for( ;; ) { /* Send the value to the queue. The queue was created before the scheduler was started. The 2nd parameter -> address of the data to be sent. The 3rd parameter -> time the task should wait for space in the queue. In this case a block time is not specified because the queue should never contain more than one item and therefore never be full */ xStatus = xQueueSendToBack( xQueue, &lValueToSend, 0 ); if( xStatus != pdPASS ) { /* The send operation could not complete because the queue was full - must be an error as the queue should never have more than one item! */ vPrintString( "Could not send to the queue.rn" ); } /* Allow the other sender task to execute. taskYIELD() informs the scheduler that a switch should occur now rather than keeping this task in the Running state until the end of the current time slice */ taskYIELD(); } }
  • 76. Queue System Calls: examples Maths is not everything RMR©2012 66 static void vReceiverTask( void *pvParameters ) { long lReceivedValue; portBASE_TYPE xStatus; const portTickType xTicksToWait = 100 / portTICK_RATE_MS; for( ;; ) { /* call should always find the queue empty as this task will immediately remove any data that is written to the queue */ if( uxQueueMessagesWaiting( xQueue ) != 0 ) { vPrintString( "Queue should have been empty!rn" ); } /* Receive data from the queue. 2nd par. -> the buffer that receives data in queue. Buffer is an address of a var. with the required size to hold the data. 3rd parameter -> time the task should wait for data to be available, should the queue already be empty.*/ xStatus = xQueueReceive( xQueue, &lReceivedValue, xTicksToWait ); if( xStatus == pdPASS ) {/* Data successfully received from queue, printout the value */ vPrintStringAndNumber( "Received = ", lReceivedValue ); } else { /* Data was not received from the queue even after waiting for 100ms. Must be an error as the sending tasks are free running and will be continuously writing to the queue. */ vPrintString( "Could not receive from the queue.rn" ); } } }
  • 77. Queue System Calls: examples Maths is not everything RMR©2012 67
  • 78. Queues: transferring compound types Maths is not everything RMR©2012 68
  • 79. Queues: transferring compound types /* Define the structure type that will be passed on the queue. */ typedef struct { unsigned char ucValue; unsigned char ucSource; } xData; /* Declare two variables of type xData that will be passed on the queue. */ static const xData xStructsToSend [ 2 ] = { { 100, mainSENDER_1 }, /* Used by Sender1 */ { 200, mainSENDER_2 } /* Used by Sender2 */ }; Maths is not everything RMR©2012 69
  • 80. Queues: transferring compound types Maths is not everything RMR©2012 70 /* To store the reference to the queue that is accessed by all three tasks. */ xQueueHandle xQueue; int main( void ) { /* queue is to hold a max of 3 values, each of structure of type xData */ xQueue = xQueueCreate( 3, sizeof( xData ) ); if( xQueue != NULL ) { /* Create 2 instances of the task that will send to the queue. Task par. is used to pass the struct that the task will write to the queue; only one task will send xStructsToSend[0] to the queue while the other task will xStructsToSend[1]. Both tasks created w/ prio 2 */ xTaskCreate(vSenderTask,"Sender1",1000,&(xStructsToSend[0],2,NULL ); xTaskCreate(vSenderTask,"Sender2",1000,&(xStructsToSend[1],2,NULL); /* Create the task that will read from the queue. The task is created with priority 1, so below the priority of the sender tasks */ xTaskCreate( vReceiverTask, "Receiver", 1000, NULL, 1, NULL ); /* Start the scheduler so the created tasks start executing. */ vTaskStartScheduler(); }else { /* The queue could not be created. */ } /* If all is well then main() will never reach here as the scheduler will now be running the tasks. Otherwise, it is likely that there was insufficient heap memory available for the idle task to be created*/ for( ;; ); }
  • 81. Queues: transferring compound types static void vSenderTask( void *pvParameters ) { portBASE_TYPE xStatus; const portTickType xTicksToWait = 100 / portTICK_RATE_MS; Maths is not everything RMR©2012 71 } for( ;; ) { /* Send to the queue. The queue was created before the scheduler was started. 2nd parameter -> address of the structure being sent. The 3rd parameter -> time the task should wait for space in the queue. A block time is specified as the sending tasks have a higher priority than the receiving task so the queue is expected to become full. The receiving task will remove items from the queue when both sending tasks are Blocked */ xStatus = xQueueSendToBack( xQueue, pvParameters, xTicksToWait ); if( xStatus != pdPASS ) { /* The send operation could not complete even after waiting for 100ms - must be an error as the receiving task should make space in the queue as soon as both sending tasks are in the Blocked state */ vPrintString( "Could not send to the queue.rn" ); } /* Allow the other sender task to execute. taskYIELD() informs the scheduler that a switch should occur now rather than keeping this task in the Running state until the end of the current time slice */ taskYIELD(); }
  • 82. Queues: transferring compound types static void vReceiverTask( void *pvParameters ) { xData xReceivedStructure; portBASE_TYPE xStatus; const portTickType xTicksToWait = 100 / portTICK_RATE_MS; Maths is not everything RMR©2012 72 } for( ;; ) { /* always expects the queue to have 3 items */ if( uxQueueMessagesWaiting( xQueue ) != 3 ) { vPrintString( "Queue should have been full!rn" ); } /* Receive data from the queue. 2nd par. -> the buffer (address of a var) with the required size to hold the data. 3rd parameter -> time the task should wait for data to be available when queue is empty. It is not needed as this task will only run when the queue is full.*/ xStatus = xQueueReceive( xQueue, &xReceivedStructure, 0 ); if( xStatus == pdPASS ) { /* Data successfully received from queue, printout the value */ if( xReceivedStructure.ucSource == mainSENDER_1) { vPrintStringAndNumber( "From Sender 1 = ", xReceivedStructure.ucValue ); } else { vPrintStringAndNumber( "From Sender 2 = ", xReceivedStructure.ucValue ); } } else { /* Nothing was received from the queue. Must be an error as this tasks should only runs when the queue is full */ vPrintString( "Could not receive from the queue.rn" ); } }
  • 83. Queues: transferring compound types Maths is not everything RMR©2012 73
  • 84. Queues: handling big data When the data being stored is large it is preferable to use the queue to transfer pointers rather than copy the data itself into and out of the queue, byte by byte. However ... The owner of the RAM being pointed to must be clearly defined only the sending task should access the memory until a pointer to the memory has been queued, only the receiving task should access the memory after the pointer has been received from the queue. The RAM being pointed to remains valid Maths is not everything RMR©2012 74 If the memory being pointed to was allocated dynamically then exactly one task should be responsible for freeing it. No tasks should attempt to access the memory after it has been freed. A pointer should never be used to access data that has been allocated on a task stack.
  • 85. Queue Management API Maths is not everything RMR©2012 75
  • 86. Maths is not everything FreeRTOS Interrupts and Synchronization RMR©2012
  • 87. Interrupt Handling Embedded real-time systems have to take actions in response to external events a packet from a communication interface (event) might require passing to a TCP/IP stack for processing (action) Usually, events are handled through interrupts inside an ISR. but how much processing should be done inside the ISR? Maths is not everything RMR©2012 77 how can these events be communicated from a ISR to the application tasks and this code can be structured to best accommodate processing of potentially asynchronous occurrences?
  • 88. Interrupt Handling Interrupt handling is critical for the app performance ➟ the ISR should be short and execute fast. In FreeRTOS, an ISR should: Acknowledge the interrupt Collect data from the event Defer the “hard work” to a “handler” task Maths is not everything RMR©2012 78 a context switch to the “handler” task should occur when it has a higher priority than the interrupted task which is preempted
  • 89. Interrupt Handling Maths is not everything RMR©2012 79
  • 90. Communication between an IH and the Handler Task An IH can defer the event heavy processing to a Handler task through a synchronization mechanism. A simple way to do it is through a binary semaphore Maths is not everything RMR©2012 80
  • 91. Communication between an IH and the Handler Task An IH can defer the event heavy processing to a Handler task through a synchronization mechanism. A simple way to do it is through a binary semaphore Maths is not everything RMR©2012 80
  • 92. Communication between an IH and the Handler Task An IH can defer the event heavy processing to a Handler task through a synchronization mechanism. A simple way to do it is through a binary semaphore Maths is not everything RMR©2012 80
  • 93. Communication between an IH and the Handler Task An IH can defer the event heavy processing to a Handler task through a synchronization mechanism. A simple way to do it is through a binary semaphore Maths is not everything RMR©2012 80
  • 94. Communication between an IH and the Handler Task An IH can defer the event heavy processing to a Handler task through a synchronization mechanism. A simple way to do it is through a binary semaphore Maths is not everything RMR©2012 80
  • 95. Communication between an IH and the Handler Task An IH can defer the event heavy processing to a Handler task through a synchronization mechanism. A simple way to do it is through a binary semaphore Maths is not everything RMR©2012 80
  • 96. Synchronization mechanisms FreeRTOS has the following synchronization mechanisms: Binary Semaphores Counting Semaphores Queues Maths is not everything RMR©2012 81 These mechanisms can be used in the communication/synchronization between tasks and between interrupt handlers and tasks.
  • 97. Binary Semaphores Binary Semaphore Creation & Manipulation void vSemaphoreCreateBinary (xSemaphoreHandle xSemaphore); portBASE_TYPE xSemaphoreTake (xSemaphoreHandle xSemaphore, portTickType xTicksToWait); portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore); portBASE_TYPE xSemaphoreGiveFromISR ( xSemaphoreHandle xSemaphore, signed portBASE_TYPE *pxHigherPriorityTaskWoken); Maths is not everything RMR©2012 82
  • 98. Binary Semaphores Binary Semaphore Creation & Manipulation void vSemaphoreCreateBinary (xSemaphoreHandle xSemaphore); portBASE_TYPE xSemaphoreTake (xSemaphoreHandle xSemaphore, portTickType xTicksToWait); portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore); portBASE_TYPE xSemaphoreGiveFromISR ( xSemaphoreHandle xSemaphore, signed portBASE_TYPE *pxHigherPriorityTaskWoken); xSemaphore - referenced by a variable and must be explicitly created before being used. Maths is not everything RMR©2012 82 xTicksToWait - The maximum amount of time the task should wait for the semaphore if it is not already available. If xTicksToWait is 0 then xSemaphoreTake() will return immediately if the semaphore is not available. Setting xTicksToWait to portMAX_DELAY will cause the task to wait indefinitely (without timing out) provided INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h. pxHigherPriorityTaskWoken - If xSemaphoreGiveFromISR() sets this value to pdTRUE then a context switch should be performed before the interrupt is exited. This will ensure the interrupt returns directly to the highest priority Ready state task.
  • 99. Binary Semaphores Binary Semaphore Creation & Manipulation void vSemaphoreCreateBinary (xSemaphoreHandle xSemaphore); portBASE_TYPE xSemaphoreTake (xSemaphoreHandle xSemaphore, portTickType xTicksToWait); portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore); portBASE_TYPE xSemaphoreGiveFromISR ( pdPASS will only be xSemaphoreHandle xSemaphore, returned if the call signed portBASE_TYPE *pxHigherPriorityTaskWoken); was successful. xSemaphore - referenced by a variable and must be explicitly created before being used. Maths is not everything RMR©2012 82 xTicksToWait - The maximum amount of time the task should wait for the semaphore if it is not already available. If xTicksToWait is 0 then xSemaphoreTake() will return immediately if the semaphore is not available. Setting xTicksToWait to portMAX_DELAY will cause the task to wait indefinitely (without timing out) provided INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h. pxHigherPriorityTaskWoken - If xSemaphoreGiveFromISR() sets this value to pdTRUE then a context switch should be performed before the interrupt is exited. This will ensure the interrupt returns directly to the highest priority Ready state task.
  • 100. Binary Semaphores Binary Semaphore Creation & Manipulation void vSemaphoreCreateBinary (xSemaphoreHandle xSemaphore); portBASE_TYPE xSemaphoreTake (xSemaphoreHandle xSemaphore, portTickType xTicksToWait); portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore); portBASE_TYPE xSemaphoreGiveFromISR ( pdFALSE will be returned if the semaphore was not pdPASS will only be xSemaphoreHandle xSemaphore, available. returned if the call signed portBASE_TYPE *pxHigherPriorityTaskWoken); was successful. xSemaphore - referenced by a variable and must be explicitly created before being used. Maths is not everything RMR©2012 82 xTicksToWait - The maximum amount of time the task should wait for the semaphore if it is not already available. If xTicksToWait is 0 then xSemaphoreTake() will return immediately if the semaphore is not available. Setting xTicksToWait to portMAX_DELAY will cause the task to wait indefinitely (without timing out) provided INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h. pxHigherPriorityTaskWoken - If xSemaphoreGiveFromISR() sets this value to pdTRUE then a context switch should be performed before the interrupt is exited. This will ensure the interrupt returns directly to the highest priority Ready state task.
  • 101. Forcing a context switch in the IH To force the context switching from an ISR one should call: void portEND_SWITCHING_ISR(portBASE_TYPE flag); // ARM port void portSWITCH_CONTEXT(); // DOS port The flag parameter should use the value returned in the pxHigherPriorityTaskWoken variable used by the primitives “FromISR” called in the ISR. Maths is not everything RMR©2012 83
  • 102. Communication between an IH and the Handler Task: example Maths is not everything RMR©2012 84 int main( void ) { /*In this example a binary semaphore is created. */ vSemaphoreCreateBinary( xBinarySemaphore ); /* Install the interrupt handler. DOS emulation case*/ _dos_setvect( 0x82, vExampleInterruptHandler ); if( xBinarySemaphore != NULL ) /* Check if it was created successfully */ { /* This is the task that will be synchronized with the interrupt. The handler task is created with a high priority to ensure it runs immediately after the interrupt exits */ xTaskCreate( vHandlerTask, "Handler", 1000, NULL, 3, NULL ); /* Create the task that will periodically generate a software interrupt. This is created with a priority below the handler task to ensure it will get pre-empted each time the handler task exits the Blocked state */ xTaskCreate( vPeriodicTask, "Periodic", 1000, NULL, 1, NULL ); /* Start the scheduler so the created tasks start executing. */ vTaskStartScheduler(); } /* If main() does reach here then it is likely that there was insufficient heap memory available for the idle task or for the semaphore (data structures) to be created with success*/ for( ;; ); }
  • 103. Communication between an IH and the Handler Task: example Maths is not everything RMR©2012 85 static void vPeriodicTask( void *pvParameters ) { for( ;; ) { /* This task is just used to 'simulate' an interrupt by generating a software interrupt every 500ms. */ vTaskDelay( 500 / portTICK_RATE_MS ); /* Generate the interrupt, printing a message both before and after so the sequence of execution is evident from the output produced when the example is executed. */ vPrintString( "Periodic task - About to generate an interrupt.r n" ); __asm{ int 0x82 } /* generates the interrupt. */ vPrintString( "Periodic task - Interrupt generated.rnrnr n" ); } }
  • 104. Communication between an IH and the Handler Task: example static void vHandlerTask( void *pvParameters ) { /* As per most tasks, this task is implemented within an infinite loop. */ for( ;; ) { /* Use the semaphore to wait for an event. The task blocks indefinitely so the call will only return once the semaphore has been successfully taken. There is therefore no need to check the function return value. */ xSemaphoreTake( xBinarySemaphore, portMAX_DELAY ); /* To get here the event must have occurred. Process the event. In this case processing is simply a matter of printing out a message. */ vPrintString( "Handler task - Processing event.rn" ); } } Maths is not everything RMR©2012 86 static void __interrupt __far vExampleInterruptHandler( void ) { static portBASE_TYPE xHigherPriorityTaskWoken; xHigherPriorityTaskWoken = pdFALSE; /* 'Give' the semaphore to unblock the task. */ xSemaphoreGiveFromISR( xBinarySemaphore, &xHigherPriorityTaskWoken ); if( xHigherPriorityTaskWoken == pdTRUE ) { /* Giving the semaphore unblocked a task, and the priority of the unblocked task is higher than the currently running task - force a context switch to ensure that the interrupt returns directly to the unblocked (higher priority) task. NOTE: The actual macro to use (context switch) from an ISR is dependent on the port. This is the correct macro for the Open Watcom DOS port. Other ports may require different syntax */ portSWITCH_CONTEXT(); // e.g.portEND_SWITCHING_ISR (xHigherPriorityTaskWoken); } }
  • 105. Communication between an IH and the Handler Task: example Maths is not everything RMR©2012 87
  • 106. Counting Semaphores Binary semaphores are useful for low interrupt rates. However, when this rate increases, failing to attend events is very likely to happen. a binary semaphore can latch at most one interrupt event; any subsequent events occurring before the latched event has been processed would be lost. In such cases, counting semaphores can be used instead of binary semaphores. Counting semaphores can be used for: Maths is not everything RMR©2012 88 Handling events. Managing the access to resources
  • 107. Handling events with Counting Semaphores Maths is not everything RMR©2012 89
  • 108. Handling events with Counting Semaphores Maths is not everything RMR©2012 89
  • 109. Handling events with Counting Semaphores Maths is not everything RMR©2012 89
  • 110. Handling events with Counting Semaphores Maths is not everything RMR©2012 89
  • 111. Handling events with Counting Semaphores Maths is not everything RMR©2012 89
  • 112. Handling events with Counting Semaphores Maths is not everything RMR©2012 89
  • 113. Handling events with Counting Semaphores Maths is not everything RMR©2012 89
  • 114. Counting Semaphores: creation and manipulation xSemaphoreHandle xSemaphoreCreateCounting (unsigned portBASE_TYPE uxMaxCount, unsigned portBASE_TYPE uxInitialCount); portBASE_TYPE xSemaphoreTake( xSemaphoreHandle xSemaphore, portTickType xBlockTime); portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore); portBASE_TYPE xSemaphoreGiveFromISR ( xSemaphoreHandle xSemaphore, signed portBASE_TYPE *pxHigherPriorityTaskWoken); Maths is not everything RMR©2012 90
  • 115. Counting Semaphores: creation and manipulation xSemaphoreHandle xSemaphoreCreateCounting (unsigned portBASE_TYPE uxMaxCount, unsigned portBASE_TYPE uxInitialCount); portBASE_TYPE xSemaphoreTake( xSemaphoreHandle xSemaphore, portTickType xBlockTime); portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore); portBASE_TYPE xSemaphoreGiveFromISR ( xSemaphoreHandle xSemaphore, signed portBASE_TYPE *pxHigherPriorityTaskWoken); uxMaxCount - The maximum value the semaphore will count to. When the semaphore is used to count or latch events uxMaxCount is the maximum number of events that can be latched. When the semaphore is used to manage access to a collection of resources uxMaxCount should be set to the total number of resources that are available. Maths is not everything RMR©2012 90 uxInitialCount - The initial count value of the semaphore after it has been created. When the semaphore is used to count or latch events uxInitialCount should be set to 0 – as presumably when the semaphore is created no events have yet occurred. When the semaphore is used to manage access to a collection of resources uxInitialCount should be set to equal uxMaxCount – as presumably when the semaphore is created all the resources are available.
  • 116. Counting Semaphores: example of use in an IH int main( void ) { /* In this example a counting semaphore is created. The semaphore is created to have a maximum count value of 10, and an initial count value of 0 */ xCountingSemaphore = xSemaphoreCreateCounting( 10, 0 ); /* Install the interrupt handler. DOS emulation case*/ _dos_setvect( 0x82, vExampleInterruptHandler ); if( xBinarySemaphore != NULL ) /* Check if it was created successfully */ { /* This is the task that will be synchronized with the interrupt. The handler task is created with a high priority to ensure it runs immediately after the interrupt exits */ xTaskCreate( vHandlerTask, "Handler", 1000, NULL, 3, NULL ); /* Create the task that will periodically generate a software interrupt. This is created with a priority below the handler task to ensure it will get pre-empted each time the handler task exits the Blocked state */ xTaskCreate( vPeriodicTask, "Periodic", 1000, NULL, 1, NULL ); /* Start the scheduler so the created tasks start executing. */ vTaskStartScheduler(); } /* If main() does reach here then it is likely that there was insufficient heap memory available for the idle task or for the semaphore (data structures) to be created with success*/ for( ;; ); Maths is not everything RMR©2012 91 }
  • 117. Counting Semaphores: example of use in an IH Maths is not everything RMR©2012 92 static void __interrupt __far vExampleInterruptHandler( void ) { static portBASE_TYPE xHigherPriorityTaskWoken; xHigherPriorityTaskWoken = pdFALSE; /* 'Give' the semaphore multiple times. The first will unblock the handler task, the following 'gives' are to demonstrate that the semaphore latches the events to allow the handler task to process them in turn without any events getting lost. This simulates multiple interrupts being taken by the processor, even though in this case the events are simulated within a single interrupt occurrence.*/ xSemaphoreGiveFromISR( xCountingSemaphore, &xHigherPriorityTaskWoken ); xSemaphoreGiveFromISR( xCountingSemaphore, &xHigherPriorityTaskWoken ); xSemaphoreGiveFromISR( xCountingSemaphore, &xHigherPriorityTaskWoken ); if( xHigherPriorityTaskWoken == pdTRUE ) { /* Giving the semaphore unblocked a task, and the priority of the unblocked task is higher than the currently running task - force a context switch to ensure that the interrupt returns directly to the unblocked (higher priority) task. NOTE: The actual macro to use (context switch) from an ISR is dependent on the port. This is the correct macro for the Open Watcom DOS port. Other ports may require different syntax */ portSWITCH_CONTEXT(); // e.g.portEND_SWITCHING_ISR (xHigherPriorityTaskWoken); } }
  • 118. Semaphore Management API Maths is not everything RMR©2012 93
  • 119. Synchronizing IH and Tasks with Queues Semaphores are used to communicate events. Queues are used to both communicate events and transfer data. Maths is not everything RMR©2012 94 xQueueSendToFrontFromISR(), xQueueSendToBackFromISR() and xQueueReceiveFromISR() are versions of xQueueSendToFront(), xQueueSendToBack() and xQueueReceive() respectively that are safe to use within an interrupt service routine.
  • 120. Queue System Calls (from ISR): send to queue portBASE_TYPE xQueueSendToFrontFromISR ( xQueueHandle xQueue, const void* pvItemToQueue, portBASE_TYPE *pxHigherPriorityTaskWoken); portBASE_TYPE xQueueSendToBackFromISR ( xQueueHandle xQueue, const void* pvItemToQueue, portBASE_TYPE *pxHigherPriorityTaskWoken); Maths is not everything RMR©2012 95
  • 121. Queue System Calls (from ISR): send to queue portBASE_TYPE xQueueSendToFrontFromISR ( xQueueHandle xQueue, const void* pvItemToQueue, portBASE_TYPE *pxHigherPriorityTaskWoken); portBASE_TYPE xQueueSendToBackFromISR ( xQueueHandle xQueue, const void* pvItemToQueue, portBASE_TYPE *pxHigherPriorityTaskWoken); xQueueSendFromISR() is equivalent to xQueueSendToBackFromISR() Maths is not everything RMR©2012 95
  • 122. Queue System Calls (from ISR): send to queue portBASE_TYPE xQueueSendToFrontFromISR ( xQueueHandle xQueue, const void* pvItemToQueue, portBASE_TYPE *pxHigherPriorityTaskWoken); portBASE_TYPE xQueueSendToBackFromISR ( xQueueHandle xQueue, const void* pvItemToQueue, portBASE_TYPE *pxHigherPriorityTaskWoken); xQueueSendFromISR() is equivalent to xQueueSendToBackFromISR() pvItemToQueue - A pointer to the data that will be copied into the queue. Maths is not everything RMR©2012 95 pxHigherPriorityTaskWoken - If calling the API function causes a task to leave the Blocked state, and the unblocked task has a priority higher than the task that was interrupted, then the API function will internally set *pxHigherPriorityTaskWoken to pdTRUE. If xQueueSendToFrontFromISR() or xQueueSendToBackFromISR() sets this value to pdTRUE then a context switch should be performed before the interrupt is exited. This ensure the interrupt returns directly to the highest priority Ready state task.
  • 123. Queue System Calls (from ISR): send to queue portBASE_TYPE xQueueSendToFrontFromISR ( pdPASS will only be returned if data was xQueueHandle xQueue, successfully sent to the const void* pvItemToQueue, queue. portBASE_TYPE *pxHigherPriorityTaskWoken); portBASE_TYPE xQueueSendToBackFromISR ( xQueueHandle xQueue, const void* pvItemToQueue, portBASE_TYPE *pxHigherPriorityTaskWoken); xQueueSendFromISR() is equivalent to xQueueSendToBackFromISR() pvItemToQueue - A pointer to the data that will be copied into the queue. Maths is not everything RMR©2012 95 pxHigherPriorityTaskWoken - If calling the API function causes a task to leave the Blocked state, and the unblocked task has a priority higher than the task that was interrupted, then the API function will internally set *pxHigherPriorityTaskWoken to pdTRUE. If xQueueSendToFrontFromISR() or xQueueSendToBackFromISR() sets this value to pdTRUE then a context switch should be performed before the interrupt is exited. This ensure the interrupt returns directly to the highest priority Ready state task.
  • 124. Queue System Calls (from ISR): send to queue portBASE_TYPE xQueueSendToFrontFromISR ( pdPASS will only be returned if data was xQueueHandle xQueue, successfully sent to the const void* pvItemToQueue, queue. portBASE_TYPE *pxHigherPriorityTaskWoken); errQUEUE_FULL will be returned if data could not be written to the queue because the queue was already full. portBASE_TYPE xQueueSendToBackFromISR ( xQueueHandle xQueue, const void* pvItemToQueue, portBASE_TYPE *pxHigherPriorityTaskWoken); xQueueSendFromISR() is equivalent to xQueueSendToBackFromISR() pvItemToQueue - A pointer to the data that will be copied into the queue. Maths is not everything RMR©2012 95 pxHigherPriorityTaskWoken - If calling the API function causes a task to leave the Blocked state, and the unblocked task has a priority higher than the task that was interrupted, then the API function will internally set *pxHigherPriorityTaskWoken to pdTRUE. If xQueueSendToFrontFromISR() or xQueueSendToBackFromISR() sets this value to pdTRUE then a context switch should be performed before the interrupt is exited. This ensure the interrupt returns directly to the highest priority Ready state task.
  • 125. Queue System Calls: (from ISR) receive from queue portBASE_TYPE xQueueReceiveFromISR ( xQueueHandle xQueue, void *pvBuffer, portBASE_TYPE *pxHigherPriorityTaskWoken); Maths is not everything RMR©2012 96
  • 126. Queue System Calls: (from ISR) receive from queue portBASE_TYPE xQueueReceiveFromISR ( xQueueHandle xQueue, void *pvBuffer, portBASE_TYPE *pxHigherPriorityTaskWoken); pvBuffer - A pointer to the memory into which the received data will be copied. Maths is not everything RMR©2012 96 pxHigherPriorityTaskWoken - If calling the API function causes a task to leave the Blocked state, and the unblocked task has a priority higher than the task that was interrupted, then the API function will internally set *pxHigherPriorityTaskWoken to pdTRUE. If xQueueSendToFrontFromISR() or xQueueSendToBackFromISR() sets this value to pdTRUE then a context switch should be performed before the interrupt is exited. This ensure the interrupt returns directly to the highest priority Ready state task.
  • 127. Queue System Calls: (from ISR) receive from queue pdPASS will only be returned if data was successfully read from the queue. portBASE_TYPE xQueueReceiveFromISR ( xQueueHandle xQueue, void *pvBuffer, portBASE_TYPE *pxHigherPriorityTaskWoken); pvBuffer - A pointer to the memory into which the received data will be copied. Maths is not everything RMR©2012 96 pxHigherPriorityTaskWoken - If calling the API function causes a task to leave the Blocked state, and the unblocked task has a priority higher than the task that was interrupted, then the API function will internally set *pxHigherPriorityTaskWoken to pdTRUE. If xQueueSendToFrontFromISR() or xQueueSendToBackFromISR() sets this value to pdTRUE then a context switch should be performed before the interrupt is exited. This ensure the interrupt returns directly to the highest priority Ready state task.
  • 128. Queue System Calls: (from ISR) receive from queue pdPASS will only be returned if data was successfully read from the queue. errQUEUE_EMPTY will be returned if data could not be read from the queue because the queue was already empty. portBASE_TYPE xQueueReceiveFromISR ( xQueueHandle xQueue, void *pvBuffer, portBASE_TYPE *pxHigherPriorityTaskWoken); pvBuffer - A pointer to the memory into which the received data will be copied. Maths is not everything RMR©2012 96 pxHigherPriorityTaskWoken - If calling the API function causes a task to leave the Blocked state, and the unblocked task has a priority higher than the task that was interrupted, then the API function will internally set *pxHigherPriorityTaskWoken to pdTRUE. If xQueueSendToFrontFromISR() or xQueueSendToBackFromISR() sets this value to pdTRUE then a context switch should be performed before the interrupt is exited. This ensure the interrupt returns directly to the highest priority Ready state task.
  • 129. Interrupt Nesting FreeRTOS ports allow interrupts to nest. These ports require one or both of the following constants to be defined within FreeRTOSConfig.h configKERNEL_INTERRUPT_PRIORITY - Sets the interrupt priority used by the tick interrupt (SysTick), normally configured with the least possible priority. configMAX_SYSCALL_INTERRUPT_PRIORITY - Sets the highest interrupt priority from which interrupt safe FreeRTOS API functions can be called. when executing a critical section the kernel disables every interrupt of equal or lower priority than the one defined by this constant. This means that FreeRTOS doesn’t disable all the interrupts even inside critical sections. Maths is not everything RMR©2012 97 If configMAX_SYSCALL_INTERRUPT_PRIORITY constant is not used in the port, then any interrupt that uses the interrupt safe FreeRTOS API functions must also execute at SysTick priority.
  • 130. Interrupt Nesting: example ! •! Interrupts w/ prio. 1 to 3 - prevented from executing while in a critical section, but they can use the interrupt safe FreeRTOS API functions. ! •! Interrupts w/ prio. ≥ 4 - not affected by critical sections (kernel cannot prevent these ISR), within the limitations of the microcontroller itself. Applications requiring very strict timing accuracy (e.g.motor control) would use a priority above 3 to ensure the scheduler does not introduce jitter into the interrupts response time. Maths is not everything RMR©2012 98
  • 131. Interrupt Nesting: example as long as they don’t use FreeRTOS API ! •! Interrupts w/ prio. 1 to 3 - prevented from executing while in a critical section, but they can use the interrupt safe FreeRTOS API functions. ! •! Interrupts w/ prio. ≥ 4 - not affected by critical sections (kernel cannot prevent these ISR), within the limitations of the microcontroller itself. Applications requiring very strict timing accuracy (e.g.motor control) would use a priority above 3 to ensure the scheduler does not introduce jitter into the interrupts response time. Maths is not everything RMR©2012 98
  • 132. Interrupt Nesting: example cannot use FreeRTOS API as long as they don’t use FreeRTOS API ! •! Interrupts w/ prio. 1 to 3 - prevented from executing while in a critical section, but they can use the interrupt safe FreeRTOS API functions. ! •! Interrupts w/ prio. ≥ 4 - not affected by critical sections (kernel cannot prevent these ISR), within the limitations of the microcontroller itself. Applications requiring very strict timing accuracy (e.g.motor control) would use a priority above 3 to ensure the scheduler does not introduce jitter into the interrupts response time. Maths is not everything RMR©2012 98
  • 133. Interrupt handlers: good practices configKERNEL_INTERRUPT_PRIORITY must be set with the lowest possible priority. All ISR using the safe FreeRTOS API need to be initialized with a priority level ≤ configMAX_SYSCALL_INTERRUPT_PRIORITY. ISR extremely critical may have a higher priority than configMAX_SYSCALL_INTERRUPT_PRIORITY but cannot use any FreeRTOS ISR primitive. Maths is not everything RMR©2012 99 Note: In some µP, high-priority relates with high int. numbers, while in others (e.g. ARM) higher int. numbers means lower priority.
  • 134. Maths is not everything FreeRTOS Resource Management RMR©2012
  • 135. Sharing resources in a multitask environment In a multitasking system there is the potential risk of a task to be interrupted while accessing a resource without completing it. the task may leave the resource in an inconsistent state which could result in data corruption if other task or interrupt tries to access the same resource. Examples of shared resources: Global variables Maths is not everything Peripherals Code RMR©2012 101
  • 136. Accessing global variables Let’s assume the following C code: GlobalC += 10; In assembly we got: 1. LOAD R, [#1234] 2. SUM R, 10 3. STORE R, [#1234] The C statement is not atomic. What are the consequences? Suppose that: Task A exec. Inst. 1 ➟ A preempted by B ➟ Task B changes GlobalC and sleeps afterwards ➟ Task A resumes and exec. 2 and 3, using an old value of GlobalC Maths is not everything RMR©2012 102 When a global variable is accessed by more than 1 task, to assure its consistency, one needs to control the access to it!
  • 137. Accessing peripherals Consider the following scenario where two tasks attempt to write to an LCD: Task A executes and starts to write the string “Hello world” to the LCD. Task A is preempted by Task B after outputting just the beginning of the string – “Hello w”. Task B writes “Abort, Retry, Fail?” to the LCD before entering the Blocked state. Maths is not everything RMR©2012 103 Task A continues from the point at which it was preempted and completes outputting the remaining characters – “orld”. The LCD will now be displaying the corrupted string “Hello wAbort, Retry, Fail?orld”.
  • 138. Function Reentrancy A function is reentrant when it’s safe to call the function from more than one task, or from interrupts. Each task maintains its own stack and a fresh set of register values. If a function does not access any data other than data that is allocated to the stack or held in a register then the function is reentrant. Maths is not everything RMR©2012 104 /* A parameter is passed into the function. This will either be passed on the stack or in a CPU register. Either way is safe as each task maintains its own stack and its own set of register values. */ long lAddOneHundered( long lVar1 ) { /* This function scope variable will also be allocated to the stack or a register, depending on compiler and optimization level. Each task or interrupt that calls this function will have its own copyof lVar2. */ long lVar2; lVar2 = lVar1 + 100; /* Most likely the return value will be placed in a CPU register, although it too could be placed on the stack. */ return lVar2; }
  • 139. Function Reentrancy A function not reentrant when works with global variables (or static). Even though each task works with its own stack and a fresh set of register values, the function does access data that is shared among all the tasks. Maths is not everything /* In this case lVar1 is a global variable so every task that calls the function will be accessing the same single copy of the variable. */ long lVar1; long lNonsenseFunction( void ) { /* This variable is static so is not allocated on the stack. Each task that calls the function will be accessing the same single copy of the variable. */ static long lState = 0; long lReturn; switch( lState ) { case 0 : lReturn = lVar1 + 10; lState = 1; break; case 1 : RMR©2012 105 } } lReturn = lVar1 + 20; lState = 0; break;
  • 140. Mutual Exclusion Accessing resources shared between tasks or between tasks and interrupts needs to be managed using a ‘mutual exclusion’ technique. to ensure that once a task starts accessing a shared resource the same task has exclusive access until the resource has been returned to a consistent state. FreeRTOS provides several features for implementing mutual exclusion Maths is not everything RMR©2012 106 but the best is to assure (if possible) that resources are not shared and each resource is only accessed from a single task.
  • 141. Mutual Exclusion by implementing Critical Sections Basic critical sections are regions of code that are surrounded by calls to the macros: taskENTER_CRITICAL() taskEXIT_CRITICAL() /* Ensure access to the PORTA register cannot be interrupted -> critical section */ taskENTER_CRITICAL(); /* A switch to another task cannot occur between the call to taskENTER_CRITICAL() and to taskEXIT_CRITICAL(). Interrupts may still execute on FreeRTOS ports that allow interrupt nesting, but only interrupts whose priority is above the value assigned to the configMAX_SYSCALL_INTERRUPT_PRIORITY constant */ PORTA |= 0x01; /* We have finished accessing PORTA so can safely leave the critical section */ taskEXIT_CRITICAL(); Maths is not everything It’s a “brute force” method as: disables all the int. up to configMAX_SYSCALL_INTERRUPT_PRIORITY RMR©2012 107 preemption results from an interrupt, so taskENTER_CRITICAL() assures that the task stays in Running until taskEXIT_CRITICAL()
  • 142. Mutual Exclusion by implementing Critical Sections: example void vPrintString( const portCHAR *pcString ) { /* Write the string to stdout, using a critical section as a crude method of mutual exclusion. */ taskENTER_CRITICAL(); { printf( "%s", pcString ); fflush( stdout ); } taskEXIT_CRITICAL(); } Maths is not everything RMR©2012 108 Critical sections must be kept very short otherwise they will adversely affect interrupt response times.
  • 143. implementing Critical Sections by pausing the scheduler Critical sections implemented by suspending the scheduler only protects a region of code from access by other tasks because interrupts remain enabled A critical section that is too long to be implemented by disabling interrupts can instead be implemented by suspending the scheduler ‘un-suspending’ the scheduler may be a relatively lengthy operation. Maths is not everything RMR©2012 109 void vPrintString( const portCHAR *pcString ) { /* Write the string to stdout, suspending the scheduler as a method of mutual exclusion. */ vTaskSuspendScheduler(); { printf( "%s", pcString ); fflush( stdout ); } xTaskResumeScheduler(); }
  • 144. Mutual Exclusion through the use of Mutexes Mutex is a special type of binary semaphore used to control accesses to a shared resource. A mutex can be conceptually thought of as a token that is associated with the resource being shared. For a task to legitimately access the resource it must first successfully ‘take’ the token (be the token holder). When the token holder has finished with the resource it must ‘give’ the token back (different from BinSem.) Maths is not everything RMR©2012 110 Only when the token has been returned can another task successfully take the token and then safely access the same shared resource. A task is not permitted to access the shared resource unless it holds the token.
  • 145. Mutual Exclusion through the use of Mutexes: examples Maths is not everything RMR©2012 111
  • 146. Mutual Exclusion through the use of Mutexes: examples Maths is not everything RMR©2012 111
  • 147. Mutual Exclusion through the use of Mutexes: examples Maths is not everything RMR©2012 111
  • 148. Mutual Exclusion through the use of Mutexes: examples Maths is not everything RMR©2012 111
  • 149. Mutual Exclusion through the use of Mutexes: examples Maths is not everything RMR©2012 111
  • 150. Mutual Exclusion through the use of Mutexes: examples Maths is not everything RMR©2012 111
  • 151. Mutual Exclusion through the use of Mutexes: examples Maths is not everything RMR©2012 111
  • 152. Mutual Exclusion through the use of Mutexes: examples Maths is not everything RMR©2012 111 The mechanism works purely through the discipline of the application writer. There is no reason why a task cannot access the resource at any time, but each task “agrees” not to unless they are first able to become the mutex holder.
  • 153. Mutex Semaphores MUTEX Creation & Manipulation xSemaphoreHandle vSemaphoreCreateMutex(void); portBASE_TYPE xSemaphoreTake (xSemaphoreHandle xSemaphore, portTickType xTicksToWait); portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore); Maths is not everything RMR©2012 112
  • 154. Mutex Semaphores MUTEX Creation & Manipulation xSemaphoreHandle vSemaphoreCreateMutex(void); portBASE_TYPE xSemaphoreTake (xSemaphoreHandle xSemaphore, portTickType xTicksToWait); portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore); When to use Maths is not everything RMR©2012 112 When sharing a resource between a task and an ISR, the only option is to use a critical section, disabling interrupts. When sharing a resource between tasks the standard mechanism should be the MUTEX.
  • 155. Mutex Semaphores MUTEX Creation & Manipulation xSemaphoreHandle vSemaphoreCreateMutex(void); portBASE_TYPE xSemaphoreTake (xSemaphoreHandle xSemaphore, portTickType xTicksToWait); portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore); non-NULL will only be returned if the MUTEX was created successfully. When to use Maths is not everything RMR©2012 112 When sharing a resource between a task and an ISR, the only option is to use a critical section, disabling interrupts. When sharing a resource between tasks the standard mechanism should be the MUTEX.
  • 156. Mutex Semaphores MUTEX Creation & Manipulation xSemaphoreHandle vSemaphoreCreateMutex(void); portBASE_TYPE xSemaphoreTake (xSemaphoreHandle xSemaphore, portTickType xTicksToWait); portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore); non-NULL will only be returned if the MUTEX was created successfully. NULL will be returned if the MUTEX could not be created. When to use Maths is not everything RMR©2012 112 When sharing a resource between a task and an ISR, the only option is to use a critical section, disabling interrupts. When sharing a resource between tasks the standard mechanism should be the MUTEX.
  • 157. Using a Mutex static void prvNewPrintString( const portCHAR *pcString ) { /* The mutex already exists by the time this task first executes. Attempt to take the mutex, blocking indefinitely to wait for the mutex if it is not available straight away. */ /* The call to xSemaphoreTake() will only return when the mutex has been successfully obtained so there is no need to check the function return value. If any other delay period was used then the code must check that xSemaphoreTake() returns pdTRUE before accessing the shared resource (which in this case is standard out). */ xSemaphoreTake( xMutex, portMAX_DELAY ); { /* The following line will only execute once the mutex has been successfully obtained. Standard out can be accessed freely now as only one task can have the mutex at any one time. */ printf( "%s", pcString ); fflush( stdout ); } /* The mutex MUST be given back! */ xSemaphoreGive( xMutex ); Maths is not everything RMR©2012 113 }
  • 158. Using a Mutex static void prvPrintTask( void *pvParameters ) { char *pcStringToPrint; /* Two instances of this task are created so the string the task will send to prvNewPrintString() is passed into the task using the task parameter */ pcStringToPrint = ( char * ) pvParameters; for( ;; ) { /* Print out the string using the newly defined function. */ prvNewPrintString( pcStringToPrint ); /* Wait a pseudo random time. Note that rand() is not necessarily reentrant, but in this case it does not really matter as the code does not care what value is returned. In a more secure application a version of rand() that is known to be reentrant should be used, or calls to rand() should be protected using a critical section. */ vTaskDelay( ( rand() & 0x1FF ) ); Maths is not everything } } RMR©2012 114
  • 159. Using a Mutex Maths is not everything RMR©2012 115 int main( void ) { /* Before a semaphore is used it must be explicitly created */ xMutex = xSemaphoreCreateMutex(); /* Tasks will use a pseudo random delay -> seed the random number generator */ srand( 567 ); /* Check if the semaphore was created successfully before creating the tasks*/ if( xMutex != NULL ) { /* Create two instances of the tasks that write to stdout. The string they write is passed in as the task parameter. Tasks are created at different priorities so some preemption will occur */ xTaskCreate( prvPrintTask, "Print1", 1000, "Task 1 ******************************************rn", 1, NULL ); xTaskCreate( prvPrintTask, "Print2", 1000, "Task 2 ------------------------------------------rn", 2, NULL ); /* Start the scheduler to execute the created tasks */ vTaskStartScheduler(); } /* If all is well then main() will never reach here as the scheduler will now be running the tasks. */ for( ;; ); }
  • 160. Using a Mutex Maths is not everything RMR©2012 116 The possible sequence of execution depicted shows the higher priority Task 2 having to wait for the lower priority Task 1 to give up control of the mutex
  • 161. Mutex Problems: Priority Inversion A higher prio. task being delayed by a lower prio.task due to a mutual exclusion issue is called ‘priority inversion’. If a medium priority task started to execute while the high priority task was waiting for the semaphore the result could even be worse: a high priority task waiting for a low priority task without the low priority task even being able to execute Maths is not everything RMR©2012 117
  • 162. Mutex Problems: Priority Inversion A higher prio. task being delayed by a lower prio.task due to a mutual exclusion issue is called ‘priority inversion’. If a medium priority task started to execute while the high priority task was waiting for the semaphore the result could even be worse: a high priority task waiting for a low priority task without the low priority task even being able to execute An interesting REAL example of priority inversion Maths is not everything RMR©2012 117 http://www.motherboardpoint.com/really-happened-mars-priority-inversion-and-marspathfinder-t169706.html
  • 163. Priority Inheritance it temporarily raises the mutex holder priority to that of the highest priority task attempting to obtain the same mutex. ➟ LP task holding the mutex ‘inherits’ the priority of the HP waiting task. binary semaphores don’t have this feature Maths is not everything RMR©2012 118 assumes a task will only hold a single mutex at any one time. FreeRTOS mutexes automatically provide a basic ‘priority inheritance’ mechanism.
  • 164. Mutex Problems: deadlock when two tasks cannot proceed because they are both waiting for a resource that is held by the other. Example: Task A executes and successfully takes mutex X. Task A is pre-empted by Task B. Task B successfully takes mutex Y before attempting to also take mutex X – but mutex X is held by Task A so is not available to Task B. Task B opts to enter the Blocked state to wait for mutex X to be released. Task A continues executing. It attempts to take mutex Y – but mutex Y is held by Task B so is not available to Task A. Task A opts to enter the Blocked state to wait for mutex Y to be released. Maths is not everything RMR©2012 119 Task A is waiting for a mutex held by Task B, and Task B is waiting for a mutex held by Task A. Deadlocks are design errors of an application.
  • 165. Gatekeepers Gatekeeper tasks provide a clean method of mutual exclusion without the worry of priority inversion or deadlock. A gatekeeper is a task that has sole ownership of a resource. Any other task needing to access the resource can only do so indirectly by using the services of the gatekeeper Maths is not everything RMR©2012 120 May ease the access to a resource from an interrupt handler
  • 166. Gatekeepers Resource Task 1 Task 2 Maths is not everything RMR©2012 121 Queue M S G 2 M S G 1 Gatekeeper
  • 167. The Gatekeeper itself Maths is not everything RMR©2012 122 static void prvStdioGatekeeperTask( void *pvParameters ) { char *pcMessageToPrint; /* This is the only task that is allowed to write to the terminal output. Any other task wanting to write a string to the output does not access the terminal directly, but instead sends the string to this task. As only this task accesses standard out there are no mutual exclusion or serialization issues to consider within the implementation of the task itself. */ for( ;; ) { /* Wait for a message to arrive. An indefinite block time is specified so there is no need to check the return value – the function will only return when a message has been successfully received. */ xQueueReceive( xPrintQueue, &pcMessageToPrint, portMAX_DELAY ); /* Output the received string. */ printf( "%s", pcMessageToPrint ); fflush( stdout ); /* Now simply go back to wait for the next message. */ } }
  • 168. The tasks that generate messages for the gatekeeper static void prvPrintTask( void *pvParameters ) { int iIndexToString; /* Two instances of this task are created. The task parameter is used to pass an index into an array of strings into the task */ iIndexToString = ( int ) pvParameters; for( ;; ) { /* Print out the string, not directly but instead by passing a pointer to the string to the gatekeeper task via a queue. The queue is created before the scheduler is started. A block time is not specified because there should always be space in the queue. */ xQueueSendToBack( xPrintQueue, &( pcStringsToPrint[ iIndexToString ] ), 0 ); /* Wait a pseudo random time. Note that rand() is not necessarily reentrant, but in this case it does not really matter as the code does not care what value is returned. In a more secure application a version of rand() that is known to be reentrant should be used - or calls to rand() should be protected using a critical section. */ vTaskDelay( ( rand() & 0x1FF ) ); Maths is not everything RMR©2012 123 } }
  • 169. Interrupt Hook using also the gatekeeper void vApplicationTickHook( void ) { static int iCount = 0; portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; /* Print out a message every 200 ticks. The message is not written out directly, but sent to the gatekeeper task. */ iCount++; if( iCount >= 200 ) { /* In this case the last parameter (xHigherPriorityTaskWoken) is not actually used but must still be supplied. */ xQueueSendToFrontFromISR( xPrintQueue, &( pcStringsToPrint[ 2 ] ), &xHigherPriorityTaskWoken ); /* Reset the count ready to print out the string again in 200 ticks time. */ iCount = 0; } Maths is not everything RMR©2012 124 } void vApplicationTickHook( void ); ! Tick hook functions execute within the context of the tick interrupt so must be kept very short, use only a moderate amount of stack space, and not call any FreeRTOS API functions whose name does not end with ‘FromISR()’.
  • 170. creating everything in the Main Maths is not everything RMR©2012 125 static char *pcStringsToPrint[] = { "Task 1 ****************************************************rn", "Task 2 ----------------------------------------------------rn", "Message printed from the tick hook interrupt ##############rn" }; /*-----------------------------------------------------------*/ /* Declare a variable of type xQueueHandle. This is used to send messages from the print tasks and the tick interrupt to the gatekeeper task. */ xQueueHandle xPrintQueue; /*-----------------------------------------------------------*/ int main( void ) { /* Before a queue is used it must be explicitly created. The queue is created to hold a maximum of 5 character pointers. */ xPrintQueue = xQueueCreate( 5, sizeof( char * ) ); /* The tasks are going to use a pseudo random delay, seed the random number generator. */ srand( 567 ); /* Check the queue was created successfully. */ if( xPrintQueue != NULL ){ /* Create two instances of the tasks that send messages to the gatekeeper.The index to the string the task uses is passed to the task via the task parameter. The tasks are created at different priorities so the higher priority task will occasionally preempt the lower priority task. */ xTaskCreate( prvPrintTask, "Print1", 1000, ( void * ) 0, 1, NULL ); xTaskCreate( prvPrintTask, "Print2", 1000, ( void * ) 1, 2, NULL ) /* Create the gatekeeper task. This is the only task that is permitted to directly access standard out. */ xTaskCreate( prvStdioGatekeeperTask, "Gatekeeper", 1000, NULL, 0, NULL ); /* Start the scheduler so the created tasks start executing. */ vTaskStartScheduler(); }
  • 171. Maths is not everything FreeRTOS Memory Management RMR©2012
  • 172. Managing memory dynamically Every time a task, queue or semaphore is created➟kernel has to allocate RAM. The standard malloc() and free() library functions can be used but can also suffer from one or more of the following problems: They are not always available on small embedded systems. Their implementation can be relatively large so take up valuable code space. They are not deterministic. The amount of time taken to execute the functions will differ from call to call. Maths is not everything RMR©2012 127 They can suffer from memory fragmentation.
  • 173. Managing memory dynamically Different embedded systems have varying RAM allocation and timing requirements FreeRTOS treats memory allocation as part of the portable layer (as opposed to part of the core code base). This enables individual applications to provide their own specific implementation when appropriate. When the kernel requires RAM, instead of calling malloc() directly it instead calls pvPortMalloc(). When RAM is being freed, instead of calling free() directly the kernel instead calls vPortFree(). Maths is not everything RMR©2012 128 These primitives have the same prototypes as the original ones. It’s up to the developer to provide an implementation for the pvPortMalloc() e vPortFree() allocation memory functions.
  • 174. Managing memory dynamically FreeRTOS provides 4 different implementations that are available in "FreeRTOS/Source/portable/MemMang" heap_1.c: just allocates memory. heap_2.c: allocates and frees memory but does not handle any fragmentation. heap_3.c: uses the standard C lib malloc() and free() implementation. Maths is not everything RMR©2012 129 heap_4.c: only available from FreeRTOS 7.2.0 allocates and frees memory, handles fragmentation and is more efficient than the majority of C lib implementations.
  • 175. HEAP_1 Heap_1.c implements a very basic version of pvPortMalloc() and does not implement vPortFree(). The allocation scheme simply subdivides a simple array into smaller blocks as calls to pvPortMalloc() are made. The array is the FreeRTOS heap. The total size (in bytes) of the array is set by the definition configTOTAL_HEAP_SIZE within FreeRTOSConfig.h. Defining a large array in this manner can make the application appear to consume a lot of RAM – even before any of the array has actually been assigned Heap_1 is always deterministic. Maths is not everything RMR©2012 130 Useful in: any application that never deletes a task, queue or semaphore.
  • 176. HEAP_2 It uses a best fit algorithm to allocate memory and unlike heap_1 it does allow memory to be freed. Heap_2.c also uses a simple array dimensioned by configTOTAL_HEAP_SIZE.. Again the array is statically declared so it will make the application appear to consume a lot of RAM. The best fit algorithm ensures pvPortMalloc() uses the free block of memory that is closest in size to the number of bytes requested. Heap_2 can suffer from fragmentation Heap_2 is not deterministic. Maths is not everything RMR©2012 131 Useful in: applications that repeatedly create and delete tasks provided the size of the stack allocated to the created tasks does not change. size_t xPortGetFreeHeapSize(void);
  • 177. HEAP_3 Heap_3.c simply uses the standard library malloc() and free() function but in a thread safe way. configTOTAL_HEAP_SIZE does not affect the size of the heap and is instead defined by the linker configuration. There is no statically allocated buffer in compilation time Maths is not everything RMR©2012 132 void *pvPortMalloc( size_t xWantedSize ) { void *pvReturn; vTaskSuspendAll(); { pvReturn = malloc( xWantedSize ); } xTaskResumeAll(); return pvReturn; } void vPortFree( void *pv ) { if( pv != NULL ) Useful in: applications that repeatedly { vTaskSuspendAll(); allocate and free memory buffers of { different size. free( pv ); } xTaskResumeAll(); } }
  • 178. The Stack Memory region used for local variables, registers and parameters. Each task has its own stack If its size is under-dimensioned a stack overflow will occur. Some techniques do exist for monitoring the use of the stack and the existence of overflow situations FreeRTOS provides several features to assist trapping and debugging stack related issues Maths is not everything RMR©2012 133
  • 179. Stack Overflow - WaterMark uxTaskGetStackHighWaterMark() is used to query how near a task has come to overflowing the stack space allocated to it. This value is called the stack 'high water mark'. unsigned portBASE_TYPE uxTaskGetStackHighWaterMark(xTaskHandle xTask); Maths is not everything RMR©2012 134
  • 180. Stack Overflow - WaterMark uxTaskGetStackHighWaterMark() is used to query how near a task has come to overflowing the stack space allocated to it. This value is called the stack 'high water mark'. unsigned portBASE_TYPE uxTaskGetStackHighWaterMark(xTaskHandle xTask); xTask - The handle of the task whose stack high water mark is being queried. A task can query its own stack high water mark by passing NULL in place of a valid task handle Maths is not everything RMR©2012 134 Returned value - The amount of stack the task is actually using will grow and shrink as the task executes and interrupts are processed. uxTaskGetStackHighWaterMark() returns the minimum amount of remaining stack space that was available since the task started executing. This is the amount of stack that remained unused when the stack usage was at its greatest (deepest) value. The closer the high water mark is to 0 the closer the task has come to overflowing its stack.
  • 181. Stack Overflow : Run Time Checking FreeRTOS includes two optional run time stack checking mechanisms. controlled by the configCHECK_FOR_ST ACK_OVERFLOW compile time configuration constant within FreeRTOSConfig.h. Both methods will increase the time it takes to perform a context switch. In any of these methods the kernel will monitor the task stacks and execute a stack overflow hook (or callback) function upon detecting an overflow. Maths is not everything RMR©2012 135 void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed char *pcTaskName); Use this function to identify and correct stack problems during development. The goal is simplify the debug and not to recover from a stack that has overflown.
  • 182. Stack Overflow : Run Time Checking Run Time Stack Checking - Method 1 configCHECK_FOR_STACK_OVERFLOW= 1. Kernel will check whether the stack pointer remains within the valid stack space after the context has been saved. The stack overflow hook is called if the stack pointer is found to be outside of its valid range. This method is quick to execute but can miss stack overflows that occur between context saves. Run Time Stack Checking - Method 2 configCHECK_FOR_STACK_OVERFLOW= 2. Maths is not everything RMR©2012 136 When a task is created its stack is filled with a known pattern. This method walks the last valid 20 bytes of the task stack space to check that this pattern has not been overwritten. The stack overflow hook function is called if any of the 20 bytes have changed from their expected value. not as quick to execute as 1 but very likely to catch all stack overflows
  • 183. Maths is not everything FreeRTOS Additional Features RMR©2012