You are on page 1of 91

SRI RAMAKRISHNA ENGINEERING COLLEGE

[Educational Service : SNR Sons Charitable Trust]


[Autonomous Institution, Reaccredited by NAAC with ‘A+’ Grade]
[Approved by AICTE and Permanently Affiliated to Anna University, Chennai]
[ISO 9001:2015 Certified and all eligible programmes Accredited by NBA]
VATTAMALAIPALAYAM, N.G.G.O. COLONY POST, COIMBATORE – 641 022.

B.E. ELECTRONICS & COMMUNICATION


ENGINEERING

20EC2E25 – REAL TIME OPERATING


SYSTEMS
Semester : 06 Year : III
Academic Year : 2022-2023
FREE RTOS ATTRIBUTES

• Interrupt Management: Free RTOSAPI from an ISR- Deferred


Interrupt Processing-Binary and Counting Semaphores-
Interrupt Nesting- Resource Management: Critical Sections
and Suspending the scheduler - Mutexes- Gate keeper Tasks

20EC2E25- RTOS RAJASEKAR T, AP/ECE 2


Interrupt Management: Free
RTOSAPI from an ISR
• Interrupt Service Routines (ISRs) are a mechanism used by
Real-Time Operating Systems (RTOS) to handle hardware
interrupts. FreeRTOS provides APIs that allow
communication between the ISR and the RTOS kernel.
However, it is important to note that some FreeRTOS API
functions are not safe to be called from an ISR, as they may
block for an extended period or perform other operations
that are not suitable for an ISR context.
• To call a FreeRTOS API function from an ISR, you should use
the "FromISR" version of the API function. These functions
are specifically designed to be called from an ISR and take
the necessary precautions to ensure that they do not block
for an extended period or interfere with the operation of the
20EC2E25- RTOS RAJASEKAR T, AP/ECE 3
RTOS kernel.
• For example, to send a message to a queue from an ISR, you
can use the xQueueSendFromISR() function. Similarly, to give
a semaphore from an ISR, you can use the
xSemaphoreGiveFromISR() function.
• It is also important to note that some interrupts may have
higher priority than the RTOS kernel, which means that they
may preempt the RTOS kernel and execute before the ISR
has finished executing. To prevent this, you should ensure
that interrupts are disabled during the critical sections of the
ISR.

20EC2E25- RTOS RAJASEKAR T, AP/ECE 4


• In summary, to call a FreeRTOS API function from an ISR, you
should use the "FromISR" version of the API function, and
take the necessary precautions to ensure that the ISR does
not block for an extended period or interfere with the
operation of the RTOS kernel.

20EC2E25- RTOS RAJASEKAR T, AP/ECE 5


Deferred Interrupt Processing
• Deferred Interrupt Processing is a technique used in
FreeRTOS to handle interrupts that require longer processing
times than can be allowed in the context of the ISR. The
basic idea behind deferred interrupt processing is to use a
deferred processing task to complete the processing of the
interrupt after the ISR has completed.
• To implement deferred interrupt processing in FreeRTOS,
you need to create a deferred processing task and use a
queue to pass data from the ISR to the deferred processing
task. When an interrupt occurs, the ISR sends the data to the
queue and returns immediately, allowing the interrupt to be
processed quickly. The deferred processing task waits for
data to arrive on the queue, and when it does, it processes
20EC2E25- RTOS RAJASEKAR T, AP/ECE 6
the data as required.
• Here are the general steps to implement deferred interrupt
processing in FreeRTOS:
• Create a deferred processing task using xTaskCreate().
• Create a queue to pass data from the ISR to the deferred
processing task using xQueueCreate().
• In the ISR, use xQueueSendFromISR() to send data to the
queue.
• In the deferred processing task, use xQueueReceive() to wait
for data to arrive on the queue.
• Process the data as required in the deferred processing task.

20EC2E25- RTOS RAJASEKAR T, AP/ECE 7


• It's important to note that deferred interrupt processing can
introduce some additional overhead, as the data needs to be
passed from the ISR to the deferred processing task through
the queue. However, it can be a useful technique for
handling interrupts that require longer processing times or
that cannot be handled directly in the context of the ISR.
• Also, note that it is important to take care when using
deferred interrupt processing to ensure that the deferred
processing task does not block for extended periods, as this
can cause problems with the overall system performance. To
avoid blocking, you can use techniques such as time slicing or
priority levels to ensure that the deferred processing task
runs regularly and does not interfere with other tasks in the
20EC2E25- RTOS RAJASEKAR T, AP/ECE 8
system.
Deferred Interrupt Processing
• An interrupt service routine must record the cause of
the interrupt, and clear the interrupt. Any other
processing necessitated by the interrupt can often be
performed in a task, allowing the interrupt service
routine to exit as quickly as is practical.
• This is called ‘deferred interrupt processing’, because
the processing necessitated by the interrupt is
‘deferred’ from the ISR to a task.
• Deferring interrupt processing to a task also allows
the application writer to prioritize the processing
relative to other tasks in the application, and use all
the FreeRTOS API functions.

20EC211- Embedded Systems


Rajasekar T AP/ECE 9
& IoT
Contd.
• If the priority of the task to which interrupt
processing is deferred is above the priority of
any other task, then the processing will be
performed immediately, just as if the processing
had been performed in the ISR itself.
• This scenario is shown in Figure 5, in which Task
1 is a normal application task, and Task 2 is the
task to which interrupt processing is deferred.

20EC211- Embedded Systems


Rajasekar T AP/ECE 10
& IoT
Contd.

Figure 5

20EC211- Embedded Systems


Rajasekar T AP/ECE 11
& IoT
Contd.
• In Figure 5, interrupt processing starts at time
t2, and effectively ends at time t4, but only
the period between times t2 and t3 is spent
in the ISR.
• If deferred interrupt processing had not been
used then the entire period between times t2
and t4 would have been spent in the ISR.

20EC211- Embedded Systems


Rajasekar T AP/ECE 12
& IoT
Contd.
• Deferring processing to a task is most useful when: The
processing necessitated by the interrupt is not trivial.
• For example, if the interrupt is just storing the result of an
analog to digital conversion, then it is almost certain this is
best performed inside the ISR, but if result of the
conversion must also be passed through a software filter,
then it may be best to execute the filter in a task.
• It is convenient for the interrupt processing to perform an
action that cannot be performed inside an ISR, such as
write to a console, or allocate memory.
• The interrupt processing is not deterministic—meaning it
is not known in advance how long the processing will take.

20EC211- Embedded Systems


Rajasekar T AP/ECE 13
& IoT
Binary Semaphores Used for
Synchronization
• The interrupt safe version of the Binary
Semaphore API can be used to unblock a task
each time a particular interrupt occurs,
effectively synchronizing the task with the
interrupt.
• This allows the majority of the interrupt event
processing to be implemented within the
synchronized task, with only a very fast and
short portion remaining directly in the ISR.
• The binary semaphore is used to ‘defer’
interrupt processing to a task1

20EC211- Embedded Systems


Rajasekar T AP/ECE 14
& IoT
Contd.
• As previously demonstrated in Figure 5, if the
interrupt processing is particularly time critical, then
the priority of the deferred processing task can be set
to ensure the task always preempts the other tasks in
the system.
• The ISR can then be implemented to include a call to
portYIELD_FROM_ISR(), ensuring the ISR returns
directly to the task to which interrupt processing is
being deferred.
• This has the effect of ensuring the entire event
processing executes contiguously (without a break) in
time, just as if it had all been implemented within the
ISR itself.
20EC211- Embedded Systems
Rajasekar T AP/ECE 15
& IoT
Contd.

Figure 6

20EC211- Embedded Systems


Rajasekar T AP/ECE 16
& IoT
Contd.
• Figure 6 repeats the scenario shown in Figure 5,
but with the text updated to describe how the
execution of the deferred processing task can be
controlled using a semaphore.
• The deferred processing task uses a blocking
‘take’ call to a semaphore as a means of entering
the Blocked state to wait for the event to occur.
When the event occurs, the ISR uses a ‘give’
operation on the same semaphore to unblock
the task so that the required event processing
can proceed.

20EC211- Embedded Systems


Rajasekar T AP/ECE 17
& IoT
• In FreeRTOS, binary and counting semaphores are two types
of synchronization mechanisms used to coordinate tasks
and/or interrupts.
• Binary Semaphores:
• Binary semaphores are used to synchronize the access to a
shared resource, which can be accessed by only one task at a
time. Binary semaphores can have two states: available or
unavailable. When a task requests a binary semaphore that
is in the available state, the semaphore state is changed to
unavailable, and the task can access the shared resource. If
another task tries to access the same resource while the
semaphore is in the unavailable state, it will be blocked until
the semaphore state is RAJASEKAR
20EC2E25- RTOS
changed back to available by the task
T, AP/ECE 18
that owns it. Binary semaphores can be created using the
• Counting Semaphores:
• Counting semaphores are used to synchronize the access to
a shared resource that can be accessed by multiple tasks
simultaneously. Counting semaphores can have multiple
states, where the state value represents the number of
available resources. When a task requests a counting
semaphore, the semaphore state is decremented, and the
task can access the shared resource. If another task tries to
access the same resource while the semaphore state is zero,
it will be blocked until the semaphore state is incremented
back to a non-zero value by another task that releases it.
Counting semaphores can be created using the
xSemaphoreCreateCounting() function and can be used with
20EC2E25- RTOS RAJASEKAR T, AP/ECE 19
functions like xSemaphoreTake(), xSemaphoreGive(), etc.
• In summary, binary semaphores are used to protect a shared
resource that can be accessed by only one task at a time,
while counting semaphores are used to protect a shared
resource that can be accessed by multiple tasks
simultaneously. Both types of semaphores can be used to
prevent race conditions and to synchronize the execution of
tasks in a FreeRTOS system.

20EC2E25- RTOS RAJASEKAR T, AP/ECE 20


Resources management
• Binary semaphores
• Binary semaphores are used for both managing
Shared Resource and synchronization purposes.
• A binary semaphore can be seen as a queue
which contains only one element.
• Tasks and interrupts using the queue don't care
what the queue holds - they only want to know
if the queue is empty or full. This mechanism can
be exploited to synchronize (for example) a task
with an interrupt.
20EC211- Embedded Systems
Rajasekar T AP/ECE 21
& IoT
Contd.
• Consider the case where a task is used to service a
peripheral.
• Polling the peripheral would be wasteful of CPU
resources, and prevent other tasks from executing. It
is therefore preferable that the task spends most of its
time in the Blocked state (allowing other tasks to
execute) and only execute itself when there is actually
something for it to do.
• This is achieved using a binary semaphore by having
the task Block while attempting to 'take' the
semaphore.

20EC211- Embedded Systems


Rajasekar T AP/ECE 22
& IoT
Contd.
• An interrupt routine is then written for the
peripheral that just 'gives' the semaphore
when the peripheral requires servicing. The
task always 'takes' the semaphore (reads
from the queue to make the queue empty),
but never 'gives' it.
• The interrupt always 'gives' the semaphore
(writes to the queue to make it full) but never
takes it.

20EC211- Embedded Systems


Rajasekar T AP/ECE 23
& IoT
The semaphore is not available, so the task is blocked, waiting for the semaphore

xSemaphoreTake()

An interrupt occurs and gives a semaphore

xGiveSemaphoreFromISR() xSemaphoreTake()

Which unblocks the task

xGiveSemaphoreFromISR() xSemaphoreTake()

And allows it to take successfully the semaphore.

xSemaphoreTake()
20EC211- Embedded Systems
Rajasekar T AP/ECE 24
& IoT
.
Another interrupt occurs and gives another semaphore. In the meanwhile,
the task is processing the first interrupt

xGiveSemaphoreFromISR() xSemaphoreTake()

When the task has finished to process its first work, it waits for another semaphore and gets it
directly, since an interrupt occurred. The task is now able to process the second interrupt.

xSemaphoreTake()

Fig : A binary semaphore is equivalent to a queue which can contain one element

20EC211- Embedded Systems


Rajasekar T AP/ECE 25
& IoT
Handle binary semaphores
• Creation of a semaphore
SemaphoreHandle_t xSemaphoreCreateBinary( void );
Creates a binary semaphore, and returns a handle by
which the semaphore can be referenced.

Each binary semaphore require a small amount of RAM


that is used to hold the semaphore's state. If a binary
semaphore is created using
xSemaphoreCreateBinary() then the required RAM is
automatically allocated from the FreeRTOS heap.

20EC211- Embedded Systems


Rajasekar T AP/ECE 26
& IoT
Contd.
The semaphore is created in the 'empty' state, meaning
the semaphore must first be given using
the xSemaphoreGive() API function before it can
subsequently be taken (obtained) using
the xSemaphoreTake() function.
Return values:
NULL The semaphore could not be created because
there was insufficient FreeRTOS heap available.
Any other value The semaphore was created
successfully. The returned value is a handle by which
the semaphore can be referenced.
20EC211- Embedded Systems
Rajasekar T AP/ECE 27
& IoT
Example usage:
SemaphoreHandle_t xSemaphore;
void vATask( void * pvParameters )
{ /* Attempt to create a semaphore. */
xSemaphore = xSemaphoreCreateBinary();
if( xSemaphore == NULL )
{ /* There was insufficient FreeRTOS heap available for the
semaphore to be created successfully. */
}
else
{ /* The semaphore can now be used. Its handle is stored in the
xSemahore variable. Calling xSemaphoreTake() on the semaphore
here will fail until the semaphore has first been given. */
}
}

20EC211- Embedded Systems


Rajasekar T AP/ECE 28
& IoT
Taking a semaphore
• This operation is equivalent to a P() operation,
or if compared to queues, to a Receive()
operation. A task taking the semaphore must
wait it to be available and is blocked until it is or
until a delay is elapsed (if applicable).
xSemaphoreTake
(
SemaphoreHandle_t xSemaphore,
TickType_t xTicksToWait
);
taking a semaphore
20EC211- Embedded Systems
Rajasekar T AP/ECE 29
& IoT
Contd.
• xSemaphore A handle to the semaphore being taken -
obtained when the semaphore was created.
• xTicksToWait The time in ticks to wait for the semaphore
to become available.
• The macro portTICK_PERIOD_MS can be used to convert
this to a real time. A block time of zero can be used to poll
the semaphore.
• If INCLUDE_vTaskSuspend is set to '1' then specifying the
block time as portMAX_DELAY will cause the task to block
indefinitely (without a timeout).
• Returns: pdTRUE if the semaphore was obtained. pdFALSE
if xTicksToWait expired without the semaphore becoming
available.

20EC211- Embedded Systems


Rajasekar T AP/ECE 30
& IoT
Giving a semaphore
• Giving a semaphore can be compared to a V()
operation or to writing on a queue
xSemaphoreGive
( SemaphoreHandle_t xSemaphore );
giving a semaphore

20EC211- Embedded Systems


Rajasekar T AP/ECE 31
& IoT
Contd.
• xSemaphore A handle to the semaphore
being released.
• pdTRUE if the semaphore was released.
pdFALSE if an error occurred.
• Semaphores are implemented using queues.
An error can occur if there is no space on the
queue to post a message - indicating that the
semaphore was not first obtained correctly.

20EC211- Embedded Systems


Rajasekar T AP/ECE 32
& IoT
Mutexes
• A mutex provides mutual exclusion among tasks,
when they access a shared resource.
• When used for mutual exclusion the mutex acts like a
token that is used to guard a resource. When a task
wishes to access the resource it must first obtain
('take') the token. When it has finished with the
resource it must 'give' the token back - allowing other
tasks the opportunity to access the same resource.
Mutexes cannot be used in interrupt service routines.
• Mutexes use the same semaphore access API
functions.

20EC211- Embedded Systems


Rajasekar T AP/ECE 33
& IoT
Contd.
• Binary semaphores and mutexes are very similar but have some
subtle differences: Mutexes include a priority inheritance
mechanism, binary semaphores do not.
• This makes binary semaphores the better choice for implementing
synchronisation (between tasks or between tasks and an
interrupt), and mutexes the better choice for implementing simple
mutual exclusion.
• A binary semaphore need not be given back once obtained, so task
synchronisation can be implemented by one task/interrupt
continuously 'giving' the semaphore while another continuously
'takes' the semaphore.
• A task that obtains a mutex that is used for mutual exclusion must
always give the mutex back. Otherwise, no other task will ever be
able to obtain the same mutex

20EC211- Embedded Systems


Rajasekar T AP/ECE 34
& IoT
Usual use case of a mutex
• Two tasks want to access a resource. But only a task which holds the
mutex is allowed to work with it.

Task 1
Resource
to
protect
Task 2

Task 1 tries to take the mutex. Since it is available, it gets it and is allowed
to work with the resource.

Task 1
Resource
to
protect
Task 2
20EC211- Embedded Systems
Rajasekar T AP/ECE 35
& IoT
Task 2 tries to take the same mutex, but task 1 still has it.Task 2 is not permitted to access the resource.

Task 1
Resource
to
protect

X
Task 2

Task 2 is blocked until Task 1 has finished to work with the resource, and has given
back the mutex.

Task 1

Resource
to
protect
20EC211- Embedded Systems
Rajasekar T AP/ECE 36
& IoT Task 2
Task 1 has given back the mutex and task 2 can take it and is allowed to work with the
resource

Task 1

Resource
to
protect
Task 2

Task 2 gives back the mutex. It is now available to whichever task that need to
work with the associated resource.

Task 1

Resource
to
protect
Task 2

20EC211- Embedded Systems


Rajasekar T AP/ECE 37
& IoT
Priority inheritance
• Priority inheritance is a difference between a binary
semaphore and a mutex.
• The priority of a task that 'takes' a mutex can
potentially be raised if another task of higher priority
attempts to obtain the same mutex.
• The task that owns the mutex 'inherits' the priority of
the task attempting to 'take' the same mutex.
• This means the mutex must always be 'given' back -
otherwise the higher priority task will never be able to
obtain the mutex, and the lower priority task will
never 'disinherit' the priority.
20EC211- Embedded Systems
Rajasekar T AP/ECE 38
& IoT
Counting semaphores
• A counting semaphore is a semaphore that
can be taken several (but limited) times
before is becomes unavailable. It maintains a
value which is increased as the semaphore is
given, and decreased when is taken.
• Is comparable to a queue with a certain
amount of elements. When created, a
counting semaphore can be initialized to be
available an arbitrary number of times.

20EC211- Embedded Systems


Rajasekar T AP/ECE 39
& IoT
Counting semaphore routines
• Creation
• A counting semaphore can be taken a limited
maximum times and is initialized to be
available for an arbitrary number of take
operations.
• These characteristics are given when the
semaphore is created

20EC211- Embedded Systems


Rajasekar T AP/ECE 40
& IoT
Contd.
SemaphoreHandle_t xSemaphoreCreateCounting
(
UBaseType_t uxMaxCount,
UBaseType_t uxInitialCount
);

Creates a counting semaphore and returns a handle by which the


newly created semaphore can be referenced.
configSUPPORT_DYNAMIC_ALLOCATION must be set to 1 in
FreeRTOSConfig.h, or left undefined

Creation of a counting semaphore.

20EC211- Embedded Systems


Rajasekar T AP/ECE 41
& IoT
Contd.
• uxMaxCount The maximum count value that can
be reached. When the semaphore reaches this
value it can no longer be 'given'.
• uxInitialCount The count value assigned to the
semaphore when it is created.
• Returns: If the semaphore is created successfully
then a handle to the semaphore is returned. If
the semaphore cannot be created because the
RAM required to hold the semaphore cannot be
allocated then NULL is returned.

20EC211- Embedded Systems


Rajasekar T AP/ECE 42
& IoT
Contd.
• Each counting semaphore require a small
amount of RAM that is used to hold the
semaphore's state.
• If a counting semaphore is created using
xSemaphoreCreateCounting() then the
required RAM is automatically allocated from
the FreeRTOS heap

20EC211- Embedded Systems


Rajasekar T AP/ECE 43
& IoT
Contd.
Counting semaphores are typically used for two things:
Counting events.
• In this usage scenario an event handler will 'give' a
semaphore each time an event occurs (incrementing
the semaphore count value), and a handler task will
'take' a semaphore each time it processes an event
(decrementing the semaphore count value). The
count value is therefore the difference between the
number of events that have occurred and the number
that have been processed. In this case it is desirable
for the initial count value to be zero

20EC211- Embedded Systems


Rajasekar T AP/ECE 44
& IoT
[The semaphore count is 0]

xSemaphoreTake()

An interrupt occurs...that The task is blocked waiting


‘gives’ the semaphore…. for a semaphore

Interrupt! [The semaphore count is 1]

xSemaphoreGiveFromISR() xSemaphoreTake()

[The semaphore count is0

xSemaphoreTake()

Interrupt! The semaphore count is 2

xSemaphoreGiveFromISR() xSemaphoreTake()
Another two interrupts occur while the task is still
processing the first event.
20EC211- Embedded Systems
Rajasekar T AP/ECE 45
& IoT
Contd.
Resource management.
• In this usage scenario the count value indicates the
number of resources available. To obtain control of a
resource a task must first obtain a semaphore -
decrementing the semaphore count value. When the
count value reaches zero there are no free resources.
When a task finishes with the resource it 'gives' the
semaphore back - incrementing the semaphore count
value. In this case it is desirable for the initial count
value to be equal to the maximum count value,
indicating that all resources are free.

20EC211- Embedded Systems


Rajasekar T AP/ECE 46
& IoT
Contd.
void vATask( void * pvParameters )
{
SemaphoreHandle_t xSemaphore;
/* Create a counting semaphore that has a maximum
count of 10 and an initial count of 0. */
xSemaphore = xSemaphoreCreateCounting( 10, 0 );
if( xSemaphore != NULL )
{ /* The semaphore was created successfully. */
}
}

20EC211- Embedded Systems


Rajasekar T AP/ECE 47
& IoT
Contd.
UBaseType_t uxSemaphoreGetCount
(
SemaphoreHandle_t xSemaphore
);
Returns the count of a semaphore.
xSemaphore The handle of the semaphore being queried.
Returns: If the semaphore is a counting semaphore then the
semaphore’s current count value is returned. If the
semaphore is a binary semaphore then 1 is returned if the
semaphore is available, and 0 is returned if the semaphore
is not available.

20EC211- Embedded Systems


Rajasekar T AP/ECE 48
& IoT
Handling interrupts
• An interrupt is a mechanism fully implemented
and handled by hardware.
• Software and more particularly FreeRTOS tasks
or kernel can only give methods to handle a
given interrupt, or it can raise some by calling an
hardware instruction.
• Assume using a micro controller that handles 7
different levels of interrupts.
• Interrupts priorities are not, in any case, related
to tasks priorities, and will always preempt
them.
20EC211- Embedded Systems
Rajasekar T AP/ECE 49
& IoT
Contd.
• A function defined as an interrupt handler cannot use
freely FreeRTOS API: access to queues or semaphores
is forbidden through the normal functions described
in previous section, but FreeRTOS provides some
specialized functions to be used in that context: for
instance, in an interrupt handler, a V() operation to a
semaphore must be realized using
xSemaphoreGiveFromISR() instead of
xSemaphoreGive().
• The prototypes for these method can be different as
they can involve some particular problems

20EC211- Embedded Systems


Rajasekar T AP/ECE 50
& IoT
Contd.
• Interrupt management can be configured in FreeRTOS
using constants available in FreeRTOSConfig.h.
• configKERNEL_INTERRUPT_PRIORITY sets the
interrupt priority level for the tick interrupt.
• configMAX_SYSCALL_INTERRUPT_PRIORITY defines
the highest interrupt level available to interrupts that
use interrupt safe FreeRTOS API functions.
• If this constant is not defined, then any interrupt
handler function that makes use of FreeRTOS API
must execute at configKERNEL_INTERRUPT_PRIORITY.

20EC211- Embedded Systems


Rajasekar T AP/ECE 51
& IoT
Contd.
• Any interrupt whose priority level is greater
than configMAX_SYSCALL_INTERRUPT_
PRIORITY or
configKERNEL_INTERRUPT_PRIORITY if
configMAX_SYSCALL_INTERRUPT_PRIORITY is
not defined, will never be preempted by the
kernel, but are forbidden to use FreeRTOS
API functions

20EC211- Embedded Systems


Rajasekar T AP/ECE 52
& IoT
Interrupt organization in FreeRTOS

Micro-controller provides 7 levels of interrupt

20EC211- Embedded Systems


Rajasekar T AP/ECE 53
& IoT
Manage interrupts using a binary
semaphore
• Interrupt handlers are pieces of code run by the
microcontroller and therefore are not handled by FreeRTOS.
• This can potentially create problems with memory access
since the operating system cannot handle these context
changes.
• This is a reason why several functions exists in two versions:
one for regular tasks and another is intended to interrupts
handler.
• This is the case of queue management functions like
xQueueReceive() and xQueueReceiveFromISR().
• For this reason, it is necessary to make interrupts handlers'
execution as short as possible.

20EC211- Embedded Systems


Rajasekar T AP/ECE 54
& IoT
Contd.
• Even if tasks have been assigned a very high priority, they
will only run if no interrupts are being serviced by the
hardware.
• ISRs can disrupt (add ‘jitter’ to) both the start time, and
the execution time, of a task.
• Depending on the architecture on which FreeRTOS is
running, it might not be possible to accept any new
interrupts, or at least a subset of new interrupts, while an
ISR is executing.
• The application writer needs to consider the
consequences of, and guard against, resources such as
variables, peripherals, and memory buffers being accessed
by a task and an ISR at the same time.

20EC211- Embedded Systems


Rajasekar T AP/ECE 55
& IoT
Contd.
• Some FreeRTOS ports allow interrupts to
nest, but interrupt nesting can increase
complexity and reduce predictability. The
shorter an interrupt is, the less likely it is to
nest.

20EC211- Embedded Systems


Rajasekar T AP/ECE 56
& IoT
• In FreeRTOS, interrupt nesting refers to the situation where
an interrupt occurs while another interrupt is being serviced.
Interrupt nesting can happen when multiple interrupts are
triggered in quick succession or when an interrupt takes a
long time to complete.
• FreeRTOS provides interrupt nesting support to ensure that
the system can handle multiple interrupts without losing
data or blocking the execution of other tasks. When an
interrupt occurs, FreeRTOS temporarily masks lower priority
interrupts to allow the interrupt service routine (ISR) to
execute without interruption. This is done to ensure that
critical data is not lost or corrupted by other interrupts.
20EC2E25- RTOS RAJASEKAR T, AP/ECE 57
• The FreeRTOS kernel provides a mechanism to manage
interrupt nesting through the use of an interrupt priority
level. The interrupt priority level is a hardware register that
is set to a specific value when an interrupt occurs. The value
of the interrupt priority level determines which interrupts
are allowed to occur while the ISR is executing.

• FreeRTOS provides the vPortEnterCritical() and


vPortExitCritical() functions to enable and disable interrupts,
respectively. These functions should be used to prevent
interrupt nesting when accessing shared resources from an
ISR.
20EC2E25- RTOS RAJASEKAR T, AP/ECE 58
• When a task wants to access a shared resource, it can use a
synchronization mechanism like a semaphore to signal the
ISR to release the shared resource. The ISR can then use the
same synchronization mechanism to signal the task when the
shared resource is available. This ensures that the task can
access the shared resource without blocking the execution of
the ISR or other tasks.
• In summary, FreeRTOS provides interrupt nesting support to
ensure that the system can handle multiple interrupts
without losing data or blocking the execution of other tasks.
Interrupt nesting is managed using an interrupt priority level
and synchronization mechanisms like semaphores to prevent
race conditions when accessing shared resources from an
20EC2E25- RTOS RAJASEKAR T, AP/ECE 59
ISR.
• In FreeRTOS, resource management involves managing
access to shared resources such as hardware peripherals,
memory, and communication channels. Since multiple tasks
and interrupts may need to access these resources
simultaneously, proper resource management is essential to
prevent data corruption, race conditions, and deadlocks.

20EC2E25- RTOS RAJASEKAR T, AP/ECE 60


• FreeRTOS provides several mechanisms for resource
management:
• Semaphores: Semaphores are synchronization primitives
that allow tasks and interrupts to communicate and
coordinate access to shared resources. They can be used to
implement mutual exclusion, signaling, and synchronization
between tasks and interrupts.
• Mutexes: Mutexes are similar to semaphores but are used to
provide mutual exclusion for shared resources. A mutex can
be locked by a task or an interrupt and can only be released
by the same task or interrupt that locked it.

20EC2E25- RTOS RAJASEKAR T, AP/ECE 61


• Queues: Queues provide a message passing mechanism
between tasks and interrupts. Tasks can send messages to a
queue, and other tasks can receive these messages from the
queue. Queues can be used to pass data between tasks,
synchronize tasks, and coordinate access to shared
resources.
• Event Groups: Event groups allow tasks and interrupts to
synchronize and communicate based on a set of flags or
events. Tasks can set and clear flags in an event group, and
other tasks can wait for specific combinations of flags to be
set.

20EC2E25- RTOS RAJASEKAR T, AP/ECE 62


• Software Timers: Software timers allow tasks and interrupts
to schedule and execute functions at specific intervals or
after a specific delay. They can be used to schedule periodic
tasks, timeouts, and other time-dependent operations.
• To manage resources effectively, it's essential to define
critical sections in the code where shared resources are
accessed. These critical sections should be protected by a
synchronization mechanism such as a semaphore or a mutex
to prevent race conditions and data corruption.

20EC2E25- RTOS RAJASEKAR T, AP/ECE 63


Here's an example of how resource management can be
implemented in FreeRTOS:
SemaphoreHandle_t xSemaphore;

void Task1(void *pvParameters)


{
while (1)
{
// Wait for the semaphore to become available
xSemaphoreTake(xSemaphore, portMAX_DELAY);

20EC2E25- RTOS RAJASEKAR T, AP/ECE 64


// Access the shared resource
// Release the semaphore to signal that the shared resource is available
xSemaphoreGive(xSemaphore);
}
}
void Task2(void *pvParameters)
{
while (1)
{
// Wait for a message to arrive in the queue
uint32_t data;
xQueueReceive(xQueue, &data, portMAX_DELAY);
// Process the message
20EC2E25- RTOS RAJASEKAR T, AP/ECE 65
// Set a flag in the event group to signal that Task2 has completed
processing the message
xEventGroupSetBits(xEventGroup, TASK2_COMPLETE_FLAG);
}
}
void Interrupt_Handler(void)
{
// Lock the mutex to prevent other interrupts or tasks from accessing the
shared resource
xSemaphoreTakeFromISR(xMutex, NULL);
// Access the shared resource
// Unlock the mutex to allow other interrupts or tasks to access the
shared resource

20EC2E25- RTOS RAJASEKAR T, AP/ECE 66


xSemaphoreGiveFromISR(xMutex, NULL);
}
int main(void)
{
// Create a binary semaphore and a mutex
xSemaphore = xSemaphoreCreateBinary();
xMutex = xSemaphoreCreateMutex();
// Enable the interrupt
NVIC_EnableIRQ(Interrupt_IRQn);
// Create a queue and an event group
xQueue = xQueueCreate(10, sizeof(uint32_t));
xEventGroup = xEventGroupCreate();

20EC2E25- RTOS RAJASEKAR T, AP/ECE 67


// Create Task1 and Task2
xTaskCreate(Task1, "Task1", configMINIMAL_STACK_SIZE, NULL,
tskIDLE_PRIORITY, NULL);
xTaskCreate(Task2, "Task2", configMINIMAL_STACK_SIZE, NULL,
tskIDLE_PRIORITY, NULL);

// Start the FreeRTOS scheduler


vTaskStartScheduler();

// Should

20EC2E25- RTOS RAJASEKAR T, AP/ECE 68


• In FreeRTOS, critical sections and suspending the scheduler
are two techniques that are used to protect shared
resources from concurrent access by multiple tasks or
interrupt service routines (ISRs).
• A critical section is a region of code that must be executed
atomically, without interruption from other tasks or ISRs. In
FreeRTOS, critical sections are typically implemented using
interrupts to disable and re-enable the scheduler. The
taskENTER_CRITICAL() and taskEXIT_CRITICAL() macros can
be used to disable and re-enable interrupts, respectively. By
disabling interrupts, the scheduler is prevented from
switching between tasks or interrupting the execution of a
task while it is in the critical section. This ensures that the
20EC2E25- RTOS RAJASEKAR T, AP/ECE 69
critical section is executed atomically and without
• Suspending the scheduler is another technique that is used
to protect shared resources from concurrent access. When
the scheduler is suspended, the current task is allowed to
continue executing, but the scheduler will not switch to any
other tasks, even if they have a higher priority. In FreeRTOS,
suspending the scheduler is typically achieved using the
vTaskSuspendAll() and xTaskResumeAll() functions. The
vTaskSuspendAll() function suspends the scheduler, while
xTaskResumeAll() resumes it. While the scheduler is
suspended, critical sections can be executed without
interruption, but other tasks or ISRs will not be able to run.

20EC2E25- RTOS RAJASEKAR T, AP/ECE 70


• It is important to note that critical sections and suspending
the scheduler should be used with caution, as they can
impact system performance and cause priority inversion
issues. Priority inversion occurs when a low-priority task
holds a resource that a high-priority task needs, and the
high-priority task is blocked while waiting for the low-priority
task to release the resource. To avoid priority inversion,
FreeRTOS provides several synchronization mechanisms like
semaphores, mutexes, and queues, which should be used to
manage access to shared resources wherever possible.

20EC2E25- RTOS RAJASEKAR T, AP/ECE 71


• In summary, critical sections and suspending the scheduler
are two techniques that can be used to protect shared
resources from concurrent access in FreeRTOS. These
techniques should be used with caution, and other
synchronization mechanisms like semaphores, mutexes, and
queues should be used wherever possible to avoid priority
inversion issues.

20EC2E25- RTOS RAJASEKAR T, AP/ECE 72


Critical sections
• Sometimes a portion of code needs to be protected from any
context change so as to prevent a calculation from being
corrupted or an I/O operation being cut or mixed with
another.
• FreeRTOS provides two mechanisms to protect some as
small portions as possible; some protects from any context
change, either from a scheduler operation, or an interrupt
event, others only prevents scheduler from preempting the
task.
• Handling this can be very important as many instructions, for
instance, may look atomic but require several hardware
instructions (load variable address to a register, load a value
toEmbedded
20EC211- another
Systems register and move the value to the matching
Rajasekar T AP/ECE 73
& IoT
memory address using the two registries).
Suspend interrupts
• This form or critical section is very efficient
but must be kept as short as possible since it
makes the whole system in such a state that
any other portion of code cannot be
executed.
• This can be a problem for a task to meet its
time constraint, or an external event to be
treated by an interrupt.

20EC211- Embedded Systems


Rajasekar T AP/ECE 74
& IoT
Contd.
• Critical sections are entered by calling
taskENTER_CRITICAL() and exited by calling
taskEXIT_CRITICAL().

20EC211- Embedded Systems


Rajasekar T AP/ECE 75
& IoT
Contd.
• The taskENTER_CRITICAL() and taskEXIT_CRITICAL() macros provide a
basic critical section implementation that works by simply disabling
interrupts, either globally or up to a specific interrupt priority level.

• Calls to taskENTER_CRITICAL() and taskEXIT_CRITICAL() are designed to


nest. Therefore, a critical section will only be exited when one call to
taskEXIT_CRITICAL() has been executed for every preceding call to
taskENTER_CRITICAL().

• Critical sections must be kept very short. Otherwise, they will adversely
affect interrupt response times. Every call to taskENTER_CRITICAL() must
be closely paired with a call to taskEXIT_CRITICAL().
• FreeRTOS API functions must not be called from within a critical section.

20EC211- Embedded Systems


Rajasekar T AP/ECE 76
& IoT
Contd.
• If the FreeRTOS port being used does not
make use of the
configMAX_SYSCALL_INTERRUPT_PRIORITY
kernel configuration constant, then calling
taskENTER_CRITICAL() will leave interrupts
globally disabled.

20EC211- Embedded Systems


Rajasekar T AP/ECE 77
& IoT
Contd.
• If the FreeRTOS port being used does make use
of the
configMAX_SYSCALL_INTERRUPT_PRIORITY (or
configMAX_API_CALL_INTERRUPT_PRIORITY,
depending on the port) kernel configuration
constant, then calling taskENTER_CRITICAL() will
leave interrupts at and below the interrupt
priority set by
configMAX_SYSCALL_INTERRUPT_PRIORITY
disabled and all higher priority interrupt
enabled.

20EC211- Embedded Systems


Rajasekar T AP/ECE 78
& IoT
Stop the scheduler
• A less drastic method to create a critical section
consists in preventing any task from preempting
it, but let interrupts to do their job.
• This goal can be achieved by preventing any task
to leave the “Ready” state to “Running”, it can
be understood as stopping the scheduler, or
stopping all the tasks.
• Notice it is important that FreeRTOS API
functions must not be called when the scheduler
is stopped
20EC211- Embedded Systems
Rajasekar T AP/ECE 79
& IoT
Contd.
• void vTaskSuspendAll( void );
• Suspends the scheduler without disabling interrupts.
• Context switches will not occur while the scheduler is
suspended. RTOS ticks that occur while the scheduler
is suspended will be held pending until the scheduler
has been unsuspended using a call to
xTaskResumeAll()
• API functions that have the potential to cause a
context switch (for example, vTaskDelayUntil(),
xQueueSend(), etc.) must not be called while the
scheduler is suspended.
20EC211- Embedded Systems
Rajasekar T AP/ECE 80
& IoT
Contd.
• void vTask1( void * pvParameters ) { for( ;; )
• { // Task code goes here.
• // ...
• // At some point the task wants to perform a long operation during // which it
does not want to get swapped out. It cannot use // taskENTER_CRITICAL
()/taskEXIT_CRITICAL () as the length of the // operation may cause interrupts to
be missed - including the // ticks.
• // Prevent the RTOS kernel swapping out the task.
vTaskSuspendAll ();
• // Perform the operation here. There is no need to use critical // sections as we
have all the microcontroller processing time. // During this time interrupts will
still operate and the RTOS kernel // tick count will be maintained.
• // ...
• // The operation is complete. Restart the RTOS kernel.
xTaskResumeAll ();
• }
• }

20EC211- Embedded Systems


Rajasekar T AP/ECE 81
& IoT
Contd.
• When Calling xTaskResumeAll() is called, it
returns pdTRUE if no task requested a
context change while scheduler was
suspended and returns pdFALSE if there was.

20EC211- Embedded Systems


Rajasekar T AP/ECE 82
& IoT
• In FreeRTOS, a mutex is a synchronization object that is used
to protect shared resources from concurrent access by
multiple tasks. A mutex can be used to ensure that only one
task can access a shared resource at a time, preventing race
conditions and other synchronization issues.
• A mutex is essentially a binary semaphore, with additional
functionality to prevent priority inversion. A mutex can be in
one of two states: "available" or "unavailable." When a task
wants to access a shared resource that is protected by a
mutex, it first attempts to take the mutex. If the mutex is
available, the task takes the mutex and can access the
shared resource. If the mutex is unavailable, the task blocks
until the mutex becomes available.
20EC2E25- RTOS RAJASEKAR T, AP/ECE 83
• FreeRTOS provides several functions for creating and using
mutexes. The xSemaphoreCreateMutex() function is used to
create a mutex. This function returns a handle to the mutex,
which can be used by tasks to take and give the mutex. The
xSemaphoreTake() function is used by tasks to take the
mutex, while the xSemaphoreGive() function is used to give
the mutex back. If a task attempts to take a mutex that is
already taken, it will block until the mutex becomes
available.

20EC2E25- RTOS RAJASEKAR T, AP/ECE 84


• One important feature of mutexes in FreeRTOS is their ability
to prevent priority inversion. Priority inversion occurs when
a high-priority task is blocked by a low-priority task that is
holding a shared resource. To prevent priority inversion,
FreeRTOS implements a priority inheritance protocol for
mutexes. When a high-priority task attempts to take a mutex
that is held by a lower-priority task, the priority of the lower-
priority task is temporarily raised to the priority of the high-
priority task. This ensures that the high-priority task is not
blocked by the lower-priority task, and can access the shared
resource in a timely manner.

20EC2E25- RTOS RAJASEKAR T, AP/ECE 85


• In summary, mutexes are an important synchronization
mechanism in FreeRTOS, used to protect shared resources
from concurrent access by multiple tasks. FreeRTOS mutexes
implement a priority inheritance protocol to prevent priority
inversion, ensuring that high-priority tasks are not blocked
by lower-priority tasks that are holding shared resources.

20EC2E25- RTOS RAJASEKAR T, AP/ECE 86


• A gatekeeper task is a special type of task in FreeRTOS that is
responsible for controlling access to a shared resource or a
group of resources. The gatekeeper task acts as a proxy
between other tasks and the shared resources, allowing only
one task at a time to access the resources.

20EC2E25- RTOS RAJASEKAR T, AP/ECE 87


• The gatekeeper task is usually implemented as a task with a
high priority, and it is responsible for maintaining a queue of
requests for access to the shared resource. When a task
needs to access the shared resource, it sends a request to
the gatekeeper task, which then decides whether to grant
access or not. If access is granted, the gatekeeper task allows
the requesting task to access the shared resource, and
updates its internal state to reflect the change in the
availability of the resource. When the task has finished
accessing the resource, it notifies the gatekeeper task, which
then makes the resource available for other tasks to access.

20EC2E25- RTOS RAJASEKAR T, AP/ECE 88


• The gatekeeper task can also implement additional features
such as priority inheritance, fairness, and timeouts. For
example, the gatekeeper task can use priority inheritance to
ensure that high-priority tasks are not blocked by lower-
priority tasks that are holding the shared resource. Fairness
can be ensured by using a round-robin scheduling algorithm
to serve requests from different tasks in a fair manner.
Timeouts can be implemented to prevent tasks from waiting
indefinitely for access to the shared resource.

20EC2E25- RTOS RAJASEKAR T, AP/ECE 89


• In summary, gatekeeper tasks are a useful technique for
managing access to shared resources in FreeRTOS. They
provide a simple and effective way to control access to
shared resources, while also allowing for additional features
such as priority inheritance, fairness, and timeouts.
Gatekeeper tasks can be especially useful in systems where
multiple tasks need to access a shared resource, and where
the order and timing of access is important.

20EC2E25- RTOS RAJASEKAR T, AP/ECE 90


THANK YOU

20EC2E25- RTOS RAJASEKAR T, AP/ECE 91

You might also like