s emb t13-freertos

190
RMR©2012 Maths is not everything Embedded Systems 7 - Real-Time Operating System (FreeRTOS) Introduction Task Management Queue Management Interrupts and Synchronization Resource Management Memory Management Aditional Features

Upload: joao-moreira

Post on 10-May-2015

826 views

Category:

Technology


3 download

TRANSCRIPT

Page 1: S emb t13-freertos

RMR©2012

Maths is not everything

Embedded Systems7 - Real-Time Operating System (FreeRTOS)

IntroductionTask ManagementQueue Management

Interrupts and SynchronizationResource ManagementMemory ManagementAditional Features

Page 2: S emb t13-freertos

RMR©2012

Maths is not everything

FreeRTOS

Introduction

Page 3: S emb t13-freertos

RMR©2012

Maths is not everything

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 real-time OSSimple but yet very powerful

3

Page 4: S emb t13-freertos

RMR©2012

Maths is not everything

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 ManualAPI functions and configuration options

Online documentationwww.freertos.org

4

Page 5: S emb t13-freertos

RMR©2012

Maths is not everything

FreeRTOS History

FreeRTOSV4.0.0

FreeRTOSV3.0.0

FreeRTOSV2.0.0

FreeRTOSV1.0.1

FreeRTOSV5.0.0

FreeRTOS V1.0.1+

Scalability +

New Task APIs

API Changes+

Directory Names Changed

+Changes in Kernel

FreeRTOS V3.0.0+

Co-routinesAPI Changes

FreeRTOSV6.0.0

2009Backward Comp.

MPU Support

5

Page 6: S emb t13-freertos

RMR©2012

Maths is not everything

FreeRTOS Features

ArchitectureSource codePortableScalablePreemptive and co-operative schedulingMultitaskingServicesInterrupt managementAdvanced features

6

Page 7: S emb t13-freertos

Application

Task 1 Task 2 Task 3 Task 4

RMR©2012

Maths is not everything

Architecture

7

Page 8: S emb t13-freertos

include

Portable

main kernel source directory

CommonDir xRMR©2012

Maths is not everything

Source Code Organization

8

FreeRTOS

Source

kernel header files directory

Compiler xCompiler yMemMang

Demo

kernel port

compiler x portcompiler x portmalloc/free implementation

Dir y

demo app common directorydemo app of port xdemo app of port y

Page 9: S emb t13-freertos

RMR©2012

Maths is not everything

Source Code Organization

9 port.c and portmacro.h files within the HAL

Page 10: S emb t13-freertos

RMR©2012

Maths is not everything

Portability

Highly portable C

24 architectures supported

Assembly is kept minimum.

Ports are freely available in source code.

Other contributions do exist.

10

Page 11: S emb t13-freertos

RMR©2012

Maths is not everything

Scalable

Use the service you only need:

FreeRTOSConfig.hVery few services / Complete services availableA group of #defines determines scalability.

Minimum footprint = 4 KB

11

Page 12: S emb t13-freertos

RMR©2012

Maths is not everything

FreeRTOSConfig.h

#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...

12

Page 13: S emb t13-freertos

RMR©2012

Maths is not everything

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

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

Application = Tasks

Or Application = Tasks + Co-routines

Tasks have higher priority than Co-routines13

Page 14: S emb t13-freertos

RMR©2012

Maths is not everything

Tasks vs Co-routines

Tasksno restrictions

totally prioritized

each task maintains its own stack

re-entrance has to be tackled carefully when used with preemption

14

Co-routinesAPI calls have restrictions

totally prioritized among co-routines but interruptible by tasks when using hybrid mode

stack shared among them

re-entrance managed by cooperation (less problematic)

cooperation only between co-routines

Page 15: S emb t13-freertos

RMR©2012

Maths is not everything

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

15

Page 16: S emb t13-freertos

RMR©2012

Maths is not everything

Services

Queues

SemaphoresBinary and counting

Mutexes With priority inheritance

Support recursion

16

Page 17: S emb t13-freertos

RMR©2012

Maths is not everything

Interrupts

An interrupt can suspend a task execution.

Interrupt mechanism is port dependent.Nesting

Scheduling after interrupts

Preemptive or cooperative scheduler

17

Page 18: S emb t13-freertos

RMR©2012

Maths is not everything

Advanced Features

Execution tracing

Run time statistics collection

Memory management

Memory protection support

Stack overflow protection18

Page 19: S emb t13-freertos

RMR©2012

Maths is not everything

Conventions: variables’ names

19

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”

Page 20: S emb t13-freertos

RMR©2012

Maths is not everything

Conventions: functions’ names

20

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

Page 21: S emb t13-freertos

RMR©2012

Maths is not everything

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

FreeRTOS can’t be used in any comparisons without the authors’ permission.

21

Page 22: S emb t13-freertos

RMR©2012

Maths is not everything

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)

Compliant with:

FDA510(k) Class III medical device standards

EN6230422

Page 23: S emb t13-freertos

RMR©2012

Maths is not everything

FreeRTOS

Kernel Structure - Tasks

Page 24: S emb t13-freertos

RMR©2012

Maths is not everything

Task States

Runningtask is executing owning the CPU

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

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

Suspendedtask may enter this state only through specific calls

there is no associated timeout

not considered in scheduling

24

Page 25: S emb t13-freertos

RMR©2012

Maths is not everything

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.

25

Task prototypevoid ATaskFunction(void *pvParameters);

Page 26: S emb t13-freertos

RMR©2012

Maths is not everything

Task skeleton

26

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 );}

Page 27: S emb t13-freertos

RMR©2012

Maths is not everything

Typical Application

27

Page 28: S emb t13-freertos

RMR©2012

Maths is not everything

Task creation

28

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.

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.

Page 29: S emb t13-freertos

RMR©2012

Maths is not everything

Task creation

29

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.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.

Page 30: S emb t13-freertos

RMR©2012

Maths is not everything

Example application that uses RTOS

30

v

v

v

v

Page 31: S emb t13-freertos

RMR©2012

Maths is not everything

Example application: execution sequence (ARM)

31

Page 32: S emb t13-freertos

RMR©2012

Maths is not everything

Task Control Block

32

Page 33: S emb t13-freertos

0

1

2

3

n-1

pxReadyTaskList

currentTask

NULL

NULL

NULL

NULL

NULL

0

1

2

3

n-1

pxReadyTaskList

currentTask

NULL

Task1

NULL

NULL

NULL

RMR©2012

Maths is not everything

Example application: Data-structures maintained by RTOS

Initially

33

After TaskCreate(1)

Page 34: S emb t13-freertos

0

1

2

3

n-1

pxReadyTaskList

currentTask

NULL

Task1

Task2

NULL

NULL

0

1

2

3

n-1

Task2

pxReadyTaskList

currentTask

idle

Task1

NULL

NULL

NULL

RMR©2012

Maths is not everything

Example application: Data-structures maintained by RTOS

After TaskCreate(2)

34

After TaskStartSchedule ()

Page 35: S emb t13-freertos

RMR©2012

Maths is not everything

Ready and Blocked Lists

35

Page 36: S emb t13-freertos

RMR©2012

Maths is not everything

Hypothetical DelayedTaskList

36

Page 37: S emb t13-freertos

RMR©2012

Maths is not everything

Tasks within tasks

37

void vTask1( void *pvParameters ){const char *pcTaskName = "Task 1 is running\r\n";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. */

}

}

}

Page 38: S emb t13-freertos

RMR©2012

Maths is not everything

Using the task parameter

38

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

}}

}

/* 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 running\r\n”;static const char *pcTextForTask2 = “Task 2 is running\t\n”;

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( ;; );}

Page 39: S emb t13-freertos

RMR©2012

Maths is not everything

Block State: the delay primitive

39

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

C o n s t a n t s c o n f i g T I C K _ R A T E _ M S a n d configTICK_RATE_HZ usable to get desired time delay

Page 40: S emb t13-freertos

RMR©2012

Maths is not everything

Blocking: delaying a task for a period of time

40

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 );

}}

Page 41: S emb t13-freertos

RMR©2012

Maths is not everything

Block State: the exact delay primitive

41

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

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())

Page 42: S emb t13-freertos

RMR©2012

Maths is not everything

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

42

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 ) ); }}

Page 43: S emb t13-freertos

RMR©2012

Maths is not everything

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

Tasks may have the same priority. In this case the scheduler will execute them in a round-robin fashion.

43

Page 44: S emb t13-freertos

RMR©2012

Maths is not everything

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.

44

Page 45: S emb t13-freertos

RMR©2012

Maths is not everything

Scheduler and Priorities

There is no automatic management of prioritiesa 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.

45

Page 46: S emb t13-freertos

RMR©2012

Maths is not everything

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

46

Page 47: S emb t13-freertos

RMR©2012

Maths is not everything

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)

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.

47

Page 48: S emb t13-freertos

RMR©2012

Maths is not everything

Idle Task Hook

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

Measuring the amount of spare processing capacitymeasuring 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

48

/* Declare a variable that will be incremented by the hook function. */unsigned long ulIdleCycleCount = 0UL;

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

/* This hook function does nothing but increment a counter. */ ulIdleCycleCount++;}

Page 49: S emb t13-freertos

RMR©2012

Maths is not everything

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

provide the implementation of the hook function using:

49

void vApplicationTickHook( void );

Page 50: S emb t13-freertos

RMR©2012

Maths is not everything

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

50

Page 51: S emb t13-freertos

RMR©2012

Maths is not everything

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.

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

51

Page 52: S emb t13-freertos

RMR©2012

Maths is not everything

Task Management API

52

Page 53: S emb t13-freertos

RMR©2012

Maths is not everything

FreeRTOS

Queues

Page 54: S emb t13-freertos

RMR©2012

Maths is not everything

FreeRTOS Queues

Queue is a communication mechanism between tasks or between tasks and interrupt handlers

Tasks: xQueueSend, xQueueReceive, uxQueueMessagesWaitingISRs: xQueueSendFromISR, xQueueReceiveFromISR

Tasks can wait for items to enter/exit the queue while allowing other tasks to execute

54

Page 55: S emb t13-freertos

RMR©2012

Maths is not everything

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.

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 pointers55

Page 56: S emb t13-freertos

RMR©2012

Maths is not everything

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.

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.

56

Page 57: S emb t13-freertos

RMR©2012

Maths is not everything

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.

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.

57

Page 58: S emb t13-freertos

RMR©2012

Maths is not everything

Queue read/write: example

58

Page 59: S emb t13-freertos

RMR©2012

Maths is not everything

Queue read/write: example

58

Page 60: S emb t13-freertos

RMR©2012

Maths is not everything

Queue read/write: example

58

Page 61: S emb t13-freertos

RMR©2012

Maths is not everything

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

59

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.

xQueueHandle MyQueue;int main( void ){ ... MyQueue = xQueueCreate( 20, sizeof( unsigned char ) ); ...}

Page 62: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls: send to queue

60

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

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

Page 63: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls: send to queue

60

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()

Page 64: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls: send to queue

60

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.

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.

Page 65: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls: send to queue

60

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.

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.

pdPASS will only be returned if data was successfully sent to the queue.

Page 66: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls: send to queue

60

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.

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.

pdPASS will only be returned if data was successfully sent to the queue.

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

Page 67: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls: receive from queue

61

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

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

Page 68: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls: receive from queue

61

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

Page 69: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls: receive from queue

61

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 queuepvBuffer - A pointer to the memory into which the received data will be copied.

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.

Page 70: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls: receive from queue

61

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 queuepvBuffer - A pointer to the memory into which the received data will be copied.

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.

pdPASS will only be returned if data was successfully read from the queue.

Page 71: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls: receive from queue

61

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 queuepvBuffer - A pointer to the memory into which the received data will be copied.

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.

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.

Page 72: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls: auxiliary

uxQueueMessagesWaiting() is used to query the number of items that are currently in a queue

62

unsigned portBASE_TYPE uxQueueMessagesWaiting ( xQueueHandle xQueue);

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

Page 73: S emb t13-freertos

RMR©2012

Maths is not everything

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().

63

Page 74: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls: examples

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 willnow be running the tasks. Otherwise, it is likely that there was insufficient heap memory available for the idle task to be created*/for( ;; );

}

Page 75: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls: examples

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.\r\n" );

}/* 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(); }}

Page 76: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls: examples

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!\r\n" );}/* 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.\r\n" ); } }}

Page 77: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls: examples

67

Page 78: S emb t13-freertos

RMR©2012

Maths is not everything

Queues: transferring compound types

68

Page 79: S emb t13-freertos

RMR©2012

Maths is not everything

Queues: transferring compound types

69

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

};

Page 80: S emb t13-freertos

RMR©2012

Maths is not everything

Queues: transferring compound types

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 willnow be running the tasks. Otherwise, it is likely that there was insufficient heap memory available for the idle task to be created*/for( ;; );

}

Page 81: S emb t13-freertos

RMR©2012

Maths is not everything

Queues: transferring compound types

71

static void vSenderTask( void *pvParameters ){portBASE_TYPE xStatus;const portTickType xTicksToWait = 100 / portTICK_RATE_MS;

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.\r\n" );

}/* 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(); }}

Page 82: S emb t13-freertos

RMR©2012

Maths is not everything

Queues: transferring compound types

72

static void vReceiverTask( void *pvParameters ){xData xReceivedStructure;portBASE_TYPE xStatus;const portTickType xTicksToWait = 100 / portTICK_RATE_MS;

for( ;; ) {

/* always expects the queue to have 3 items */if( uxQueueMessagesWaiting( xQueue ) != 3 ) { vPrintString( "Queue should have been full!\r\n" );}/* 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.\r\n" ); } }}

Page 83: S emb t13-freertos

RMR©2012

Maths is not everything

Queues: transferring compound types

73

Page 84: S emb t13-freertos

RMR©2012

Maths is not everything

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

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.

74

Page 85: S emb t13-freertos

RMR©2012

Maths is not everything

Queue Management API

75

Page 86: S emb t13-freertos

RMR©2012

Maths is not everything

FreeRTOS

Interrupts and Synchronization

Page 87: S emb t13-freertos

RMR©2012

Maths is not everything

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?

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? 77

Page 88: S emb t13-freertos

RMR©2012

Maths is not everything

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

a context switch to the “handler” task should occur

when it has a higher priority than the interrupted task which is preempted

78

Page 89: S emb t13-freertos

RMR©2012

Maths is not everything

Interrupt Handling

79

Page 90: S emb t13-freertos

RMR©2012

Maths is not everything

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

80

Page 91: S emb t13-freertos

RMR©2012

Maths is not everything

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

80

Page 92: S emb t13-freertos

RMR©2012

Maths is not everything

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

80

Page 93: S emb t13-freertos

RMR©2012

Maths is not everything

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

80

Page 94: S emb t13-freertos

RMR©2012

Maths is not everything

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

80

Page 95: S emb t13-freertos

RMR©2012

Maths is not everything

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

80

Page 96: S emb t13-freertos

RMR©2012

Maths is not everything

Synchronization mechanisms

F r e e R T O S h a s t h e f o l l o w i n g synchronization mechanisms:

Binary Semaphores

Counting Semaphores

Queues

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

81

Page 97: S emb t13-freertos

RMR©2012

Maths is not everything

Binary Semaphores

Binary Semaphore Creation & Manipulation

82

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);

Page 98: S emb t13-freertos

RMR©2012

Maths is not everything

Binary Semaphores

Binary Semaphore Creation & Manipulation

82

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.

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.

Page 99: S emb t13-freertos

RMR©2012

Maths is not everything

Binary Semaphores

Binary Semaphore Creation & Manipulation

82

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.

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.

pdPASS will only be returned if the call was successful.

Page 100: S emb t13-freertos

RMR©2012

Maths is not everything

Binary Semaphores

Binary Semaphore Creation & Manipulation

82

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.

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.

pdPASS will only be returned if the call was successful.

pdFALSE will be returned if the semaphore was not available.

Page 101: S emb t13-freertos

RMR©2012

Maths is not everything

Forcing a context switch in the IH

To force the context switching from an ISR one should call:

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

83

void portEND_SWITCHING_ISR(portBASE_TYPE flag); // ARM port

void portSWITCH_CONTEXT(); // DOS port

Page 102: S emb t13-freertos

RMR©2012

Maths is not everything

Communication between an IH and the Handler Task: example

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( ;; ); }

Page 103: S emb t13-freertos

RMR©2012

Maths is not everything

Communication between an IH and the Handler Task: example

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.\r\n\r\n\r\n" );}

}

Page 104: S emb t13-freertos

RMR©2012

Maths is not everything

Communication between an IH and the Handler Task: example

86

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.\r\n" );

}}

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); }}

Page 105: S emb t13-freertos

RMR©2012

Maths is not everything

Communication between an IH and the Handler Task: example

87

Page 106: S emb t13-freertos

RMR©2012

Maths is not everything

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:

Handling events.

Managing the access to resources

88

Page 107: S emb t13-freertos

RMR©2012

Maths is not everything

Handling events with Counting Semaphores

89

Page 108: S emb t13-freertos

RMR©2012

Maths is not everything

Handling events with Counting Semaphores

89

Page 109: S emb t13-freertos

RMR©2012

Maths is not everything

Handling events with Counting Semaphores

89

Page 110: S emb t13-freertos

RMR©2012

Maths is not everything

Handling events with Counting Semaphores

89

Page 111: S emb t13-freertos

RMR©2012

Maths is not everything

Handling events with Counting Semaphores

89

Page 112: S emb t13-freertos

RMR©2012

Maths is not everything

Handling events with Counting Semaphores

89

Page 113: S emb t13-freertos

RMR©2012

Maths is not everything

Handling events with Counting Semaphores

89

Page 114: S emb t13-freertos

RMR©2012

Maths is not everything

Counting Semaphores: creation and manipulation

90

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);

Page 115: S emb t13-freertos

RMR©2012

Maths is not everything

Counting Semaphores: creation and manipulation

90

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.

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.

Page 116: S emb t13-freertos

RMR©2012

Maths is not everything

Counting Semaphores: example of use in an IH

91

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( ;; ); }

Page 117: S emb t13-freertos

RMR©2012

Maths is not everything

Counting Semaphores: example of use in an IH

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); }}

Page 118: S emb t13-freertos

RMR©2012

Maths is not everything

Semaphore Management API

93

Page 119: S emb t13-freertos

RMR©2012

Maths is not everything

Synchronizing IH and Tasks with Queues

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

xQueueSendToFrontFromISR(), xQueueSendToBackFromISR() and xQueueReceiveFromISR() are versions of xQueueSendToFront(), xQueueSendToBack() and xQueueReceive() respectively that are safe to use within an interrupt service routine.

94

Page 120: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls (from ISR): send to queue

95

portBASE_TYPE xQueueSendToFrontFromISR (xQueueHandle xQueue,const void* pvItemToQueue,portBASE_TYPE *pxHigherPriorityTaskWoken);

portBASE_TYPE xQueueSendToBackFromISR ( xQueueHandle xQueue,const void* pvItemToQueue,portBASE_TYPE *pxHigherPriorityTaskWoken);

Page 121: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls (from ISR): send to queue

95

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()

Page 122: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls (from ISR): send to queue

95

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.

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.

Page 123: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls (from ISR): send to queue

95

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.

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.

pdPASS will only be returned if data was successfully sent to the queue.

Page 124: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls (from ISR): send to queue

95

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.

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.

pdPASS will only be returned if data was successfully sent to the queue.

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

Page 125: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls: (from ISR) receive from queue

96

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

Page 126: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls: (from ISR) receive from queue

96

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

pvBuffer - A pointer to the memory into which the received data will be copied.

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.

Page 127: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls: (from ISR) receive from queue

96

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

pvBuffer - A pointer to the memory into which the received data will be copied.

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.

pdPASS will only be returned if data was successfully read from the queue.

Page 128: S emb t13-freertos

RMR©2012

Maths is not everything

Queue System Calls: (from ISR) receive from queue

96

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

pvBuffer - A pointer to the memory into which the received data will be copied.

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.

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.

Page 129: S emb t13-freertos

RMR©2012

Maths is not everything

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.

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.

97

Page 130: S emb t13-freertos

RMR©2012

Maths is not everything

Interrupt Nesting: example

98

! •! 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.

Page 131: S emb t13-freertos

RMR©2012

Maths is not everything

Interrupt Nesting: example

98

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.

Page 132: S emb t13-freertos

RMR©2012

Maths is not everything

Interrupt Nesting: example

98

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.

Page 133: S emb t13-freertos

RMR©2012

Maths is not everything

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.

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

99

Page 134: S emb t13-freertos

RMR©2012

Maths is not everything

FreeRTOS

Resource Management

Page 135: S emb t13-freertos

RMR©2012

Maths is not everything

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 variablesPeripheralsCode

101

Page 136: S emb t13-freertos

RMR©2012

Maths is not everything

Accessing global variables

Let’s assume the following C code: GlobalC += 10;

In assembly we got:1. LOAD R, [#1234]2. SUM R, 103. 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

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

102

Page 137: S emb t13-freertos

RMR©2012

Maths is not everything

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.

Task A continues from the point at which it was pre-empted and completes outputting the remaining characters – “orld”.

The LCD will now be displaying the corrupted string “Hello wAbort, Retry, Fail?orld”.

103

Page 138: S emb t13-freertos

RMR©2012

Maths is not everything

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.

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;}

Page 139: S emb t13-freertos

RMR©2012

Maths is not everything

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.

105

/* 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 : lReturn = lVar1 + 20; lState = 0;

break;

}}

Page 140: S emb t13-freertos

RMR©2012

Maths is not everything

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

but the best is to assure (if possible) that resources are not shared and each resource is only accessed from a single task.

106

Page 141: S emb t13-freertos

RMR©2012

Maths is not everything

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()

107

/* 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();

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

preemption results from an interrupt, so taskENTER_CRITICAL() assures that the task stays in Running until taskEXIT_CRITICAL()

Page 142: S emb t13-freertos

RMR©2012

Maths is not everything

Mutual Exclusion by implementing Critical Sections: example

Critical sections must be kept very short otherwise they will adversely affect interrupt response times.

108

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();

}

Page 143: S emb t13-freertos

RMR©2012

Maths is not everything

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.

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();

}

Page 144: S emb t13-freertos

RMR©2012

Maths is not everything

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.)

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.

110

Page 145: S emb t13-freertos

RMR©2012

Maths is not everything

Mutual Exclusion through the use of Mutexes: examples

111

Page 146: S emb t13-freertos

RMR©2012

Maths is not everything

Mutual Exclusion through the use of Mutexes: examples

111

Page 147: S emb t13-freertos

RMR©2012

Maths is not everything

Mutual Exclusion through the use of Mutexes: examples

111

Page 148: S emb t13-freertos

RMR©2012

Maths is not everything

Mutual Exclusion through the use of Mutexes: examples

111

Page 149: S emb t13-freertos

RMR©2012

Maths is not everything

Mutual Exclusion through the use of Mutexes: examples

111

Page 150: S emb t13-freertos

RMR©2012

Maths is not everything

Mutual Exclusion through the use of Mutexes: examples

111

Page 151: S emb t13-freertos

RMR©2012

Maths is not everything

Mutual Exclusion through the use of Mutexes: examples

111

Page 152: S emb t13-freertos

RMR©2012

Maths is not everything

Mutual Exclusion through the use of Mutexes: examples

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.

Page 153: S emb t13-freertos

RMR©2012

Maths is not everything

Mutex Semaphores

MUTEX Creation & Manipulation

112

xSemaphoreHandle vSemaphoreCreateMutex(void);portBASE_TYPE xSemaphoreTake (xSemaphoreHandle xSemaphore,

portTickType xTicksToWait);portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore);

Page 154: S emb t13-freertos

RMR©2012

Maths is not everything

Mutex Semaphores

MUTEX Creation & Manipulation

112

xSemaphoreHandle vSemaphoreCreateMutex(void);portBASE_TYPE xSemaphoreTake (xSemaphoreHandle xSemaphore,

portTickType xTicksToWait);portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore);

When to use

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.

Page 155: S emb t13-freertos

RMR©2012

Maths is not everything

Mutex Semaphores

MUTEX Creation & Manipulation

112

xSemaphoreHandle vSemaphoreCreateMutex(void);portBASE_TYPE xSemaphoreTake (xSemaphoreHandle xSemaphore,

portTickType xTicksToWait);portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore);

When to use

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.

non-NULL will only be returned if the MUTEX was created successfully.

Page 156: S emb t13-freertos

RMR©2012

Maths is not everything

Mutex Semaphores

MUTEX Creation & Manipulation

112

xSemaphoreHandle vSemaphoreCreateMutex(void);portBASE_TYPE xSemaphoreTake (xSemaphoreHandle xSemaphore,

portTickType xTicksToWait);portBASE_TYPE xSemaphoreGive (xSemaphoreHandle xSemaphore);

When to use

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.

non-NULL will only be returned if the MUTEX was created successfully.

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

Page 157: S emb t13-freertos

RMR©2012

Maths is not everything

Using a Mutex

113

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 );}

Page 158: S emb t13-freertos

RMR©2012

Maths is not everything

Using a Mutex

114

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 ) );

}

}

Page 159: S emb t13-freertos

RMR©2012

Maths is not everything

Using a Mutex

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 ******************************************\r\n", 1, NULL ); xTaskCreate( prvPrintTask, "Print2", 1000, "Task 2 ------------------------------------------\r\n", 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( ;; );}

Page 160: S emb t13-freertos

RMR©2012

Maths is not everything

Using a Mutex

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

Page 161: S emb t13-freertos

RMR©2012

Maths is not everything

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

117

Page 162: S emb t13-freertos

RMR©2012

Maths is not everything

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

117

An interesting REAL example of priority inversion

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

Page 163: S emb t13-freertos

RMR©2012

Maths is not everything

Priority Inheritance

FreeRTOS mutexes automatically provide a basic ‘priority inheritance’ mechanism.

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

118

assumes a task w

ill only hold a single mutex at any one tim

e.

Page 164: S emb t13-freertos

RMR©2012

Maths is not everything

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.

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.119

Page 165: S emb t13-freertos

RMR©2012

Maths is not everything

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

May ease the access to a resource from an interrupt handler

120

Page 166: S emb t13-freertos

Task 1

Task 2

MSG2

MSG1

Gatekeeper

Resource

Queue

RMR©2012

Maths is not everything

Gatekeepers

121

Page 167: S emb t13-freertos

RMR©2012

Maths is not everything

The Gatekeeper itself

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

} }

Page 168: S emb t13-freertos

RMR©2012

Maths is not everything

The tasks that generate messages for the gatekeeper

123

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 ) );

}

}

Page 169: S emb t13-freertos

RMR©2012

Maths is not everything

Interrupt Hook using also the gatekeeper

124

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;

}

} 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()’.

Page 170: S emb t13-freertos

RMR©2012

Maths is not everything

creating everything in the Main

125

static char *pcStringsToPrint[] = { "Task 1 ****************************************************\r\n", "Task 2 ----------------------------------------------------\r\n", "Message printed from the tick hook interrupt ##############\r\n"};/*-----------------------------------------------------------*//* 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();

}}

Page 171: S emb t13-freertos

RMR©2012

Maths is not everything

FreeRTOS

Memory Management

Page 172: S emb t13-freertos

RMR©2012

Maths is not everything

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.

They can suffer from memory fragmentation.

127

Page 173: S emb t13-freertos

RMR©2012

Maths is not everything

Managing memory dynamically

Different embedded systems have varying RAM allocation and timing requirementsFreeRTOS 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().

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.

128

Page 174: S emb t13-freertos

RMR©2012

Maths is not everything

Managing memory dynamically

FreeRTOS prov ides 4 d i f ferent 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.

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.

129

Page 175: S emb t13-freertos

RMR©2012

Maths is not everything

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

130

Heap_1 is always deterministic.

Useful in: any application that never deletes a task, queue or semaphore.

Page 176: S emb t13-freertos

RMR©2012

Maths is not everything

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 a lso uses a s imple array d imensioned 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.

131

Heap_2 can suffer from fragmentation

Heap_2 is not deterministic.

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);

Page 177: S emb t13-freertos

RMR©2012

Maths is not everything

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

132

void *pvPortMalloc( size_t xWantedSize ){void *pvReturn; vTaskSuspendAll(); { pvReturn = malloc( xWantedSize ); } xTaskResumeAll(); return pvReturn;}void vPortFree( void *pv ){ if( pv != NULL ) { vTaskSuspendAll(); {

free( pv ); } xTaskResumeAll(); }}

Useful in: applications that repeatedly allocate and free memory buffers of different size.

Page 178: S emb t13-freertos

RMR©2012

Maths is not everything

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

133

Page 179: S emb t13-freertos

RMR©2012

Maths is not everything

Stack Overflow - WaterMark

134

unsigned portBASE_TYPEuxTaskGetStackHighWaterMark(xTaskHandle xTask);

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'.

Page 180: S emb t13-freertos

RMR©2012

Maths is not everything

Stack Overflow - WaterMark

134

unsigned portBASE_TYPEuxTaskGetStackHighWaterMark(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

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.

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'.

Page 181: S emb t13-freertos

RMR©2012

Maths is not everything

Stack Overflow : Run Time Checking

FreeRTOS includes two optional run time stack checking mechanisms.

controlled by the configCHECK_FOR_ST ACK_OVERFLOW c o m p i l e t i m e c o n fi g u r a t i o n c o n s t a n t w i t h i n 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.

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.

Page 182: S emb t13-freertos

RMR©2012

Maths is not everything

Stack Overflow : Run Time Checking

Run Time Stack Checking - Method 1configCHECK_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 2configCHECK_FOR_STACK_OVERFLOW= 2.

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 overflows136

Page 183: S emb t13-freertos

RMR©2012

Maths is not everything

FreeRTOS

Additional Features

Page 184: S emb t13-freertos

RMR©2012

Maths is not everything

Software Timer

A Software Timer provides a mechanism for calling back a function when a certain time passes.

The timer's callback function is executed when the timer's period expires.

It doesn’t execute a timer callback functions from an interrupt context.

It does not consume any processing time unless a timer has actually expired,

It is not part of the kernel and it does not add any processing overhead to the tick interrupt, and does not walk any link list structures while interrupts are disabled.

138

Page 185: S emb t13-freertos

RMR©2012

Maths is not everything

Software Timer

Basically, the FreeRTOS software timer implementation acts like a task using the resources provided by the FreeRTOS.Timer callback functions execute in the context of the timer service task.

Essential that timer callback functions never attempt to block. For example, a timer callback function must not call vTaskDelay(), vTaskDelayUntil(), or specify a non zero block time when accessing a queue or a semaphore.

APIs that communicate with the timer task through queues.

139

Page 186: S emb t13-freertos

RMR©2012

Maths is not everything

Software Timer

140

Page 187: S emb t13-freertos

RMR©2012

Maths is not everything

Software Timer Creation

141

xTimerHandle xTimerCreate(const signed char *pcTimerName, portTickType xTimerPeriod, unsigned portBASE_TYPE uxAutoReload, void * pvTimerID, tmrTIMER_CALLBACK pxCallbackFunction);

portBASE_TYPE xTimerDelete( xTimerHandle xTimer, portTickType xBlockTime);

Page 188: S emb t13-freertos

RMR©2012

Maths is not everything

Software Timer Handling

142

portBASE_TYPE xTimerStart(xTimerHandle xTimer, portTickType xBlockTime);

portBASE_TYPE xTimerReset(xTimerHandle xTimer, portTickType xBlockTime);

portBASE_TYPE xTimerStop(xTimerHandle xTimer, portTickType xBlockTime);

Page 189: S emb t13-freertos

RMR©2012

Maths is not everything

Software Timer - types

One-shotexecutes the callback function just once although it can be re-armed manually

Auto-reloadupon executing the callback function it an automatic rearming is performed thus executing the callback function periodically

143

Page 190: S emb t13-freertos

RMR©2012

Maths is not everything

Enabling Software Timers

To enable this functionality, add timers.c to the project and configure the following options in FreeRTOSConfig.h:configUSE_TIMERS: “1” to enable the timer.

configTIMER_TASK_PRIORITY : t i m e r t a s k priority.

configTIMER_QUEUE_LENGTH: timer task queue size.

configTIMER_TASK_STACK_DEPTH: timer task stack size.

144