Ein grundsätzliches Problem bei Hardware naher Softwareentwicklung stellt das Debugging und die Programmkontrolle dar.
Es existieren auch für die ATMEL Prozessoren Software-Emulatoren, die Prozessoren und Register, sowie Ein-/Ausgebeports nachbilden können. Diese Werkzeuge stellen eine gute Möglichkeit zum Kennen lernen der Mikrocontrollerhardware oder für Unterrichtszwecke dar, doch eine Reaktion von Hardwarebausteinen, wie z.B. ein Zählsignal am Timer/Counter1 Eingang, ist mit Emulatoren nicht oder nur sehr umständlich abbildbar.
Dennoch kann es oft notwendig sein, dass in der Entwickungsphase an beliebiger Stelle des Programmablaufs eine Systemrückmeldung zur Programmkontrolle erforderlich ist, die von einem kurzen Aufleuchten einer Leuchtdiode bis zur Klartext-Fehlermeldung reichen kann. Diese Systemreaktionen müssen zudem noch einfach ein- und ausschaltbar sein.
Eine kleine Bibliothek von Makros und Unterprogrammen wurde geschaffen, die über eine Assemblerdirektive während der Entwicklungsphase zu Testzwecken bedingt in die Hauptdatei RF_Control.asm eingebunden werden kann.
; ----------------------------------
; debug functions
; ----------------------------------
.ifdef DEBUG
.include "debug_fun.inc" ; debug functions (conditional include)
.endif
Um debug-kritische Situationen austesten zu können, wurden in einer
weiteren Include-Datei (testfunc.asm) entsprechende Testfunktionen
angelegt, die Initialisierungen vornahmen und Unterprogramme zu Testzwecken
ausführten.
Die beiden Hilfsdateien befinden sich laut Anhang D.2 im Hauptverzeichnis der Entwicklungsumgebung (siehe auch Absch. 7.5.3).Makros zur Ausgabe des Inhaltes eines Registers oder Registerpaares wurden erstellt, die keine Seiteneffekte aufweisen und an jeder Stelle des Programms aufgerufen werden können, ohne den Programmablauf (abgesehen vom Status der LCD-Anzeige, in der die Werte ausgegeben werden) sonst irgendwie zu beeinflussen.
; ----------------------------------
; display a character as prefix and the
; hexadecimal value of a register
;
; affected: none (not even the flags)
; Parameter: @0 .. prefix char
; @1 .. register
.macro DEBUG_REGISTER
PUSHF ; save flags
push iic_sendbyte
push @1 ; put register value onto stack
ldi iic_sendbyte,@0 ; write out ascii character
rcall LCDINIT_SEND_ACHAR
pop iic_sendbyte
rcall LCDINIT_SEND_HEX ; write out hex value
pop iic_sendbyte
POPF ; restore flags
.endmacro
Verwendung:
DEBUG_REGISTER 'R',return2
Ein Beispiel das den Einsatz demonstriert.
In Abschnitt 7.8.1.3, der sich mit
der 5-Phasensteuerung beschäftigt, wird darauf hingewiesen, dass der
in der Phase I (S. ) gemessene ,,Losfahrwert'',
als Zielwert für die Phase III (S.
)
angesteuert wird. Außerdem stellte dieser Rotations-Startwert einen
Anhaltspunkt für die Festlegung eines sinnvollen Steuerungs-Startwertes
für die Phase I dar. Ein Startwert von 0 würde nur unnötige Wartezeit
bewirken, da die Drehbewegung erst bei einem wesentlich höheren Startwert
(ca. 130) einsetzt.
Um diese konkreten Werte zu ermitteln, wurde in einer früheren Code-Version das ,,DEBUG_REGISTER'' Makro eingesetzt.
phase_speed_down:
push temp1
push temp2
push ltmp2
STSB rotation_mode, ModeSpeedDown ; rotation mode is go down
lds temp1, rot_speed_value ; get current rotation speed value
lds ltmp2, rot_contrl_minimum ; get value of rotation startup value
LCDINIT_ERASE_LINE 0
DEBUG_REGISTER 's',temp1
DEBUG_REGISTER 'm',ltmp2
BLINK_RED_LED
decrease_speed: ; decreasing speed until
in temp2, TIMSK ; read TIMSK port
sbrc temp2, OCIE1B ; is bit OCIE1B set?
rjmp speed_slowdown_fast ; if yes, back to loop
Die Display-Zeile 0 ist üblicherweise mit einem fixen Text versehen
und ,,verdeckt'' durch die Debug-Ausgabe keine betriebsrelevanten
Informationen, das Makro ,,LCDINIT_ERASE_LINE'' sichert ebenfalls
alle Register und verändert damit keine Register, Flags sind an dieser
Stelle nicht relevant. Dies führt zu einer Anzeige, wie sie in Abb.
7.5 beispielhaft dargestellt ist.
Wie werden diese Werte nun interpretiert?
Sollten kompliziertere Zustände untersucht werden, die umfangreicheren Code benötigen, wurden diese Routinen als Unterprogramme ebenfalls in die Debug-Datei mit aufgenommen und in Abhängigkeit von der DEBUG-Direktive bedingt über ein Makro aufgerufen.
; ----------------------------------
; conditional DEBUG call
; this is executed if DEBUG directive is set...
; the subroutine should be between .ifdef DEBUG and .endif
; to avoid assemblation of the debug code if DEBUG
; directive is not set
; ----------------------------------
; Parameter: @0 .. debug subroutine
.macro CALL_DEBUG
.ifdef DEBUG
rcall @0
.endif
.endmacro
Verwendung:
CALL_DEBUG show_preproc_state
CALL_DEBUG debug_rotation_mode
CALL_DEBUG debug_show_angle
Diese Aufrufe verzweigen in Unterprogramme, die umfangreichere Statusinformationen
ausgeben, wenn die DEBUG-Direktive gesetzt ist, wenn nicht, werden
die Anweisungen ignoriert.
Als Beispiel wird die Funktion show_preproc_state betrachtet, die in Version 0.8 der Steuerungssoftware noch vorhanden war und am Ende der Routine rotation_preproc aufgerufen wurde.
show_prepoc_state:
push temp1
PUSHW REG_Z
PUSHW REG_B
LCDINIT_ERASE_LINE 0
INWR REG_B, TCNT1 ; get current value currpos(REG_B)
LCDINIT_WRITE_HEXWORD REG_B
LCDINIT_WRITE_CHARACTER '-'
LCDINIT_WRITE_HEXWORD REG_A
LCDINIT_ERASE_LINE 1
LCDINIT_WRITE_CHARACTER '='
LCDINIT_WRITE_SRAM rot_angle_godown+1
LCDINIT_WRITE_SRAM rot_angle_godown
LCDINIT_ERASE_LINE 2
in iic_sendbyte, TIMSK
rcall LCDINIT_SEND_BINARY
rcall wait_key_confirm
POPW REG_B
POPW REG_Z
pop temp1
ret
Bemerkungen:Das Unterprogramm zeigt dabei folgende Daten an (Abb. 7.6):
Das Unterprogramm rotation_preproc ermittelt unter anderem den Rotations-Endwinkel (REG_A), in Registerpaar REG_B wurde der aktuelle Winkel (Inhalt des Zählers TCNT1) eingelesen. Das Makro ,,LCDINIT_WRITE_SRAM'' gibt den Inhalt einer Speicheradresse am LCD aus, im vorliegenden Fall einen 16-Bit Wert im LSB-Format, der in der Speicherstelle (Variablen) rot_angle_godown und der Folgeadresse abgelegt ist.
gerhard.reithofer@tech-edv.co.at