Introducere
Linia de produse Raspberry Pi a fost extinsă (feb. 2017) cu un nou dispozitiv și anume Raspberry Pi Zero W1, un computer personal de $10 cu conectivitate wireless. Ce timpuri minunate sunt acestea pentru pasionați, producători, meseriași, hackeri și da, cei câțiva dintre noi care încercăm să ne facem treaba, proiectând produse (electronice) reale! Deoarece am urmărit de curând anunțul video al lu Eben Upton, nu am putut să nu îmi amintesc de primii mei ani. Întorcându-mă în timp, pe la mijlocul anilor `80, nu îmi puteam permite un computer BBC, sau un luxos Amiga. Dar mi-am cheltuit toți banii pentru a achiziționa un Sinclair ZX Spectrum. Astfel, eforturile lui Eben de a face sistemele de calcul “accesibile pentru toți” a rezonat cu adevărat cu mine.
Sunt uimit de noul record atins de ceea ce este în fond un computer personal puternic, la dimensiunile unei plăcuțe de circuit PCB, adică 6 cm × 3 cm pentru a fi mai exact. Ca o reflexie suplimentară, m-am întrebat adesea dacă nu cumva tocmai frugalitatea Spectrumului și multele sale limitări au fost acelea care m-au făcut să sap adânc și m-au făcut să mă îndrăgostesc de o lume stranie – acea frontieră între software și hardware pe care astăzi o numim embedded.
Mici sisteme pe un cip
Designul Raspberry Pi Zero este bazat pe un sistem pe cip (SoC) (BCM2835) care include un nucleu ARM® de 1GHz, precum și o unitate de procesare grafică (GPU), o interfață video, câteva interfețe seriale (USB, UART, SPI, I2C) și o interfață de memorie externă pentru a gestiona memoria necesară RAM (512 MB DDR2) și unitatea de stocare (SD card) necesară pentru a rula sistemul de operare Linux® (OS). Acestea sunt capabilități impresionante pentru un dispozitiv pe un singur cip, în special atunci când sunt comparate cu generațiile anterioare de computere personale văzute în tinerețe. Putem argumenta că nu este disproporționată comparația cu cele mai recente microcontrolere utilizate în zilele noastre în tot soiul de aplicații de control embedded. În vreme ce viteza de ceas și de aici și puterea de procesare, este mult inferioară (de la 10 la ~ 100MHz), toate micile microcontrolere sunt astăzi adevărate mici sisteme pe cip. După cum vă așteptați pentru un microcontroler, tot RAM-ul și memoria flash sunt prezente pe cip. Interfețele seriale (USB, UART, SPI și I2C) sunt prezente, dar și stabilizarea tensiunii de alimentare și circuitele de supervizare a tensiunii sunt integrate. Este uzuală găsirea a cinci sau mai multe oscilatoare (precise) diferite pe cip pentru o mai mare flexibilitate și control al consumului energetic. Există, de asemenea, câteva periferice analogice (ADC, DAC, Amplificatoare operaționale, Comparatoare analogice …) cu multiplexoare mari de intrare/ieșire, în locul capabilității video deosebite a Raspberry Pi, reflectând diferența evidentă în ceea ce privește alegerea de proiectare în favoarea embedded în loc de computing.
De fapt, nu este o surpriză că atunci când utilizatorii Raspberry Pi au nevoie de interfațare cu lumea reală, în afara blândelor aplicații I/O de clipire proverbială a LED-urilor, micile microcontrolere (adesea de fapt microcontrolere pe 8-biți) vin în ajutor prin intermediul așa numitelor “hats”, mici plăci fiică ce oferă interfețele necesare I/O și translațiile de tensiune dorite.
Nu intenționez să forțez mai mult această paralelă incorectă între două lumi așa de diferite, dar trebuie să arăt cum, atunci când vine vorba de suporul dezvoltatorilor, ambele partajează aceeași grijă: “păstrarea sub control a complexității” și în același timp “atragerea de utilizatori începători”. Nu este nevoie să se mai spună că soluțiile sunt similare, dar în cele din urmă divergente.
Ambele platforme încep prin a oferi unelte software gratuite care includ medii de dezvoltare integrate (IDE), compilatoare, elemente de legătură, simulatoare, depanatoare (opțional disponibile în ediții profesionale la un cost redus), un middleware mai mult sau mai puțin deschis și (RT-)OS și o selecție mică de opțiuni hardware (plăci).
Diferențele dintre cele două tabere, embedded și sistem de calcul general, sunt mai mici decât vă puteți închipui. Ambele se bazează pe un lanț de unelte, măcar similar, dacă nu identic, care, pentru cea mai mare parte sunt bazate pe GNU. La nivel de middleware opțiunile de sursă deschisă sunt din nou foarte asemănătoare odată ce abstractizați corect straturile de jos ale driverului. La nivel de sistem de operare diferența este mai mare, deoarece multe dintre microcontrolere rulează un RTOS, dar sunt incapabile de a susține greutatea unui kernel Linux complet. Acest lucru reflectă diferențele vocaționale reale. Timpul real este parte a sarcinii sistemului de operare OS.
Inflație
Este atunci când te uiți într-o documentație și observi cum inflația complexității apare de ambele părți. Unul dintre exemplele mele favorite este cazul unui mic și modest microcontroler, bazat pe o arhitectură populară PIC® pe 8 biți. PIC16F1619 este utilizat frecvent pentru a controla electrocasnice mici: acesta integrează o memorie flash de numai 16KB într-o capsulă mică cu 20 de pini, câteva interfețe periferice digitale și cam tot atâtea module analogice. Și totuși datele sale tehnice au ajuns la 650 de pagini și asta înainte de a ajunge la datele caracteristice, diagrame și grafice2.
Unele dintre perifericele oferite de acest mic sistem pe cip (SoC), de exemplu un temporizator de măsurare semnal (Signal Measurement Timer), necesită aproximativ 50 de pagini pentru a fi documentat corespunzător. Acest lucru înseamnă de aproape două ori numărul de pagini necesare pentru a descrie nucleul PIC actual și setul său complet de instrucțiuni.
La Raspberry Pi, problema este similară dacă se mărește proporțional (10x) deoarece trebuie luate în considerare câteva documentații tehnice, fiecare documentând numai o parte din componentele hardware ale sistemului pe cip (periferice SoC, GPU, nucleu), iar nucleul în sine ia mai mult de 750 de pagini.
Arhitectură software Embedded
După cum este aproape evident, nimeni nu se așteaptă să se citească sau doar să se țină pasul cu o așa de vastă cantitate de informații. Dezvoltatorii embedded, în particular, sunt întotdeauna sub presiune pentru a livra aplicațiile în timpi din ce în ce mai reduși, în eterna solicitare a celui mai rapid timp de apariție pe piață. O soluție uzuală este de a partiționa o aplicație utilizând o arhitectură pe straturi și cu folosirea unor biblioteci periferice standardizate pentru a abstractiza detaliile hardware. Straturile pot fi reprezentate îngrijit ca formând o stivă în care aplicația se află în partea superioară a nivelului de abstractizare hardware HAL (Hardware Abstraction Layer). De fapt, această imagine poate fi rafinată mai mult pentru a identifica mai bine HAL, astfel încât un strat middleware ar avea în sarcină implementarea de servicii/funcții uzuale precum rețea, sistem de fișiere și interfețe grafice dacă sunt prezente/cerute.
Notă: Pachetul software poate fi rafinat și mai mult prin separarea unui strat de driver și a unuia de suport placă de la HAL, dar nu avem nevoie de acest nivel de detaliu în considerațiile de față.
Această arhitectură software este derivată direct din lumea “sistemelor de calcul” și operează bine în majoritatea cazurilor generale. Din păcate, atunci când se folosește în lumea aplicațiilor embedded, ea suferă de două deficiențe fundamentale:
• Arhitectura pe nivele simplifică problema inflației de documentație atâta vreme cât concentrarea este pe funcțiile standard oferite de stratul superior middleware. La nivelul inferior al spectrului aplicației, acolo unde stratul middleware este foarte subțire, rezultatul este în mare parte confuz. Un dezvoltator trebuie să se bazeze pe documentația HAL, sub forma unei mari interfețe de programare a aplicațiilor (API), un volum la fel de mare care poate cuprinde câteva mii de pagini, dar care niciodată nu te învață cu adevărat specificul dispozitivului. Atunci când apar probleme, dezvoltatorul trebuie să se scufunde adânc într-un teritoriu străin și într-o zonă vastă de programare.
• Stratul HAL oferă un ajutor foarte mare pentru suportul serviciilor standard middleware, dar datorită naturii sale foarte rigide sfârșește prin a șterge toate caracteristicile unice de diferențiere ale unui anumit dispozitiv. Aceste caracteristici ar putea oferi un avantaj tehnic unei aplicații particulare și poate fi motivul de alegere a unui anumit model.
• La capătul superior al spectrului de aplicații, acolo unde stratul middleware este foarte gros, cum este cazul Raspberry Pi, numai kernelul Linux OS adaugă problemei3 milioane de linii de cod. În vreme ce se poate argumenta că acesta este cod sursă deschis, nu este deloc confortabil pentru dezvoltatorul mediu, care speră să nu trebuiască să sape mai adânc aici.
Lăsați mașina să facă ceea ce face ea mai bine!
Până la urmă, dezvoltatorii Raspberry Pi vor fi capabili de a se baza pe câștigurile oferite de performanțele de “calcul” și vastele resurse oferite de plăcile mici. Comoditatea sistemului de operare Linux standard va compensa mai mult decât complexitatea și amploarea API-ului.
Eu sunt preocupat de dezvoltatorii de sisteme SoC mici: utilizatorii de microcontrolere moderne. Pentru aceștia, avantajul de a lucra cu un HAL standardizat este diminuat, deoarece apar scăderi de performanță, iar caracteristicile de unicitate sunt reduse la o arhitectură de pachete software.
O cale inteligentă de ieșire din acest impas este reprezentată de noua generație de unelte de dezvoltare pentru o dezvoltare rapidă. Aceasta este o nouă clasă de generatoare de cod sau configuratoare care au apărut recent pe piața de control embedded. În ciuda unui scepticism inițial semnificativ și adesea justificat, aceste unelte sunt oferite nu numai pentru a fi eficiente, dar și necesare pentru orice dezvoltator serios de sisteme embedded.
Printre caracteristicile cele mai importante găsim:
– Integrare completă în mediile de dezvoltare uzuale (IDE) care le face disponibile în cadrul contextului unui proiect: selecție model (număr producător) și bibliotecă middleware.
– Suport pentru periferice unice și complexe. De exemplu, sus-menționatul temporizator de măsurare a semnalului (SMT) poate fi prezentat vizual utilizatorului într-o singură pagină/dialog compusă numai dintr-o listă desfășurătoare, căsuțe de selecție și opțiuni intuitive. Vedeți figura 2 cu privire la o captură de ecran MPLAB® Code Configurator (MCC)4, unealta de dezvoltare rapidă pentru microcontrolerele PIC, de la Microchip Technology, Inc.
– Utilizarea unui șablon de motor, având grijă ca translatarea opțiunilor de configurare să fie realizată într-un set mic de funcții complet particularizate. Acest lucru înseamnă că este generat numai un API minimal, cu puține funcții de învățat, cu convenții de numire consistente și intuitive. Particularizarea funcțiilor garantează că majoritatea abstractizării hardware-ului este realizată static în timpul compilării (de fapt chiar mai repede). Acest lucru reduce lista de parametri necesari/pasați fiecărei funcții, iar de aici permițând performanțe crescute și densitate de cod. Vedeți listarea 1, care prezintă un exemplu de creare tipică, simplă și rapidă a configuratorului de cod MPLAB.
void SMT1_Initialize(void) {
// CPOL rising edge; EN enabled; SPOL high/rising edge enabled; SMT1PS 1:1 Prescaler; …
SMT1CON0 = 0x80;
// SMT1MODE Counter; SMT1GO disabled; SMT1REPEAT Single Acquisition mode;
SMT1CON1 = 0x08;
// SMT1CPRUP SMT1PR1 update complete; SMT1TS not incrementing; RST SMT1TMR1 update complete …
SMT1STAT = 0x00;
SMT1CLK = 0x00; // SMT1CSEL FOSC;
SMT1WIN = 0x00; // SMT1WSEL SMTWINx;
SMT1SIG = 0x00; // SMT1SSEL SMTxSIG;
MT1PRU = 0x00; // SMT1PR16 0x0;
SMT1PRH = 0x00; // SMT1PR8 0x0;
SMT1PRL = 0x00; // SMT1PR0 0x0;
}
void SMT1_DataAcquisitionEnable(void) {
SMT1CON1bits.SMT1GO = 1; // Start the SMT module by writing to SMTxGO bit
}
void SMT1_SetPeriod(uint32_t periodVal) {
// Write to the SMT1 Period registers
SMT1PRU = (periodVal >> 16);
SMT1PRH = (periodVal >> 8);
SMT1PRL = periodVal;
}
Listare 1: Secțiune a fișierului sursă (smt1.c) generat de MCC pentru configurarea perifericului SMT
– Ieșirea este compusă din fișiere sursă foarte scurte (limbaj C) care pot fi complet inspectate de utilizator, oferind o oportunitate de învățare, dar putând fi, de asemenea, optimizate manual de experți. Generatoarele moderne de cod amestecă programele lor cu programe de utilizator, având abilitatea de a păstra integritatea și permițând ca prețioasele caracteristici hardware avansate să fie complet exploatate.
În principiu, configuratoarele/generatoarele de cod fac ceea ce “mașinile” fac mai bine. Faza repetitivă și susceptibilă de erori a configurării perifericului hardware pentru a construi un HAL care necesită adesea ore de căutare în documentațiile tehnice, dispare sau se scurtează considerabil la câteva minute plăcute și stimulative intelectual bazate pe descoperire și creație. De fapt, utilizatorii pot învăța despre capabilitățile specifice ale perifericelor hardware de la aceeași interfață cu utilizatorul, eliminând esențial (sau cel puțin reducând substanțial) necesitatea pentru prezența împreună a tuturor datelor tehnice. Stratul de abstractizare hardware devine o parte flexibilă a proiectului și este, de fapt, regenerat adesea și rapid după cum este nevoie de a optimiza performanțele aplicației.
În zece (în binar) linii de cod
Odată ce configurația (perifericului) este rezolvată, mintea este liberă să se concentreze imediat pe aplicație, cea mai inteligentă parte a proiectului, la nivelul stratului de aplicație, ceea ce se află în “bucla principală”, în opoziție cu ce vine înaintea sa.
LED_Toggle();
__delay_ms(500);
Listare 2: Vor fi necesare numai două linii de cod pentru a crea primul vostru “Hello World” embedded
Până la urmă, mulțumită generatoarelor de cod, chiar și în lumea embedded, clasicul exemplu “Hello World”, care este invariabil translatat în clipirea unui LED, devine un exercițiu de programare de numai două linii! Veți fi capabili să găsiți mai multe (20) exemple practice ale aceleiași utilizări rapide a uneltelor de dezvoltare în cartea mea recent publicată: “În 10 linii de cod”5.
Lupta cu complexitatea
După cum micile microcontrolere migrează către mici sisteme pe cip SoC, iar computerele personale se micșorează în dimensiuni către Raspberry Pi, nu este vorba despre timpul pierdut sau despre sarcina cognitivă, ci și de vulnerabilitatea care este introdusă atunci când lucrăm pe sisteme pe care nu le putem înțelege/stăpâni complet.
Complexitatea nu este o consecință inevitabilă a progresului tehnologic. Configuratoarele/generatoarele de cod moderne ne pot ajuta prin multiplicarea procesului de dezvoltare software, automatizând și eventual răspunzând comenzii de creș- tere rapidă a numărului de funcții/opțiuni disponibile.
Autor: Lucio Di Jasio,
EMEA Business Development Manager
Lucio Di Jasio este Director de Dezvoltare a Afacerii EMEA pentru Microchip Technology Inc. El a acoperit în ultimii 18 ani numeroase roluri tehnice și de marketing în cadrul companiei, în departamentele de 8, 16 și 32-biți. Ca autor tehnic prolific, Lucio a publicat numeroase articole și câteva cărți în ceea ce privește programarea pentru aplicații de control embedded.
Urmându-și pasiunea pentru zbor și-a obținut licențe de zbor privat FAA și EASA. Puteți citi mai multe despre cele mai recente cărți și proiecte ale lui Lucio pe blog-ul său la: http://blog.flyingpic24.com
Bibliografie
1 The RaspberryPi ZeroW announcement. https://www.raspberrypi.org/blog/raspberry-pi-zero-w-joins-family/
2 PIC16F1619 datasheet. http://microchip.com/pic16f1619
3 Lines of code in the Linux kernel. https://arstechnica.com/business/2012/04/linux-kernel-in-2011-15-million-total-lines-of-code-and-microsoft-is-a-top-contributor/
4 MPLAB Code Configurator. http://microchip.com/mcc
5 In 10 Lines of Code. http://blog.flyingpic24.com/10lines
Microchip Technology | www.microchip.com