86
II. Dezvoltarea aplicaţiilor de timp real sub FreeRTOS II. 1 Facilităţi FreeRTOS - descriere generală: - SOTR open source, dezvoltat sub C se asigura fiabilitate ridicată + stabilitate (există şi versiunea SAFE RTOS); există companii dedicate în a oferi suport; aplicaţiile nu sunt open source, dar există multe exemple oferite gratuit. - compatibilitate cu diverse arhitecturi, portabilitate. - servicii generoase de depanare: trace, detectie depasire stiva, kit dezvoltare sub Win.

Patr curs 2

Embed Size (px)

DESCRIPTION

Patr programing

Citation preview

  • II. Dezvoltarea aplicaiilor de timp real sub FreeRTOS

    II. 1 Faciliti FreeRTOS - descriere general:

    - SOTR open source, dezvoltat sub C se asigura fiabilitate ridicat + stabilitate (exist i versiunea SAFE RTOS); exist companii dedicate n a oferi suport; aplicaiile nu sunt open source, dar exist multe exemple oferite gratuit.

    - compatibilitate cu diverse arhitecturi, portabilitate.

    - servicii generoase de depanare: trace, detectie depasire stiva, kit dezvoltare sub Win.

  • - asigura flexibilitate: nu exista limite pentru nr taskuri, nr prioritati, taskurile se pot crea dinamic, accepta mod preemtiv-cooperativ (corutine), pot fi mai multe taskuri pe acelasi nivel de pioritate.

    - facilitati diverse pentru gestionarea resurselor pasive si sincronizarea intre procese

    Consum redus de memorie

    Simplu de neles

    Uor de utilizat

    - procese acceptate de FreeRTOS: Taskuri + ISR + Corutine

    - planificator clock driven

  • T2 T1 T1T2 T2 T2T3 T3

    while(1){ if() operatii task 1 if() operatii task 2 etc }

    Motontasking

    while(1){

    }

    Multitasking

    ISR

    Task1

    ISR

    Task2 Task3

    - FreeRTOS va decide ce task preia procesorul

    Avantaje abordare multitasking: - Extensie simpla adaugare taskuri - Prioritati diferite - Temporizari & restrictii de timp mai

    flexibil de gestionat independent pentru fiecare task

  • Distributie

    FreeRTOS este compatibilizat cu numeroase arhitecturi/procesoare >> pentru simplitate toate variantele incluse n kit

    (fiind disponibile printr-un singur download)

    Structura directoare

    FreeRTOS +-Demo +-Common Fisiere demo commune tuturor arhitecturilor. +-Dir x Fisiere demo specifice arhitecturii x +-Dir y Fisiere demo specifice arhitecturii y +-Source Cod Kernel +-Portable cod kernel specific arhitecturii.

  • Fisierele kernel principale:

    tasks.c, queue.c list.c corutine.c

    La laborator se va utiliza particularizarea pentru dsPIC33 + MPLAB

    Se pot crea aplicatii proprii, pornind de la demonstrativele oferite, modificand convenabil fisierele din directorul Demo

    (acest mod de lucru permite folosirea setarilor pentru compilare si linkeditare)

    Aplicatiile sunt construite ca proiecte ce cuprind: - fisierele sursa utilizator (eventual demonstrative) - fisierele sistemului de operare

    \ FreeRTOS\ Source

  • Fisierele FreeRTOS din proiect: Source/Task.c, Source/List.c, Source/Queue.c, Source/Corutine.c Source/portable/MLPAB/PIC24_dsPIC/ port.c

    (particularizari pe arhitectura hardware folosita) Source/portable/MemMang/heap_1.c (sau heap_2.c sau heap_3.c)

    (asigura o schema de memorie heap) + Urmtoarele directoare trebuie s fie n path: Source/include ,

    Source/portable/MLPAB/PIC24_dsPIC

    Fisierele sursa utilizator: Obligatoriu main.c, pot fi si altele Optional: Demo/[Processor name]/ParTest/ParTest.c (daca se folosesc functiile

    din acest fisier dedicate gestionarii ledurilor conectate pe PORTB Recomandare - surse plasate in calea Demo/, caz in care urmtoarele directoare

    trebuie s fie n path: Demo/Common, Demo/dsPIC_MPLAB

  • II. 2 Gestionare taskuri

    sunt considerate procese concurente

    int main( void ) {

    .

    xTaskCreate(TaskFct,T1 ); xTaskCreate(TaskFct, T2,.); ..

    vTaskStartScheduler(); return 0;

    }

    Activare planificator (+idle task)

    Creare Task T1 si T2

    void TaskFct( void *pvParameters ) { for( ;; ) { Corpul task-ului } }

    Taskurile sunt implementate ca bucla infinita

    Va contine intarzieri + alte asteptari de evenimente

    Taskurile nu returneaza nimic

  • Strile posbile sunt:

    in execuie (running): ocup procesorul

    gata de execuie (ready): ateapt ocuparea procesorului;

    In punctele de planificare, planificatorul alege taskul ce va ocupa procesorul (candidati la primirea procesorului: taskul running, taskurile din lista ready).

    n ateptare-blocat (blocking): ateapta un eveniment (sosirea unui mesaj, eliberarea unei resurse, trecerea unui interval de timp, etc) i nu este considerat de planificator.

    suspendat (suspended): task ce nu mai cere s fie executat, nu va fi considerat de planificator >> starea este forat temporar de programator cu vTaskSuspend

  • in blocare (blocking)

    Apel vTaskSuspend()

    in curs de executie (running)

    Evenimentul asteptat a avut loc

    pregatita pentru executie (ready)

    Blocare prin apelul unor servicii API

    suspendata (suspended)

    vTaskResume()

    Primeste procesorul la

    decizia planificatorului

    Pierde procesorul la (preempt)

    vTaskSuspend()

    vTaskSuspend()

    vTaskCreate()

  • Implementare taskuri - generalitati:

    sunt create/sterse dinamic construire xTaskCreate(), distrugere vTaskDelete().

    prioritatea ntre 0 i configMAX_PRIORITIES 1 (setare configMAX_PRIORITIES n FreeRTOSConfig.h)

    programatorul lanseaz n main i planificatorul, care va arbitra ulterior execuia taskurilor vTaskStartScheduler

    taskurile sunt implementate ca bucle infinite

    in gestionarea taskurilor, FreeRTOS poate folosi modul preemtiv (toate taskurile preemtive) sau modul nepreemtiv (toate taskurile nepreemtive)

    o modul preemtiv/nepreemtiv este stabilit din FreeRTOSConfig.h (#define configUSE_PREEMPTION 1)

  • Cateva servicii API:

    vTaskCreate, vTaskDelete - creare/stergere task

    xTaskGetCurrentTaskHandle determinare handler task curent

    vTaskSuspend, vTaskResume, vTaskResumeFromISR forare stare suspendat/ revenire din starea suspendat un task se poate autosuspenda sau poate suspenda alt task orice task sau ISR poate cere reactivarea unui task suspendat

    vTaskDelay, vTaskDelayUntil forare ateptare pentru un interval de timp; pe acest interval taskul intr n blocare.

    vTaskPrioritySet, uxTaskPriorityGet modificare / citire prioritate

    in blocare (blocking)

    Apel vTaskSuspend()

    in curs de executie (running)

    Evenimentul asteptat a avut loc

    pregatita pentru executie (ready)

    Blocare prin apelul unor servicii API

    suspendata (suspended)

    vTaskResume()

    Primeste procesorul la

    decizia planificatorului

    Pierde procesorul la (preempt)

    vTaskSuspend()

    vTaskSuspend()

    vTaskCreate()

  • Observatii:

    taskurile au stiva proprie (dimensiunea stivei este indicat la creare)>> se poate ajunge la consum mare de memorie, dar exist o protecie a datelor.

    o un task poate avea acces doar la stiva proprie (mod User)

    orice task poate modifica on-line prioritatea unui alt task sau prioritatea sa

    planificatorul poate fi pornit/oprit de programator cu vTaskStartSheduler/ vTaskEndSheduler

    xSchedulerRunning = pdTrue/pdFalse

    planificatorul poate fi suspendat de-suspendat de programator: vTaskSuspendAll()/vTaskResumeAll() ++ uxSchedulerSuspended/--uxSchedulerSuspended

  • int main( void ) {

    .

    xTaskCreate(Task1, ); xTaskCreate(Task2, .); ..

    vTaskStartScheduler(); return 0;

    }

    void Task1( void *pvParameters ){ for( ;; ){ .

    vTaskDelay( 1000 ); } }

    Setari in FreeRTOSConfig.h:

    #define configUSE_PREEMPTION 1 #define configTICK_RATE_HZ ((portTickType)1000)

    etc

    void Task2( void *pvParameters ){ for( ;; ){ .

    vTaskDelay( 2000 ); } }

    +

  • Folosirea planificatorului FreeRTOS:

    se configureaz frame- ul >> gestionat intern cu o rutina de tratare a unei intreruperi de la un

    numrator (de timp real)

    se activeaz planificatorul.

    CND planificatorul arbitreaz ocuparea procesorului:

    In mod preemtiv: la fiecare nceput de frame (periodic)

    Replanificarea asigurat din rutina de ceas a SOTR

    acestea sunt planificri ce NU rezult din codul taskului

  • Suplimentar, indiferent de modul preemtiv/nepreemtiv, FreeRTOS forteaza replanificarea dac:

    o taskul in curs de executie intr n suspendare sau blocare (pentru a evita ocuparea inutil a procesorului de ctre un task care nu mai are nevoie de resursa activ) - executie vTaskSuspend, vTaskDelay, vTaskDelayUntil, stergerea taskului in curs de executie.

    o replanificri incluse n execuia altor servicii API, ca de exemplu: crearea unui task de prioritate mai mare dect cel n curs de

    execuie (se presupune ca se foloseste un model de memorie care permite crearea dinamica a taskurilor);

    scderea prioritii taskului curent.

    (vezi lista completa la sfarsitul acestui curs)

    acestea sunt planificri ce rezult din codul taskului

  • Observatie:

    crearea/stergerea, suspendarea/revenirea din suspendare trebuie rar folosite

    uzual taskurile sunt create la inceputul aplicaiei i blocate la nevoie.

    suspendarea temporar a planificatorului prin vTaskSuspendAll/ vTaskResumeAll nseamn absena planficrilor periodice

    trebuie folosit ct mai rar!!!!!

  • CE TASK preia procesorul la replanificare - algoritm planificare:

    o taskul mai prioritar preia procesorul

    o daca exista mai multe taskuri pe nivelul maxim de prioritate

    n mod preemtiv se foloseste planificarea de tip round robin - fiecare task primeste pe rand procesorul (cte un frame)

    o Exceptie: taskul iddle vezi detalii in subcapitol urmator

    n mod nepreemtiv, unul din taskurile de prioritate maxima primeste procesorul, fara a asigura replanificare la fiecare inceput de frame

  • Ex: mod preemtiv, prioriti P_T1 > P_T2 > P_T3; timp de executie mare pentru fiecare ciclu for al fiecarui task.

    T2 T1 T1T2 T2 T2T3 T3 T3I I T2

    Se deblocheaza T1

    T2 se blocheaza, punct de replanificare

    Punct replanificare cerut de T3 care intra in blocare Se trece la task Idle

    T1 intra in blocare, punct de replanificare

    Inceput de frame= punct de replanificare Taskuri ready T2 si T3

    Se deblocheaz T2

  • Ex: mod preemtiv, T1, T2, T3 taskuri ready, de prioritate egala, maxima; timp de executie mare pentru fiecare ciclu for al fiecarui task.

    T1 T2 T3 T1 T2 T3 T1T2 T3 T2 T3

    T1 intra in blocare, punct de replanificare, se trece la urmatorul task ready de prioritate maxima

    Inceput de frame = punct de replanificare

    Inceput de frame = punct de replanificare, se trece la urmatorul task ready de prioritate maxima

    Inceput de frame = punct de replanificare T1, T2, T3 sunt ready

  • Ex: mod nepreemtiv, P_T1 > P_T2 > P_T3; timp de executie mare pentru fiecare ciclu for al fiecarui task.

    T2 T2 T2T1 T1 T1T3 T3 T3 I I T2

    Se deblocheaza T1, dar acesta va sta in lista ready pana la urmatorul punct de replanificare

    T1 se blocheaza, punct de replanificare

    Punct replanificare cerut de T3 care intra in blocare Task Idle preia procesorul.

    T2 intra in blocare, punct de replanificare

    T2 in curs de executie, T3 ready

    Se deblocheaz T2

  • Ex: mod nepreemtiv, T1, T2, T3 de prioritate egal, strict pozitiv (ready la t = 0), T4 de prioritate maxim (blocat la t = 0); timp de executie mare pentru fiecare ciclu for al fiecarui task.

    T1 T1 T1T2 T2 T2T3 T3 T3T4 T4 T4 T4

    Inceput de frame nu este punct de replanificare

    Un punct replanificare inclus intr-un serviciu API, de exemplu T2 este sters

    Se deblocheaza un task prioritar T4, dar el va astepta in lista ready pana la urmatorul punct de replanificare

    Punct replanificare cerut de T3 care intra in blocare T4 (cel mai prioritar) primeste procesorul

    T1 intra in blocare, punct de replanificare, se trece la urmatorul task ready de prioritate maxima

  • Observatii:

    - apariia unui task prioritar n lista ready prin deblocare este considerat doar dac se lucreaz in mod preemtiv iesirea din blocare este decisa de rutina de ceas a sistemului de operare,

    replanificarea are loc imediat doar dac se lucreaz in mod preemtiv. in mod nepreemtiv acesta nu este punct de replanificare - taskurile

    deblocate prioritare nu pot prelua imediat procesorul

    - apariia unui task prioritar n lista ready prin xTaskCreate sau revenire din starea suspendata foreaz replanificare, indiferent de modul de lucru preemptiv/ nepreemptiv

    acest punct de replanificare este decis de taskul in curs de executie (este un apel voit la planificator)

    avantaj: tratarea rapida a proceselor prioritare noi sau revenite din suspendare

  • Totusi, la introducerea in lista de taskuri ready a unui task nou prin xTaskCreate sau revenire din starea suspendata, acest task nu poate preempta un task de aceeasi prioritate.

    >> pe mod nepreemtiv, daca taskul nou nu primeste imediat controlul, el ramane in lista ready pn la urmatorul punct de replanificare (care poate fi peste mai multe frame-uri).

  • Atentie:

    - orice task e implementat ca bucl infinita

    un task prioritar trebuie s intre in blocare pentru a permite accesul taskurilor mai putin prioritare la procesor

    - taskul idle este implicit creat i trebuie s primeasc acces la procesor.

    acest lucru este posibil doar cand toate taskurile de prioritate mai mare sunt in blocare

  • Observatii:

    planul este admisibil (restrictiile de timp sunt respectate) doar daca prioritatile au fost corect alocate de programator!!!

    algoritmul de planificare nu modific dinamic prioritile, pentru algoritmul de planificare prioritile sunt date de intrare;

    in anumite situaii, programatorul poate fora creterea/scderea prioritilor pentru anumite taskuri;

    dac anumite faciliti trebuie asigurate n rare situaii (de exemplu, reconfigurarea unui sistem n cazul detectrii unei anomalii), taskul specific poate fi creat dinamic (folosind cel putin modelul de memorie heap_2.c) sau scos din suspendare cand este necesar, pentru a nu ncrca inutil procesorul.

  • Procesorul este mereu cedat catre ISR, daca IF permite

    o - daca ISR foloseste un serviciu API ce conduce la necesitatea unei comutri de task, acest lucru este semnalat, pentru a putea forta din ISR predarea procesorului catre un task diferit de cel care a fost intrerupt.

    T1 T1 ISR T2 T2

    Cerere de intrerupere acceptata, se pred controlul rutinei de tratare

    Replanificarea ceruta de ISR asigura executia lui T2

    ISR-ul forteaza revenirea din suspendare a lui T2 care este mai prioritar ca T1 ISR cere replanificare

    T1 este taskul prioritar ready

  • Ideea de proiect folosit de FreeRTOS

    fiecare task are asociat o structur de control TCB:

    typedef struct tskTaskControlBlock { signed char pcTaskName[ configMAX_TASK_NAME_LEN unsigned portBASE_TYPE uxPriority;

    portSTACK_TYPE *pxStack;//baz stiv volatile portSTACK_TYPE *pxTopOfStack;//varf stiva

    ..........

    } tskTCB;

    !!!! Toate STOR folosesc o structur echivalent

  • taskurile sunt gestionate prin liste dublu inlantuite pe TCB-uri

    orice task existent in memorie se gsete intr-o list:

    lista de taskuri ready; dou liste cu taskuri blocate: cu i fr depire la numrtor; lista taskuri suspendate;

    lista taskuri pentru care s-a solicitat tranziia din starea suspendenta n cadrul unui ISR;

    list cu taskuri sterse ce trebuie eliberate din memorie

    struct xLIST_ITEM{ portTickType xItemValue; /*camp folosit la sortare */ volatile struct xLIST_ITEM * pxNext; volatile struct xLIST_ITEM * pxPrevious void * pvOwner; /* pointer la TCB */ void * pvContainer; /*pointer la lista proprietar*/ }

    pointerul la lista proprietar este cmp i n TCB

  • listele sunt ntreinute ca liste ordonate - dup prioritate task, timp deblocare:

    o lista de taskuri ready este sortat dup prioritate

    planificatorul pred controlul taskului din capul listei de taskuri ready

    prioritatea maxim curent a unui task ready: uxTopReadyPriority

    serviciile API apeleaz planificatorul dac este necesar, indiferent de mod preemptiv-nepreemtiv: cedare procesor prin blocare-suspendare-tergere, scdere prioritate task curent, etc.

    funcii pentru planificare: portYIELD_WITHIN_API, taskYIELD, portYIELD

  • Gestionare frame

    Pentru a implementa frame-ul, FreeRTOS foloseste o rutina de tratare a unei intreruperi venita de la un numarator hardware numita intreruperea sistem

    rutina este disponibila n port.c FreeRTOS/source/portable/[compiler]/[microcontroller]/port.c.

    Lungimea frame-ului (tick-ului) este stabilita de

    #define configTICK_RATE_HZ ( ( portTickType ) 1000 ) // 1 msec.

    i influeneaz

    o frecventa punctelor de replanificare periodica, pe modul preemtiv

    o frecventa punctelor in care se decide deblocarea taskurilor i rezolutia intarzierilor asigurate

  • void __attribute__((__interrupt__, auto_psv)) _T1Interrupt( void ) { /* Clear the timer interrupt. */ IFS0bits.T1IF = 0;

    vTaskIncrementTick();//inclusiv deblocari de taskuri

    #if configUSE_PREEMPTION == 1 portYIELD(); //(portasm_dsPIC.s)

    // - forteaz o comutare de context #endif }

    In portYIELD()este apelat vTaskSwitchContext:

    void vTaskSwitchContext( void ) { Apelul unor hookuri utile pentru monitorizare Cedeaz controlul taskului din capul listei de taskuri ready

    }

  • Limitri impuse de numrtorul folosit

    In general:

    CTMIN constanta_numarator (inclusiv prescalare) CTMAX

    valori posibile frame

    La DSPIC33: Timer 1, 16 biti

  • Atentie, la SOTR trebuie asigurat un compromis intre doua obiective conflictuale:

    Eficienta SOTR: interval alocat executiei taskurilor (fr comutare) n unitatea de timp

    Obiectiv: se doreste alocarea unui timp procesor mai mare pentru executie taskuri, nu pentru comutari de context

    Debit: nr. taskuri tratate pe unitatea de timp Obiectiv: se doreste avansarea la cat mai multe taskuri de prioritate egala, respectiv tratarea cat mai prompta a taskurilor prioritate mai mare (reducerea timpului de asteptare in coada ready, fara acces la procesor)

    >> lungimea frame-ului este esentiala

  • Serviciile periodice pot fi incluse prin Tick Hook

    un hook = o rutina lansata implicit de SO, ntr-un anumit context

    TickHook se va executa implicit la fiecare frame, dac configUSE_TICK_HOOK =1

    Poate fi scrisa de utilizator folosind prototipul:

    void vApplicationTickHook( void );

    atentie: functia va fi apelata de o rutina de tratare a unei intreruperi: sa implice timp executie mic sa nu foloseasca servicii/operatii nepermise

    (alege doar serviciile FreeRTOS care contin sufixul ISR)

  • Taskul idle

    odata cu planificatorul se activeaz implicit i taskul idle, de prioritate 0 (cea mai mic)

    o acest task asigura eliberarea memoriei la distrugerea taskurilor cu vTaskDelete()

    trebuie s primeasc procesorul, adic taskurile mai prioritare trebuie s intre n ateptare (din cnd n cnd)

    Observatie: sunt acceptate i alte taskuri de prioritate 0 (tskIDLE_PRIORITY), desi toate serviciile de aceasta prioritate se prefera a fi asigurate de Idle Hook

    Idle task este implementat ca bucla infinita for (;;){......} - la fiecare ciclu, apeleaza Idle Hook, care poate fi scrisa de utilizator pentru a implementa servicii proprii.

  • for( ;; ){

    Verifica daca anumite taskuri au fost sterse, elibereaz memoria si decrementeaza uxCurrentNumberOfTasks

    #if ( configUSE_IDLE_HOOK == 1 ){ vApplicationIdleHook(); } #endif

    #if ( mod nepreemtiv ) { //forteaza o comutare de context (pot exista taskuri disponibile): taskYIELD(); } #endif

    #if ( ( mod preemtiv ) && ( configIDLE_SHOULD_YIELD == 1 ) ){ //Daca exista un task de prioritate tskIDLE_PRIORITY, ii cedeaza //procesorul:

    taskYIELD(); } #endif

    }

  • IdleTaskHook

    IdleHook este implicit aplelata in taskul idle la fiecare parcugere a buclei for, dac configUSE_IDLE_HOOK =1 (in FreeRTOSConfig.h).

    Mod de implementare:

    Scrie functia conform prototipului:

    void vApplicationIdleHook( void );

    aceasta functie poate include faciliti dorite pentru prioritate minima

    este varianta preferata (fata de optiunea de a crea taskuri suplimentare de prioritate tskIDLE_PRIORITY )

  • Ex: mod preemtiv, configIDLE_SHOULD_YIELD =0, P_T1 = P_T2 = P_T3=0, P_T4=3

    T1 T2 T3 I T1 T4 T4 T4T2 T3 I T1

    T1, T2,T3 ready, T4 blocat

    Planificare round rubin intre T1, T2, T3, idle

    Punct replanificare cerut de T4 care intra in blocare Round rubin

    Deblocare T4, punct de replanificare

    Se vor executa mai multe cicluri for, la fiecare ciclu este apelat idle hook

  • Ex: mod preemtiv, configIDLE_SHOULD_YIELD =1, P_T1 = P_T2 = P_T3=0, P_T4=3

    T1 T2 T3 IT1 T2 T4 T4 T4T3 IT1 T2 T3

    T1, T2, T3 ready, T4 blocat

    Planificare round rubin intre T1, T2, T3, idle

    Punct replanificare cerut de T4 care intra in blocare Round rubin

    Deblocare T4, punct de replanificare cerut de rutina de ceas

    Replanificare ceruta de idle. T1 va primi procesorul pentru mai putin de un frame.

    Replanificare ceruta de rutina de ceas a sistemului de operare

  • Ex: mod nepreemtiv, configIDLE_SHOULD_YIELD, P_T1 = 0, P_T2=3

    I T1 T1T2 T2 T2 T2 T2I I I I

    T1, T2 blocate Punct replanificare cerut de T2 care intra in blocare

    Punct de replanificare cerut de T1 prin blocare T1 deblocat

    Replanificare ceruta de idle task

    Idle hook apelat la fiecare ciclu for

    T2 deblocat

  • Exemplul 1 Verifica mod preemtiv/nepreemtiv, round rubin, etc

    FreeRTOSConfig.h #ifndef FREERTOS_CONFIG_H #define FREERTOS_CONFIG_H

    #include

    #define configUSE_PREEMPTION 0 // sau 1 #define configUSE_IDLE_HOOK 1 #define configUSE_TICK_HOOK 0 #define configTICK_RATE_HZ ( ( portTickType ) 100 ) #define configCPU_CLOCK_HZ ( ( unsigned long ) 40000000 #define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 4 ) #define configMINIMAL_STACK_SIZE ( 105 ) #define configTOTAL_HEAP_SIZE ( ( size_t ) 5120 ) #define configMAX_TASK_NAME_LEN ( 4 ) #define configUSE_TRACE_FACILITY 1 #define configUSE_16_BIT_TICKS 1 #define configIDLE_SHOULD_YIELD 1 #define configUSE_CO_ROUTINES 1

  • #define INCLUDE_vTaskPrioritySet 1 #define INCLUDE_uxTaskPriorityGet 0 #define INCLUDE_vTaskDelete 0 #define INCLUDE_vTaskCleanUpResources 0 #define INCLUDE_vTaskSuspend 1 #define INCLUDE_vTaskDelayUntil 1 #define INCLUDE_vTaskDelay 1 #define INCLUDE_xTaskGetCurrentTaskHandle 1 #define INCLUDE_xTaskGetTickCount 1

    #define configKERNEL_INTERRUPT_PRIORITY 0x01 #endif /* FREERTOS_CONFIG_H */

  • Main.c

    #include #include "FreeRTOS.h" #include "task.h" #include "queue.h" #include "croutine.h" #include "partest.h" _FOSCSEL(FNOSC_FRC); // Select Internal FRC at POR _FOSC(FCKSM_CSECMD & OSCIOFNC_OFF); // Enable Clock Switching and Configure // FRC + PLL

    xTaskHandle handT1; xTaskHandle handT2;

    unsigned int varaux1, varaux2, varauxidle; portTickType no_ticks; static char t2first;

    extern portBASE_TYPE uxCurrentNumberOfTasks;

  • static void prvSetupHardware( void );

    void initPLL(void){ // Configure PLL prescaler, PLL postscaler, PLL divisor

    PLLFBD = 41; // M = 43 FRC CLKDIVbits.PLLPOST=0; // N1 = 2 CLKDIVbits.PLLPRE=0; // N2 = 2 // Initiate Clock Switch to Internal FRC with PLL (NOSC = 0b001) __builtin_write_OSCCONH(0x01); // FRC __builtin_write_OSCCONL(0x01);

    // Wait for Clock switch to occur while (OSCCONbits.COSC != 0b001); // FRC while(OSCCONbits.LOCK!=1) {}; }

    static void prvSetupHardware( void ){ vParTestInitialise(); initPLL(); }

  • void Task1(void *params) { portTickType xLastWakeTime= xTaskGetTickCount(); for (;;){ varaux1=varaux1+1; no_ticks=xTaskGetTickCount(); vParTestToggleLED(15); vTaskDelayUntil( &xLastWakeTime, 45 ); }}

    void Task2(void *params) { portTickType xLastWakeTime; xLastWakeTime = xTaskGetTickCount(); for (;;){

    no_ticks=xTaskGetTickCount(); varaux2=varaux2+1; if (no_ticks 50){ vParTestToggleLED(14); vTaskDelayUntil( &xLastWakeTime, 10 );}}}

  • void vApplicationIdleHook( void ) { varauxidle++;}

    int main( void ){ /* Configure any hardware required for this demo. */ prvSetupHardware();

    xTaskCreate(Task2, (signed portCHAR *) "T2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, &handT2);

    vTaskStartScheduler(); return 0; }

    Observatii: - pe mod preemptiv: P_T1=P_T2, T1 nu va preempta T2, fiind de aceeasi prioritate (la breakpointul indicat se va gasi t2first=1 si no_ticks=50). P_T1>P_T2, T1 va preempta T2 (la breakpointul indicat se va gasi t2first=0 si no_ticks=50).

    Ce se schimba pe mod nepreemtiv?

  • Exemplu 2: idem, inlocuind P_ T1=P_T2=P_idle si: void Task1(void *params) { portTickType xLastTime = xTaskGetTickCount()-1; for (;;){ no_ticks=xTaskGetTickCount(); if (xLastTime!=no_ticks){varaux1=varaux1+1;xLastTime=no_ticks;} if ((no_ticks/15)*15 == no_ticks) {vParTestToggleLED(15);} }}

    void Task2(void *params) { portTickType xLastTime = xTaskGetTickCount();//la primul frame valoarea este 0 for (;;){ no_ticks=xTaskGetTickCount(); if (xLastTime!=no_ticks){varaux2=varaux2+1;xLastTime=no_ticks;} if (no_ticks 50){ if ((no_ticks/15)*15 == no_ticks) {vParTestToggleLED(14);} }}} Q: cu P_T1=P_T2=P_idle, obtin varauxidle varaux1, varaux1+varaux2 =no_ticks. (executiile pe frame-uri sunt: T2&I, T1, ). Pe modul nepreemtiv se executa doar T2.

  • Exercitiul 1

    Desenati secventele de ocupare a procesorului pentru cazurile: mod preemptiv cu configIDLE_SHOULD_YIELD = 0 sau =1, respectiv mod nepreemtiv.

    Aplicatia creeaz taskurile T1 (prioritate P1), T2 (prioritate P2), T3 (prioritate P3) si apoi starteaza planificatorul.

    T1 sterge taskul T3 (daca acesta exista) si se blocheaza pentru 2 frame-uri. T2 creeaz un task nou T3, de prioritate P3 (daca acesta nu exista deja), si

    apoi se blocheaza pentru 2 frame-uri. Daca taskul T3 exista, executa cateva actualizari de variabile si apoi se blocheaza pentru 2 frame-uri.

    T3 executa cateva actualizari de variabile si apoi se blocheaza pentru 1 frame.

    Idem pentru suspend/ resume in loc de sterge/ creeaza. Idem pentru T3 executat fara intrare in blocare.

    Cazuri particulare: P1=1, P2=2, P3=2; P1=3, P2=2, P3=1; etc.

  • Detalii implementare a aplicatiilor de timp real cu procese de tip taskuri

    Conventii de nume in fiierele kernel

    - pentru variabile: o tip char - prefix c o tip short - prefix s o tip long - prefix l o tip float - prefix f o tip double - prefix d o enumeratii - prefix e o alte tipuri (ex. struct, union) - prefix x o pointeri - prefix suplimentar p o unsigned prefix suplimentar u

    -pentru funcii: o Serviciu API prefix n funcie de tip o Numele funciei ncepe cu numele fiierului n care apare definiia

    (vTaskDelete - tip void, in task. C)

    Exemple: ucPriority, pcPointerChar

  • Tipuri de date predefinite

    - vezi portmacro.h (din FreeRTOS\Source\portable\MPLAB\PIC24_dsPIC)

    definitii particularizate pentru fiecare arhitectura

    #define portCHAR char #define portFLOAT float #define portDOUBLE double #define portLONG long #define portSHORT short #define portSTACK_TYPE unsigned short #define portBASE_TYPE short

    #if( configUSE_16_BIT_TICKS == 1 ) typedef unsigned portSHORT portTickType; #define portMAX_DELAY ( portTickType ) 0xffff #else typedef unsigned portLONG portTickType; #define portMAX_DELAY ( portTickType ) 0xffffffff #endif

  • Pentru a folosi o anumita configuratie a SOTR, sunt necesare setari specifice in FreeRTOSConfig.h:

    #include // legatura cu arhitectura hardware

    #define configUSE_PREEMPTION 1 //toate taskurile sunt preemtive // = 0 >> nepreemtive

    #define configUSE_IDLE_HOOK 1 // cu TaskIddleHook #define configUSE_TICK_HOOK 0 // fara TickHooh

    #define configTICK_RATE_HZ ( ( portTickType ) 1000 ) //frecventa nucleului >> frame de 1 msec

    #define configCPU_CLOCK_HZ ( ( unsigned long ) 40000000 ) /* Fosc / 2 */ //ceasul magistralei

    #define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 4 ) //nivele de prioritate admise < 4

    #define configMINIMAL_STACK_SIZE ( 105 ) // stiva minima 105B

  • #define configTOTAL_HEAP_SIZE ( ( size_t ) 5120 ) //RAM folosit pentru kernel; //valoarea trebuie sa permita folosirea // schemei de alocare a memoriei

    #define configMAX_TASK_NAME_LEN ( 4 ) //maxim 4 car. pentru numele unui task // (inclusiv terminatorul NULL)

    #define configUSE_TRACE_FACILITY 0 //fara facilitati de trace // =1 solicita si rezervarea spatiului // pentru bufferul de trace

    #define configUSE_16_BIT_TICKS 0 // portTickType este unsigned pe 32 biti // daca =1, e pe 16 biti

    // stabileste lungimea constantei pentru contorul soft ce // numara tickurile, pentru a implementa intarzieri

    #define configIDLE_SHOULD_YIELD 1 // valoarea conteaza doar in mod preemtiv, //pentru planific. taskurilor de priorit. egala cu iddle task // =1 forteaz ca iddle task sa cedeze procesorul imediat ce

    // alt task de prioritate 0 este ready // =0 iddle task >>iddle task ocupa frame-uri intregi

  • #define INCLUDE_vTaskPrioritySet 1 #define INCLUDE_uxTaskPriorityGet 0 #define INCLUDE_vTaskDelete 0 #define INCLUDE_vTaskCleanUpResources 0 #define INCLUDE_vTaskSuspend 1 #define INCLUDE_vTaskDelayUntil 1 #define INCLUDE_vTaskDelay 1

    #if ( INCLUDE_vTaskDelete == 1 )

    ...................

    #endif Amprenta mica de memorie

  • Detalii servicii API specifice - vezi task.h i task.c i validri din FreeRTOSConfig.h

    1. Creare/stergere taskuri

    typedef void * xTaskHandle;= handler la un task

    portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, const portCHAR * const pcName, unsigned portSHORT usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pvTask );

    pvTaskCode Pointer la functia asociata taskului pcName Numele taskului cu nr. maxim de caractere precizat de configMAX_TASK_NAME_LEN. usStackDepth Adancimea stivei (dimeniunea stivei = adancime x latime, cu latimea = sizeof

    (portSTACK_TYPE)) (aici unsigned short) pvParameters Pointer la parametrii taskului uxPriority Prioritatea taskului. pxTask Handler la taskul creat

    Returneaz : pdPASS pentru executie cu succes, un cod de eroare la executie esuata - vezi projdefs. h exemplu #define errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ( -1 )

  • void vTaskDelete( xTaskHandle pxTask );

    Exemplu:

    void vTaskCode( void * pvParameters ){ for( ;; ){ //instructiuni diverse } }

    void vOtherFunction( void ){ static unsigned char ucParameterToPass = a; xTaskHandle xHandle; xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass,

    .tskIDLE_PRIORITY, &xHandle ); .......

    vTaskDelete( xHandle ); }

    Un task poate fi creat in main sau in alta functie, doar daca modelul de memorie heap o permite!!!

  • xTaskCreate (caz fara Memory Protection Unit) { aloca memorie pentru Task Control Block si stiva

    if alocarea este cu succes {

    fixeaz vrful stivei si initializeaz in TCB nume, prioritate, adncime stiva, etc.

    Marcheaz inceput sectiune critic uxCurrentNumberOfTasks++; if (este primul task)

    initializeaz lista de taskuri si pxCurrentTCB = pxNewTCB; else {

    adauga taskul in lista de taskuri ready if( scheduler inactivat )

    if( taskul nou are prioritate maxima) pxCurrentTCB = pxNewTCB; }

    daca acest task este mai prioritar ca cel curent, uxTopUsedPriority=prioritate task

    Marcheaz final sectiune critic }

  • #if ( configUSE_TRACE_FACILITY == 1 ) { Asigura servicii de monitorizare specifice }

    if alocarea este cu succes, planificatorul este activat si taskul este de prioritate maxima

    forteaza replanificarea apeland portYIELD_WITHIN_API();

    }

  • #if ( INCLUDE_vTaskDelete == 1 ) {

    vTaskDelete { Marcheaz inceput sectiune critic Elimina taskul din lista Actualizeaz nr. taskuri sterse (++uxTasksDeleted;) Asigura servicii de monitorizare (dac sunt activate) Marcheaz sfarsit sectiune critic

    if( planificatorul este activ si se sterge taskul curent) forteaz o replanificare: portYIELD_WITHIN_API(); }

    }

    #endif

  • 2. Activare/dezactivare planificator

    Initial, planificatorul nu este activ. Activarea este realizata prin apelul

    void vTaskStartScheduler( void );

    care starteaz modulul de gestionare a frame-ului i asigur planificarea taskurilor.

    Planificatorul este oprit cu

    void vTaskEndScheduler( void );

    care asigura stergerea tuturor taskurilor i oprirea planificatorului oprirea modulului de gestionare tick, eliberarea resurselor ocupate de SOTR.

  • Exemplu de utilizare:

    void vAFunction( void ) {

    // Creeaz cel putin un task inainte de activarea planificatorului xTaskCreate( vTaskCode, "TP", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );

    // Start planificator. vTaskStartScheduler();

    // in acest punct se ajunge doar dupa apel vTaskEndScheduler ()

    }

    void vTaskCode( void * pvParameters ) { for( ;; ) { vTaskEndScheduler (); } }

  • Implementare vTaskStartScheduler/ vTaskEndScheduler

    void vTaskStartScheduler( void ) { creeaza task idle if (task idle este creat cu succes)(

    xSchedulerRunning = pdTRUE; xTickCount = ( portTickType ) 0;

    configureaz frecventa (mai mare) pentru calculul timpilor de executie (monitorizare)

    seteaza timerul de timp real alte initializri context de lucru

    } }

    void vTaskEndScheduler( void ) { dezactiveaza ntreruperile xSchedulerRunning = pdFALSE; vPortEndScheduler(); }

  • 3. Suspendare/ revenire din starea suspendat

    void vTaskSuspend( xTaskHandle pxTaskToSuspend );

    pxTaskToSuspend Handler la taskul ce este suspendat NULL - autosuspendare.

    void vTaskResume( xTaskHandle pxTaskToResume ); pxTaskToSuspend Handler la taskul ce este reactivat

    portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume ); pxTaskToSuspend Handler la taskul ce este reactivat

    Returneaz: pdTRUE va fi necesara o comutare de context dupa terminarea ISR pdFALSE nu va fi necesar o comutare de context dupa terminarea ISR

  • Exemplu de utilizare: Cu INCLUDE_vTaskSuspend =1, INCLUDE_xTaskResumeFromISR =1

    xTaskHandle xHandle;

    void vAFunction( void ) { xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );

    // ... Restul codului. }

    void vTaskCode( void *pvParameters ){ for( ;; ) { vTaskSuspend( NULL ); // autosuspendare } }

    void vAnExampleISR( void ) { portBASE_TYPE xYieldRequired; xYieldRequired = xTaskResumeFromISR( xHandle ); if( xYieldRequired == pdTRUE ){ portYIELD_FROM_ISR();} }

  • #if ( INCLUDE_vTaskSuspend == 1 ){ void vTaskSuspend( xTaskHandle pxTaskToSuspend ){ Marcheaz inceput sectiune critic Sterge taskul din lista de taskuri ready si scrie-l in lista de taskuri suspendate Asigura servicii de monitorizare Marcheaz sfarsit sectiune critic Daca se suspend taskul curent, forteaz o comutare }

    } #endif

    #if ( INCLUDE_vTaskSuspend == 1 ){ void vTaskResume( xTaskHandle pxTaskToResume ){ if (nu e taskul curent si taskul este suspendat){

    Marcheaz inceput sectiune critic Insereaza taskul in lista de taskuri ready si sterge-l din lista de taskuri suspendate Asigura servicii de monitorizare Marcheaz sfarsit sectiune critic Daca prioritatea acestui task este >= cu cea a taskului curent, asigura replanificare}

    } } #endif

  • #if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) { portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume ) {

    if (Taskul este suspendat){ Insereaza taskul in lista de taskuri ready si sterge-l din lista de taskuri suspendate Asigura servicii de monitorizare Daca taskul este de prioritate >= prioritatea taskului intrerupt, marcheaza ca necesara o replanificare

    } } } #endif

  • 4. Modificare prioritati

    unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask );

    pxTask Handler la taskul la care se citeste prioritatea NULL taskul running (citirea propriei prioritati)

    Returneaz: prioritate task

    Cerinta: INCLUDE_uxTaskPriorityGet = 1

    void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority );

    pxTask Handler la taskul la care se citeste prioritatea NULL taskul running (setarea propriei prioritati)

    uxNewPriority Prioritatea alocata taskului

    Cerinta: INCLUDE_vTaskPrioritySet = 1

  • Exemplu de utilizare: Cu INCLUDE_uxTaskPriorityGet = 1, INCLUDE_vTaskPrioritySet = 1

    xTaskHandle xHandle;

    void vAFunction1( void ) { xTaskCreate(vTaskCode,"T1",STACK_SIZE,NULL,tskIDLE_PRIORITY, &xHandle); }

    void vAFunction2( void ) { if( uxTaskPriorityGet( xHandle ) == tskIDLE_PRIORITY ) { vTaskPrioritySet( xHandle, uxTaskPriorityGet( NULL ) + 1 ); } }

  • #if (INCLUDE_vTaskPrioritySet == 1) void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority ){ if (noua prioritate >= configMAX_PRIORITIES ) { uxNewPriority = configMAX_PRIORITIES - 1; }

    marcheaz inceput sectiune critica

    asigura servicii de monitorizare

    obtin prioritatea taskului curent (uxCurrentPriority) if( uxCurrentPriority != uxNewPriority ) { if( uxNewPriority > uxCurrentPriority ){ if( schimb. de priorit se face pentru alt task decat cel curent) marchez ca va fi necesara replanificarea;} else if(schimb. de priorit de face pentru taskul curent) marchez ca va fi necesara replanificarea; actualizeaza prioritatea gestionata de mutexuri modifica prioritatea

    if (taskul e ready), pentru reordonarea listei de taskuri ready, taskul e sters din lista si apoi introdus in pozitia noua

    if (a fost solicitata replanificarea} portYIELD_WITHIN_API(); } marcheaz sfarsit sectiune critica

    } #endif

  • #if (INCLUDE_uxTaskPriorityGet = 1) unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask ){ returneaz prioritate taskului pxTask } #endif

    #if ( INCLUDE_uxTaskPriorityGet == 1 )

    unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask ) { tskTCB *pxTCB; unsigned portBASE_TYPE uxReturn;

    portENTER_CRITICAL(); { /* If null is passed in here then we are changing the priority of the calling function. */ pxTCB = prvGetTCBFromHandle( pxTask ); uxReturn = pxTCB->uxPriority; } portEXIT_CRITICAL();

    return uxReturn; }

    #endif

  • 5. Asteptare pe durata unui anumit un interval de timp

    void vTaskDelay( portTickType xTicksToDelay ); xTicksToDelay Intervalul de asteptare/ blocare, exprimat in tick-uri

    Explicaii: taskul va intra imediat in blocare pentru nr. de tickuri precizat; nr tickuri = interval exprimat in msec / portTick_RATE_MS

    Observatie: n portmacro.h exista #define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ ), iar configTICK_RATE_HZ este setat in FreeRTOSConfig.h

    Exemplu: void vTaskFunction( void * pvParameters ) { const portTickType xDelay = 500 / portTICK_RATE_MS;//astept 500 msec for( ;; ){ vToggleLED(); vTaskDelay( xDelay );}

    }

  • void vTaskDelayUntil( portTickType *pxPreviousWakeTime, portTickType xTimeIncrement );

    pxPreviousWakeTime Pointer la o variabila care indica momentul la care taskul a fost ultima data deblocat. Variabila trebuie initializata (de exemplu cu momentul actual de timp inainte de prima utilizare a functiei). Apoi variabila este actualizata de apelurile successive ale acestui serviciu API.

    xTimeIncrement Taskul va intra in blocare pana la momentul (*pxPreviousWakeTime + xTimeIncrement), cand se va debloca. Momentul deblocarii este automat memorat in *pxPreviousWakeTime, pentru utilizari viitoare. Daca (*pxPreviousWakeTime + xTimeIncrement) este din trecut, taskul nu este blocat.

    Exemplu: void vTaskFunction( void * pvParameters ){ portTickType xLastWakeTime; const portTickType xPer = 10; xLastWakeTime = xTaskGetTickCount(); for( ;; ) { vTaskDelayUntil( &xLastWakeTime, xPer ); // aici - instructiuni diverse. } }

  • #if ( INCLUDE_vTaskDelay == 1 ) void vTaskDelay( portTickType xTicksToDelay ){ if( xTicksToDelay > ( portTickType ) 0 ){//e necesara intarzierea Blocheaza planificatorul

    Asigura servicii de monitorizare Calculeaza momentul de deblocare:

    xTimeToWake = xTickCount + xTicksToDelay; Elimina taskul din lista taskurilor ready

    Adauga taskul la lista de taskuri blocate, verificand daca pana la deblocare nu va aparea overflow pe numarator

    Folosind if( xTimeToWake < xTickCount ) Deblocheaza planificatorul

    } Forteaza replanificarea } #endif

  • #if ( INCLUDE_vTaskDelayUntil == 1 ) void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement ) { Blocheaza planificatorul Calculeaza momentul de deblocare:

    xTimeToWake = *pxPreviousWakeTime + xTimeIncrement; Verifica daca e overflow si marchez daca intarzierea poate avea loc

    Actualizeaza *pxPreviousWakeTime = xTimeToWake; if (e necesara intarzierea){ Asigura servicii de monitorizare Elimina taskul din lista taskurilor ready

    Insereaza taskul in lista de taskuri blocate (eventual intaziere cu overflow la contorul timp)

    } Deblocheaza planificatorul

    Forteaza replanificarea } #endif

  • Iesirea taskurilor din starea blocat este decisa din rutina de ceas a sistemului

    - la fiecare frame este verificata lista de taskuri blocate si se stabileste care trebuie trecut in starea ready

    void vTaskIncrementTick( void ){ if( planificator nesuspendat: uxSchedulerSuspended == pdFALSE ) { ++xTickCount; if( xTickCount == ( portTickType ) 0 )//overflow contor de timp { xNumOfOverflows++;

    Aleg lista de taskuri blocate cu intarzieri ce conduceau la overflow

    } Alege taskurile care trebuie deblocate Elimina aceste taskuri din lista taskurilor in asteptare Trece aceste taskuri in lista de taskuri ready} else ++uxMissedTicks;

    #if ( configUSE_TICK_HOOK == 1 ) vApplicationTickHook(); #endif }

    Asigura servicii de monitorizare }

  • 6 Alte servicii pentru controlul kernelului

    taskYIELD () - macro ce foreaz o comutare de context daca planificatorul nu este suspendat: salveaza in stiva TCB, registri; alege taskul prioritar ready si preda controlul acestuia

    taskDISABLE_INTERRUPTS inactiveaz acceptarea cererilor de ntreruperi mascabile (inclusiv rutina de ceas a sistemului de operare) taskENABLE_INTERRUPTS activeaz acceptarea cererilor de ntreruperi mascabile

    taskENTER_CRITICAL, taskEXIT_CRITICAL - marcheaza sectiuni critice ce nu vor permite replanificare la inceput de frame

    void vPortEnterCritical( void ){ portDISABLE_INTERRUPTS();//inclusiv rutina de ceas SOTR uxCriticalNesting++; } void vPortExitCritical( void ){ uxCriticalNesting--; if( uxCriticalNesting == 0 ){portENABLE_INTERRUPTS(); } } Atentie: nu folosi apeluri de servicii API in secventa critica!!!

  • void vTaskSuspendAll( void ) suspend planificatorul: nu pot avea loc deblocari de taskuri, etc nu sunt inactivate ISR-uri, ci anumite servciii oferite de rutina de ceas a sistemului:

    taskul n curs de execuie se va executa fr preemtare, pn la apelul urmtor de xTaskResumeAll (); pna atunci NU pot fi folosite servicii API care pot genera schimbare de context.

    + portBASE_TYPE xTaskResumeAll( void ) - revenire din starea suspendata a planificatorului;

    Returneaz: pdTRUE (e necesara o comutare de context), altfel pdFALSE.

    Exemplu

    void vTask1( void * pvParameters ){ for( ;; ) { xTaskSuspendAll (); // nicio comutare de context nu poate avea loc if( !xTaskResumeAll () ) { taskYIELD (); } } }

  • void vTaskIncrementTick( void ){ if( planificator nesuspendat: uxSchedulerSuspended == pdFALSE ) {

    ++xTickCount; if( xTickCount == ( portTickType ) 0 )//overflow contor de timp { xNumOfOverflows++;

    Aleg lista de taskuri blocate cu intarzieri ce conduceau la overflow

    } Alege taskurile care trebuie deblocate Elimina aceste taskuri din lista taskurilor in asteptare Trece aceste taskuri in lista de taskuri ready}

    else ++uxMissedTicks;

    #if ( configUSE_TICK_HOOK == 1 ) vApplicationTickHook(); #endif }

    Asigura servicii de monitorizare }

    Numarul de tickuri pierdute cat timp planificatorul este suspendat este folosit pentru actualizarea corecta a lui xTickCount la de-suspendarea planificatorului

  • void vTaskSuspendAll( void ) { ++uxSchedulerSuspended; }

    signed portBASE_TYPE xTaskResumeAll( void ){

    marchez nceput sectiune critica --uxSchedulerSuspended;

    if( planificatorul trebuie de-suspendat: uxSchedulerSuspended == 0 ){

    if( exista taskuri in memorie: uxCurrentNumberOfTasks > 0 ){ asigura schimbarile de stare cerute de ISR-uri i marcheaz daca e

    necesara replanificarea if( planificatorul a pierdut cel putin un frame: uxMissedTicks>0){ while(uxMissedTicks>0){vTaskIncrementTick();--uxMissedTicks;} #if configUSE_PREEMPTION == 1 xYieldRequired = pdTRUE; #endif } if( e necesar replanificare ){ xAlreadyYielded = pdTRUE; xMissedYield = pdFALSE; portYIELD_WITHIN_API(); } } } marchez sfrit sectiune critica return xAlreadyYielded; }

  • 7. Servicii APIce ofer informaii despre SOTR:

    xTaskHandle xTaskGetCurrentTaskHandle( void ); - returneaz handler la taskul curent

    unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ); - returneaz numrul de taskuri create in sistem i neterse din memorie

    incrementat de xTaskCreate, decrementat de idle task la prima execuie dup un apel vTaskDelete

    sau acces direct la citirea si vizualizarea in Watch a variabilei extern portBASE_TYPE uxCurrentNumberOfTasks;

    volatile portTickType xTaskGetTickCount( void ); - returneaz nr de tickuri scurse de la activarea planificatorului sau acces direct la citirea si vizualizarea in Watch a variabilei extern portTickType xTickCount;

    Atentie: Nu este recomandat sa modificati valorile xTickCount sau uxCurrentNumberOfTasks (desi e posibil), deoarece va fi distorsionata functionarea SOTR. Folosirea serviciilor API echivalente este preferabil.

  • Lista servicii API care folosesc replanificare:

    vTaskSuspend - daca se autosuspenda taskul curent;

    vTaskResume - daca se de-suspenda un task suspendat anterior, cu prioritate mai mare sau egala cu cel curent;

    xTaskResumeAll daca un task de priroitate cel putin egala cu cel curent este n PendingList sau cel putin o planificare implicita periodica a fost pierduta pe mod preemptiv;

    vTaskDelay daca intarzierea este pozitiva, este apelat vTaskSuspendAll si apoi xTaskResumeAll la final;

    vTaskDelayUntil este mereu apelat vTaskSuspendAll si apoi xTaskResumeAll la final.

  • vTaskPrioritySet daca prioritatea noua este diferita de cea a taskului curent in cazurile: i) se scade prioritatea taskului curent; ii) se schimba prioritatea unui task difierit de cel curent cu o valoare mai mare decat

    prioritatea taskului curent.

    xTaskCreate daca planificatorul este activat si prioritarea taskului nou mai mare strict ca prioritatea taskului curent;

    vTaskDelete - daca planificatorul nu este suspendat i este sters taskul curent.

  • Exemple

    demo site:

    partest.c functii dedicate gestionrii ledurilor

    main.c - start-stop planificator

    death.c creare si stergere taskuri

    flash.c joc cu leduri

  • FLASH (+ main.c) // joc cu leduri

    #include

    #include "FreeRTOS.h" #include "task.h" #include "partest.h" #include "flash.h"

    #define ledSTACK_SIZE configMINIMAL_STACK_SIZE #define ledNUMBER_OF_LEDS ( 3 ) #define ledFLASH_RATE_BASE ( ( portTickType ) 333 )

    /* Variable used by the created tasks to calculate the LED number to use, and the rate at which they should flash the LED. */ static volatile unsigned portBASE_TYPE uxFlashTaskNumber = 0;

    /* The task that is created three times. */ static portTASK_FUNCTION_PROTO( vLEDFlashTask, pvParameters );

    ! Exista in portmacro.h: #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )

  • /*-----------------------------------------------------------*/ void vStartLEDFlashTasks( unsigned portBASE_TYPE uxPriority ){ signed portBASE_TYPE xLEDTask;

    /* Create the three tasks. */ for( xLEDTask = 0; xLEDTask < ledNUMBER_OF_LEDS; ++xLEDTask ){

    xTaskCreate( vLEDFlashTask, ( signed char * ) "LEDx", ledSTACK_SIZE, NULL, uxPriority, ( xTaskHandle * ) NULL );

    } } /*-----------------------------------------------------------*/

    static portTASK_FUNCTION( vLEDFlashTask, pvParameters ){ portTickType xFlashRate, xLastFlashTime; unsigned portBASE_TYPE uxLED; ( void ) pvParameters; /* The parameters are not used. */

    portENTER_CRITICAL();{/* Calculate the LED and flash rate. */ uxLED = uxFlashTaskNumber;

    uxFlashTaskNumber++;} portEXIT_CRITICAL();

    xFlashRate = ledFLASH_RATE_BASE + ( ledFLASH_RATE_BASE *( portTickType )uxLED ); xFlashRate /= portTICK_RATE_MS; xFlashRate /= ( portTickType ) 2;

    xLastFlashTime = xTaskGetTickCount();

    !

    !

    Exista in portmacro.h: #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )

  • for(;;) { vTaskDelayUntil( &xLastFlashTime, xFlashRate ); vParTestToggleLED( uxLED );//led on vTaskDelayUntil( &xLastFlashTime, xFlashRate ); vParTestToggleLED( uxLED );//led oFF } }

  • Exercitiul 2

    i) Scrieti codul C pentru exercitiul 1 ii) Cum poate fi verificata corectitudinea secventei de executie?