You are on page 1of 9

FreeRTOSTutorial

FromEmbeddedSystemsLearningAcademy

Contents
1Introduction
1.1Screencast
2WhatisanOS
3FreeRTOSmain()andTasks
3.1TheMAINFunction
3.2WhatisStackMemory?
3.3TaskStackSize
3.4ControllingTasks
3.5SimpleTask
3.6TerminalTask
4FreeRTOSIntertaskCommunication
4.1QueueCommunication
4.1.1Explanation
4.1.2PracticalExample
4.2Semaphores
4.2.1Mutex
4.2.2BinarySemaphore
4.2.3CountingSemaphore
5FAQ
6GoingBeyond

Introduction
ThisarticleisaboutlearningFreeRTOS.TheFreeRTOSsampleprojectrunningonSJOneBoardisusedas
reference,butanyFreeRTOSprojectonanycontrollercanbenefitfromthisarticle.
NotesabouttheFreeRTOSSampleProject:
TheDevelopmentPackageZIPFilecontainstheFreeRTOSsampleproject,however,thelatestcopycan
alwaysbedownloadedfrom:https://sourceforge.net/projects/armdevpkg/files
ThisarticleassumesyouknowhowtocompileandloadasampleprojecttotheSJOneBoard.

Screencast
IcreatedsomescreencaststoquicklygothroughFreeRTOS,however,IHIGHLYencourageyoutoreadthis
articleinfullfirst.
TasksandQueues
FreeRTOStasksandQueues(http://www.youtube.com/watch?v=8lIpI30Tjg)
FreeRTOSQueues(http://www.youtube.com/watch?v=yHfDO_jiIFw)

Semaphores:
FreeRTOSMutex(http://www.youtube.com/watch?v=PjDHn_G078k)
FreeRTOSBinarySemaphore(http://www.youtube.com/watch?v=grXuVMttVuU)
FreeRTOSInterruptProcessingusingBinarySemaphore(http://www.youtube.com/watch?
v=06TH2NgrKkA)
C++WrapperforFreeRTOStasks(http://www.youtube.com/watch?v=4gawgXminv4)
UsethistutorialaftermasteringthebasicFreeRTOSconcepts
ThesourcecodeisincludedinSJSU_Devdevelopmentpackage.

WhatisanOS
AnEmbeddedOperatingSystemlikeFreeRTOSisnothingbutsoftwarethatprovidesmultitaskingfacilities.
FreeRTOSallowstorunmultipletasksandhasasimpleschedulertoswitchbetweentasks.Herearesomeofthe
FreeRTOSfeatures:
Prioritybasedmultitaskingcapability
Queuestocommunicatebetweenmultipletasks
Semaphorestomanageresourcesharingbetweenmultipletasks
UtilitiestoviewCPUutilization,stackutilizationetc.

FreeRTOSmain()andTasks
TheMAINFunction
ThemainfunctioninFreeRTOSbasedprojectisnothingbutafunctionthatcreatestasks.FreeRTOSwillletyou
multitaskbasedonyourtasksandtheirpriority.Rememberthata"task"issimplya"function"nameoftype:void
my_task(void*p)

WhatisStackMemory?
Beforeyoucreateatask,youneedtoknowwhatisstackmemory.Everyvariableyoudeclareusesmemoryonthe
stack.Thismemoryisgenerallypreferredoverheapallocatedmemorythatcomesfrommallocornewoperators.
WhatusesStackMemory?
LocalVariablesofthetask.
Functioncalls(functionparameters+functionreturnaddress)
Localvariablesoffunctionsyourtaskcalls.
Howisstackmanaged?
Everytimeyoudeclareavariable,stackpointermovesdown.
Ifyoudeclareanint,yourassemblycodewillgenerate:SUBSP,1
Ifyoudeclarecharmem[128]yourassemblycodewillgenerate:SUBSP,32assuming32bitmachine
Thatiswhyyoushouldusecurlybracesandlimitthescopeofvariablesasmuchaspossible.Thisway,

everytimeavariablegoesoutofscope,youwillseesomethinglike:ADDSP,##indicatingmemory
released.
ThisiswhystackmemoryispreferredoverheapbecausestackusesjusttwoADDandSUBinstructionsto
managememorywhereasheapusesratherexpensivemallocoperations.Furthermore,mallocfragmentsyour
memoryandinasmallersystem,fragmentedmemorymayresultinmallocreturningNULLpointers.
Let'sstartwithexamplesonhowtoestimateyourstackmemory:
voidhello_world_task(void*p)
{
charmem[128];
while(1){
}
}
//Thetaskaboveuses128bytesofstack.

voidhello_world_task(void*p)
{
charmem[128];
intint_mem[128];//4bytesperint
while(1){
}
}
//Thetaskaboveuses128+(128*4)bytesofstack.

voidhello_world_task(void*p)
{
charmem[128];
while(1){
foo();//Assumefoouses128bytesofstack.
}
}
//Thetaskaboveuses128+128bytesofstack.

voidhello_world_task(void*p)
{
charmem[128];
while(1){
if(...){
charmem_one[128];
}
else(...){
charmem_two[256];
}
}
}
/*Thetaskaboveuses128+256bytesofstack.
*Notethatitisnot128+128+256,becauseonlyonebranchstatement
*willexecuteandintheworstcase,branchtwo'scodewillendup
*using128+256bytesofstack.
*/

voidhello_world_task(void*p)

{
char*mem=char*malloc(128);
while(1){
}
}
//Thetaskaboveusesjust4bytesofstack(toholdmempointer)
//TheactualmemorycomesfromHEAP,whichisnotpartofthestack.

TaskStackSize
Thestacksizeofataskdependsonthememoryconsumedbyitslocalvariablesandfunctioncalldepth.Please
notethatifyourtask(orfunction)usesprintf,itconsumesaround1024bytesofstack.Atminimumhowever,you
wouldneedatleast512bytes+yourestimatedstackspaceabove.Ifyoudon'tallocateenoughstackspace,
yourCPUwillruntoanexceptionand/orfreeze.
Youshoulddefinitelyreadthefollowingarticletostudythememorylayout:
StackHeapWalkthrough

ControllingTasks
InFreeRTOS,youhaveprecisecontrolofwhentaskswillusetheCPU.Therulesaresimple:
Taskwithhighestprioritywillrunfirst,andnevergiveuptheCPUuntilitsleeps
If2ormoretaskswiththesameprioritydonotgiveuptheCPU(theydon'tsleep),thenFreeRTOSwill
sharetheCPUbetweenthem(timeslice).
HerearesomeofthewaysyoucangiveuptheCPU:
vTaskDelay()Thissimplyputsthetaskto"sleep"youdecidehowmuchyouwanttosleep.
xQueueSend()IftheQueueyouaresendingtoisfull,thistaskwillsleep(block).
xQueueReceive()IftheQueueyouarereadingfromisempty,thistaskwillsleep(block).
xSemaphoreTake()Youwillsleepifthesemaphoreistakenbysomebodyelse.

Rememberthateachfunctiongivenabovetakesaparameterthatdecideshowlongyouarewillingtosleep.You
couldusethisparameterasatimeout.Forexample,yourlogicmaybe:"I'mgoingtowait1secondtoreceive
somethingfromthequeue,otherwiseIwill<dowhatever>".

SimpleTask
Belowisasimpletaskexamplethatprintsamessageonceasecond.NotethatvTaskStartScheduler()never
returnsandFreeRTOSwillbeginservicingthetasksatthispoint.Alsonotethateverytaskmusthaveaninfinite
loopandNEVEREXIT.
voidhello_world_task(void*p)
{
while(1){
puts("HelloWorld!");
vTaskDelay(1000);
}
}

intmain()
{

xTaskCreate(hello_world_task,(signedchar*)"task_name",STACK_BYTES(2048),0,1,0);
vTaskStartScheduler();

return1;
}

TerminalTask
TheFreeRTOSsampleprojectcreates"terminal"taskthatallowsyoutointeractwiththeserialport.Youcantype
"help"andpressenterinHerculesprogramtoseethecommandssupportedbytheterminaltask.Youcan,of
course,addmorecommandstoit.Youshouldnowpausereadingthisarticleandnowlookathowtheterminal
taskworks.Hereisascreenshotofterminaltaskinteraction:TODO:Addscreenshot

FreeRTOSIntertaskCommunication
QueueCommunication
YoucancommunicatebetweentasksbyusingQueuesorSemaphores.Let'screateanexampletocommunicate
betweentwotasksbasedontheSoftwareFrameworkinthesampleproject.Here'ssomesamplecode:
//GlobalQueueHandle
QueueHandle_tqh=0;

voidtask_tx(void*p)
{
intmyInt=0;
while(1)
{
myInt++;
if(!xQueueSend(qh,&myInt,500)){
puts("Failedtosenditemtoqueuewithin500ms");
}
vTaskDelay(1000);
}
}

voidtask_rx(void*p)
{
intmyInt=0;
while(1)
{
if(!xQueueReceive(qh,&myInt,1000)){
puts("Failedtoreceiveitemwithin1000ms");
}
else{
printf("Received:%u\n",myInt);
}
}
}

intmain()
{
qh=xQueueCreate(1,sizeof(int));

xTaskCreate(task_tx,(signedchar*)"t1",STACK_BYTES(2048),0,1,0);
xTaskCreate(task_rx,(signedchar*)"t2",STACK_BYTES(2048),0,1,0);
vTaskStartScheduler();


return1;
}

Explanation
Notethefollowingitems:
Inmain(),wecreatetheQueuebeforecreatingtasks,otherwisesendingtouninitializedQueuewillcrash
thesystem.
Intask_tx(),wesendoneitemeverysecond,andifthequeueisfull,weprintafailuremessage.
Intask_rx(),wereceiveoneitem,andwedonotusevTaskDelay().Thisisbecauseifthereisnothinginthe
queue,FreeRTOSwillsleep(orblock)thistaskfromrunning.ThetimeoutitselfinxQueueReceive()allows
ustosleepfor1000msbutwakeupifanitemisavailableinthequeueearlier.
Ifthepriorityofthereceivingqueue(task_rx())ishigher,FreeRTOSwillswitchtasksthemoment
xQueueSend()happens,andthenextlineinsidetask_tx()willnotexecutesinceCPUwillbeswitchedover
totask_rx().

PracticalExample
Apracticalexampleofaqueuemaybetostartanothertasktostartdoingitsworkwhiletheprimarytaskcontinues
doingitsownworkindependently.Inthefollowingexample,wedemonstratehowaterminaltaskcankickoff
anothertasktobeginplayinganmp3songwhileitoperatesindependentlytohandlethenextcommandfroma
terminal(userinput).
voidterminal_task(void*p)
{
//Assumeyougotausercommandtoplayanmp3:
xQueueSend(song_name_queue,"song_name.mp3",0);

...
}

voidmp3_play_task(void*p)
{
charsong_name[32];
while(1){
if(xQueueReceive(song_name_queue,&song_name[0],portMAX_DELAY)){
//Starttoplaythesong.
}
}
}

Semaphores
Semaphoresaremeanttolimitaccesstoresources,buttherearemanyapplications.Therearealsomanytypesof
semaphoresandthetextbelowdiscussessomeofthemandtheirapplication.
Mutex

Oneofthebestexampleofamutexistoguardaresourceoradoorwithakey.Forinstance,let'ssayyouhavean
SPIBUS,andonlyonetaskshoulduseitatatime.Mutexprovidesmutualexclusionwithpriorityinversion
mechanism(http://en.wikipedia.org/wiki/Priority_inversion).MutexwillonlyallowONEtasktogetpast
xSemaphoreGet()operationandothertaskswillbeputtosleepiftheyreachthisfunctionatthesametime.
//Inmain(),initializeyourMutex:
SemaphoreHandle_tspi_bus_lock=xSemaphoreCreateMutex();

voidtask_one()
{
while(1){
if(xSemaphoreGet(spi_bus_lock,1000)){
//UseGuardedResource

//GiveSemaphoreback:
xSemaphoreGive(spi_bus_lock);
}
}
}
voidtask_two()
{
while(1){
if(xSemaphoreGet(spi_bus_lock,1000)){
//UseGuardedResource

//GiveSemaphoreback:
xSemaphoreGive(spi_bus_lock);
}
}
}

Inthecodeabove,onlyONEtaskwillenteritsxSemaphoreGet()branch.Ifbothtasksexecutethestatementatthe
sametime,onewillgetthemutex,theothertaskwillsleepuntilthemutexisreturnedbythetaskthatwasableto
obtainitinthefirstplace.
BinarySemaphore
Binarysemaphorecanalsobeusedlikeamutex,butbinarysemaphoredoesn'tprovidepriorityinversion
mechanism.Binarysemaphoresarebettersuitedforhelpertasksforinterrupts.Forexample,ifyouhavean
interruptandyoudon'twanttodoalotofprocessinginsidetheinterrupt,youcanuseahelpertask.Toaccomplish
this,youcanperformasemaphoregiveoperationinsidetheinterrupt,andadedicatedaskwillsleeporblockon
xSemaphoreGet()operation.
//Somewhereinmain():
SemaphoreHandle_tevent_signal;
vSemaphoreCreateBinary(event_signal);//Createthesemaphore
xSemaphoreTake(event_signal,0);//Takesemaphoreaftercreatingit.

voidSystem_Interrupt()
{
xSemaphoreGiveFromISR(event_signal);
}

voidsystem_interrupt_task()
{
while(1){
if(xSemaphoreTake(event_signal,9999999)){
//Processtheinterrupt
}

}
}

Theabovecodeshowsexampleofadeferredinterruptprocessing.Theideaisthatyoudon'twanttoprocessthe
interruptinsideSystem_Interrupt()becauseyou'dbeinacriticalsectionwithsysteminterruptsgloballydisabled,
therefore,youcanpotentiallylockupthesystemordestroyrealtimeprocessingiftheinterruptprocessingtakes
toolong.
Anotherwaytousebinarysemaphoreistowakeuponetaskfromanothertaskbygivingthesemaphore.Sothe
semaphorewillessentiallyactlikeasignalthatmayindicate:"Somethinghappened,nowgodotheworkin
anothertask".Inthesampleproject,binarysemaphoreisusedtoindicatewhenanI2Creadoperationisdone,and
theinterruptgivesthissemaphore.NotethatwhenyoucreateabinarysemaphoreinFreeRTOS,itisreadyto
betaken,soyoumaywanttotakethesemaphoreafteryoucreateitsuchthatthetaskwaitingonthis
semaphorewillblockuntilgivenbysomebody.
CountingSemaphore
Countingsemaphoresaresuitedforapplicationsinwhichmorethanoneuserisallowedaccesstoaresource.For
example,ifyouhaveaparkinggarageof10cars,youcanallow10semaphoreaccess.Eachcarenteringagarage
willtake1semaphoreuntil10carstake10semaphoresandnomorecarswillbeallowedaccesstothegarage.

FAQ
IwrotemyownversionofQueue,Idon'twanttouseFreeRTOSqueuesinceitisnotefficient
Becarefulhere.FreeRTOSqueuesmaybemoreexpensive,buttheyprovidebenefitsyourqueuemay
notprovide.FreeRTOS'squeuescanswitchtasksuponQueuesendandreceive,andyourtaskswillbe
managedbetterandsleepasappropriatewhereasyourownversionlikelydoesn'tintegratewellwith
FreeRTOS.Forexample,FreeRTOSmayswitchcontextinsideofxQueueSend()ifitfindsthat
someonewithhigherprioritywaswaitingforaniteminthisqueue.
WhatifIsendanitemonFreeRTOSqueueandmyitemgoesoutofscope?
FreeRTOScopiesvalueoftheitemyousend,sothisisperfectlyokay.
IfIusedeferredinterruptprocessing,butstillwanttoprocessinterruptquickly,whatcanIdo?
Youcansetthepriorityofthedeferredinterrupttaskashighest,andassoonasinterruptgivesthe
binarysemaphoreandexit,FreeRTOSwillswitchcontexttoyourinterrupttask.
Ihavealotoflittletasksbutendupusingalotofstackmemoryforeachtask.WhatcanIdo?
First,thinkaboutconsolidatingtasks.Ifyourtasksdoabunchofthingseverysecond,thencombine
theprocessingintoasingletask.Ifyouhaveanumberofthingshappeningperiodically,consider
usingaFreeRTOStimer.FreeRTOStimersusecommonstackbutprovideindependenttimers.
HowmuchstackspaceamIreallyusing?
UseFreeRTOS's:vTaskList()functiontogetameasureofthestackspace.Thesampleprojectsare
specificallymodifiedsuchthatthisfunctionwillreportstackfreeinbytes,alongwithCPUutilization
ofeachtask.

I'musingadelayfunctionandCPUutilizationisveryhigh
Yourdelayfunctionisprobablyabusywaitloop.UseFreeRTOS'svTaskDelay(),whichisactually
smartenoughtoputthetasktosleepandwakeituppreciselywhenthetimeoutisdone.Ifataskuses
littleprocessingeverysecondandyouusevTaskDelay(1000)yourCPUutilizationwillbenearzero
percent.
Idon'tunderstandthedifferencebetweenvTaskDelay()andvTaskDelayUntil()
vTaskDelay()willdelaybythedefinedamount,andifyouwantedapreciseperiodicprocessingofone
second,thisfunctionmightnotworkasyou'dexpect.Intheexamplebelow,evenifyouwantedsensor
updateofonceper1000ms,youractualratewouldbeanywherefrom1005to1050msbecause
update_sensor()function'sprocessingtimecanvary.Inthisexample,ifweswitchoverto
vTaskDelayUntil(),wewillbeupdatingsensorsexactlyonceper1000ms.
voidmy_task(void*p)
{
while(1){
update_sensors();//Assumethisfunctioncantake550ms
vTaskDelay(1000);
}
}

GoingBeyond
ThebasictasksshowyouaroundFreeRTOScentricsystemandthisisjustthestartingpoint.Forexample,ifyou
arecreatingarelayswitchthatgetsturnedonbasedonthelightlevel,youmaywanttocreateatask,getthelight
readingfromthelightsensor,andcontroltherelay.Logicallythinking,youmaywanttomonitorthelightreading
onceasecond,sodon'tforgettousevTaskDelay().
Asyourprojectgetsmorecomplex,youwilldeterminebyexperiencethatwhichtaskscanbeputtolowerpriority
andwhichtasksneedhighpriority.Byprioritizingthetasks,youcancreateadeterministicsystemandguarantee
realtimeoperationofcriticaltaskswhilecompleting"background"processingusinglowerprioritytasks.
ValuableReads:
Read2012SJOneHelloWorldSampleProjecttogetnewbieorienteddetailsabouthowtoreadsensor
valuesofyourSJOneBoard.
ReadFreeRTOSAPI(http://www.freertos.org/a00106.html)tounleashthepowerofthisOS.
Retrievedfrom"http://www.socialledge.com/sjsu/index.php?title=FreeRTOS_Tutorial&oldid=5620"
Thispagewaslastmodifiedon5March2014,at09:29.
Thispagehasbeenaccessed75,924times.
ContentisavailableunderPublicDomain.