Sulautettu reaaliaikakäyttöjärjestelmä¶
Osaamistavoitteet: Sulautetun ohjelmoinnin yleisiä periaatteita.
Aloitamme sulauttujen laitteiden ohjelmointiin perehtymisen käymällä ensin läpi ohjelman rakenteen (SensorTag-laitteessa) ja sitten lisäämme mukaan toiminnallisuuksia opettelemalla eri oheislaitekirjastojen käytön.
Reaaliaikakäyttöjärjestelmä¶
Sensortagin valmistaja (Texas Instruments) tarjoaa laitteen ohjelmointia helpottavan reaaliaikakäyttöjärjestelmän (engl. Real-time operating system, RTOS), jonka kirjastoja ja palveluita käytämme siis harjoitteluun ja lopuksi harjoitustyön toteuttamiseen. Tässä materiaalissa esitetään laitteelle ohjelmointiesimerkkejä, mutta parhaiten asioita oppii tietysti itse kokeilemalla ja tekemällä. Mutta aluksi muutamia aiheeseen liittyviä käsitteitä.
Käyttöjärjestelmä on tietokoneen sovelluksia pyörittävä ohjelmisto, jolla on kaksi pääasiallista tehtävää. Se tarjoaa suoritusympäristön sovelluksille ja hallinnoi tietokoneen laiteresursseja, oheislaitteita sekä käyttöoikeuksia. Käyttöjärjestelmä tarjoaa palveluita rajapintojen ja kirjastojen kautta sovelluksille näiden resussien käyttöön, mm. muistihallintaan, tiedostojärjestelmän, oheislaitteiden käyttöön ja tiedonsiirtoon järjestelmästä ulospäin. Käyttöjärjestelmä myös kontrolloi sovellusten suoritusta, jakaen prosessori(e)n suoritusaikaa ja muistia sovellusten kesken. Tarkemmin näitä asioita käsitellään myöhemmällä Käyttöjärjestelmät-kurssilla, joten ohitamme tässä kattavan esityksen.
Reaaliaikakäyttöjärjestelmä taas tarjoaa suoritusympäristön sulautettujen järjestelmien sovelluksille. Reaaliaikaisuus tässä yhteydessä tarkoittaa sitä, että käyttöjärjestelmä takaa toiminnallisuuksille tietyn vasteajan, esimerkiksi johonkin syötteeseen/tapahtumaan reagoidaan varmasti yhden millisekunnin sisällä ja reagointi saa kestää max 10 millisekuntia. RTOS itsessään voi olla hyvin kevyesti toteutettu, se voi esimerkiksi pelkästään jakaa prosessoriaikaa sovellusten kesken. Kevyt toteutus tukee myös osaltaan sovelluksia, joissa on tiukat reaaliaikavaatimukset, koska käyttöjärjestelmän omien rutiinien suoritukseen ei kulu juurikaan aikaa. RTOS:n palveluiden oma toteutus vaikuttaa siis merkittävästi sulautetun ohjelman suunnitteluun, toteutukseen ja ylläpitoon.
Kuten aiemmin esitettiin, sulautettuja järjestelmiä on toki mahdollista ohjelmoida ilman käyttöjärjestelmää ja/tai laiteohjelmistoa, mutta tällöin ohjelmoija on vastuussa laitteen vastaavien toiminnallisuuksien, kun oheiskomponenttien kytkemisestä mikrokontrolleriin ohjelmallisesti sekä sovelluksen tarvitsemien rajapintojen/palveluiden toteuttamisesta.
Sulautetun ohjelman toteutus¶
Kuten aiemmassa C-kielen materiaalissa todettiin, tietokoneohjelmien toteuttamisessa modulaarisesti on hyvinkin paljon järkeä ja myös järkeä. Sulautettujen
maailmassa myös ohjelman kokonaisuus on järkevää jakaa modulaarisesti eri tehtäviin, joiden toiminnallisuus voidaan loogisesti kapseloida, eli erottaa toisistaan. Nyt ohjelmassa jokaiselle tehtävälle määritellään omat syötteet mihin se reagoi ja omat vasteet.
maailmassa myös ohjelman kokonaisuus on järkevää jakaa modulaarisesti eri tehtäviin, joiden toiminnallisuus voidaan loogisesti kapseloida, eli erottaa toisistaan. Nyt ohjelmassa jokaiselle tehtävälle määritellään omat syötteet mihin se reagoi ja omat vasteet.
Esimerkiksi, kurssilla SensorTag-laitteessa tehtäviä voisi olla sensoridatan lukeminen, näytön päivitys tai langaton tiedonsiirto. Nojoo, nämä eivät ole vain esimerkkejä vain juuri niitä tullaan harjoitustyössä toteuttamaan..
Nyt on tietysti järkevää antaa RTOS huolehtia tehtävien rinnakkaisesta suorittamisesta, jotta vasteisiin voidaan vastata mahdollisimman tehokkaasti. Ohjelmoijan tehtäväksi jää sittensuoritettavan tehtävän toteutus ja sen suoritusparametrien määrittely tehokkuusvaatimukset huomioiden. Näitä suoritusparametrejä ovat esimerkiksi ajoitus, prioriteetti, muistin määrä, erilaiset alkuasetukset, jne. Tässä suhteessa sulautetun ohjelmoinnin opettelu on näiden valmiiden RTOS:n ominaisuuksien käytön opettelua kirjastojen, rajapintojen ja ohjelmistorakenteiden kautta.
Vaihtoehto olisi tietysti ohjelmoida RTOS tai laiteohjelmisto itse, tyyliin Arduinon superloop-rakenne (iso main-funktion sisäinen silmukka jossa on kaikki ohjelman toiminnallisuus). Kuten todettu, niin superloop on ok ratkaisu pienehköjen sulautettujen järjestelmien toteuttamiseksi, joilla ei ole kummoisia resurssi- eikä suoritusvaatimuksia. Mutta tässä menetetään ainakin iso osa modulaarisuuden hyötyjä ja ohjelmoija voi jopa vaikeuttaa ohjelman suoritusta. Ylläpidollisesti tällainen ratkaisu voi olla ns. painajainen, koska pienikin koodimuunnos saattaa muuttaa tarkasti hioittuja ajoituksia pieleen. Tuskin kukaan lähtisi itse toteuttamaan superlooppiin esimerkiksi eri tehtävien prioriteettien mukaista suoritusta, ratkaisu olisi väistämättä kömpelö. No, siellä työelämässä sulautettujen ohjelmointi onkin yleiseen työasemaohjelmointiin nähden oma taiteenlajinsa, kun päästään tekemään tehtäviä kovilla vaatimuksilla, oheislaiteajureita tai jopa omaa käyttöjärjestelmää.
Tehtävien toteutuksen ja suoritusparametrien määrittelyn lisäksi tehtävien toiminnan synkronointi edellyttää ratkaisuja. Esimerkiksi yksittäiseen syötteeseen, kuten napin painallukseen laitteessa, voi yksi tai reagoida useampi tehtävä tai se voi aiheuttaa sarjan peräkkäisiä toimintoja eri tehtävissä. Miten tällainen toteutus voidaan tehdä?
Itseasiassa, nyt aletaan mennä jo sinne Käyttöjärjestelmät-kurssin tontille, joten jätetään asiat sinne. Kuitenkin tähän on olemassa digitaalitekniikasta tuttu helpohko ratkaisu, jota tulemme käyttämään kurssilla, nimittäin tilakoneet. Kurssilla ei ole tarkoitus mennä syvemmälle tilakoneiden teoriaan (todella iso juttu), mutta käytämme niitä toteuttamaan tehtävien välistä synkronointia ohjelmassamme.
Lyhyesti tilakoneen idea on, että ohjelman looginen suoritus etenee tilasta toiseen syötteiden, tehtävien ja vasteiden kautta. Tätä varten ohjelmassa määritellään (ainakin yksi) tilamuuttuja, jonka arvoa muutetaan tapahtumaa ja tehtävää vastaavaksi. Tehtävät ja tapahtumiin reagoivat ohjelmistokomponentit (lue funktiot) saavat tiedon tilamuutoksesta ja toteuttavat sitä vastaan toiminnon. Sen jälkeen tila muuttuu seuraavaan tilaan ja siihen taas ohjelminstokomponentit reagoivat. Esimerkiksi tilamuutokset sulautetussa ohjelmassa voisivat aiheuttaa seuraavaa:
odotustila -> napin painallus -> luetaan sensoridata -> tulos näytölle/viestitys -> odotustila
Tässä esimerkissä ohjelmassa voisi olla kolme/neljä eri tehtävää: napin painallukseen reagoiva keskeytyksen käsittelijä, tehtävä sensorin kanssa kommunikointiin, tehtävä näytönpäivitykseen ja yhtäaikanen tehtävä langattomaan tiedonsiirtoon. Ehkä vielä tehtävä datan esikäsittelyyn, mutta tämä on suunnittelukysymys riippuen mm. siitä kuinka paljon dataa on. Nyt tämän loogisen toiminnallisuuden voisi tietenkin toteuttaa superloopiin perustuen, mutta tällöin kaikissa osatehtävissä pitäisi huomioida se missä tilassa ohjelman muut toiminnallisuudet ovat, esimerkiksi kommunikoidaanko juuri oheislaitteiden kanssa. Esimerkiksi yo. tilakoneessa emme voisi vastaanottaa viestejä samaan aikaan kun luemme sensoridataa.
Esimerkki. Tilakonepohjainen sulautetun ohjelman toteutus Arduinolle. Tämä sivu kannattaa vilkaista jo pelkästään yleiskuvan takia ja siksi että samantyyppistä ratkaisua tulemme käyttämään kurssilla. Noh, tästä lisää hetken päästä.
TI-RTOS:n esittely¶
Kuvassa lohkokaavio TI-RTOS:n, firmiksen ja laiteajurien tarjoamista valmiista toiminnallisuuksista SensorTag-laitteelle. RTOS tarjoaa ohjelmoijalle rajapintoja (kuvassa punainen alue), jotka piilottavat alemman tason toteutuksen yksityiskohdat, kuten laite-ja komponenttiajurit, reaaliaika-ominaisuudet ja tiedonsiirron detaljit. Tällä kurssilla meitä kiinnostaa sovellustaso, jossa käytämme erilaisia kirjastoja rajapintojen kautta (engl. application programming interface, API). Kurssilla pysymme punaisen alueen sisällä, jota syvemmälle laitteen toiminnassa ei tarvitse mennä.
Mainitsemme joitakin näistä kirjastoista jo nyt, mutta niiden käyttöön ohjelmissa perehdymme yksityiskohtaisesti myöhemmin luentomateriaalissa.
(Kiinnostuneille: Osa RTOS:n lähdekoodista tulee CCS:n asennuspaketin mukana. Niistä voi löytyä paljon muutakin mielenkiintoista, johon ei tässä materiaalissa perehdytä).
Palvelut ja kirjastot¶
Seuraavia kirjastoja tulemme käyttämään ohjelmien toteuttamisessa. Ao. terminologia käydään tulevassa materiaalissa kyllä läpi.
- Pin Kirjasto mikrokontrollerin I/O-pinnien hallintaan. Sensortagin painonappeja ja ledejä ohjataan tätä kautta. Myös GPIO-kirjastolla voidaan ohjata yleisiä I/O-pinnejä.
- Display Kirjasto tekstin ja grafiikan tuottamiseen LCD-näytölle.
- driverlib Laiterekisterit ja bittimaskit.
- I2C Kirjasto i2c-tiedonsiirtoväylän käyttämiseen. Moniin SensorTagin antureihin päästään käsiksi tällä kirjastolla.
- wireless_lib Kurssin henkilökunnan toteuttama kirjasto langattomaan tiedonsiirtoon 6LoWPAN-radioteknologialla.
- UART Sarjaliikenneprotokolla oheislaitteiden kanssa kommunikointiin. Esimerkiksi PC:lle voidaan lähettää dataa tai vastaanottaa komentoja PC:ltä tällä kirjastolla.
- (PWM Kirjasto Pulssinleveysmodulaation (PWM) tuottamiseen SensorTagin I/O-pinneillä. PWM:llä voidaan digitaalipinnistä syöttää analogista jännitettä tietyllä taajuudella vaikkapa ledin kirkkauden säätämiseen.)
(Kiinnostuneille: Tarkempaa tietoa kirjastosta löytyy TI-RTOS Kernel User Guide:sta ja TI RTOS User's Guide:sta.)
Ohjelman toiminta¶
Otetaan vielä esimerkiksi SensorTagin C-ohjelman main-funktio. SensorTagin RTOS:n ja kirjastojen C-kieli voi alkuun vaikuttaa kryptiseltä, koska käytetään niin paljon valmiiksi määriteltyä tavaraa. Mutta, tässä auttaa koodiin perehtyminen ja miettiminen, että mitä siinä oikeastaan tapahtuu.
Myös SensorTagin ohjelmalla on yksi main-funktio, josta ohjelman suoritus lähtee. Ok, RTOS tekee ensin omiaan piilossa taustalla ennen main-funktion suoritusta, mutta emme murehdi siitä tällä kurssilla.
Alla esimerkki SensorTag-ohjelman
main
-funktiosta:// SensorTagin kirjastot mukaan
#include <xdc/runtime/System.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/drivers/I2C.h>
#include <ti/drivers/PIN.h>
int main(void) {
// Hox! Esimerkin alusta on jätetty ao. muuttujien esittely pois
Board_initGeneral(); // alustetaan laite
Board_initI2C(); // alustetaan i2c-väylä käyttöön
// I/O-määritys jolla otetaan painonappi käyttöön
buttonHandle = PIN_open(&buttonState, buttonConfig);
if(!buttonHandle) {
System_abort("Error initializing button\n");
}
// Asetetaan painonapille sen tapahtuman käsittelijä (keskeytys)
// eli tässä funktio buttonFxn
if (PIN_registerIntCb(buttonHandle, &buttonFxn) != 0) {
System_abort("Error registering button callback function");
}
// Alustetaan sovellukseen yksi tehtävä, totetus taskFn-funktiossa
Task_Params_init(&taskParams);
taskParams.stackSize = STACKSIZE;
taskParams.stack = &taskStack;
taskParams.priority=2;
task = Task_create((Task_FuncPtr)taskFxn, &taskParams, NULL);
if (task == NULL) {
System_abort("Task create failed!");
}
// Kerrotaan debuggerin kautta, että laitteen alustus onnistui
System_printf("Initialization OK!\n");
System_flush();
// Käynnistetään RTOS (laiteohjelmisto BIOS),
// jolloin tehtävä lähtee suoritukseen
BIOS_start();
return 0;
}
Kuten kaikissa C-ohjelmissa, ohjelman alussa esikääntäjäkäskyillä tuodaan kirjastot ohjelman käyttöön. SensorTagin RTOS:n kanssa niitä onkin koko joukko, eikä tässä vielä (läheskään) kaikki.
Sen jälkeen
Lisäksi, esimerkissä haluamme käyttää I2C-kirjastoa kommunikointiin anturien kanssa, joten se alustetaan funktiokutsulla
main
-funktion alussa alustetaan itse laite. Itseasiassa, mitä tässä tehdään niin kerrotaan RTOS:lle että se pyörii SensorTag-laitteessa. Muistetaan että TI:n RTOS on yleinen käyttöjärjestelmä TI:n kaikille sulautetuille laitealustoille, joten siksi tämä tarvitaan ottamaan laitteen resurssit, olemassaolevat oheislaitteet, I/O-määrittelyt, laitekohtaiset kytkennät, jne.Lisäksi, esimerkissä haluamme käyttää I2C-kirjastoa kommunikointiin anturien kanssa, joten se alustetaan funktiokutsulla
Board_initI2C
. Kun laite on alustettu, otetaan ohjelmaan mukaan valitut oheislaitteet, tekemällä niille alustukset ja erilaiset I/O-määrittely. Esimerkissä otetaan ohjelman käyttöön toinen laitteen painonapeista ja kerrotaan napinpainalluksesta syntyvän tapahtuman (keskeytys) käsittelijä, eli tässä funktio
buttonFxn
. Jokainen SensorTagin tehtävä on siis C-kielinen funktio ja niiden kirjoittamiseen ja käyttöön pätee (varauksin) samat säännöt kuin C-kielen funktioiden yleensä. Sitten olisi main-funktiossa tilaa tehdä mahdollisia muita alustuksia ohjelman toiminnan ohjaamiseen. Esimerkiksi, jos käytämme ajastimia ohjaamaan taskien suoritusta, ne voidaan alustaa tässä.
Tämän jälkeen on hyvä lähettää terveisiä debuggerin avulla kehitysympäristön konsoli-ikkunalle, jotta näemme, että laitteen alustus on onnistunut. Konsoli-ikkunaan voidaan kirjoittaa
System_printf
-funktiolla, joka toimii (pienin poikkeuksin) samoin kuin C:n standardikirjaston printf-funktio. Muistetaanpas aiempi puhe siitä standardikirjastojen sulautetut toteutukset vaihtelee toteutettujen ominaisuuksien suhteen. Viimeiseksi, funktiossa käynnistetään "varsinainen" ohjelma eli taskien suoritus funktiokutsulla
BIOS_start
. Tämän jälkeen ohjelma vain ja ainoastaan reagoi tässä main-funktiossa määriteltyihin oheislaitteiden aiheuttamiin tapahtumiin. Huomatkaa, että koodissa käytetään paljon alustuksien jälkeisiä tarkistuksia varmistamaan, että alustukset menivät oikein. Nämä tarvitaan juuri siitä syystä, että sulautettuja ohjelmoidessa meillä on rajoitettu näkymä laitteen sisäiseen toimintaan..
Lopuksi¶
Näin olemme tutustuneet ohjelmien suorittamisen perusteisiin RTOS:ssa. Opettelemme RTOS:n kirjastojen käyttöä syvemmin kurssin laboratorioharjoituksessa.
Esimerkkikoodi yllä saattaa vaikuttaa kryptiseltä, aiemman selkeän C-kielen jälkeen, mutta kuten perehtymällä nähdään niin SensorTag-koodissa käytetään paljon valmiita kirjastoja, niiden funktiokutsuja, joilla on oma nimeämiskäytäntönsä, valmiita tietorakenteita, osoittimia ja vakioita. Lähemmin tarkastellen kuitenkin kyse on ihan samasta C-kielestä..
Anna palautetta
Kommentteja materiaalista?