Skip to main content

Tartsuk kordában a bonyolultságot…

Megjelent: 2018. június 05.

Microchip lid 3…a beágyazott alkalmazásokban

Ahogy a hagyományos mikrovezérlőket egyre inkább „rendszercsipek” segítségével valósítják meg a félvezetőgyártók, úgy válik „hirtelen” egyre bonyolultabbá az eszközök konfigurálása. A személyes hangvételű cikk szerzője a folyamat okait és következményeit boncolgatja, és a problémákra ad megoldási javaslatot.

 

Bevezetés

A Raspberry Pi terméksor 2017 februárjában tovább bővült a Raspberry Pi Zero W1-gyel, egy 10 dolláros, vezetékmentesen (is) kommunikáló személyi számítógéppel. Remek hír ez a hobbiszámítógépek kedvelőinek, a barkácsolóknak, bütykölőknek, hekkereknek, és igen, azoknak a keveseknek is, akik megpróbálják végezni a munkájukat, és valóságos elektronikus termékeket terveznek. Eben Upton, a Raspberry Pi alapítvány létrehozója videobejelentéséből[i] arra következtettem, hogy ebben már közreműködni nem tudok, de a jelenség az ifjúságomra, az 1980-as évekre emlékeztet. Akkor nem telt egy BBC hobbiszámítógépre, még kevésbé a „luxuskivitelű” Amigára, így az összes pénzemet egy Sinclair ZX Spectrum megvásárlására költöttem. Ezért aztán Eben erőfeszítései a „mindenki által megfizethető” számítástechnika létrehozására bennem is valódi „rezonanciákat” ébresztettek. 

Meglepett az új rekord, hogy milyen apró (hogy pontos legyek, 6 × 3 cm méretű) nyomtatott áramköri lapon sikerült egy hatékony személyi számítógépet elhelyezni. Ez egy további gondolatot is ébresztett bennem: annak idején a Spectrum egyszerű és takarékos felépítése és számos korlátozása volt az ok, amely megtanított arra, hogy „mélységében” is meg kell ismernem a gépemet, és eközben „szerettem bele” abba a furcsa világba, ami a hardver és a szoftver határterületén húzódik, és amit ma beágyazott elektronikának nevezünk.

 

Egy egész kis rendszer – egyetlen csipen

A Raspberry Pi Zero felépítése egy rendszercsipen (System on Chip – SoC), a BCM2835 típusú integrált áramkörön alapul, amelyben egy 1 GHz-es órajelű ARM® processzormag, egy grafikus processzor (GPU), egy videointerfész, néhány különféle soros kommunikációs interfész (USB, UART, SPI, I2C) és egy külső memóriainterfész kapott helyet. Az utóbbi egy jókora RAM-ot (512 MB DDR2) és egy háttértárolóként használt SD-kártyát képes kezelni, amelyek a Linux operációs rendszer (OS) futtatásához szükségesek. Ezek figyelemre méltó képességek egy egyetlen csipre integrált eszközben, különösen ha összehasonlítjuk azokkal a korábbi generációs személyi számítógépekkel, amelyek végigkísérték az ifjúságomat. Vitatkozhatunk azon, hogy ezek a tulajdonságok összevethetők-e vagy nem azokkal a szerény mikrovezérlőkkel, amelyek a jelenkor beágyazott vezérlési alkalmazásaiban állnak általános használatban. Miközben ezek órajele – és ezzel együtt számítási teljesítménye – lényegesen alacsonyabb (10…100 MHz), ezek a kis eszközök „saját vadászterületükön” valóságos csodák. Amint azt egy mikrovezérlőtől el is várjuk, minden szükséges RAM és flashmemória a csipre integrálva található, éppúgy mint a soros interfészek (USB, UART, SPI és I2C), sőt még a tápfeszültségszabályozás és azok felügyeleti áramkörei is. Teljesen általános, hogy – a nagyobb rugalmasság és az energiafogyasztás minimalizálása érdekében – öt vagy több precíziós oszcillátor is az integrált rendszer része. Vannak analóg perifériáik (ADC, DAC, műveleti erősítők, analóg komparátorok stb.) nagyméretű be- és kimeneti multiplexerekkel. Ezek a Raspberry Pi kiváló videografikus képességeit biztosító áramkörei helyét foglalják el, jelezve azokat a tervezési szempontok közötti, maguktól értetődő különbségeket, amelyek a beágyazott és a „számítógépszerű” alkalmazások között tapasztalhatók.
Valójában nem meglepő, hogy a Raspberry Pi felhasználóinak még az olyan legegyszerűbb I/O-műveletekhez is külön interfészről kell gondoskodniuk a „való világhoz” való illesztések megvalósításához, mint a „közhelynek” számító ledvillogtatás, és kisebb (gyakran 8 bites) mikrovezérlőket kell apró vendégkártyákon elhelyezni ahhoz, hogy megoldja a bonyolultabb I/O-feladatoknál és a logikai feszültségszintek átalakításánál felmerülő problémákat.
Nem szeretnék további, méltánytalan párhuzamot vonni a két – egymástól annyira különböző – alkalmazástechnikai tartomány között, de meg kell mutatnom, hogyan valósítja meg mindkettő a közös célt: tartsuk a bonyolultságot ellenőrzésünk alatt, miközben a kezdő felhasználók érdeklődését szeretnénk felkelteni. Mondani sem kell, hogy a megoldások – bár lényegüket tekintve azonosak – végső soron jelentős eltérésekre vezetnek.
Mindkét típusú platform kiindulópontja, hogy ingyenes szoftvereszközöket ajánlanak, amelyek között megtalálhatók az integrált fejlesztőkörnyezetek (Integrated Development Environment – IDE), fordítóprogamok, programmodul-csatolók (linkerek), szimulátorok, hibakeresők (amelyeknek nem ritkán a „többet tudó”, „fizetős”, professzinonális változatai is elfogadható áron elérhetők), a többé-kevésbé nyílt forráskódú „közbenső szintű” szoftverek (szokványos és valós idejű operációs rendszerek [OS, RTOS]), és végül a kisebb-nagyobb, opcionális hardver-(kártya-) választék.
A két „tábor” (a beágyazott és az általános célú számítástechnikai alkalmazás) közötti különbség kisebb, mint gondolnánk. Mindegyik hasonló (ha nem azonos), többségében GNU[1]-alapú szoftver-eszközkészletet használ, és a közbenső szintű (middleware) szoftverek ugyancsak nagyon hasonlók lehetnek, ha elvonatkoztatunk az alacsony szintű (akár le a puszta hardverig terjedő) meghajtóprogramok rétegétől. Az operációsrendszer-szinten a legnagyobb a különbség: míg egy mikrovezérlő „vígan” elboldogul egy valós idejű operációs rendszerrel, ugyanakkor nem tud megbirkózni egy teljes Linux-kernel futtatásának terhével. Ez a kétféle operációs rendszer feladata, rendeltetése közötti különbség következménye: a „valós idejűség” az operációs rendszer „munkaköri leírásának” része.

 

ME 2018 6 Microchip 2

1. ábra  Szoftververem sémája beágyazott alkalmazásokban. (Megjegyzés: a verem felépítését tovább lehetne finomítani például azzal, ha különválasztanánk a driver (eszközmeghajtó) réteget, valamint a HAL-nak egy „kártyatámogató” rétegét, de a további megfontolások megértéséhez a szintek ilyen mértékű részletezésére nincs szükség.)

 

A bonyolultság „elburjánzása”

Ha a dokumentációkra nézünk, megállapíthatjuk, hogy a bonyolultság erős fokozódása, „elburjánzása” mindkét alkalmazási területen megnyilvánul. Az egyik kedvenc példám erre egy kicsiny és szerény képességű mikrovezérlő, amely a népszerű, nyolcbites PIC® architektúrájú eszközök valamelyikén alapul. A PIC16F1619 típust gyakran használják kisebb háztartási gépek vezérlésére. Ehhez kis mennyiségű programmemória szükséges, amelynek jól megfelel az eszköz 16 kbájtnyi flashmemóriája, kis méretű, 20 kivezetéses tokozata, valamint tucatnyi digitális perifériainterfésze és majdnem ugyanennyi analóg támogatómodulja. Mégis az eszköz „adatlapja”[ii] 650 „nettó” oldalt tesz ki, a jellemző adatok, ábrák és diagramok nélkül is. Ennek a „tényleg kicsiny” rendszercsipnek néhány perifériája, mint például a jelidőzítés-mérőegység (Signal Measurement Timer – SMT) ebből egymaga 50 oldalnyi helyet igényel ahhoz, hogy alaposan dokumentáltnak nevezhessük. Majdnem kétszer ennyi helyet igényel az eszköz PIC processzormagjának és teljes utasításkészletének leírása.
A Raspberry Pi esetében a problémák hasonlóak, csak tízszeresre felnagyítva, mivel néhány alkaltrészadatlapot is figyelembe kell venni, amelyek mindegyike a SoC hardver egy-egy alkatrészét (pl. a SoC perifériáit, a GPU-t vagy a processzormagot) dokumentálja, amelyből egyedül a processzormag-leírása 750 oldalnál is több.

 

A beágyazott szoftverarchitektúra

Amint az nagyon is magától értetődő, senkitől nem lehet elvárni, hogy ilyen hatalmas mennyiségű információt elolvasni – vagy legalábbis részleteiben áttekinteni – legyen képes. Különösen a beágyazott eszközök fejlesztői állnak állandó nagy nyomás alatt, hogy alkalmazásaikat még rövidebb időkereten belül tudják szállítani, aminek a piacképes termék előállításának felgyorsítására irányuló örökös hajsza a mozgatóereje. A probléma egyik szokásos megoldása az alkalmazások rétegstruktúra szerinti felosztása, és olyan szabványosított perifériakönyvtárak használata, amelyek képesek elvonatkoztatni a hardver részleteitől. Ezek a rétegek egy veremként ábrázolhatók (1. ábra), ahol az alkalmazás a hardver absztrakciós réteg (Hardware Abstraction Layer – HAL) tetején „ül”. A valóságos rendszerekben ezt a modellt tovább lehet finomítani, amelyben a HAL egyértelműen azonosított, és ennek a tetején található egy „közbenső szintű szoftver” (middleware) -réteg, amely olyan – általánosan használt – szolgáltatásokat és funkciókat valósít meg, mint a hálózati kommunikáció, a fájlrendszer és a grafikus felhasználói interfész (ha van ilyen, vagy szükséges).
Ezt a szoftverarchitektúrát közvetlenül a „számítógép-típusú” alkalmazások szerkezetéből örökölte a beágyazott fejlesztés, és ez jól modellezi is a legtöbb általános alkalmazás felépítését. Sajnos azonban a beágyazott alkalmazásokra vonatkoztatva két alapvető hiányosságra is fény derül:

  • A réteges architektúra csak addig enyhíti a dokumentáció „felfúvódásának” problémáját, amíg azokra a szabványos funkciókra koncentrál, amelyek a legfelső middleware rétegben valósulnak meg. Az egyszerűbb alkalmazásoknál, ahol ez a middleware réteg nagyon vékony (ha egyáltalán létezik), az eredmény leginkább „ködösítésnek” tűnik. A fejlesztőnek a HAL dokumentációjára kell támaszkodnia, amely egy alkalmazásprogramozási interfész (Application Programming Interface – API) leírása formájában jelenik meg. Ez önmagában is terjedelmes dokumentum, amely akár néhány ezer oldalas is lehet, de sohasem igazán lehet belőle megtudni az eszközspecifikus információkat. Ha probléma adódik, a fejlesztő vagy a „pokol tornácán” marad, vagy mélyre ássa magát a számára „idegen” terület anyagában és megpróbál áttekinteni egy hatalmas adag programkódot.
  • A HAL réteg jelentős segítség a szabványos middleware szolgáltatások támogatásában, de a nagyon merev szerkezete miatt megakadályozza egy adott eszköz bármilyen egyedi jellemvonásának érvényesítését. Már pedig ezek az egyéni jellemzők nagyon jól kihasználható műszaki előnyöket jelenthetnek bizonyos alkalmazásokban, amely maga volt az az „alapos ok”, amiért a fejlesztő egy bizonyos eszköztípust választott a feladata megoldásához.
  • Az alkalmazási spektrum felső szélén, ahol a middleware réteg nagyon „vastag” (mint például a Raspberry Pi esetében is), a Linux operációs rendszer kernelje egymaga többmillió kódsorral „súlyosbítja” ezt a problémát[iii]. Lehet azzal érvelni, hogy ez „nyílt forráskódú” anyag, ám ez nagyon sovány vigasz azoknak az átlagfejlesztőknek, akik abban reménykednek, hogy sohasem kell „mélyre ásniuk” benne.

 

ME 2018 6 Microchip 3

2. ábra A Signal Measurement Timer opciói az MPLAB Code Configurator kezelőfelületén

 

Hagyjuk, hogy a gép azt csinálja, amire a legalkalmasabb!

Végül is a Raspberry Pi-re fejlesztők képesek lehetnek kihasználni az eszköz jelentős „számítási kapacitásából”, és a kis kártyához mérten hatalmas erőforrás-kínálatából származó előnyöket. A szabványos Linux operációs rendszer kényelme számukra „több, mint egy egyszerű kompenzálás” az API bonyolultságának és terjedelmességének negatívumait tekintve. Akire azonban ez a cikk koncentrálni kíván, az a modern mikrovezérlőként használt SoC eszközökre alkalmazást fejlesztő mérnök. Számukra minimális előny származik a szabványosított HAL felhasználásából, mivel ezek a futási teljesítmény csökkenését okozzák, és az eszköz speciális tulajdonságait „elmossa” az egységesítésre törekvő, veremszervezésű szoftver-architektúra.
Ebből a csapdából jelent „okos” menekülőutat az új generációs, gyors fejlesztésre kiélezett szoftverfejlesztési eszközök alkalmazása. Ez a „kódgenerátor” vagy „konfigurátor” szoftverek új osztálya, amely nemrég jelent meg a beágyazott eszközök piacán. A kezdeti jelentős – és gyakran indokolt – szkepticizmus ellenére ezek az eszközök mára nem csak hatékonynak, de szükségesnek is bizonyultak minden komoly beágyazottrendszer-fejlesztő számára. Az új eszközök megkülönböztető jegyei közt az alábbiakat találjuk:

  • Teljes integráció a népszerű integrált fejlesztő környezetekkel (IDE) oly módon, hogy az eszköz „tisztában van” a projekt fő jellemzőivel, „kontextusával”, tehát lehetővé teszi például az alkalmazott SoC típusszáma szerinti választást és az elérhető middleware könyvtár figyelembe vételét.
  • Támogatás az egyedi és összetett perifériákra is. Például a korábban említett Signal Measurement Timer (SMT) vizuálisan is megjeleníthető egy egyoldalas dialógus formájában, amelyet csupán görgethető listákkal, „kattintással” kijelölhető lehetőségekkel, valamint néhány intuitív opció közüli választással lehet konfigurálni. A 2. ábrán látható képernyőkép a Microchip Technology, Inc. PIC mikrovezérlőihez készült gyors fejlesztőeszközeinek „zászlóshajója”, az MPLAB® Code Configurator[iv] (MCC) kezelőfelületéről készült.
  • Egy űrlap (template) -generáló eszköz használatával gondoskodik a konfigurációs döntések teljesen alkalmazásspecifikus funkciók kis készletévé átalakításáról. Ez azt jelenti, hogy csak egy minimális API generálódik kisszámú „megtanulandó” funkcióval, amely egységes és intuitív elnevezési konvenciókat követ. A funkciók „testreszabása” garantálja, hogy a legtöbb hardverabsztrakció statikusan (azaz a fordítási idő előtt) megvalósuljon. Ez csökkenti a függvények számára szükséges és átadandó paraméterek listáját, és ezzel javítja a futásteljesítményt, fokozza a kód tömörségét. Az 1. programlista példa arra, milyen egyszerűen valósul ez meg az MPLAB Code Configurator segítségével.
  • A kimenet egy nagyon tömör, C nyelvű forráskód, amely teljesen olvasható és érthető a felhasználó számára, ráadásul „kézi” optimalizálási módszerekkel tovább is javítható.
  • A modern kódgenerátorok úgy keverik a saját maguk és a felhasználó által előállított kódokat, hogy megtartják annak integritását, és értékes, fejlett hardvererőforrásokat tesznek kihasználhatóvá.

1programlista

1. programlista   A forrásfájl (smt1.c) egy részlete, amelyet az MCC generált az SMT periféria konfigurálására

 

A kódkonfigurátorok alapvetően azt végzik, amire a „gépek” a leginkább alkalmasak. Az ismétlődő és elhibázásra hajlamosító hardverperiféria-konfiguráció vagy egy HAL felépítése – amely gyakran igényel sok órányi „bogarászást” az adatlapokban – elkerülhető vagy jelentősen lerövidíthető néhány „élvezhetőbb” és intellektuálisan ösztönzőbb percre is, és a „különbözet” felfedezésre és alkotásra fordítható. 

Valójában a felhasználók ugyanabból a felhasználói interfészből ismerhetik meg a perifériák sepcifikus hardverképességeit, lényegében kiküszöbölve (vagy legalábbis jelentősen lecsökkentve) az igényt arra, hogy az adatlapokhoz kellene fordulniuk.
A hardver absztrakciós réteg ezáltal a projekt flexibilis részévé válik, és valójában elég gyakran és gyorsan újragenerálható ahhoz, hogy a felhasználó optimalizálhassa az alkalmazás teljesítőképességét.

 

2programlista

2. programlista   Csupán két programsornyi kód szükséges ahhoz, hogy megírjuk a beágyazott világ „Hello World” programjának tekinthető „ledvillogtató” programot

 

10 kódsorban (kettes számrendszerben kifejezve)

Ha egyszer a perifériák konfigurációja megtörtént, a felhasználó elméje szabaddá válik arra a célra, hogy közvetlenül az alkalmazásra, a teljes terv intelligensebb részére, az alkalmazási réteg megalkotására koncentrálhasson; arra, ami a program fő ciklusán belül van, és ne kelljen többé azzal foglakoznia, amit ezenkívül, „előkonfigurálással” is el lehet végezni. 

Végül is, a kódgenerátoroknak köszönhetően még az a program(ocska) is tovább egyszerűsíthető, amit a beágyazott világ „Hello world”-jének is nevezhetnénk: egy led villogtatása a 2. programlistán látható 102 (azaz 210 ) darab programsort igényli. (Megjegyzés: számos további gyakorlati példát talál az olvasó a gyors fejlesztőeszközök hatékony felhasználására az „In 10 Lines of Code” című könyvben[v].

 

Összefoglalás

Ahogy a kis mikrovezérlők kis rendszercsipekké fejlődnek, vagy ahogy a személyi számítógépek Raspberry PI kártyákká „zsugorodnak”, nem csak az időveszteséget és a szellemi terhelésünket, hanem azt a sebezhetőséget is növeljük, amely abból származik, hogy olyan rendszereken dolgozunk, amelynek a működését nem ismerjük, a kezelését pedig nem uraljuk teljesen. A bonyolultság nem a technológiai fejlődés elkerülhetetlen velejárója. A modern kódkonfigurátorok és kódgenerátorok képesek segíteni minket abban, hogy növeljük a programfejlesztési munkafolyamat színvonalát, automatizáljuk a programozási munka egy részét, és ezzel végső soron megőrizhessük az áttekintésünket a munkánk részletei felett az alkatrészjellemzők és opciók rohamosan növekvő száma ellenére is.

 

Hivatkozások

[i] A RaspberryPi ZeroW bejelentése: https://www.raspberrypi.org/blog/raspberry-pi-zero-w-joins-family/
[ii] PIC16F1619 datasheet. http://microchip.com/pic16f1619
[iii] A Linux-kernel kódsorai: https://arstechnica.com/business/2012/04/linux-kernel-in-2011-15-million-total-lines-of-code-and-microsoft-is-a-top-contributor/
[iv] MPLAB Code Configurator. http://microchip.com/mcc
[v] In 10 Lines of Code. http://blog.flyingpic24.com/10lines

 

Szerző: Lucio Di Jasio – Microchip Technology Inc.

 

A fordítás és a közlés a Microchip Technology, Inc. engedélyével valósult meg.

 

www.microchip.com

 

[1]Nyílt forráskódú, Unix-szerű, de Unixból származó kódot nem tartalmazó operációs rendszer és más szoftvereszközök neve. A GNU rövidítés érdekes, „rekurzív” gondolkodásmódot tükröz: GNU = GNU’s Not Unix. – A ford. megj.