Proiectarea Optimă a Sistemelor Embedded:

by donpedro

o abordare inteligentă (2)

În numărul trecut al revistei am făcut o scurtă prezentare a câtorva dintre modalităţile posibile în abordarea proiectării hardware în scopul reducerii numărului de pini I/O, reducerea drastică a consumului aplicaţiei, reducerea numărului de componente externe şi implicit a costurilor finale. În acest număr vom face o trecere în revistă a modalităţilor de abordare a modulelor software în scopul obţinerii unui sistem embedded mult mai fiabil, mai sigur în funcţionare, predictibilitate sporită în funcţionare, cu restricţii constructive mai mici impuse în proiect ceea ce implicit duce la costuri mai mici în timp pentru un astfel de proiect.
În continuare sunt prezentate modalităţi prin care un sistem embedded poate fi folosit optim din punct de vedere al resurselor. De cele mai multe ori un minimum de software necesar pentru funcţionarea unui program minimal într-un sistem embedded este un “super loop” de genul:

De cele mai multe ori este necesar, însă, să avem mai multe taskuri care să proceseze diferite evenimente. În funcţie de modul de tratare a priorităţilor şi constrângerilor impuse putem vorbi de sisteme embedded bazate pe:

• “single-task system” (superloop)
• “multi-task system”
1. “co-operative multitasking”
2. “pre-emptive multitasking”

În faza de proiectare şi specificaţii se poate identifica sistemul cel mai adecvat pentru aplicaţie, însă în cele mai multe cazuri un sistem “single-task” sau “multi-tasking co-operativ” este acoperitor pentru constrângerile impuse sistemului. În cazul unor sisteme de timp real (timpul de răspuns al sistemului în ce priveşte evenimentele procesate este foarte mic (us-ns) – pilot automat, radar aeronave etc) este impetuos necesară prezenţa unui sistem “multi-tasking pre-emptiv”.

Single-task system (superloop)

Un astfel de sistem este de fapt un modul care se execută la infinit într-o buclă “super-loop”, fără a folosi un kernel de timp real. Doar interrupt service routines (ISRs) trebuie folosite pentru rezolvarea operaţiilor critice. Un astfel de sistem este utilizat mai ales în sisteme mici, nu foarte complicate şi unde un comportament de timp real nu este necesar.
Într-un astfel de sistem, însă, sunt câteva probleme de predicţie şi sincronizare care pot apărea. De acestea trebuie ţinut cont în faza de proiectare. Deoarece, nu avem un kernel de timp real şi doar o stivă este necesară, astfel memoria ROM / RAM a unui astfel de sistem se dovedeşte a fi extrem de redusă în dimensiuni. Un astfel de sistem se poate dovedi foarte greu de întreţinut, însă, dacă programul devine foarte mare. Deoarece o componentă software nu poate fi întreruptă de altă componentă software (avem un singur task activ la un moment dat), reacţia în răspuns a componentelor depinde foarte mult de celelalte din sistem (exemplul din figura de mai sus). Un comportament de timp real este foarte dificil de obţinut de la un astfel de sistem – performanţe mai bune pot depinde de experienţa de programator. Un astfel de sistem cu buclă infinită “super loop” sau “endless loop” va continua să ruleze atâta timp cât alimentarea uC nu este întreruptă. O astfel de abordare la ora actuală acoperă peste două treimi din aplicaţiile embedded dedicate. Tendinţa în viitor este spre sisteme mai uşor de întreţinut, mai predictibile, mai apropiate de constrângerile unui sistem de timp real şi mai ales se doreşte o modularizare la maxim a părţilor software.

Co-operative multitasking
Acest tip de sistem se bazează pe cooperarea tuturor taskurilor. Acest lucru presupune că un task trebuie să cedeze de la sine utilizarea procesorului, unui alt task. În caz contrar sistemul poate fi blocat şi asfel celelalte taskuri nu ajung să intre în execuţie. Acest lucru este ilustrat în figura următoare.

Dacă sistemul embedded nu este unul foarte critic din punct de vedere al evenimentelor tratate – nu este un sistem de timp real – acest tip de sistem se dovedeşte cât se poate de robust şi fiabil. Cele mai multe din aplicaţiile existente nu pun probleme drastice timpului de procesare a evenimentelor, ceea ce face ca un sistem co-operativ să fie suficient. În cazul sistemului co-operativ comutarea între taskuri nu se face în funcţie de timp, ci fiecare task după execuţie cedează comanda planificatorului de taskuri care în funcţie de condiţiile impuse, dă execuţia următorului task din listă. Această modalitate de planificare a taskurilor impune în faza de proiectare identificarea timpului maxim necesar pentru execuţie, a fiecărui task. În majoritatea cazurilor din punct de vedere al proceselor necesare/existente într-un astfel de sistem embedded, acestea se pot clasifica la nivel de proiectare în:

• “Periodic tasks” – sunt active la o perioadă de timp predeterminată (100ms spre exemplu), însă sunt mai puţin utilizate
• “One-shot tasks” – sunt active după o perioadă de pauză (50ms spre exemplu)

Plecând de la acest context putem repartiza procesele, în funcţie de importanţa şi prioritatea lor în sistem, în astfel de “task”-uri. Însă avem nevoie de un planificator de taskuri (scheduler), minimal, pentru supervizarea execuţiei proceselor. Spre exemplu presupunem că avem trei taskuri (A, B, C), şi taskul A se doreşte să se execute la o perioadă de 10ms, taskul B la o perioadă de 30ms şi taskul C la o perioadă de 25ms. Planificatorul de taskuri în acest caz este necesar să se execute la un interval de timp suficient de mic pentru a putea face o comutare între taskuri fără probleme. Pentru aceasta vom determina cel mai mare divizor comun al perioadelor tuturor taskurilor, şi această valoare va fi perioada la care planificatorul de taskuri se va executa.

Divizori pentru perioada taskului A (10ms) sunt: 1ms, 2ms, 5ms şi 10ms
Divizori pentru perioada taskului B (30ms) sunt: 1ms, 2ms, 3ms, 5ms, 6ms, 10ms, 15ms şi 30ms
Divizori pentru perioada taskului C (25ms) sunt: 1ms, 5ms şi 25ms

În acest caz cel mai mare divizor comun (cmmdc) este de 5ms (la această perioadă este necesar să se execute planificatorul nostru de taskuri). În această situaţie vom configura unul dintre timere (preferabil un timer de 16 biţi pentru a putea obţine şi perioade de timp mai mari) la o perioadă de 5ms. La depăşire, se activează întreruperea aferentă şi astfel planificatorul de taskuri poate verifica dacă taskul în execuţie şi-a încheiat perioada de execuţie sau nu. În cazul în care timpul alocat taskului a expirat, se dă controlul următorului task din lista de taskuri printr-un “dispecer”, iar în caz contrar se aşteaptă următoarea întrerupere la multiplu de 5ms pentru reverificare. Un exemplu de structură de date pentru fiecare task poate fi următoarea:
Desigur trebuie implementată o metodă cel puţin primară de rezolvare a erorilor în situaţii în care anumite condiţii nu sunt îndeplinite. De obicei planificatorul de taskuri generează / setează o variabilă globală de erori.

Un planificator de taskuri co-operativ conţine următoarele componente:
Structură de date identică pentru fiecare task
O metodă de iniţializare
O singură rutină de întrerupere (ISR), folosită la intervale regulate prestabilite de timp pentru actualizări în lista de taskuri
O metodă de creare şi adăugare noi taskuri
O metodă ‚dispecer’ care se ocupă de lansarea în execuţie a taskurilor
O metodă de ştergere a taskurilor (opţional)

Cel mai simplu planificator de taskuri este de genul “round-robin”; acesta conţine o listă de taskuri din care se alege după un algoritm dorit următorul task care trebuie executat.

Cu un planificator de taskuri co-operativ se poate implemena un sistem predictibil şi fiabil
Operaţie:
Taskurile sunt planificate să ruleze la momente specifice de timp
Când un task este planificat să se execute este adăugat în lista de aşteptare
Dacă controlerul devine liber, următorul task în aşteptare din listă este lansat în execuţie
Fiecrae task rulează până la terminare, apoi predă controlul planificatorului de taskuri
Implementare:
Este simplă, şi poate fi implementată în dimensiuni mici de cod
Alocare memorie pentru taskuri se face doar pentru un singur task odată
Planificatorul de taskuri poate fi scris într-un limbaj de nivel înalt
Planificatorul de taskuri face parte din cod şi nu este o aplicaţie separată
Performanţă:
În cazul evenimentelor externe critice este nevoie de atenţie în faza de proiectare
Fiabilitate şi siguranţă:
Planificatorul de taskuri co-operativ este simplu, predictibil, fiabil şi sigur în funcţionare

Pre-emptive multitasking

Acest sistem este folosit în situaţii critice de timp, în cazul sistemelor de timp real, unde tratarea evenimentelor este foarte importantă. Un astfel de sistem are nevoie de o întrerupere de timp care să întrerupă taskul la un moment dat şi să execute o comutare la un alt task. Taskul cu prioritatea cea mai mare este executat înaintea celorlalte, chiar dacă avem un eveniment extern (întrerupere) care are o prioritate mai mică.

Astfel de implementări la ora actuală în sistemele embedded sunt folosite în mod special la procesări de sunete, imagini, unde timpul este critic şi numărul de taskuri şi priorităţi este mare. Aria de acoperire în aplicaţii pentru un astfel de sistem este mai mică de o zecime la ora actuală, însă tendinţa este de creştere, datorită posibilităţilor si performanţelor mari pe care le oferă această implementare.
Diferenţe semnificative între cele două timpuri de sisteme multitasking sunt legate de modul de execuţie şi tratare a proceselor şi evenimentelor şi de cuantumul resurselor necesare. Pe baza unor astfel de sisteme se pot scrie module-taskuri în diferite limbaje de programare şi apoi se pot scrie în memorie la adrese fixe (blocuri), astfel obţinându-se o modularizare foarte mare a sistemului.
Din punct de vedere al consumului de resurse a procesorului, implementarea unui sistem “co-operative” sau “pre-emptive” se dovedeşte foarte util.
În cazul unui sistem de măsurare a temperaturii pe 3 canale la perioade de timp diferite (1sec, 3sec, respectiv 7sec) şi acţionarea unor actuatori pentru fiecare temperatură, consumurile de resurse ale controlerului (PIC16F688/4MHz), se prezintă astfel (“super loop”, “co-operative”, respectiv “pre-emptive” – a se vedea graficele alăturate).

Distribuitor în România al produselor:
Str. Bună Ziua FN, 400495 Cluj-Napoca
Tel: 0264-503540, 0264-503541, 0264-503542, 0264-503543, 0264-503544 Fax: 0264596862; 0264438403
microchip@vitacom.ro;
industrie@vitacom.ro;
www.vitacom.ro

S-ar putea să vă placă și

Adaugă un comentariu