Pulsație și performanță în timp real

by donpedro

Am participat recent la un curs practic menit să introducă un grup de “mileniali” (denumiți și Generația Y) – care aveau deja o bază de informatică – în arta programării embedded. Desigur, unul dintre primele exemple de proiecte s-a dovedit a fi proverbialul “Hello World”, care a însemnat: clipirea unei diode cu emisie de lumină (LED).

Instructorul a făcut o treabă destul de bună, evitând să intre în prea multe detalii și ispite. El a îndrumat clasa în procesul de configurare a unui simplu port de intrare/ieșire (I/O) și a ales utilizarea celei mai simple soluții posibile. Aceasta a însemnat o pereche de bucle de blocare (în așteptare) și două atribuiri care, după cum a explicat el, vor fi transformate într-o singură instrucțiune de microcontroler (MCU) (bit-set și bit-clear), de către inteligentul compilator C. Curând, camera a fost umplută de lumina intermitentă a LED-urilor roșii. Dar, spre dezamăgirea instructorului, mulțimea nu părea prea entuziasmată de rezultat. Din spatele clasei am început să aud nemulțumirile. Ulterior, a ieșit la iveală și sursa nemulțumirilor din cadrul grupului: există clipire și apoi există pulsație (ca o respirație), precum fac multe laptopuri și telefoane moderne atunci când sunt în modul de așteptare. Așa cum se întâmplă adesea, a fost o chestiune de așteptări incorect stabilite.

Scade performanța (rămânem fără MIPS)

Din acel moment, cursul a luat o întorsătură neașteptată, deoarece instructorul a încercat să mulțumească publicul și a pornit pe un alt drum către explicarea complexității relative pe care o implică noua sarcină. A trebuit introdus un temporizator și, odată cu acesta, un semnal cu lățime modulată (PWM – Pulse-Width Modulation) pentru a regla ieșirea vizibil luminoasă a LED-ului, controlând factorul de umplere. În continuare, s-a aventurat într-o explicație a modului în care acest lucru a trebuit să fie schimbat treptat, printr-o serie de pași crescători și descrescători, definiți tabelar. Sincronizarea fiecărui pas a necesitat încă un temporizator (mai lent), care a produs o întrerupere. Microcontrolerul răspunde la această întrerupere și calculează (sau consultă un tabel de căutare) pentru a atribui un nou factor de umplere pentru semnalul PWM.

Figura 1: Fereastra MCC cu resursele proiectului

Acest lucru a fost deja prea mult pentru cursanți, la prima lor incursiune în lumea embedded, dar lucrurile au devenit și mai complicate pe măsură ce instructorul a încercat să-i impresioneze cu un calcul rapid.

Figura 2: Fereastra MCC de configurare a sistemului – detaliu oscilator intern

Acesta este calculul așa cum mi-l amintesc:

  1. Alegeți o frecvență PWM astfel încât să putem conta pe efectul de persistență retiniană: 30 ~ 120Hz.
  2. Să înmulțim această valoare astfel încât să rezulte un efect lin de atenuare a luminii, să spunem în 256 pași. Rezultă, astfel, o frecvență de ~ 32 kHz. Până acum, totul este ok. În fiecare microcontroler PIC® este disponibil un oscilator intern, cu consum de putere extrem de scăzut, exact la această frecvență!
  3. Acum, dacă dorim să producem cel mai simplu efect de pulsație/„respirație” (folosind un semnal în formă triunghiulară) cu o perioadă cuprinsă între 0.5 și 2 secunde, va trebui să urcăm și să coborâm 512 pași (în total) pentru fiecare perioadă.
  4. Acest lucru înseamnă că este necesară actualizarea factorului de umplere PWM la aproximativ fiecare milisecundă. În termeni de ciclu de instrucțiune pentru microcontroler, la frecvența de ceas de 32 kHz vom primi o întrerupere la fiecare opt cicluri de instrucțiune.

Chiar și pentru cel mai experimentat proiectant de sisteme embedded, acest lucru sună ca o propunere imposibilă. Trebuia mărit semnalul de ceas sau, cu alte cuvinte, eram pe cale să reducem foarte mult performanța MIPS!

Figura 3: Fereastra de configurare pentru PWM6

Acest lucru a fost ca o revelație pentru unii cursanți, deoarece au înțeles, pentru prima oară, că termenul de performanță (în MIPS și MHz) are un sens foarte diferit în acest context. A trebuit să forțăm microcontrolerul să execute mai rapid sarcinile, chiar dacă nu încercam să facem niciun calcul; era nevoie doar să răspundem în timp util la un eveniment!

Aceasta a fost prima lor întâlnire cu noțiunea de performanță în timp real.

Simte ritmul

Exercițiul a rezonat și cu mine, fapt pentru care citiți aici despre el. Am căutat modalități simple de a ilustra limitările abordării microcontrolerului tradițional, centrat pe nucleu, pentru aplicațiile embedded. Astăzi suntem, cumva, obsedați de performanță, MIPS, megahertz și megabyte, dar, de multe ori, acesta este tipul greșit de performanță pe care ne concentrăm. Pentru mine, acest lucru a devenit foarte clar, participând la acest curs.

Uneori, făcând un pas înapoi pentru a privi problema dintr-un alt unghi, se poate dezvălui o soluție ascunsă, mai elegantă și mai echilibrată. De exemplu, atunci când abordăm problema LED-ului prezentat mai sus, care pulsează, haideți să facem o pauză și să încercăm să ne eliberăm mintea de cutumele culturii microcontrolerului centrat pe nucleu și să nu ne mai gândim la întreruperi și tabele de căutare.

Dacă vă concentrați asupra cerințelor inițiale ale problemei, opriți-vă o secundă și uitați-vă la semnalul de formă dreptunghiulară cu factor de umplere variabil treptat și s-ar putea să observați o asemănare izbitoare cu un fenomen, adesea experimentat ca efect acustic, produs de “bătaia” a două semnale periodice de frecvență apropiată, care se însumează și se anulează reciproc. Suma celor două ajunge la urechile noastre drept un singur semnal acustic, cu perioadă ușor de recunoscut și cu o frecvență egală cu diferența dintre cele două unde. Acest lucru nu este dificil de implementat: cu doar câteva porți logice și un microcontroler ales cu periferia potrivită.

Figura 4: Fereastra de configurare pentru TMR6

O soluție independentă de nucleu

Primul lucru de care avem nevoie este să găsim o modalitate de a genera două semnale periodice (cele de formă dreptunghiulară sunt în regulă), dar a căror frecvență să difere cu doar 0.5 până la 2Hz. O pereche de temporizatoare digitale cu un registru de reîncărcare (cu alte cuvinte periferice PWM elementare) pot fi utilizate pentru a crea cele două semnale. Va trebui să alegem cu atenție cele două valori de reîncărcare ale registrului astfel încât să fie apropiate, dar totuși diferite, pentru a produce frecvența de ritm dorită. De exemplu, dacă folosim un microcontroler PIC cu un ceas la 32 kHz, două temporizatoare pe 8-biți și modulele PWM aferente, putem genera o frecvență de 60.5Hz și o ieșire de 61.5Hz. Putem folosi apoi una dintre celulele logice configurabile (CLC – Configurable Logic Cells), un mic bloc logic programabil similar blocurilor macro FPGA/PLD, pentru a efectua operația logică ȘI (AND) a celor două semnale. La final, putem direcționa semnalul generat către oricare dintre pinii I/O la care va fi conectat un LED. Acest lucru ne va oferi un efect vizibil de pulsație a LED-ului de 1Hz, asemănător unei respirații. Creșterea ritmului se va realiza prin creșterea diferenței dintre cele două frecvențe (ceea ce face ca a doua perioadă de PWM să fie mai scurtă) și invers, o pulsație mai lentă se va realiza prin reducerea diferenței dintre cele două până la 0.1Hz, când cei doi regiștri de reîncărcare sunt doar la o diferență de un tact.

Figura 5: Fereastra de configurare pentru PWM7

Celula logică configurabilă este elementul fundamental dintr-o unitate CIP (Core Independent Peripherals – Periferice independente de nucleu) existentă în microcontrolerele moderne (PIC), iar pentru restul soluției am folosit doar temporizatoare standard și module PWM.

V-ați putea întreba în acest moment la ce mai folosește microcontrolerul în sine? Nucleul microcontrolerului va fi utilizat în timpul pornirii aplicației, doar pentru a configura perifericele. Chiar mai interesant, am ajuns la soluția noastră folosind un oscilator cu un consum de putere foarte scăzut și avem în continuare 100% din performanța microcontrolerului (MIPS, MHz, indiferent cum doriți să o măsurați), disponibilă pentru alte sarcini (sperăm mai interesante) din aplicația noastră.

Fără linii de cod!

Dacă v-am captat interesul prin acest lucru, veți fi și mai încântați să aflați că punerea în practică nu necesită deschiderea unei fișe tehnice sau scrierea unei singure linii de cod! Trebuie să vedeți pentru a crede, așa că vă încurajez să citiți articolul în continuare.

Figura 6: Fereastra de configurare pentru TMR4

Pentru simplitate, voi folosi una dintre plăcile ieftine de evaluare, MPLAB® Xpress. Voi folosi PIC16F18855, care este inclus pe placă, deși pot fi utilizate oricare dintre noile microcontrolere PIC16F1 care dispun de CIP (periferie independentă de nucleu).

Haideți să creăm un „Proiect nou” (New project) cu ajutorul asistentului MPLAB X Integrated Development Environment (IDE), cu modelul PIC selectat. Vom folosi, de asemenea, configuratorul de cod MPLAB (MCC) – un plugin MPLAB X IDE gratuit – pentru a ne ajuta să inițializăm și să conectăm toate perifericele. Putem pur și simplu să le alegem din lista “Device Resources” (Resurse dispozitive) făcând dublu clic pe numele lor. În cazul nostru, putem selecta TMR4, TMR6, PWM6, PWM7 și unul dintre modulele CLC. Am ales CLC1 pentru acest exemplu.

Figura 7: Fereastra de configurare pentru CLC1

În fereastra “Project Resources”,unde sunt enumerate și selectate resursele proiectului – vezi Figura 1 – putem acum să facem clic pe fiecare dintre acestea și să continuăm să examinăm ferestrele de dialog pentru configurarea lor. Aici putem afla despre opțiunile specifice disponibile pentru fiecare periferic.

Partea de sus a listei de resurse a proiectului conține și grupul “System” (Sistem). “System Module” (modulul de sistem) conține, în particular, elementele esențiale ale microcontrolerului, precum ar fi: oscilatoarele și selecțiile de configurare a biților.

Puneți oscilatorul pe modul “31kHz_LF” (cel mai mic consum de putere dintre toate), ca în figura 2.

Apoi, faceți clic pe resursa PWM6 – vedeți figura 3. Selectați un temporizator ca bază de timp – Timer 6 va fi alegerea noastră. Toate celelalte opțiuni necesare sunt deja configurate, în mod implicit. Acestea înseamnă: un factor de umplere de 50% și o polaritate de ieșire neinversoare.

Făcând clic pe TMR6, vedeți figura 4, ne sunt prezentate din nou o serie de valori implicite importante; haideți să facem perioada să fie de 16.2 ms.

Faceți clic pe PWM7, vedeți figura 5 și selectați Timer 4 pentru baza de timp, astfel încât să putem selecta o perioadă diferită.

Figura 8: Fereastra MCC cu grila managerului de pini

Faceți clic pe TMR4 acum și modificați valoarea perioadei la 16ms, ca în figura 6.

În final, faceți clic pe modulul CLC1 și configurați primele două semnale de intrare astfel încât să fie conectate la ieșirile PWM6 și respectiv PWM7 (vedeți figura 7). Conectați-le la porțile GATE1 și GATE2 și asigurați-vă că este selectată funcția „AND-OR”.

Apoi, utilizați fereastra „Pin Manager: grid” pentru a accesa grila de configurare pentru intrări/ieșiri (I/O), unde va trebui să alocați unul sau mai mulți pini la ieșirea CLC1. Mulțumită caracteristicii Peripheral Pin Select (selecție a pinului pentru periferie), mai multe LED-uri pot fi comandate simultan de ieșirea CLC-ului. În cazul nostru selectați RA0-2, care sunt conectate fizic la cele patru LED-uri ale plăcii de evaluare MPLAB XPRESS, vedeți figura 8.

Figura 9: Fereastra de configurare “Pin Module”

Înapoi la grupul de resurse de sistem, puteți selecta “Pin Module” (Modulul Pin) și în fereastra sa de configurare veți putea verifica dacă toți pinii I/O utilizați sunt configurați corespunzător, vedeți figura 9.

Apăsând butonul “Generate Code“ (Generare program) va declanșa MCC-ul să genereze un set de șase fișiere sursă de mici dimensiuni (scrise în „C”) care vor livra tot codul de inițializare pentru perifericele utilizate. De fapt, MCC se va oferi voluntar să creeze un fișier principal. Vom accepta cu plăcere oferta și acesta va adăuga un fișier „main.c”, care conține apelarea pentru inițializarea perifericelor și o buclă principală goală.

Să nu vă mire dacă, în acest moment, vă recomand să cereți pur și simplu mediului MPLAB X IDE să construiască proiectul și să programeze placa Curiosity cu un ultim clic pe butonul “Make and Program”. După câteva secunde în care compilatorul, link-editorul și programatorul își fac treaba, veți fi bucuroși să vedeți micile LED-uri ale plăcii XPRESS cum pulsează asemenea unei respirații.

În mai puțin de 10 linii (binare) de cod

Poate doriți să știți că am scris recent o carte intitulată „In 10 lines of code” (În 10 linii de cod), care prezintă 20 de proiecte similare, deși, în acest caz particular, nu a trebuit să tastăm “manual”nicio linie de cod. Prin simpla combinare a câtorva module CIP pentru a construi funcția de “respirație” (pulsația LED-ului) s-a realizat tot ceea ce ne-am propus să îndeplinim și avem încă 100% din performanțele microcontrolerului disponibile pentru utilizare în restul aplicației noastre.

Veți găsi proiectul care conține configurația MCC și tot codul generat conform acestui articol la adresa https://github.com/luciodj/In10LinesOfCode, de pe GitHub.

Interesant este că, de când am publicat și am început să folosesc aceste scurte exemple, am observat că până și dezvoltatorii cu experiență, la fel ca studenții de la cursul din exemplul de mai sus, sunt surprinși de performanța „în timp real” pe care o pot livra perifericele independente de nucleu. Utilizarea lor necesită ieșirea din zona de confort “centrată pe nucleu”, dar, după ce ai experimentat acest lucru, nu mai există cale de întoarcere.

Autor: Lucio Di Jasio,
Business Development Manager pentru Divizia MCU8 de la Microchip Technology

Microchip Technology   |   https://www.microchip.com

Sigla-Microchip

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