Beágyazott és Ambiens Rendszerek 4. gyakorlat tematikája

Hasonló dokumentumok
Silabs STK3700, Simplicity Studio laborgyakorlat

Programozási segédlet DS89C450 Fejlesztőpanelhez

Az AVR programozás alapjai. Előadja: Both Tamás

Az MSP430 mikrovezérlők digitális I/O programozása

Mintavételes szabályozás mikrovezérlő segítségével

Az operációs rendszer szerkezete, szolgáltatásai

Az interrupt Benesóczky Zoltán 2004

C programozási nyelv

T Bird 2. AVR fejlesztőpanel. Használati utasítás. Gyártja: BioDigit Kft. Forgalmazza: HEStore.hu webáruház. BioDigit Kft, Minden jog fenntartva

HORVÁTH ZSÓFIA 1. Beadandó feladat (HOZSAAI.ELTE) ápr 7. 8-as csoport

Programozás C++ -ban 2007/7

A Memory Interface Generator (MIG) beállítása a Logsys Kintex-7 FPGA kártyához

Járműfedélzeti rendszerek I. 4. előadás Dr. Bécsi Tamás

loop() Referencia:

Mechatronika és mikroszámítógépek 2017/2018 I. félév. Bevezetés a C nyelvbe

T Bird 2. AVR fejlesztőpanel. Használati utasítás. Gyártja: BioDigit Kft. Forgalmazza: HEStore.hu webáruház. BioDigit Kft, Minden jog fenntartva

I. C8051Fxxx mikrovezérlők hardverfelépítése, működése. II. C8051Fxxx mikrovezérlők programozása. III. Digitális perifériák

Ingyenes DDNS beállítása MAZi DVR/NVR/IP eszközökön

Mintavételezés tanulmányozása. AD - konverzió. Soros kommunikáció

FELHASZNÁLÓI ÚTMUTATÓ

A vezérlő alkalmas 1x16, 2x16, 2x20, 4x20 karakteres kijelzők meghajtására. Az 1. ábrán látható a modul bekötése.

Labor gyakorlat Mikrovezérlők

Mikrorendszerek tervezése

Közegek és felületek megadása

ARM mikrovezérlők programozása

C++ programozási nyelv Konstruktorok-destruktorok

Programozás II. 2. Dr. Iványi Péter

C programozási nyelv Pointerek, tömbök, pointer aritmetika

4. Laborgyakorlat. A fájlokról ezeket az adatokat, a fájlrendszer tárolja. Számunkra az 1, 3, 4. oszlopok lesznek az érdekesek.

Programozás alapjai gyakorlat. 4. gyakorlat Konstansok, tömbök, stringek

Beágyazott rendszerek fejlesztése laboratórium DSP fejlesztési technológiák

Perifériák hozzáadása a rendszerhez

A függvény kód szekvenciáját kapcsos zárójelek közt definiáljuk, a { } -ek közti részt a Bash héj kód blokknak (code block) nevezi.

Dr. Schuster György október 14.

Az internet ökoszisztémája és evolúciója. Gyakorlat 1

KARAKTERFELISMERÉS AZ EVASYS-BEN

ÉRZÉKELŐK ÉS BEAVATKOZÓK I. GY1.1 SENSACT0 PÉLDAPROGRAM

Beágyazott és Ambiens Rendszerek

10. EGYSZERŰ HÁLÓZATOK TERVEZÉSE A FEJLESZTŐLAPON Ennél a tervezésnél egy olyan hardvert hozunk létre, amely a Basys2 fejlesztőlap két bemeneti

Mérési jegyzőkönyv. az ötödik méréshez

MSP430 programozás Energia környezetben. Kitekintés, további lehetőségek

Labor gyakorlat Mikrovezérlők

16F628A megszakítás kezelése

EDInet Connector telepítési segédlet

Digitális Technika. Dr. Oniga István Debreceni Egyetem, Informatikai Kar

Mechatronika és mikroszámítógépek. 2018/2019 I. félév. Külső megszakítások

SZÁMÍTÓGÉPEK BELSŐ FELÉPÍTÉSE - 1

Kameleon Light Bootloader használati útmutató

Választó lekérdezés létrehozása

Programozás II. 2. gyakorlat Áttérés C-ről C++-ra

VARIO Face 2.0 Felhasználói kézikönyv

VBA makrók aláírása Office 2007 esetén

BASH script programozás II. Vezérlési szerkezetek

HVK Adminisztrátori használati útmutató

Járműfedélzeti rendszerek II. 2. előadás Dr. Bécsi Tamás

Kézikönyv Számla-módozat rögzítése és alkalmazása

Digitális Technika. Dr. Oniga István Debreceni Egyetem, Informatikai Kar

Programozás C és C++ -ban

Programozás alapjai gyakorlat. 2. gyakorlat C alapok

SysCVideo: fiktív grafikus kártya SystemC modulként, SDL alapú megjelenítéssel

Tartalom jegyzék 1 BEVEZETŐ SZOFTVER ÉS HARDVER KÖVETELMÉNYEK 2 2 TELEPÍTÉS 2 3 KEZELÉS 5

MPLAB IDE - SIM - - Rövid ismertető a használathoz - Kincses Levente 3E22 89/ November 14. Szabadka

C++ programozási nyelv

A C programozási nyelv I. Bevezetés

A fő menüpontok között a bal vagy jobb nyíllal mozoghatunk, Enter leütésére pedig megjelenik az adott menühöz tartozó tartalom.

A programozás alapjai 1 Rekurzió

A nyomtatókkal kapcsolatos beállításokat a Vezérlőpulton, a Nyomtatók mappában végezhetjük el. Nyomtató telepítését a Nyomtató hozzáadása ikonra

Budapesti Műszaki- és Gazdaságtudományi Egyetem Villamosmérnöki és Informatikai Kar MIT. Nagyteljesítményű mikrovezérlők tantárgy [vimim342]

ARM Cortex magú mikrovezérlők

Programozás alapjai C nyelv 4. gyakorlat. Mit tudunk már? Feltételes operátor (?:) Típus fogalma char, int, float, double

MSP430 programozás Energia környezetben. Az első lépések

Új Nemzedék Központ. EFOP pályázatok online beszámoló felülete. Felhasználói útmutató

Moduláris USB billentyűzet emulátor

INFORMATIKA javítókulcs 2016

Levelező kliensek beállítása

Architektúra, megszakítási rendszerek

Kinek szól a könyv? A könyv témája A könyv felépítése Mire van szükség a könyv használatához? A könyvben használt jelölések. 1. Mi a programozás?

Labor gyakorlat Mikrovezérlők

Yottacontrol I/O modulok beállítási segédlet

A LOGSYS GUI. Fehér Béla Raikovich Tamás, Laczkó Péter BME MIT FPGA laboratórium

1) Kontírozás megkezdését megelőző lépések a Készlet modulban. A kontírozást a Készlet a főkönyvnek egy menüpont futtatásával adja át:

Minőségellenőrzési kérdőív kitöltő program Felhasználói kézikönyv

A C programozási nyelv I. Bevezetés

A Windows 7 operációs rendszerrel kompatibilis DS150E felhasználói útmutatója. Dangerfield,február 2010 V1.0 Delphi PSS

Labor 2 Mikrovezérlők

QGIS tanfolyam (ver.2.0)

3. A DIGILENT BASYS 2 FEJLESZTŐLAP LEÍRÁSA

SZÁMÍTÓGÉP ARCHITEKTÚRÁK

Pénzintézetek jelentése a pénzforgalmi jelzőszám változásáról

Felhasználói kézikönyv

3. Osztályok II. Programozás II

Szoftvertechnolo gia gyakorlat

Johanyák Zsolt Csaba: Ugráló gomb oktatási segédlet Copyright 2008 Johanyák Zsolt Csaba

Számítógép architektúrák

Digitális technika (VIMIAA02) Laboratórium 1

C programozás. 6 óra Függvények, függvényszerű makrók, globális és

_INVHU000_WriteReadParameter.cxf Frekvenciaváltók

A webáruház kezdőlapján háromféle diavetítés beállítására van lehetőség:

3. Ezután a jobb oldali képernyő részen megjelenik az adatbázistábla, melynek először a rövid nevét adjuk meg, pl.: demo_tabla

ConnectAlarm alkalmazás Központ/modul programozási segédlet V1.2 TL280 (R) v.4.x modulokhoz

Átírás:

Beágyazott és Ambiens Rendszerek 4. gyakorlat tematikája 1. Az UART0 használata Simplicity Configurator segítségével Az előző gyakorlaton mi magunk írtuk meg az UART0 perifériát a kívánt üzemmódba beállító kódot (főleg az emlib függvények segítségével, részben közvetlen regiszter hozzáféréssel). Végezzük el most ugyanezt a Simplicity Configurator használatával! (Emlékeztetőül a beállítani kívánt paraméterek: 115200 Baud, 8N1 keret formátum, PE0 használata TX jelként, PE1 használata RX jelként valamint PF7 magas értékűre állítása, hogy az UART0 periféria és a Board Controller közt engedélyezzük az összeköttetést.) 1.1. Simplicity Configurator projekt létrehozása Hozzunk létre egy új Silicon Labs projektet, és válasszuk a Simplicity Configurator Program típust! Egy egyszerű üres C projekthez képest három fontosabb új fájlt vehetünk észre: A.hwconf kiterjesztésű XML fájl tartalmazza a mikrovezérlő egyes moduljainak kívánt beállításait. A fájlt grafikus editor segítségével tudjuk szerkeszteni. Az InitDevice.(c h) állományok a.hwconf fájlban található beállításoknak megfelelő, automatikusan generált forráskódot tartalmazzák. A frissen létrejött projektben alapértelmezetten csak pár beállítás található (alapvetően azzal a céllal, hogy a GPIO perifériát bekapcsoljuk). Ezen beállítások a 14 MHz-es belső RC oszcillátort jelölik ki az órajel forrásaként, valamint engedélyezik a nagy frekvenciás periféria órajelet (általában és a GPIO periféria felé menő ágat is). A generált kódot speciális kommentek között találjuk (ezen részeket nem ajánlott kézzel szerkeszteni), például: // $[High Frequency Clock select] /* Using HFRCO at 14MHz as high frequency clock, HFCLK */ CMU_ClockSelectSet(cmuClock_HF, cmuselect_hfrco); /* Enable peripheral clock */ CMU_ClockEnable(cmuClock_HFPER, true); // [High Frequency Clock select]$ // $[Peripheral Clock enables] /* Enable clock for GPIO by default */ CMU_ClockEnable(cmuClock_GPIO, true); // [Peripheral Clock enables]$ 1

1.2. A virtuális COM port kivezetésének engedélyezése Konfiguráljuk be a PF7-es lábat kimenetnek ( Push-pull ), és állítsuk be logikai magas szintre! Ehhez a.hwconf fájl szerkesztése szükséges. A projekt létrehozása után ez a fájl jelenik meg alapértelmezetten a grafikus szerkesztői felületen (ha mégse látszódna, akkor a.hwconf fájlon kattintsunk duplán). A szerkesztői felületnek két alnézete van: DefaultMode Port I/O és DefaultMode Peripherals. Az előbbi a chip lábkiosztását mutatja, az utóbbiban pedig a mikrovezérlőben található perifériák beállítására van lehetőség. Nekünk most a lábkiosztás nézete kell. A PF7-es láb a BGA tok A sorának 6-os oszlopában van: Miután kijelöltük a PF7-es lábat, keressünk egy Properties nevű nézetet, és állítsuk be az alábbiakat: 2

(Megjegyzés: ne lepődjünk meg, ha elsőre a Data output sor helyett egy másikat ( Pullup ) látunk. Miután beállítjuk a láb módját Push-pull -ra, meg fog jelenni a Data output sor. Ezen a ponton kicsit furcsán működik a felület. Ha egérkattintással választunk ki egy opciót a legördülő listákból, akkor ahhoz, hogy érvényre is jusson a beállítás, még egy kattintás szükséges valahol az aktuális beviteli mezőn kívül. Alternatív megoldás, hogy kurzormozgató nyilakkal és ENTER billentyűvel végezzük el a beállítást. Ekkor normálisan működik a felület.) Mentsük el a változtatásokat (ez beletelik pár másodpercbe, ugyanis ekkor az InitDevice.(c h) fájlok automatikusan frissítésre kerülnek, hogy tükrözzék az általunk megtett beállításokat). Nézzük meg, hogyan jelenik meg az automatikusan generált kódban az, amit a grafikus felületen elvégeztünk! /* Pin PF7 is configured to Push-pull */ GPIO->P[5].DOUT = (1 << 7); GPIO->P[5].MODEL = (GPIO->P[5].MODEL & ~_GPIO_P_MODEL_MODE7_MASK) GPIO_P_MODEL_MODE7_PUSHPULL; A fenti kódrészlet az InitDevice.c fájlban található a PORTIO_enter_DefaultMode_from_RESET() függvény törzsében. Érdemes észrevenni, hogy a számunkra érdekes biteket kijelölő maszk inverzének segítségével először az összes érintett bitet nullázzuk, majd a szükségeseket egybe állítjuk. Mi az előző gyakorlaton abból indultunk ki, hogy reset után a bitek nullák, így csak az egybe állítással foglalkoztunk. Ha ezt nem feltételezhetjük, akkor a fenti, robusztusabb kód használata javasolt. Másik megjegyzés a fenti kódhoz, hogy itt direkt regiszter hozzáférést választottak az automatikus kód generátor készítői. Általánosságban azonban inkább az emlib funkcióit fogják a generált kódrészletek használni. Az InitDevice.h fájlban találhatóak a függvények prototípusai. Ezeken felül a saját beállításainkhoz tartozó kódrészletet is megtaláljuk: // $[User-defined pin name abstraction] #define VCOM_EN_PIN (7) #define VCOM_EN_PORT (gpioportf) // [User-defined pin name abstraction]$ 1.3. Az UART0 periféria felkonfigurálása Ehhez váltsunk át a konfigurációs fájl grafikus szerkesztőjének DefaultMode Peripherals alnézetére: 3

Rakjunk egy pipát az UART0 dobozba, hogy engedélyezzük a perifériát, majd végezzük el a szükséges konfigurációs paraméterek megadását ( Properties fül): 4

1.4. A használni kívánt lábak beállítása Először is meg kell mondanunk, hogy az UART0 jeleit (TX és RX) mely lábakra szeretnénk kivezetni. Az STK3700 kártya a Location 1 -el jelölt kombinációt feltételezi. Keressünk meg az Outline nézetet, és jelöljük ki a Port I/O sort: Ennek hatására egy másik, Peripheral Mapping nevű fülre is rákerül a fókusz (ha mégsem történne meg, akkor válasszuk mi ki). Itt görgessünk el az UART0 perifériához, és állítsuk be megfelelően: 5

Ezzel kiválasztottuk az UART0 által használni kívánt lábakat. Azonban ez még így nem elegendő (a fejlesztői környezet figyelmeztet is a hibára): A portok lábainak meghajtását ugyanis a GPIO periféria végzi. Így az RX lábat bemenetnek, a TX lábat kimenetnek ( Push-pull ) kell definiálni (továbbá ez utóbbit érdemes logikai magas értékre inicializálni, tekintve, hogy az UART kommunikáció nyugalmi állapota az 1). Menjünk tehát vissza a.hwconf szerkesztőjében a lábak nézetre ( DefaultMode Port I/O ), és végezzük el a kért beállításokat! 6

Mentés után nézzük meg, mi módosult az InitDevice.(c h) fájlokban! InitDevice.c extern void enter_defaultmode_from_reset(void) { // $[Config Calls] CMU_enter_DefaultMode_from_RESET(); UART0_enter_DefaultMode_from_RESET(); PORTIO_enter_DefaultMode_from_RESET(); // [Config Calls]$ } Látható, hogy a fő inicializáló függvény törzsébe bekerült az UART0 perifériát inicializáló függvény meghívása. Nézzük meg, mit tartalmaz ez a függvény: extern void UART0_enter_DefaultMode_from_RESET(void) { // $[UART_InitAsync] USART_InitAsync_TypeDef initasync = USART_INITASYNC_DEFAULT; initasync.baudrate = 115200; initasync.databits = usartdatabits8; initasync.parity = usartnoparity; initasync.stopbits = usartstopbits1; initasync.oversampling = usartovs16; #if defined( USART_INPUT_RXPRS ) && defined( USART_CTRL_MVDIS ) initasync.mvdis = 0; initasync.prsrxenable = 0; initasync.prsrxch = 0; #endif USART_InitAsync(UART0, &initasync); // [UART_InitAsync]$ // $[USART_InitPrsTrigger] USART_PrsTriggerInit_TypeDef initprs = USART_INITPRSTRIGGER_DEFAULT; initprs.rxtriggerenable = 0; initprs.txtriggerenable = 0; initprs.prstriggerchannel = usartprstriggerch0; } USART_InitPrsTrigger(UART0, &initprs); // [USART_InitPrsTrigger]$ 7

A helyes működéshez természetesen órajelet is kell adni az UART0 perifériának, így kiegészült a CMU-t beállító függvény is az alábbiakkal: /* Enable clock for UART0 */ CMU_ClockEnable(cmuClock_UART0, true); Valamint a portok beállítását elvégző függvénybe is bekerültek az RX, TX jelek által használt lábak beállításai: /* Pin PE0 is configured to Push-pull */ GPIO->P[4].DOUT = (1 << 0); GPIO->P[4].MODEL = (GPIO->P[4].MODEL & ~_GPIO_P_MODEL_MODE0_MASK) GPIO_P_MODEL_MODE0_PUSHPULL; /* Pin PE1 is configured to Input enabled */ GPIO->P[4].MODEL = (GPIO->P[4].MODEL & ~_GPIO_P_MODEL_MODE1_MASK) GPIO_P_MODEL_MODE1_INPUT; Valamint az általunk kért kivezetési mód: /* Module UART0 is configured to location 1 */ UART0->ROUTE = (UART0->ROUTE & ~_UART_ROUTE_LOCATION_MASK) UART_ROUTE_LOCATION_LOC1; /* Enable signals RX, TX */ UART0->ROUTE = UART_ROUTE_RXPEN UART_ROUTE_TXPEN; 1.5. A main.c módosítása Valamilyen oknál fogva a konfigurátor két apró, triviális módosításról megfeledkezik, jóllehet ezek szükségesek ahhoz, hogy a beállítások érvényre jussanak. Így ezeket nekünk kell megtennünk: Hivatkozzuk be az initdevice.h fejléc fájlt Hívjuk meg az enter_defaultmode_from_reset() függvényt a main()-ből A függvény meghívása után a mikrovezérlőnek az általunk a grafikus felületen beállított módon kell működnie. Próbáljuk is ki a kommunikációt (pl. a vett karakterek folyamatos visszaküldésével). #include "em_device.h" #include "em_chip.h" #include "InitDevice.h" #include "em_usart.h" int main(void) { /* Chip errata */ CHIP_Init(); } enter_defaultmode_from_reset(); /* Infinite loop */ while (1) { USART_Tx(UART0, USART_Rx(UART0)); } 8

Ahhoz, hogy az USART küldő és fogadó függvényeket használhassuk, természetesen be kell hivatkozni az em_usart.h fejléc fájlt. A hozzá tartozó forrás fájlt szerencsére nem kell nekünk hozzáadni a projekthez, az az UART0 engedélyezésekor automatikusan bekerült a projekt emlib alkönyvtára alá. 2. Megszakításkezelés (UART0 RX Data Valid) Az USART_Rx() függvény blokkol (addig nem tér vissza, amíg nem sikerül venni egy karaktert). Ez a fenti, egyszerű programban nem okoz gondot, de ha a főciklus bármi mást is szeretne csinálni, akkor már problémát jelentene. Egy lehetséges megoldás, ha először lekérdezzük a periféria státuszát (USART_StatusGet()), és csak akkor olvasunk, ha jött is valami. Viszont elképzelhető az az eset, hogy ideiglenesen több karakter is érkezik gyors egymásutánjában. Ekkor adatvesztés léphet fel, ha nem tudjuk azonnal kiolvasni a vett karaktert (mert a főciklus épp egy másik, időigényes feladatával foglalkozik). Ez utóbbi problémára megoldást nyújthatnak a megszakítások. A megszakítások tetszőleges kód futását meg tudják szakítani, és a kezelésükre hivatott kódrészlet így el tudja végezni az időkritikus feladatokat. A mi példánknál maradva ez a vett karakter kiolvasását jelenti egy bufferbe. Megjegyzés: a buffer méretének elegendően nagynak kell lennie ahhoz, hogy a rövid idő alatt jött karakterek feltételezett maximális száma mellett se legyen adatvesztés (ha üzemszerűen jönnek gyakrabban a karakterek, mint ahogy fel tudjuk dolgozni őket, akkor természetesen nincs akkora buffer, ami ezt ki tudná védeni). Mi most az egyszerűség kedvéért azt feltételezzük, hogy egy egy elemű buffer is elegendő, így egyszerűen egy bájtot fogunk használni a vett karakter eltárolására. (Az UART0 perifériában hardveresen így is van egy három elemű buffer, így a valóságban tulajdonképpen négy hosszú bufferünk van.) 2.1. Engedélyezzük az UART0 periféria RX Data Valid megszakítását Az első lépés az UART0 periféria megfelelő megszakításának engedélyezése. Ez legyen az RX Data Valid, ami akkor lép fel, ha van (legalább egy) kiolvasható karakter a periféria bufferében. Az engedélyezéshez az USART_IntEnable() függvényt használjuk! Első paramétere a kérdéses periféria (figyelem, ne keverjük össze az UART0 perifériát az USART0-val). A második pedig az engedélyezni kívánt megszakítás, amit az USART_IF_<megszakítás_rövid_neve> defineokkal tudunk kiválasztani (egyszerre akár többet is, ha összevagyoljuk őket). 2.2. Engedélyezzük az UART0 periféria vételi megszakítását a processzor oldalán is Az előző feladatpontban egyelőre csak azt oldottuk meg, hogy az UART0 periféria kérjen megszakítást, ha van új (még ki nem olvasott) adatt a vételi buffereiben. Ez azonban nem jelenti azt, hogy a processzor ki is fogja szolgálni ezt a megszakítást! Ehhez a processzor megszakítás vezérlőjében (NVIC 1 ) engedélyezni kell az UART0 periféria felől érkező vételi megszakítást. Megjegyzés: a vétellel kapcsolatban az UART perifériák több fajta megszakítást is kérhetnek (a fent említetten kívül tartozik megszakítás ahhoz is, ha pl. már teljesen tele van a buffer, vagy a vett 1 Nested Vectored Interrupt Controller 9

karakterben paritás hiba lépett fel). Az összes lehetséges, vétellel kapcsolatos megszakítás egy forrássá összefogva jelenik meg a processzor számára (UART0_RX). A megszakítás vezérlőben az egyes interrupt forrásokat engedélyezni az NVIC_EnableIRQ() függvénnyel lehet. Nézzük meg, hogy milyen típusú paramétert vár a függvény, és válasszuk ki a megfelelő értéket (figyelem, itt se keverjük össze az UART0 perifériát az USART0-val). 2.3. A megszakítás kezelő rutin megírása A megszakítás kezelő rutin (Interrupt Service Routine, ISR) a Cortex mikrovezérlők esetében hagyományos C nyelvű függvénnyel implementálható. Ezeket a startup kód előre definiáltan tartalmazza. Kezdőcímeiket pedig a startup kód be is írja a program memória elején található ún. megszakítás vektor táblába. Ha egy megszakítás érvényre jut, a hozzá tartozó címet innen nézi ki a processzor, és az éppen aktuális utasítás végrehajtása után a megjelölt címre ugrik. Nekünk tehát annyi a dolgunk, hogy a megfelelő névvel létrehozunk egy függvényt, amivel felüldefiniáljuk a startup kódban lévőt. Megjegyzések: A startup kódban található rutinokat weak szimbólummal kerültek definiálásra. Ez teszi lehetővé azt, hogy később mi felül tudjuk írni őket. A weak szimbólum nem standard C. Ezt ahány fordító, annyi módon oldják meg. Az, hogy egy megszakítás kezelő rutin hagyományos függvénnyel kiszolgálható, nem triviális. Az aktuális kód végrehajtása során a processzor belső regiszterei ugyanis meghatározott állapotot vesznek fel, ezt nevezik kontextusnak. Pl. az egyik általános célú regiszterben egy ciklusváltozó tárolódik, míg a legutóbbi aritmetikai utasítás bebillentett bizonyos biteket a státusz regiszterben, stb. Ha ezt tetszőleges ponton megszakítja egy interrupt, akkor a megszakítás kiszolgálására hivatott kód végrehajtása során potenciálisan felülíródhat az eredeti kontextus. Ez pedig gondot okoz majd a megszakításból való visszatérés során. Egyszerűbb architektúrák esetén a hardver automatikusan csak azt tudja, hogy hova kell majd visszatérni, de a kontextust kódból kell elmenteni. 2.3.1. Definiáljuk a megszakítás kezelő rutin függvényét Nézzük tehát meg, hogy milyen nevű rutin tartozik a startup kódban az UART0_RX megszakításhoz (a startup kód a CMSIS/EFM32GG/startup_gcc_efm32gg.s fájlban található)! Ezzel a névvel hozzunk létre egy függvényt a saját kódunkban (mind a visszatérési értéke, mind a paramétere void, továbbá itt se keverjük össze az USART0 perifériával az UART0-t)! 2.3.2. Olvassuk ki a vett karaktert Az ISR-ben értelem szerűen olvassuk ki a vett karaktert. Ezt egy globális változóba írjuk bele, hogy később majd a háttérben futó kód is hozzá tudjon férni. Kiolvasásra használható a már megismert USART_Rx(), azonban célszerűbb az USART_RxDataGet(). Az előbbi ugyanis a kilvasás előtt addig vár, ameddig a periféria nem jelzi egy megfelelő bit bebillentésével, hogy érkezett egy új karakter. Ez felesleges, ha már ISR-ünkben vagyunk, hisz az épp akkor hívódik meg, ha jött karakter. 2.3.3. Értesítsük a háttérben futó kódot A main() főciklusában futó kódot értesítsük az új karakter érkezéséről. Ezt szintén egy globális változón keresztül tudjuk megtenni (pl. egy bool, amit true-ra állítunk). 10

2.3.4. Nyugtázzuk a megszakítást Sok megszakítás esetében pusztán az a tény, hogy bekerültünk az ISR-be, nem nyugtázza az adott interruptot. Azaz az ISR-ből való kilépés után ismét fog egy ugyanolyan megszakítás keletkezni. Az interrupt kérést törölni pl. az USART_IntClear() függvény segítségével lehet. Az általunk használ megszakítás viszont olyan, hogy ha kiolvassuk a vett karaktert, akkor az egyben nyugtázásnak is megfelel, így explicit módon az interrupt nyugtázásától most eltekinthetünk. 2.4. A főciklus módosítása Módosítsuk a főciklust úgy, hogy vegyük ki a karakter fogadást (lévén azt most a megszakítás végzi el, és teszi bele egy globális változóba). Cserébe viszont a karakter visszaküldését tegyük feltétel függővé (azaz csak akkor történjen meg, ha jelzett nekünk a megszakítás). Természetesen ekkor a jelzést töröljük. 2.5. Fordítói optimalizációk hatása Próbáljuk ki, hogy mi történik, ha optimalizált módon fordítunk (ehhez a Release típusú build kell az eddigi Debug helyett). Jó eséllyel nem fog működni a programunk. Ennek az az oka, hogy az optimalizációk hatására a fordító kb. a következőképpen gondolkodik. Az a változó, amin keresztül az ISR jelez a főciklusnak, alapértelmezetten false értékű, és ezt követően sehol nem íródik át true-ra. Hisz ugyan az ISR függvényében van egy ilyen sor, de az ISR-t, mint függvényt, senki nem hívja meg, így nem is fog futni. Tehát a jelzésre használt változó végig false értékű. Így viszont a főciklusban a feltételhez kötött teljes kód kiszedhető, hisz úgyse fog soha lefutni, és feleslegesen minek foglalja a helyet a program memóriában. A probléma megoldható, ha a jelzésre használt változó definíciójába beírjuk a volatile kulcsszót is. Ez angolul illékonyat jelent. Azt mondjuk meg vele a fordítónak, hogy a megjelölt változó mögötti memória tartalma bármikor megváltozhat, így ne próbáljon meg optimalizálni, hanem minden hozzáféréskor ténylegesen olvassa ki az adott változót. Megjegyzés: nagy valószínűséggel a probléma csak a jelzésre használt változót érinti. A karakter átadására használt változó esetén nincs ilyen gond. Jóllehet, a fenti logika szerint ott is lehetne egy picit spórolni azzal, ha nem végeznénk el a változó kiolvasását minden ciklusban, hanem a kezdeti értékét feltételeznénk mindig. Talán azért, mert ez már nem jelentene nagy előnyt, talán más okból kifolyólag, de itt nem optimalizál a fordító. Mindenesetre, ha így is van, ezt a változót is jelöljük meg a volatile kulcsszóval! 3. Energia hatékony működés Nem túl hatékony dolog egy főciklusban folytonosan arra várakozni, hogy bebillenjen egy változó. A processzorokat általában el lehet altatni valamilyen mélységig, amiből általában megszakítások hatására fel tudnak ébredni. A Giant Gecko mikrovezérlők esetén is több ilyen mód van. A legegyszerűbb esetben csak magát a CPU-t tesszük el aludni (nem kap órajelet), de a többi periféria üzemel. Ezt EM1-nek nevezik. Nézzük meg először, hogy mennyit fogyaszt jelenleg a panel! 11

Ezt követően módosítsuk a kódot úgy, hogy a főciklusban léptessük be a processzort az EM1 módba! Az energiatakarékos üzemmódok közti váltásért a mikrovezérlő EMU (Energy Management Unit) perifériája felel. Így az emlib forrás fájlok közül az em_emu.c -re lesz szükségünk. Ez valószínűleg alapértelmezetten is része a projektnek. Ha nem, tegyük be! A használandó függvény az EMU_EnterEM1(). Ahhoz természetesen, hogy ezt meg tudjuk rendesen hívni, hivatkozzuk be az em_emu.h fejléc fájl! Nézzük meg, sikerült-e csökkenteni a fogyasztást. Megjegyzés: tekintettel arra, hogy most csak egy megszakítást használunk, felébredés után biztosak lehetünk abban, hogy érkezett egy karakter. Így akár a jelzésre használ változó és annak kezelése mellőzhető. 4. Az LCD használata 4.1. Gyári függvények segítségével A panelen található LCD használata az SDK részét képező függvényeknek hála igen egyszerű. A szükséges fájl a segmentlcd.c. 2 Ezt adjuk hozzá a projekthez (pl. egy drivers almappába). A benne található függvények deklarációi pedig a segmentlcd.h headerben vannak, így ezt hivatkozzuk be. Mivel az LCD vezérlésére a mikrovezérlőben található LCD kontroller perifériát használja a segmentlcd.c, ezért szükséges még az em_lcd.c 3 fájl hozzáadása is a projekthez. Az LCD-t használat előtt inicializálni kell, erre a SegmentLCD_Init() használható. Egyetlen paramétere az erősebb meghajtást engedélyezi. Alapvetően e nélkül is jók vagyunk, így legyen fasle (ha valakinél nagyon gyenge az LCD képe, ki lehet próbálni true megadásával, hátha jobb lesz tőle). Az LCD-re írást kipróbálhatjuk pl. úgy, hogy a főciklusunkat kiegészítjük a vett karakter ASCII kódjának kiírásával (SegmentLCD_Number()). A többi függvény használata self explanatory. 4.2. Szegmensenkénti meghajtás A házi feladatokhoz szükséges, hogy az LCD alsó felén elhelyezkedő, hét darab alfanumerikus karakter kiírására alkalmas kijelzőt szegmensenként is tudjuk vezérelni. Ehhez a gyári SDK nem ad támogatást. Azt nekünk kellett kiegészíteni, módosítani. Ehhez van egy demo projekt (displaysegmentfield). Ezt be lehet importálni, és meg lehet nézni, hogyan kell használni. Mivel viszonylag egyértelmű, ezért alapvetően ez is self explanatory 5. Stdio használata (UART0) Az UART0 perifériát eddig direkt módon használtuk az USART_Rx() és USART_Tx() függvények segítségével. Azonban hordozhatóbb kódot kapnánk, ha helyettük a standard getchar(), putchar() függvényeket tudnánk használni. Nem beszélve pl. a printf() nyújtotta kényelemről. Szerencsére a C nyelv standard I/O-ja átirányítható. A magas szintű, általunk használható rutinok alacsonyabb szintű függvényeket használnak, amik olyan alap funkció ellátására képesek, mint egy 2 A most használt virtuális gépen itt található: C:\SiliconLabs\SimplicityStudio\v4\developer\sdks\gecko_sdk_suite\v1.1\hardware\kit\common\drivers 3 Az emlibhez tartozó fájlok pedig itt: C:\SiliconLabs\SimplicityStudio\v4\developer\sdks\gecko_sdk_suite\v1.1\platform\emlib\src 12

karakter küldése, fogadása, stb. Ha ezen függvényeket úgy valósítjuk meg, hogy pl. egy UART perifériát használjanak, akkor végeredményben pl. egy printf() is a soros portra fog írni. 5.1. A szükséges fájlok hozzáadása Ahhoz, hogy működjön a standard I/O átirányítása, két fájlra van szükségünk: retargetio.c és retarget<periféria>.c (a mi esetünkben retargetserial.c). A retargetio.c egy nagyon vékony szoftver réteget definiál, amiben azon részeket tették bele, amik közösek, akármelyik konkrét perifériára is akarjuk átirányítani a standard be- ill. kimenetet. A másik pedig a választott perifériára implementált kódrészleteket tartalmazza. Adjuk hozzá tehát a projekthez (pl. egy drivers almappa alá) a következő fájlokat 4 : retargetio.c retargetserial.c Megjegyzések: Ha belenézünk a fájlokba, látszik, hogy a karakterek fogadása interrupt segítségével történik. Így tehát a retargetserial.c használata esetén mi magunk már nem használhatjuk a kiválasztott U(S)ART periféria Rx Data Valid megszakítását. Továbbá érdemes észrevenni, hogy a getchar() akkor is vissza fog térni, ha nincs fogatott karakter, csak épp -1 a visszatérési érték (ergo nem blokkol ez a függvényhívás). A fenti fájlok igényelnek más egyéb fájlokat. Attól függően, hogy milyen projekthez adtuk őket hozzá, több-kevesebb egyéb fájlt is hozzá kell tennünk. Első körben a retargetserial.c -nek triviális függése az alábbi, mivel a soros portra irányítunk át. Ha ez nem lenne benne a projektben, adjuk hozzá (pl. az emlib mappa alá): em_usart.c Mivel a soros porti perifériák meghajtásához kell órajel, a lábaikat megfelelően ki kell vezetni, továbbá a beállításuk során az emlib használ egyéb alap függvényeket, az alábbi három fájl is kell (ha már nem tartalmazná a projekt): em_core.c em_cmu.c em_gpio.c 5.2. A használni kívánt soros port kiválasztása Ezt preprocesszor direktívákkal tudjuk megtenni, amiket a projekt számára előre definiálnunk kell (ekkor a fordítás során parancssori paraméterként kerülnek átadásra). Két érték kell: RETARGET_UART0, hogy az UART0-t használjuk, és RETARGET_VCOM, hogy engedélyezzük is az UART0 kivezetését a Board Controlleren keresztül az USB portra mint virtuális soros port. A define-ok értéke legyen 1-1. Ezt az alábbi helyen tudjuk megtenni (Project / Properties): 4 A most használt virtuális gépben itt vannak: C:\SiliconLabs\SimplicityStudio\v4\developer\sdks\gecko_sdk_suite\v1.1\hardware\kit\common\drivers 13

1. 2. 3. 5. 4. 5.3. Használata Hivatkozzuk be először is az alábbi kettő fejlécet: stdio.h retargetserial.h Ezt követően hívjuk meg az alábbit: RETARGET_SerialInit() Opcionálisan az alábbit is meghívhatjuk: RETARGET_SerialCrLf() Ennek ha igaz értéket adunk paraméterül, akkor bármelyik sorvég karaktert is küldjük ki (\r (carriage return, kocsi vissza) vagy \n (new line, line feed, új sor, sor emelés)) automatikusan beszúrja a másikat. Így kicsit kényelmesebb a printf() használata. Ezek után az alábbinak már működnie kell: printf("hello!\n"); 14