A workshop oktatója kiváló munkát végzett a tekintetben is, hogy – kísértés ide vagy oda – nem engedte mellékszálak kelleténél nagyobb mértékű kibontakozását. Sikeresen végigvezette a kurzus résztvevőit az egyszerű I/O-portkonfiguráción, és ehhez egyenesen a legegyszerűbb megoldást választotta. Ehhez egypár várakozóhurkot és két olyan hozzárendelést választott, amelyeket az intelligens C-fordító teljes bizonyossággal egyetlen mikrokontroller-utasítássá (bitbeírás és bittörlés) konvertál. Talán mondani sem kell, hogy az oktatótermet kisvártatva sok-sok vörös LED villogása töltötte be, azonban az oktató mégsem lehetett teljesen elégedett, hiszen a résztvevők körében szinte tapintani lehetett az elégedetlenséget, aminek néhányan a hátsó sorokból konkrétan hangot is adtak. Rövidesen természetesen fény derült a zúgolódás okára: a leprogramozott megoldás villogást valósít meg, a modern laptopok és okostelefonok pulzáló vagy lélegzést imitáló, modernebb megoldásával szemben. A csalódottság okát most is a téves elképzelések adták.
Számítási kapacitás híján…
Attól kezdve a kurzus menete váratlan fordulatot vett, amikor az oktató a hallgatósága igényeit kielégítendő új irányba indult el, és megpróbálta az új feladat relatív összetettségét prezentálni. A feladatba immár egy időzítőt is be kellett építeni, amellyel impulzusszélesség-modulációt (PWM – Pulse-Width Modulation) implementálva lehetségessé vált a LED fénykimenetét szabályozni a vezérlőjel kitöltési tényezőjének módosításával. A megvalósítás magyarázatának következő fejezete a fokozatos változtatás volt, amelyet egy táblázatban lefektetett fel- és lefutási értékek definiáltak. Minden változtatási lépés időzítéséhez egy újabb, lassabb időzítő kellett, amely egy megszakítást generált. Erre a megszakításra a mikrokontroller reagált, mely során kiszámította (vagy a táblázatból lehívta) az új kitöltésitényező-értéket a PWM-hez.
Az első alkalommal ez azonban már túl sok volt a beágyazott programozás rejtelmeiben elmélyülni kívánó résztvevőknek: a dolgok azonban később még rosszabbra fordultak, amikor az instruktor a burkolószámítás részleteiben kezdett elmerülni.
Ennek matematikai háttere emlékeim szerint az alábbi volt:
- Válasszunk olyan PWM-periódust, amely az emberi szem tehetetlensége szempontjából szóba jöhet (30 … 120 Hz)!
- Szorozzuk meg ezt az értéket, hogy átmenetmentes fényerőtompítási hatást kapjunk, mondjuk, 256 lépéssel! Erre kb. 32 kHz frekvencia adódik – eddig jók vagyunk. Minden PIC®-sorozatú mikrovezérlőben megtalálható egy ultraalacsony fogyasztású, belső oszcillátor, amely pontosan ezt a frekvenciát adja.
- Ha a legegyszerűbb módon szeretnénk a lélegzést imitáló megoldást implementálni (háromszögprofillal) ½ és 2 másodperc periódusidővel, minden periódusban összesen 512 lépést kell megtenni felfelé és lefelé.
- Mindezek azt eredményezik, hogy a PWM-et kb. egy milliszekundumonként kell frissíteni. A mikrokontroller utasításciklusainak tekintetében, 32 kHz órajel-frekvencián minden nyolcadik utasításciklusban egy megszakítást fogunk kapni.
Ez még a legtapasztaltabb beágyazottrendszer-programozó számára is lehetetlen kihívást jelent! Az órajel-frekvenciát növelni kell, más szavakkal bizony számítási kapacitás híján vagyunk!
A résztvevők többsége számára ez megrengető felismerés volt, hiszen első alkalommal szembesültek a MIPS-ben vagy MHz-ben kifejezett teljesítmény valódi, átértelmezett jelentésével. A mikrokontroller oldaláról még nagyobb teljesítményre lett szükség anélkül, hogy bármi számítást végeztettünk volna vele, mivel pusztán időben kellett egy eseményre reagálni a segítségével. Ez volt a hallgatóság első alkalma arra, hogy megismerje a valódi teljesítmény fogalmát.
Lélegezzünk ütemre!
A gyakorlat tanulsága számomra is jelentős volt: ez az oka annak, hogy jelen cikk megszületett. Többféle megközelítést vettem fontolóra a hagyományos mikrokontroller/magcentrikus megközelítés korlátainak bemutatására a beágyazott alkalmazásokban. Manapság mindenki a nyers teljesítmény, MIPS-mutatók, megahertzek, megabájtok stb. megszállottja, holott gyakran ezek nem sok utalást adnak a számunkra fontos teljesítményre nézve – ez számomra már az oktatóteremben ülve világossá vált.
Sokszor hasznos lehet néhány lépést hátrafelé megtenni, és a problémát új szögből szemlélni, amely során addig rejtett, és egyúttal elegánsabb is kiegyensúlyozottabb megoldásra derülhet fény. A korábbiakban leírt lélegző LED-hatás eléréséhez tegyük ugyanezt: szabadítsuk fel elménket, és felejtsük el egy pillanatra a megszakításokat és referenciatáblázatokat!
Ha az eredeti probléma által definiált követelményekre koncentrálunk, és hunyorítva nézzük a fokozatosan változó kitöltési tényezőjű négyszögjelet, észrevehetjük, hogy kísérteties a hasonlóság azzal a többnyire akusztikai hatásként ismert jelenséggel, amelyet két, egymáshoz közeli frekvenciájú periodikus jel generál szuperponálódáskor és egymás kioltásakor. A két jel összege a fülünket felismerhetően periodikus burkolóval és a kettő közötti frekvenciakülönbséggel éri el. Ezt könnyedén lehet néhány logikai kapu segítségével implementálni, amely a mikrokontrolleren belül a megfelelő perifériák használatával egyszerű feladat.
Egy magfüggetlen megoldás
Az első, amire szükségünk van, az hogy megoldást találjunk két periodikus jel generálására (a négyszögjel preferált), amelyek frekvenciakülönbsége mindössze 0,5 … 2 Hz. A két jel előállítására egy pár, újratöltő regiszteres digitális időzítő (más néven PWM-alapperifériák) alkalmas. A két újratöltési értéket körültekintően kell megválasztani, hogy egymáshoz közeliek, de mégis különbözőek legyenek, biztosítva a szükséges frekvencia előállítását. Ha például egy 32 kHz frekvenciájú PIC mikrokontrollerünk van, két 8 bites időzítő és a PWM-modulok 60,5 Hz frekvenciát és 61,5 Hz kimenetet fognak generálni. Ezt követően felhasználhatjuk az egyik konfigurálható logikai cellát (CLC – Configurable Logic Cell), amely egy kis méretű, FPGA-hoz vagy PLD-hez hasonló, programozható logikai blokk, és alkalmas a két jel logikai ÉS-kapcsolatának megvalósítására. Végezetül a kimenetet közvetlenül az I/O-kivezetések egyikére lehet vezetni, amelyre a LED-ünk is csatlakozik.
Ez egy 1 Hz frekvenciájú, szabad szemmel jól látható lélegzőhatást fog kelteni. Gyorsabb lélegzés hatását a két jel frekvenciakülönbségének növelésével lehet elérni (amely a második PWM-periódust rövidíti), illetve az összefüggés fordítva is igaz, tehát: ha lassítani akarjuk a lélegzés ütemét, a két jel frekvenciakülönbségét csökkenteni kell, egészen akár 0,1 Hz-ig, amikor is a két újratöltő regiszter tartalma mindössze egy számjegyben tér el.
A konfigurálható logikai cella a modern PIC-sorozatú mikrovezérlők magfüggetlen perifériáinak (CIP – Core Independent Peripherals) csupán egyike, a megoldás egyéb részeiben pedig semmi mást nem használtunk, mint standard időzítőket és PWM-eket.
Felmerülhet a kérdés az eddigiek alapján, hogy magára a mikrokontrollerre van-e bármi szükség ebben az implementációban? Bár a mikrokontroller magja az alkalmazás felélesztésében részt vesz, azonban mindössze a perifériák felkonfigurálásának erejéig. Talán még érdekesebb, hogy a megoldást egy ultraalacsony fogyasztású oszcillátorral értük el, és mégis rendelkezésre áll a mikrokontroller teljesítményének 100%-a, amelyet vélhetőleg értelmesebb célokra fordíthat a találékony alkalmazásfejlesztő.
Hiszen még programkód sincs!
Ha mindez felkeltette az olvasó érdeklődését, valószínűleg még nagyobb lesz az öröm, ha megtudja, hogy mindennek a gyakorlatba történő átültetéséhez nincs szükség adatlapok bújásár vagy akár egyetlen sornyi programkód megírására sem. Ezt látni kell ahhoz, hogy elhiggyük, úgyhogy az alábbiakat javaslom.
Az egyszerűség kedvéért az illusztráláshoz a kedvező árú MPLAB® Xpress fejlesztőkitet fogom használni, fedélzetén a PIC16F18855-tel, jóllehet, a magfüggetlen perifériákat támogató, PIC16F1-sorozatú mikrokontrollerek bármelyike felhasználható.
Kezdjük az MPLAB X integrált fejlesztőkörnyezet (IDE – Integrated Development Environment) „New Project” menüpontján keresztül elérhető varázsló betöltésével, amellyel az adott PIC mikrovezérlőmodell adottságainak megfelelő, új fejlesztési projektet hozhatunk létre! Használni fogjuk az MPLAB kódkonfigurátor (MCC – MPLAB Code Configurator) nevű, ingyenes MPLAB X IDE bővítményt is, amely értékes segítséget nyújt a perifériák inicializálásában és illesztésében. Egyszerűen válasszuk ki őket a „Device Resources” menüpontban közölt listából a nevükre történő dupla egérkattintással! Esetünkben a TMR4, TMR6, PWM6, PWM7 és az egyik CLC modulra kell kattintanunk (az alábbi példában az én választásom a CLC1-re esett).
A felső ablakban a „Project Resources” listánál (lásd 1. ábra) most már bármelyikre rákattinthatunk, és megvizsgálhatjuk konfigurációs párbeszédablakaik tartalmát. Ebben a részben ismerhetjük meg az egyes perifériák egyedi opcióit, lehetőségeit.
A projekterőforrásokat részletező lista tetején látható a „System”-csoport. A „System Module” ezek közül kitüntetett szerepet élvez, mivel a mikrokontroller olyan alapelemeit tartalmazza, mint az oszcillátorok és konfigurációs bitválasztások. Állítsuk az oszcillátort a „31kHz_LF” módba (lásd 2. ábra), amely mind közül a legalacsonyabb fogyasztású üzemmód!
A következő lépésben kattintsunk a PWM6 erőforrásra (lásd 3. ábra), válasszunk egy időzítőt időalapként, amely a 6-os számú lesz a mi feladatunkban! Minden egyéb beállítás már alapértelmezés szerint az, amire nekünk szükségünk lesz, így például az 50%-os kitöltési tényező és a neminvertáló kimeneti polaritás.
A TMR6-ra kattintva (lásd 4. ábra) ismét néhány értékkel szembesülünk, amelyek közül a periódusidőt állítsuk be 16,2 ms értékre!
Most kattintsunk a PWM7-re (lásd 5. ábra), az időalapját állítsuk a 4-es számú időzítőre, így választhatunk egy eltérő periódust!
Kattintsunk most a TMR4-re (lásd 6. ábra), és állítsuk át a periódusértéket 16 ms-ra!
Végezetül kattintsunk a CLC1 modulra, és konfiguráljuk be az első két bemeneti jelet úgy, hogy a PWM6 és PWM7 kimenetekre illeszkedjenek (lásd 7. ábra)! Vezessük őket a GATE1 és GATE2 pontokra, és válasszuk ki az „AND-OR” függvényt!
Ezután a „Pin Manager:Grid” ablakban hívjuk le az I/O konfigurációs hálózatot, amelyben egy vagy több csatlakozópontot a CLC1 kimenethez kell rendelnünk! A „Peripheral Pin Select” funkció jóvoltából a CLC kimenetről egy vagy akár több LED is vezérelhető. A mi példánkban válasszuk az RA0-2 lehetőséget, amely fizikailag az MPLAB Xpress fejlesztőkártyán elhelyezett négy LED-hez csatlakozik (lásd 8. ábra)!
Az erőforrásokat összefoglaló csoportban válasszuk ki a „Pin Module” lehetőséget, amelynek konfigurációs ablakában ellenőrizhetjük, hogy minden I/O csatlakozó az elképzeléseink szerint van-e konfigurálva (lásd 9. ábra)!
A „Generate Code” gomb megnyomása az MPLAB kódkonfigurátort indítja el, amely hat, kis méretű, C-nyelven íródott forrásfájlt hoz létre, amely a teljes perifériainicializálós programkódállományt tartalmazza. Az MPLAB kódkonfigurátor valójában még a fő programfájl megírását is átvállalhatja, amelyet mi természetesen örömmel elfogadhatunk, így jutalmunk a „main.c” nevű fájl lesz, amely tartalmazza a perifériainicializálás meghívó függvényeit és egy üres fő programhurkot is.
Ne lepődjünk meg, ha ezen a pontot azt mondom, hogy kérjük meg az MPLAB X IDE-t arra, hogy építse össze a projektet, és egy utolsó klikkeléssel a „Make and Program” gombra programoztassuk fel a kártyát! A fordító és programozó néhány másodperccel később abszolválja a feladatot, mi pedig elégedetten nézhetjük, ahogy az Xpress-kártya LED-jei lélegzést imitálva pulzálnak.
Mindezt kevesebb, mint tízsornyi bináris kódból
Talán érdekelheti az olvasót, hogy nemrég könyvem jelent meg „In 10 lines of code” címmel, amelyben ezt a feladatot húsz projekt egyikeként mutattam be, jóllehet, a jelen cikkben tárgyalt megközelítésben manuálisan egyetlen sor programkódot sem kellett írnunk. Néhány magfüggetlen periféria okos kombinációjából létre tudtuk hozni a lélegzést imitáló implementációt, maradéktalanul teljesítve feladatunkat, és megőrizve mikrokontrollerünk teljesítményének 100%-át az alkalmazás többi részfeladatának ellátásához. Az MPLAB kódkonfigurátor konfigurációját valamennyi programkóddal egyetemben a GitHub-on is meg lehet találni.
Érdekesség, hogy mióta ezeket a rövid mintafeladatokat megjelentetem, gyakrabban szembesülök azzal, hogy még a tapasztaltabb beágyazottrendszer-fejlesztők (a cikk elején említett kezdő kurzus résztvevőihez hasonlóan) mekkora meglepetéssel veszik tudomásul, hogy a magfüggetlen perifériák használata milyen jelentős előnyöket jelent a beágyazott rendszer valódi teljesítménye tekintetében. A magfüggetlen perifériák használata megköveteli azt, hogy a komfortzónánkból kilépve szakítsunk a magközpontú megközelítéssel, de miután egyszer rákaptunk az ízére, garantáltan függővé válunk.