Embedding OS in AVR microcontrollers - DAIICT Intranet
Embedding OS in AVR microcontrollers - DAIICT Intranet
Embedding OS in AVR microcontrollers - DAIICT Intranet
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
<strong>Embedd<strong>in</strong>g</strong> <strong>OS</strong> <strong>in</strong> <strong>AVR</strong> <strong>microcontrollers</strong><br />
Prof. Prabhat Ranjan<br />
(prabhat_ranjan@da-iict.org)<br />
DA-IICT, Gandh<strong>in</strong>agar
Operat<strong>in</strong>g System Fundamentals<br />
➲ The kernel is the core component with<strong>in</strong> an<br />
operat<strong>in</strong>g system<br />
➲ Operat<strong>in</strong>g systems such as L<strong>in</strong>ux employ<br />
kernels that allow users access to the computer<br />
seem<strong>in</strong>gly simultaneously<br />
➲ Multiple users can execute multiple programs<br />
apparently concurrently<br />
➲ Each execut<strong>in</strong>g program is a task under<br />
control of the operat<strong>in</strong>g system. If an operat<strong>in</strong>g<br />
system can execute multiple tasks <strong>in</strong><br />
this manner it is said to be multitask<strong>in</strong>g.
Why use multitask<strong>in</strong>g <strong>OS</strong>?<br />
➲ The use of a multitask<strong>in</strong>g operat<strong>in</strong>g system<br />
can simplify the design of what would otherwise<br />
be a complex software application:<br />
● The multitask<strong>in</strong>g and <strong>in</strong>ter-task communications<br />
features of the operat<strong>in</strong>g system allow the complex<br />
application to be partitioned <strong>in</strong>to a set of<br />
smaller and more manageable tasks.<br />
● The partition<strong>in</strong>g can result <strong>in</strong> easier software<br />
test<strong>in</strong>g, work breakdown with<strong>in</strong> teams, and code<br />
reuse.<br />
● Complex tim<strong>in</strong>g and sequenc<strong>in</strong>g details can be<br />
removed from the application code and become<br />
the responsibility of the operat<strong>in</strong>g system
Multitask<strong>in</strong>g Vs Concurrency<br />
➲ A conventional processor can only execute<br />
a s<strong>in</strong>gle task at a time - but by rapidly<br />
switch<strong>in</strong>g between tasks a multitask<strong>in</strong>g operat<strong>in</strong>g<br />
system can make it appear as if<br />
each task is execut<strong>in</strong>g concurrently.
Schedul<strong>in</strong>g<br />
➲ The scheduler is the part of the kernel responsible<br />
for decid<strong>in</strong>g which task should be<br />
execut<strong>in</strong>g at any particular time. The kernel<br />
can suspend and later resume a task many<br />
times dur<strong>in</strong>g the task lifetime.<br />
➲ The schedul<strong>in</strong>g policy is the algorithm used<br />
by the scheduler to decide which task to<br />
execute at any po<strong>in</strong>t <strong>in</strong> time. The policy of a<br />
(non real time) multi user system will most<br />
likely allow each task a "fair" proportion of<br />
processor time. The policy used <strong>in</strong> real time
Context Switch<strong>in</strong>g<br />
➲ As a task executes it utilizes the processor /<br />
microcontroller registers and accesses RAM<br />
and ROM just as any other program. These<br />
resources together (the processor registers,<br />
stack, etc.) comprise the task execution<br />
context<br />
➲ A task is a sequential piece of code - it does<br />
not know when it is go<strong>in</strong>g to get suspended<br />
or resumed by the kernel and does not<br />
even know when this has happened
➲ To prevent this type of error it is essential<br />
that upon resumption a task has a context<br />
identical to that immediately prior to its suspension.<br />
➲ Kernel is responsible for ensur<strong>in</strong>g this - and<br />
does so by sav<strong>in</strong>g the context of a task as it<br />
is suspended. When the task is resumed its<br />
saved context is restored by the operat<strong>in</strong>g<br />
system kernel prior to its execution.<br />
➲ Process of sav<strong>in</strong>g the context of a task be<strong>in</strong>g<br />
suspended and restor<strong>in</strong>g at resumption<br />
is called context switch<strong>in</strong>g.
Real Time Applications<br />
➲ Real time operat<strong>in</strong>g systems (RT<strong>OS</strong>'s) objectives<br />
are very different to those of non<br />
real time systems<br />
➲ The different objective is reflected <strong>in</strong> the<br />
schedul<strong>in</strong>g policy<br />
➲ Real time / embedded systems are designed<br />
to provide a timely response to real<br />
world events<br />
➲ Events occurr<strong>in</strong>g <strong>in</strong> the real world can have<br />
deadl<strong>in</strong>es before which the real time / embedded<br />
system must respond and the<br />
RT<strong>OS</strong> schedul<strong>in</strong>g policy must ensure these<br />
deadl<strong>in</strong>es are met.
Real Time Applications<br />
➲ To achieve this objective assign a priority to<br />
each task<br />
➲ The schedul<strong>in</strong>g policy of the RT<strong>OS</strong> is to ensure<br />
that the highest priority task (that is<br />
able to execute) is given process<strong>in</strong>g time<br />
➲ This may require shar<strong>in</strong>g process<strong>in</strong>g time<br />
"fairly" between tasks of equal priority if they<br />
are ready to run simultaneously
RT Example<br />
➲ Basic example of this is a real time system<br />
that <strong>in</strong>corporates a keypad and LCD.<br />
➲ A user must get visual feedback of each key<br />
press with<strong>in</strong> a reasonable period - if the<br />
user cannot see that the key press has<br />
been accepted with<strong>in</strong> this period the software<br />
product will at best be awkward to<br />
use.<br />
➲ If the longest acceptable period was 100ms<br />
- any response between 0 and 100ms<br />
would be acceptable.
➲ Now assume the real time system is also<br />
perform<strong>in</strong>g a control function that relies on a<br />
digitally filtered <strong>in</strong>put.<br />
➲ The <strong>in</strong>put must be sampled, filtered and the<br />
control cycle executed every 2ms.<br />
➲ For correct operation of the filter the temporal<br />
regularity of the sample must be accurate<br />
to 0.5ms.
FreeRT<strong>OS</strong> Features<br />
➲ Choice of RT<strong>OS</strong> schedul<strong>in</strong>g policy<br />
● Pre-emptive:<br />
Always runs the highest available task. Tasks of<br />
identical priority share CPU time (fully pre-emptive<br />
with round rob<strong>in</strong> time slic<strong>in</strong>g).<br />
● Cooperative:<br />
Context switches only occur if a task blocks, or explicitly<br />
calls taskYIELD().<br />
➲ Message queues<br />
➲ Semaphores [via macros]<br />
➲ Trace visualisation ability<br />
➲ Majority of source code common to all supported<br />
development tools
Design Philosophy<br />
➲ Nearly all the code is written <strong>in</strong> C, with only<br />
a few assembler functions where completely<br />
unavoidable.<br />
➲ The RT<strong>OS</strong> kernel uses multiple priority lists.<br />
This provides maximum application design<br />
flexibility. Any number of tasks can share<br />
the same priority.<br />
➲ Simple, Portable, Concise
Nam<strong>in</strong>g Conventions<br />
➲ Variables<br />
● Variables of type char are prefixed c<br />
● Variables of type short are prefixed s<br />
● Variables of type long are prefixed l<br />
● Variables of type float are prefixed f<br />
● Variables of type double are prefixed d<br />
● Enumerated variables are prefixed e<br />
● Other types (e.g. structs) are prefixed x<br />
● Po<strong>in</strong>ters have an additional prefixed p, for example<br />
a po<strong>in</strong>ter to a short will have prefix ps<br />
● Unsigned variables have an additional prefixed<br />
u, for example an unsigned short will have prefix<br />
us
➲ Functions<br />
● File private functions are prefixed with prv<br />
● API functions are prefixed with their return type,<br />
as per the convention def<strong>in</strong>ed for variables<br />
● Function names start with the file <strong>in</strong> which they<br />
are def<strong>in</strong>ed. For example vTaskDelete is def<strong>in</strong>ed<br />
<strong>in</strong> task.c<br />
➲ Data Types<br />
● Data types are not directly referenced with<strong>in</strong> the<br />
RT<strong>OS</strong> kernel source code<br />
● each port has it's own set of def<strong>in</strong>itions.<br />
● char type is #def<strong>in</strong>ed to portCHAR<br />
● short data type is #def<strong>in</strong>ed to portSHORT
Application Programm<strong>in</strong>g Interface(API)
Task Creation<br />
➲ xTaskCreate - Create a new task and add<br />
it to the list of tasks that are ready to run<br />
➲ vTaskDelete - Remove a task from the<br />
RT<strong>OS</strong> real time kernels management. The<br />
task be<strong>in</strong>g deleted will be removed from all<br />
ready, blocked, suspended and event lists
Task Control<br />
➲ vTaskDelay - Delay a task for a given number<br />
of ticks<br />
➲ vTaskDelayUntil - Delay a task until a specified<br />
time<br />
➲ ucTaskPriorityGet - Obta<strong>in</strong> the priority of<br />
any task<br />
➲ vTaskPrioritySet - Set the priority of any<br />
task<br />
➲ vTaskSuspend - Suspend any task<br />
➲ vTaskResume - Resumes a suspended<br />
task
Kernel Control<br />
➲ vTaskStartScheduler - Starts the real time<br />
kernel tick process<strong>in</strong>g. After call<strong>in</strong>g the kernel<br />
has control over which tasks are executed<br />
and when.<br />
➲ vTaskEndScheduler - Stops the real time<br />
kernel tick. All created tasks will be automatically<br />
deleted and multitask<strong>in</strong>g (either preemptive<br />
or cooperative) will stop. Execution<br />
then resumes from the po<strong>in</strong>t where<br />
vTaskStartScheduler() was called, as if<br />
vTaskStartScheduler() had just returned
➲ vTaskSuspendAll - Suspends all real time<br />
kernel activity while keep<strong>in</strong>g <strong>in</strong>terrupts (<strong>in</strong>clud<strong>in</strong>g<br />
the kernel tick) enabled<br />
➲ xTaskResumeAll - Resumes real time kernel<br />
activity follow<strong>in</strong>g a call to vTaskSuspendAll<br />
(). After a call to xTaskResumeAll ()<br />
the kernel will take control of which task is<br />
execut<strong>in</strong>g at any time
Task Utilities<br />
➲ xTaskGetTickCount - count of ticks s<strong>in</strong>ce<br />
vTaskStartScheduler was called<br />
➲ xTaskGetNumberOfTasks - number of tasks<br />
that the real time kernel is currently manag<strong>in</strong>g<br />
➲ vTaskList - Lists all the current tasks
Queue Management<br />
➲ xQueueCreate - Creates a new queue <strong>in</strong>stance<br />
➲ xQueueSend - Post an item on a queue<br />
➲ xQueueReceive - Receive an item from a<br />
queue<br />
➲ xQueueSendFromISR - Post an item on a<br />
queue(safe from iSR)<br />
➲ xQueueReceiveFromISR - Receive an item<br />
from a queue (safe from ISR)
Semaphores<br />
➲ vSemaphoreCreateB<strong>in</strong>ary<br />
➲ xSemaphoreTake<br />
➲ xSemaphoreGive<br />
➲ xSemaphoreGiveFromISR
Customization<br />
➲ FreeRT<strong>OS</strong>/Demo/<strong>AVR</strong>_ATMega323_W<strong>in</strong><br />
<strong>AVR</strong>/FreeRT<strong>OS</strong>Config.h<br />
portUSE_PREEMPTION 1<br />
portCPU_CLOCK_HZ ( ( unsigned portLONG )<br />
8000000 )<br />
portTICK_RATE_HZ ( ( portTickType ) 1000 )<br />
portMAX_PRIORITIES ( ( unsigned portCHAR )<br />
4 )
➲ configCPU_CLOCK_HZ<br />
● Enter the frequency <strong>in</strong> Hz at which the <strong>in</strong>ternal<br />
processor core will be execut<strong>in</strong>g. This value is<br />
required <strong>in</strong> order to correctly configure timer peripherals.(Xtal<br />
– 4300000)<br />
➲ configTICK_RATE_HZ<br />
● frequency of the RT<strong>OS</strong> tick <strong>in</strong>terrupt<br />
● tick <strong>in</strong>terrupt is used to measure time<br />
● a higher tick frequency means time can be measured<br />
to a higher resolution
TICK_RATE<br />
● high tick frequency -> kernel will use more CPU<br />
time so be less efficient<br />
● RT<strong>OS</strong> demo applications all use a tick rate of<br />
1000Hz. This is used to test the kernel and is<br />
higher than would normally be required.<br />
● More than one task can share the same priority.<br />
The kernel will share processor time between<br />
tasks of the same priority by switch<strong>in</strong>g between<br />
the tasks dur<strong>in</strong>g each RT<strong>OS</strong> tick.<br />
● A high tick rate frequency will therefore also<br />
have the effect of reduc<strong>in</strong>g the 'time slice' given<br />
to each task.
➲ configMAX_PRIORITIES<br />
● The number of priorities available to the application<br />
● Any number of tasks can share the same priority<br />
● Each available priority consumes RAM with<strong>in</strong> the<br />
kernel so this value should not be set any higher<br />
than actually required by your application
INCLUDE Parameters<br />
➲ The macros start<strong>in</strong>g 'INCLUDE' allow those<br />
components of the real time kernel not utilized<br />
by application to be excluded from<br />
build<br />
➲ Ensures the RT<strong>OS</strong> does not use any more<br />
ROM or RAM than necessary<br />
● #def<strong>in</strong>e INCLUDE_vTaskDelete 1<br />
(change to 0 to exclude)
DEMO APPLICATION
Source Directory Structure : conta<strong>in</strong>s real time<br />
kernel source code
Demo Dir Structure
Demo files<br />
➲ flash.c<br />
● Creates upto eight tasks, each of which flash an<br />
LED at a different rate. The first LED flashes every<br />
125ms, the second every 250ms, the third<br />
every 375ms, etc.<br />
● The LED flash tasks provide <strong>in</strong>stant visual feedback.<br />
They show that the scheduler is still operational.<br />
● On <strong>AVR</strong>, by default, PORT B is used
comtest.c<br />
● Creates two tasks that operate on an <strong>in</strong>terrupt<br />
driven serial port.<br />
● A loopback connector should be used so that<br />
everyth<strong>in</strong>g that is transmitted is also received.<br />
Rx/Tx should be shorted.<br />
● The first task repeatedly sends a str<strong>in</strong>g to a<br />
queue, character at a time.<br />
● The serial port <strong>in</strong>terrupt will empty the queue<br />
and transmit the characters.<br />
● The task blocks for a pseudo random period before<br />
resend<strong>in</strong>g the str<strong>in</strong>g.
lockQ.c<br />
➲ Creates six tasks that operate on three<br />
queues as follows:<br />
● The first two tasks send and receive an <strong>in</strong>crement<strong>in</strong>g<br />
number to/from a queue. One task acts<br />
as a producer and the other as the consumer.<br />
The consumer is a higher priority than the producer<br />
and is set to block on queue reads. The<br />
queue only has space for one item - as soon as<br />
the producer posts a message on the queue the<br />
consumer will unblock, preempt the producer,<br />
and remove the item.
● The second two tasks work the other way<br />
around. Aga<strong>in</strong> the queue used only has enough<br />
space for one item. This time the consumer has<br />
a lower priority than the producer. The producer<br />
will try to post on the queue block<strong>in</strong>g when the<br />
queue is full. When the consumer wakes it will<br />
remove the item from the queue, caus<strong>in</strong>g the<br />
producer to unblock, pre-empt the consumer,<br />
and immediately re-fill the queue.
● The last two tasks use the same queue producer<br />
and consumer functions. This time the queue<br />
has enough space for lots of items and the tasks<br />
operate at the same priority. The producer will<br />
execute, plac<strong>in</strong>g items <strong>in</strong>to the queue. The consumer<br />
will start execut<strong>in</strong>g when either the queue<br />
becomes full (caus<strong>in</strong>g the producer to block) or a<br />
context switch occurs (tasks of the same priority<br />
will time slice).
death.c<br />
● Create a s<strong>in</strong>gle persistent task which periodically<br />
dynamically creates another four tasks. The orig<strong>in</strong>al<br />
task is called the creator task, the four tasks<br />
it creates are called suicidal tasks.<br />
● Two of the created suicidal tasks kill one other<br />
suicidal task before kill<strong>in</strong>g themselves - leav<strong>in</strong>g<br />
just the orig<strong>in</strong>al task rema<strong>in</strong><strong>in</strong>g.
● The creator task must be spawned after all of<br />
the other demo application tasks as it keeps a<br />
check on the number of tasks under the scheduler<br />
control. The number of tasks it expects to<br />
see runn<strong>in</strong>g should never be greater than the<br />
number of tasks that were <strong>in</strong> existence when the<br />
creator task was spawned, plus one set of four<br />
suicidal tasks. If this number is exceeded an error<br />
is flagged.
flop.c<br />
● Creates eight tasks, each of which loops cont<strong>in</strong>uously<br />
perform<strong>in</strong>g an (emulated) float<strong>in</strong>g po<strong>in</strong>t<br />
calculation.<br />
● All the tasks run at the idle priority and never<br />
block or yield. This causes all eight tasks to time<br />
slice with the idle task.<br />
● Runn<strong>in</strong>g at the idle priority means that these<br />
tasks will get pre-empted any time another task<br />
is ready to run or a time slice occurs.<br />
● More often than not the pre-emption will occur<br />
mid calculation, creat<strong>in</strong>g a good test of the<br />
schedulers context switch mechanism - a calculation<br />
produc<strong>in</strong>g an unexpected result could be a<br />
symptom of a corruption <strong>in</strong> the context of a task.
<strong>in</strong>teger.c<br />
➲ This does the same as flop.c, but uses variables<br />
of type long <strong>in</strong>stead of type double.<br />
➲ As with flop.c, the tasks created <strong>in</strong> this file<br />
are a good test of the scheduler context<br />
switch mechanism.<br />
➲ The processor has to access 32-bit variables<br />
<strong>in</strong> two or four chunks (depend<strong>in</strong>g on<br />
the processor).<br />
➲ The low priority of these tasks means there<br />
is a high probability that a context switch<br />
will occur mid calculation.
pollQ.c<br />
● This is a very simple queue test.<br />
● BlockQ.c is a more comprehensive version.<br />
● Creates two tasks that communicate over a s<strong>in</strong>gle<br />
queue.<br />
● One task acts as a producer, the other a consumer.
ma<strong>in</strong>.c<br />
➲ It creates all the various tasks<br />
➲ One task check keeps a track of all the<br />
tasks and stops flash<strong>in</strong>g the LED, if any<br />
task gives error<br />
➲ LED 0-2, flashes as per tasks <strong>in</strong> flash.c<br />
➲ LED 4-5 flashes as per serial communication<br />
Tx/Rx<br />
➲ Comment various tasks and try to see the<br />
effect.<br />
➲ Try to create a new task by yourself
Thank you