© Harry Broeders.
Deze pagina is bestemd voor Technische Informatica studenten van de THRijswijk die de minor Elektrotechniek volgen.
Z'n 20
jaar geleden was de TV serie Knight
Rider populair. In deze serie werd de hoofdrol gespeeld door een sprekende
auto KITT genaamd. Deze auto was aan de voorkant voorzien van een rijtje
rode LED's (lampjes) die in een bepaald patroon aan en uitgeschakeld werden.
Deze rij LED's moesten een scanner voorstellen waarmee KITT de omgeving
verkende.
In deze practicumopgave gaan we zelf een rijtje LED's aansturen met een bepaald patroon met behulp van de HC11 microcontroller.
mcca1\opdr1
en kopieer het voorbeeld programma
opdr1.c, het linkerscript
evm.ld en de makefile
makefile in deze directory. Internet Explorer
voegt aan de naam van sommige bestanden extensie .txt toe. Deze .txt
extensie moet je verwijderen!
Ctrl+F7
te drukken. In de
makefile staat gespecificeerd hoe het programma
vertaald en gelinkt moet worden. Deze makefile wordt uitgevoerd door het
commando make (wat verborgen zit achter de de menu optie Tools,
Compile). De uitvoer van make verschijnt in het output window van
SciTE:>C:\PROGRAM FILES\THRSIM11\SCITE\..\utils\make "C:\Program Files\THRSim11"\gcc\bin\m6811-elf-gcc.exe -g -c -m68hc11 -Wall opdr1.c "C:\Program Files\THRSim11"\gcc\bin\m6811-elf-gcc.exe -m68hc11 -T evm.ld opdr1.o "C:\Program Files\THRSim11"\gcc\bin\m6811-elf-objcopy.exe -O srec a.out a.s19 >Exit code: 0
-
a.s19
en a.out
.
De file a.s19
bevat alleen de machine code van het programma
en kan bijvoorbeeld rechtstreeks in de EVM kast geladen worden. De file
a.out
bevat de machine code van het programma in het standaard
ELF formaat inclusief debug informatie in het standaard DWARF formaat. Deze
file kan door THRSim11 worden ingelezen.a.out
in THRSim11 door in SciTE
de menu optie Tools, Go te kiezen of door op de sneltoets
F5
te drukken.$C000
) en stopt op de eerste C coderegel die wordt
uitgevoerd. In dit geval main
.for
lus in de functie wait
. Je kunt de waarde van i
in het HLL variabelen window zien. Het uitvoeren van deze lus neemt heel
wat tijd in beslag.wait
wordt
aangeroepen, wilt onderbreken dan kan dat door een breakpoint op het beginadres
van wait
te zetten. Je kunt dit doen via het Breakpoint,
Set menu.
In het programma wordt het C/C++ keyword volatile
gebruikt.
In de C++ standaard staat:
volatile is a hint to the implementation to avoid aggressive optimization involving the object because the value of the object might be changed by means undetectable by an implementation. See intro.execution for detailed semantics. In general, the semantics of volatile are intended to be the same in C++ as they are in C.
Het woord volatile betekent "vluchtig" en wordt dus gebruikt om aan te geven dat de variabele ook buiten het programma om veranderd kan worden. Dit keyword zorgt ervoor dat de compiler geen optimalisaties toepast die ervan uitgaan dat de waarde van een variabele nog hetzelfde is als die variabele door het programma zelf niet veranderd is.
volatile
: Output.
In het voorbeeld programma wordt een pointer p
gebruikt die
staat te wijzen naar een output poort:
byte* p=(byte*)0x1004;
Het type byte
is in het begin van het programma als volgt
gedefinieerd:
typedef unsigned char byte;
In de for
lus van main()
wordt telkens een nieuwe
waarde naar deze output poort geschreven:
*p=c1|c2;
Een sterk optimaliserende compiler kan nu "denken": "De waarde die ik via
de pointer wegschrijf wordt nooit meer gelezen dus ik kan dat schrijven ook
wel achterwege laten." Dat is natuurlijk niet de bedoeling, wij willen de
juiste LEDjes wel zien branden! De waarde waar de pointer naar wijst moet
dus als vluchtig (volatile
) worden gequalificeerd:
volatile byte* p=(byte*)0x1004;
Bij het compileren met gcc kun je een programma op verschillende manieren optimaliseren, zie hier, Bijvoorbeeld:
-Os
optimaliseer voor minimaal geheugengebruik.
-O3
optimaliseer voor maximale snelheid.
De versie van de gcc compiler die wij nu gebruiken (3.3.5) zal als je het
keyword volatile
bij de pointer p
vergeet, bij
het gebruik van de optie -Os
of -O3
de LEDjes toch
gewoon aansturen. Maar dat kan bij een nieuwe versie van gcc anders zijn!
volatile
: Input.
Je kunt ook een pointer naar een input poort definiëren:
byte* p=(byte*)0x....;
De waarde van deze input poort kun je dan als volgt inlezen:
waarde=*
p;
Als dit meerdere malen achter elkaar gebeurt (bijvoorbeeld in een lus) kan
een sterk optimaliserende compiler "denken": "De waarde die ik via de pointer
heb ingelezen heb ik zo meteen weer nodig. Ik kan deze waarde dus bewaren
(bijvoorbeeld in een register) en hoef deze waarde dan de tweede keer niet
opnieuw uit het geheugen te lezen." Dat is natuurlijk niet de bedoeling,
wij willen de nieuwe waarde van de inputpoort inlezen! De waarde waar de
pointer naar wijst moet dus als vluchtig (volatile
) worden
gequalificeerd:
volatile byte* p=(byte*)0x....;
De versie van de gcc compiler die wij nu gebruiken (3.3.5) zal als je het
keyword volatile
bij de pointer p
vergeet, bij
het gebruik van de optie -Os
de input poort toch gewoon opnieuw
inlezen. Bij het gebruik van de opties -O3
wordt het opnieuw
inlezen van de input poort wel weggeoptimaliseerd!.
volatile
: Tijdvertraging.
In het voorbeeldprogramma wordt een "lege" for
lus gebruikt
om een tijdvertraging te realiseren.
void wait() {
word i;
for (i=0; i<10000; ++i)
/*empty*/;
}
Een sterk optimaliserende compiler kan nu "denken": "De waarde van
i
wordt toch niet gebruikt de hele for
lus kan
dus weggeoptimaliseerd worden (en vervolgens kan de hele functie
wait()
weggeoptimaliseerd worden)." Dat is natuurlijk niet de
bedoeling, wij willen dat de functie wait()
een tijdvertraging
opleverd! De variabele i
moet dus als vluchtig
(volatile
) worden gequalificeerd:
volatile word i;
De versie van de gcc compiler die wij nu gebruiken (3.3.5) zal als je het
keyword volatile
bij de variabele i
vergeet, bij
gebruik van de optie -Os
of -O3 de lus niet helemaal
weggeoptimaliseren. De variabele i
wordt bij het gebruik van
de optie -Os
of -O3 echter telkens met
625
verhoogd in plaats van met 1
. Vraag
me niet waarom! De lus wordt dan dus maar 8x doorlopen (in plaats van
10000x).
Het voorbeeldprogramma is geschreven in C. Je kunt echter ook C++ programma's compileren en uitvoeren op de 68HC11. Het voorbeeld programma in C++ kun je vinden in de file: opdr1.cpp. Gcc kijkt dus naar de extensie van het bestand om te bepalen op de C of de C++ compiler aangeroepen moet worden.
mcca1/opdr1cpp
en kopieer het voorbeeld programma
opdr1.cpp, het linkerscript
evm.ld en de makefile
makefile in deze directory.F5
te
drukken.