This is an old revision of the document!


Tarkvaraline viide

Vajalikud teadmised: [HW] controller, [AVR] AVR arhitektuur, [LIB] Viikude teek, [LIB] Viite teek

Teooria

Tihti on mikrokontrollerite programmis vaja tekitada viiteid, et tegevusi ajastada või nende lõppu oodata. Üks idee poolest lihtsamaid meetodeid mikrokontrolleri tegevuses paus tekitada on selle protsessor mingi muu tegevusega üle koormata - näiteks panna see lugema suuri numbreid. Protsessori taktsagedusest saab välja arvutata mitmeni see numbreid loendama peaks, et kindlat ajalist viidet tekitada. Teoreetiliselt tekitaks siis mingi arvu loendamine nullist protsessori taktsageduse väärtuseni hertzides viite üks sekund. Praktikas see päris nii lihtne ei ole ning põhjuseid on mitmed.

Kui mikrokontrolleri protsessor arvutab arvudega mille kahendkuju on sama lai kui selle sisemine siin (AVR puhul 8-bitti) siis protsessoritel võtab üks aritmeetiline tehe, näiteks arvu liitmine ühega, aega 1 protsessori töötakt. Selleks, et arvutada tuhandete või miljonitega peab arv olema 16- või 32-bitine ja nende arvutamiseks kulub 8-bitistel protsessoritel rohkem kui 1 töötakt. Niisiis, suurte arvude puhul peab tundma protsessori sisemust - täpsemalt selle käsustikku.

Kuna kõrgtaseme keeles (näiteks C keeles) programmeerides ei kirjutata programm otse käsustiku baasil, peab tarkvaralise viite tekitamiseks tundma ka kompilaatorit, mis programmi masinkoodi teisendab. Just sellest sõltub mitu instruktsiooni (ja sellest tulenevalt mitu takti) kulub aritmeetilisteks arvutusteks. Keerukust lisab veel asjaolu, et kompilaator võib programmi masinkoodi teisendada mitut moodi - näiteks tehes masinkoodi võimalikult mälusäästlikuks või võimalikult kiiresti täidetavaks. Neid kompilaatori tegevusi nimetatakse optimeerimiseks. Erinevate optimeerimise režiimidega tuleb ka tarkvaralise viite masinkood ja selle ajaline kestvus erinev.

Praktika tutvustus

Järgnevalt on toodud näide tarkvaralise viite tekitamisest AVR mikrokontrolleriga. Kirjutatud on C keele programmilõik mis loendab for tsüklis muutujat x nullist sajani. Iga tsükli sees toimub ühe mitte-midagi tegeva tühi-instruktsiooni täitmine. Seda on seal vaja, kuna tsükli sisu tühjaks jättes kompilaator optimeerib tsükli programmist üldse välja kuna see on tema arvates kasutu.

unsigned char x;
 
// Tsükkel seni kuni x on 100
for (x = 0; x < 100; x++)
{
	// Tühi-instruktsiooniga nop
	asm volatile ("nop");
}

Siinkohal on aga toodud sama C-keele programmilõik pärast kompileerimist. Vasakpoolsed 2 heksadetsimaalarvu on masinkood ja paremal on assembler-keeles sõna koos operandi(de)ga. Masinkood ja assembler-keel on üks-üheselt seotud, assembler on lihtsalt masinkoodi inimesele loetaval kujul esitamiseks. Kompileerimisel on kasutatud programmi pikkuse optimeerimist (-Os).

80 e0     ldi  r24, 0x00   ; r24 registrisse arvu 0 laadimine
00 00     nop              ; Tühioperatsioon
8f 5f     subi r24, 0xFF   ; r24 registrist 255 lahutamine, ehk +1 liitmine
84 36     cpi  r24, 0x64   ; r24 registri võrdlemine arvuga 100
e1 f7     brne .-8         ; Kui võrdlus oli väär, siis siire 8 baiti tagasi

Kompileeritud kujul on näha mis tegelikult C-keele tsüklist saab ja selle järgi saab arvutada mitu instruktsiooni ühe tsükli perioodi puhul täidetakse. Antud näites kulub ühes tsükli perioodis 4 instruktsiooni täitmiseks 4 takti. Oletades, et kontrolleri töötakt on 14,7456 MHz võib välja arvutada kogu tsükli tekitatud ajalise viite:

100 * 4 / 14745600 = 27.13 μs

Näites tekitatud viide on mikrosekundites ja muutujat mida kasutatakse on 8-bitine, seega on ka masinkood üsna lihtne. Selleks, et tekitada pausi millisekundites on vaja palju suuremaid arve loendada ja siis läheb masinkood pikemaks. Võib kasutada ka üksteise sees töötavaid tsükleid kuid selle meetodi puhul pole kogu viide lineaarses sõltuvuses tsüklite arvust, sest iga tsükli tasemega tekivad pisikesed lisaviited.

Käesoleva harjutuse eesmärk ei ole siiski masinkoodi tasandil täpset tarkvaralist viidet tekitada, sest see on üsna peen töö ja pealegi on viite tekitamiseks avr-libc ja kodulabori teegis juba funktsioonid olemas. Need tulevad ka näites kasutusele.

Tarkvaralise viite puhul on aga oluline teada, et hoolimata oma põhimõttelisest lihtsusest on see äärmiselt ebaefektiivne meetod energiatarbe seisukohast. Kõigil neil taktidel mil mikrokontroller tegeleb kasutu loendamisega kulub energiat. Patareidega rakenduses ei ole seega soovitatav pikkasid tarkvaralisi viiteid teha, vaid kasutada raudvaralisi taimereid mis töötavad iseseisvalt ning äratavad protsessor uneolekust üles kui vaja midagi teha.

Praktika

Järgnev programmikood käib tarkvaralise viite funktsiooni sw_delay_ms kohta mis tekitab parameetriga count etteantud viite millisekundites. Funktsioon kasutab omakorda avr-libc teegi poolenisti assembler keeles kirjutatud funktsiooni _delay_ms. Põhjus miks harjutuses pole kohe _delay_ms kasutatud on selles, et _delay_ms puhul on maksimaalne täpne viide piiratud. sw_delay_ms funktsion võimaldab kuni 65535 ms viidet teha.

//
// Tarkvaraline viide millisekundites
//
void sw_delay_ms(unsigned short count)
{
	// Viite muutuja nullini loendamine
	while (count-- > 0)
	{
		// 1ms viide spetsiaalse funktsiooniga
		_delay_ms(1);
	}
}

Toodud funktsiooni kasutamiseks on järgnev programm mis tekitab lõputus tsüklis kaks viidet: 100 ms ja 900 ms. Lühema viite jooksul LED põleb ja pikema ajal on kustunud - tulemusena LED perioodiliselt vilgatab.

//
// Kodulabori tarkvaralise viite demonstratsioon-programm.
// Programm vilgutab ~1 sekundi järel hetkeks LED-i.
//
#include <homelab/pin.h>
#include <homelab/delay.h>
 
//
// Test LED-i viigu määramine
//
pin debug_led = PIN(B, 7);
 
//
// Põhiprogramm
//
int main(void)
{
	// LED-i viigu väljundiks seadmine
	pin_setup_output(debug_led);
 
	// Lõputu tsükkel	
	while (true)
	{
		// LED-i põlema panek
		pin_clear(debug_led);
 
		// Tarkvaraline paus 100 millisekundit
		sw_delay_ms(100);
 
		// LED-i kustutamine
		pin_set(debug_led);
 
		// Tarkvaraline paus 900 millisekundit
		sw_delay_ms(900);
	}
}
et/examples/timer/software_delay.1260874273.txt.gz · Last modified: 2020/07/20 09:00 (external edit)
CC Attribution-Share Alike 4.0 International
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0