Embedded Systems Chapter 6 Specijalne softverske tehnike Programske
Embedded Systems - Chapter 6 -
Specijalne softverske tehnike Programske tehnike koje su tipične za embedded sisteme: Manipulisanje hardverom Obrada prekida
Manipulisanje hardverom Programeri embedded sistema često treba da kreiraju kôd koji direktno manipiliše radom nekog perifernog uređaja. U zavisnosti od tipa arhitekture, taj uređaj može biti port-preslikani ili memorijskopreslikani. Ako arhitektura podržava izdvojeni U/I adresni prostor, a uređaj je port-preslikani, tada ne postoji drugi način nego da se kôd "spusti" na asemblerski jezik i na taj način obavi aktuelna manipulacija. Razlog za ovakav pristup je sledeći: Kod C-a ne postoji mogućnost direktne manipulacije portovima. Kod nekih C kompajlera postoji mogućnost korišćenja specijalnih CPU-ovih interno ugrađenih funkcija koje se u trenutku prevođenja zamenjuju CPU-ovim specifičnim asemblersko-jezičkim operacijama. To znači da kod specifičnih mašina, interne funkcije omogućavaju programeru da izbegne in-line asemblerski kôd. Sa druge strane stvari se znatno jednostavnije rešavaju ako je uređaj memorijsko-preslikani.
In-line asembliranje • Ako je potrebno da se čita ili upisuje u neki port, tada in-line asembliranje predstavlja verovatno najjednostavnije rešenje. • No, in-line adresiranje je uvek jako zavisno od kompajlera. - Neki proizvođači koriste: a) direktivu #pragma da bi izbegli asemblerske instrukcije, b) drugi koriste specijalne simbole kakvi su _asm/_endasm, c) a treći smeštaju asemblerski kôd u nešto liči na funkcijski poziv kao što je to prikazano na sledećem primeru Jedini način da se zna šta se od pojedinog kompajlera očekuje da obezbedi (ili da on dozvoljava in-line asembliranje) je da se konsultuje dokumentacija o kompajleru.
In-line asembliranje S obzirom da je in-line asembliranje zavisno od kompajlera, dobra ideja se sastoji u sledećem: Treba grupisati (wrap) sve asemblerske operacije u posebne funkcije, i memorisati ih u poseban fajl. Tada, ako postoji potreba za promenom kompajlera, pogodnost ovog pristupa je ta što će se promeniti asemblerski kôd samo na jednom mestu. Na primer, ako je potrebno da se upiše ili pročita neki registar-uređaja čija je port adresa 0 x 42, tada je potrebno kreirati funkcije pristupa na sledeći način
Kompajler ne podržava in-line asembliranje Za slučaj da kompajler ne podržava in-line asembliranje, neophodno je kreirati slične Read/Write funkcije na asemblerskom jeziku, a zatim ih povezati sa ostatkom programa. Pisanje funkcija na asemblerskom jeziku je znatno složenije iz razloga što mora biti u skladu sa konvencijama koje koristi kompajler, a odnose se na okvire magacina. Moguće je koristiti šablon za asemblerski jezik, ako se iskompajlira jednostavna funkcija na C-u koja direktno manipuliše sa korektnim brojem argumenata na asemblerskom jeziku.
Pristup memorijsko preslikanim adresama Manipulisanje memorijsko-preslikanim uređajima je relativno jednostavno. Najveći broj okruženja podržava dva metoda: a) bazirani-na-linker-u; i b) bazirani na pokazivačima. Metod baziran na linker-u koristi kvalifikator tipa extern kako bi informisao kompajler o tome da kompajler koristi resurs koji je definisan van granica programa. Linija ukazuje kompajleru da resurs obima integer, nazvan device_register, egzistira van granica programa, i nalazi se na mestu koje linker poznaje. Sa ovakvom deklaracijom ostatak programa može da čita i upisuje iz/u uređaj upravo kao da je to globalna promenljiva.
Kako linker zna gde je lociran uređaj ? Da bi uspešno povezali program sa ovim tipom eksterne deklaracije, neophodno je koristiti komandu linker-a da bi promenljivoj pridružili ime koje je odgovarajuće za tu adresu. Ako registar o kome je reč je lociran na adresi $40000000, tada komanda može biti oblika Oni koji preferiraju ovaj metod treba da koriste linker kako bi odgovarajuće simbole pridružili fizičkim adresama. Sa druge strane, oni koji za deklaraciju registra-uređaja koriste extern treba da pamte na jednom mestu svu informaciju o sistemsko-memorijskoj mapi koja se nalazi (čuva) u komandnom fajlu linkera.
Alternativni pristup memorijsko-preslikanom hardveru Alternativno, pristup memorijsko-preslikanom hardveru moguće je postići pomoću pokazivača na C-u. Jednostavni cast iskaz može da uslovi pokazivača da adresira bilo koju memorijsku lokaciju. Na primer, program može da manipuliše ASIC-uređajem koji se vidi od strane softvera kao polje od 64, 16 -bitnih, memorijsko-preslikanih registara koji počinju od memorijske adrese 0 x 40000000, koristeći se sledećim kôdom: Ovaj primer deklariše io_regs da bude pokazivač na neoznačenu 16 -bitnu (short) promenljivu. Treći iskaz dodele koristi cast sa ciljem da uslovi io_regs da ukaže na memorijsku lokaciju 0 x 40000000. cast operator usmerava kompajler da ignoriše sve što zna o tipu provere i uradi ono što programer upravo želi.
Pobitne operacije U programima embedded sistema često se javlja potreba za manipulisanje sadržajem pojedinih bitova koji su sastavni delovi hardverskih registara. U najvećem broju slučajeva, sa praktične strane najbolje je da se pročita sadržaj celokupnog registra, promeni vrednost bita, a zatim promenjena vrednost, ako postoji potreba, ponovo upiše u registar uređaja. Na primer, da bi se promenio sadržaj trećeg bita sa desne strane, koristi se sledeći kôd: Isti efekat se postiže korišćenjem sledećih operatora dodele
Maska Literal koji odgovara bitu koga treba promeniti naziva se maska. Definisanje konstante koja predstavlja masku (status_mask) izoluje ostatak kôda od nepredvidivih promena u hardveru (ili u nerazumevanju hardvera od strane programera). Konstanta takođe može značajno da poboljša čitljivost ovog tipa kôda. Naglasimo da svi embedded kompajleri podržavaju ANSI C const. Za slučaj da kompajler ne podržava const, neophodno je koristiti preprocesor čiji je zadatak da statusnoj maski dodeli simboličko ime. Forma const se preferira jer ona podržava statički tip provere.
Promena vrednosti bita Da bi se promenila vrednost bita potrebno je preduzeti sledeće aktivnosti: pročitati shadow registar modifikovati shadow registar zapamtiti vrednost shadow registra upisati novu vrednost u uređaj U svojoj najkompaktnijoj formi, kôd treba da ima sledeći oblik
Korišćenje storage klase modifikatora volatile Važan atribut koji se često izostavlja a koristi se za modifikaciju podataka kada se kôd na HLL-u C ili C++ spregne sa hardverom perifernog uređaja je modifikator storage klase nazvan volatile. Najveći broj kompajlera polazi od pretpostavke da je realna memorija u suštini prava memorija, i u cilju optimizacije kôda, čini određene pretpostavke o karakteristikama te memorije. Ključna pretpostavka je sledeća: Vrednost koja se čuva u memoriji neće se promeniti ako se u nju ne upiše novi podatak. Ipak, sadržaj hardverskoperiferijskih registara stalno se menja. Ilustracije radi, razmotrimo slučaj UART-a. UART prima serijske podatke od spoljnjeg sveta, izbacuje ekstra bitove (parnost, start bit, stop bitove), i predaje bajt podataka CPU-u radi čitanja.
Primer UART usklađuje brzinu prenosa podataka na osnovu stanja statusnog bita, nazvan TBMT (Transmitter Buffer Empty). U konkretnom primeru, TBMT bit se postavlja na nisko kada se bajt podataka preda UART-u i ostaje na nisko sve dok se vrši serijska predaja. Kôd za ovaj primer je dat sledećim listingom:
Ključna reč volatile se koristi da ukaže kompajleru da ne napravi bilo kakav pokušaj usmeren ka promeni mesta te memorijske lokacije u memorijskoj hijerarhiji. Time se obezbeđuje da se sadržaj te memorijske lokacije može spontano menjati, i da se uvek direktno čita i upisuje u tu lokaciju. Shodno preporukama, kompajler neće pokušati da optimizira pristup toj promenljivoj, a takođe neće dozvoliti i da se ona čuva u kešu. Neki kompajleri koriste i specijalne ključne reči koje omogućavaju da se promenljive takvog tipa nikada ne nalaze u kešu.
Brzina izvršenja i obim kôda U velikom broju slučajeva u situacijama kada se operacije pristupa memoriji izvršavaju koristeći pokazivače, a ne putem standardnog (direktnog) referenciranja promenljivih, kompajler generiše veoma efikasan kôd, kako u pogledu obima kôda, tako i u pogledu brzine izvršenja. Tako na primer, kada funkcija manipuliše istom promenljivom po nekoliko puta, ili zaredom pristupa elementima vektora (polja), tada referenciranja koja se baziraju na korišćenju pokazivača rezultiraju efikasnijem kôdu. Sledeća kratka sekvenca na C-u prevodi se u sekvencu asemblersko-jezičkih instrukcija koja je oblika
Brzina izvršenja i obim kôda – prod.
Prekidi i rutine za obradu prekida Prekidi u suštini predstavljaju "život" svih računarskih sistema. Ako je CPU u stanju da prihvati prekid, on prolazi kroz ciklus prihvatanja zahteva za prekid, u toku koga po automatizmu obavlja sledeće aktivnosi: v smešta povratnu adresu naredne instrukcije u magacin v pribavlja adresu ISR-a (vektor) iz tabele-izuzetaka i skače na tu adresu u memoriji radi izvršenja naredne instrukcije, nakon ovoga prelazi na izvršenje ISR-a v CPU odlučuje kada da zabrani i ponovo dozvoli rad novim prekidima v sačuva stanje internih resursa (registara) koji se koriste od strane ISR-a v da se odredi koji od uređaja je generisao zahtev za prekid (posebno ako su zahtevi deljivi) v izvrši ISR kôd v resetuje eksterne uređaje koji su generisali zahtev za prekid (ako je to neophodno) v obnovi stanje sistema v dozvoli rad drugim prekidima v obavi povratak iz prekidnog u prekinuti program.
Od polling-petlje do interrupt-driven Dijagram toka alarmnog sistema Kada broj U/I periferija postane dovoljno veliki tada vreme odziva na neki događaj kao i njegovo opsluživanje korišćenjem programirane U/I tehnike može da postane kritično pa se zbog toga rešenje traži u korišćenju interrupt-driven tehnike.
Watchdog tajmeri Kada se u toku rada embedded sistema javi greška koja može da dovede rad sistema u blokadu, tada watchdog (pas čuvar) ima zadatak da ponovo vrati sistem u normalni režim rada, tj. u život. Naglasimo pri ovome da je rad svih visoko-pouzdanih sistema nezamisliv bez watchdog tajmera. Osnovna ideja je jednostavna. Pretpostavimo da je za izvršenje main programske petlje u proseku potrebno 25 ms, a u najgorem slučaju 35 ms. Usvojimo sada da je u sistem instaliran gradivni blok tipa watchdog tajmer koji je povezan na prekid najvišeg nivoa opsluživanja, kakav je, recimo RESET ili NMI. Neka se nakon trigerovanja watchdog tajmera čeka 50 ms, a zatim, ako trigerovanje izostane, neka se aktivira signal na ulazu pina RESET, uslovljavajući da procesor startuje izvršenje programa od početka. Jedini način da se spreči da do reseta sistema ne dođe je da se koristi retriggerable monostabilni multivibrator postavljen na ulazu RESET pina CPU-a koji će se okidati svakih 50 ms i držati pin RESET na neaktivno stanje.
Dijagram toka rada. Watchdog tajmera
Fleš memorija Fleš memorije veoma brzim tempom zamenjuju ostale non-volatile memorijske tehnologije kao projektantsko rešenje za memorisanje firmware-a embedded sistema. Sa tačke gledišta embedded sistema, fleš memorije su atraktivne jer se mogu reprogramirati na licu mesta (in the field). Najstandardniji metod nazvan in-circuit programmibility, znači da se one mogu reprogramirati na samoj štampanoj ploči bez da postoji potreba za dovođenjem specijalnih napona napajanja za programiranje. Korišćenje fleš memorije omogućava projektantima embedded sistema da modifikuju performansne parametre u toku rada sistema čime se ostvaruje optimizacija (optimalna podešenost) u odnosu na tekuće stanje operativnog okruženja.
Memorijski prostor fleša Projektanti embedded sistema najčešće predlažu da se u memorijskom prostoru fleša čuvaju sledeća tri nezavisna programa: Ø Ø bootloader - je program koji se izvršava nakon power-up sistema. Ø realni aplikacioni kôd - koji se može reprogramirati pomoću algoritma za reprogramiranje fleša. RAM rezidentni algoritam za reprogramiranje - kojim se obavlja aktuelno reprogramiranje uređaja. Ovaj kôd je lociran u zaštićenom regionu fleša i kopira se u RAM kada se izabere opcija za reprogramiranje.
- Slides: 23