Tips voor debuggen van 68HC11 C programma's.

© Harry Broeders.

Deze pagina is bestemd voor studenten van de THRijswijk.

Woord vooraf.

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:

  1. Lees de source code nog eens goed door. Soms helpt het om eerst even iets heel anders te doen.
  2. Leg de werking van het programma aan iemand anders uit. Ook als die ander geen enkel benul van programmeren heeft kan dit prima helpen!
  3. Bedenk voordat je een breakpoint zet en variabelen in de debugger gaat bekijken van tevoren welke waarden je verwacht.

Voorbeeld.

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;
}

Debuggen in de simulator.

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;
}

Debuggen op het targetboard.

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:

Debuggen zonder HLL debugger.

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:

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.