© Harry Broeders.
Deze pagina is bestemd voor studenten van de THRijswijk.
Debuggen
is voor dummies...
Ja, daar zit wat in. Als je geen fouten maakt dan hoef je ze ook niet te verbeteren. Dit is natuurlijk wel erg kort door de bocht maar bedenk goed dat je beter tijd kunt investeren in het maken van een goed ontwerp als in het opsporen van fouten in een slecht (snel in elkaar geflanst) programma. Neem voordat je gaat debuggen altijd eerst de volgende stappen:
Als voorbeeld nemen we een programma dat de schakelaars kruislings
verbind met de leds. Dus PB0=PC7
, PB1=PC6
,
PB2=PC5
, ... PB7=PC0
. In het onderstaande programma
worden de schakelaars 1 voor 1 getest met behulp van de variabele
l
. Deze variabele krijgt achtereenvolgens de waarden:
00000001
, 00000010
, 00000100
, ...
10000000
(de 1
in de variabele l
schuift
dus steeds naar links). Als een schakelaar hoog is wordt de juiste led aangezet.
Dit gebeurd met de variabele r
. Deze variabele krijgt
achtereenvolgens de waarden: 10000000
, 01000000
,
00100000
, ... 00000001
(de 1
in de
variabele r
schuift dus steeds naar rechts).
int main() { typedef unsigned char byte; volatile byte* portc=(byte*)0x1003; volatile byte* portb=(byte*)0x1004; byte in, out, l, r; while (1) { in=*portc; out=0; for (l=0x01, r=0x80; l!=0; l<<=1, r>>=l) if (in&r) out|=l; *portb=out; } return 0; }
Als je dit programma simuleert en PC7
hoog maakt dan lijkt het
te werken:
Maar als je PC6
hoog maakt zie je dat het niet goed werkt omdat
led PB1
niet gaat branden.
Om de fout vinden kun je het gecompileerde programma (a.out) in THRSim11
laden en een breakpoint zetten op de for
lus. Je kunt een breakpoint
zetten op een C instructie door de betreffende regel te selecteren en op
F5 te drukken.
Als je nu het programma start (F9) dan zie je dat de stand van de schakelaars
in de variabele in
is ingelezen en dat de variabele
out
op 0
staat. De variabelen r
en
l
hebben de waarde $ff
omdat ze nog niet
geïnitialiseerd zijn.
De pointer variabelen zijn "opengeklikt" zodat je kunt zien waar ze naar
wijzen. Nadat de for
lus 1x is uitgevoerd is alles nog steeds
zoals je verwacht:
De tweede keer dat de for
lus is doorlopen zie je iets onverwachts:
Zie jij het ook?
De variabele r
heeft de waarde $20
maar had de
waarde $40
moeten hebben (als je $80
een plaats
naar rechts schuift krijg je $40
en geen $20
).
Je kunt dit nog beter zien door de variabelen in het binaire stelsel weer
te geven (met behulp van het popup menu):
Kun jij nu het probleem vinden als je de source nogmaals bekijkt?
Als je het nog niet ziet helpt het misschien om de variabelen te bekijken
nadat de for
lus nog een keer is doorlopen:
Is het balletje al gevallen? De variabele l
schuift telkens
1
plaatsje naar links maar de variabele r
schuift
eerst 1
, dan 2
plaatsen en daarna 4
plaatsen naar rechts.
Kun jij nu het probleem vinden als je de source nogmaals bekijkt?
Inderdaad de variabele r
wordt l
(in plaats van
1
) plaatsen naar rechts geschoven!
De correcte code is dus:
int main() {
typedef unsigned char byte;
volatile byte* portc=(byte*)0x1003;
volatile byte* portb=(byte*)0x1004;
byte in, out, l, r;
while (1) {
in=*portc;
out=0;
for (l=0x01, r=0x80; l!=0; l<<=1, r>>=1)
if (in&r)
out|=l;
*portb=out;
}
return 0;
}
THRSim11 maakt het ook mogelijk om een C programma op het targetboard te debuggen.
Je kunt het C programma in de EVM kast laden door het C List Window te selecteren en Ctrl+D in te typen.
Ook in dit window kun je een breakpoint plaatsen met F5.
Als je het programma op de target start (Ctrl+F9) zal het programma onderbroken worden bij het breakpoint en kun je de C variabelen bekijken met de menu optie: Target, Target High Level Language Variabeles.
Nadat de for lus 2x is doorlopen wordt ook hier het probleem zichtbaar:
Het debuggen in de simulator heeft echter de voorkeur omdat:
In de praktijk komt het regelmatig voor dat een microcontroller programma "debugged" moet worden zonder dat een HLL (High Level Language) debugger beschikbaar is.
Het debuggen van het voorbeeldprogramma zonder HLL debugger (bijvoorbeeld met de target disassembler) is lastiger omdat je alleen de assemblercode kan zien. Je kunt de door de compiler gegenereerde 68HC11 assembler code bekijken door het volgende commando in het THRSim11 Commands window in te type:
!objdump -S a.out
Je ziet dan een listing van de C source met de daarbij behorende assemblercode maar daar schiet je natuurlijk alleen maar wat mee op als je redelijk bekend bent met de 68HC11 instructieset.
Om het programma zonder HLL debugger toch te kunnen debuggen kun je de volgende veranderingen aanbrengen:
stop
) en roep deze functie
aan op elke plek in het programma waar je de waarden van de variabelen wilt
bekijken.
byte in, out, l, r; void stop() { } int main() { typedef unsigned char byte; volatile byte* portc=(byte*)0x1003; volatile byte* portb=(byte*)0x1004; while (1) { in=*portc; out=0; for (l=0x01, r=0x80; l!=0; l<<=1, r>>=l) { stop(); if (in&r) out|=l; } *portb=out; } return 0; }
Je kunt dit programma nu vanuit THRSim11 compileren de adressen van de
verschillende variabelen en van de stop
functie vinden door
achtereenvolgens de volgende commando's in het THRSim11 Commands window in
te typen:
!cd C:\My 68HC11 Program Files\debug
!make
!objdump -S a.out
In THRSim11 kun je rechtstreeks met het target board communiceren via het Target Command Window. Dit window kun je openen met de menukeuze Target, Target Command Window.
Download de machinecode in de target met behulp van het commando
load
.
Zet de target program counter op de eerste instructie van het programma met
het commando P=c000
. Zet een breakpoint op de stop
functie met het commando BR c037
. Start het programma met het
commando g
. Je kunt nu de variabelen zichtbaar maken met behulp
van het commando md 0006. Hierboven kun je zien op welke adressen de variabelen
zich bevinden. Als we de geheugeninhoud vanaf adres 0006 bekijken zien we
dus achtereenvolgens de variabelen in
, out
,
l
en r
.
Ook hier wordt het probleem zichtbaar nadat de for lus 2x is doorlopen.