Hallo!
Woran kann das liegen, dass mein Controller, sobald ich in ein
vorhandenes Programm ein Unterprogramm einfüge, mein Controller an ganz
merkwürdigen Stellen nicht mehr weiter läuft? Für sich alleine laufen
die Programme. Fügt man sie zusammen, werden Warteschleifen auf einmal
kürzer oder der Controller (mega16) bleibt irgendwo hängen. Ist in
Assembler geschrieben. Der Stackpointer ist meine ich ordentlich
initialisiert und auf das RAM Ende gesetzt. In der Simulation läuft es
normal.
Hat da jemand eine Idee, was da ein typische Fehler sein könnte?
Ja den Stackpointer setze ich auf RAMEND. Und push und pop verwende ich
garnicht. Is doch richtig, dass der Stackpointer bei AVRs von höherer
Adresse zur niedrigeren zählt oder? Also anders als beim 8051 ?
Der Stack wächst nach unten.
Irgendwelche Variablen im RAM abgelegt?
Ich halte es üblicherweise so, dass ich den Stack ans obere Ende lege,
und die Variablen am unteren Ende ablege, so dass genug Luft bleibt.
Die Rücksprünge richtig organisiert?
Sprich, die Unterprogramme auch schön ordentlich mit RET verlassen?
Gruss
Jadeclaw.
Ja eigentlich schon. In der Simulation mit AVR Studio klappt das auch
alles wunderbar. Nur im Controller selbst eben nicht. Und ab und zu
ändern sich die Stellen auch, an denen er stoppt. Find das absolut
merkwürdig. Das ganze fängt auch erst an, wenn man mehrere
Unterprogramme aufruft.
MFG Dominik
Momentan den mega16. Aber beim mega32 hab ich genau die gleichen
Probleme. Den Stack initialisieree ich so:
ldi temp1, 0xff ; LOW-Byte der obersten RAM-Adresse
out SPL, temp1
ldi temp1, 0x00 ; HIGH-Byte der obersten RAM-Adresse
out SPH, temp1
Is das so in Ordnung?
MFG Dominik
Ancalagon hat es richtig gemacht.
Dafür hat Atmel schliesslich den RAMEND definiert.
0x00ff ist etwas sehr niedrig und bei grösserer Verschachtelungstiefe
kann der Stack in die Outputregister reinlaufen.
Und dann schmiert der Prozi ab.
Für technisch interessierte, RAMEND ist für den ATMega16 auf 0x045F
gesetzt.
Gruss
Jadeclaw.
Du musst erst das HIGH-byte schreiben und dann erst das LOW-Byte !
Im Datenblatt des AVR steht für den Zugriff von 16-Bit Registern :
zum Lesen : erst das LOW-Byte (High-Byte geht dabei in ein Latch und
dann mit dem HIGH-Byte das Latch auslesen.
zum Schreiben : erst das HIGH-Byte (das geht in das Latch) und dann das
LOW-Byte (das geht dann erst zusammen mit dem Latchwert ins eigentliche
16-Bit Register).
Das heißt :
zum Schreiben eines 16 Bit Registers (wie z.B. SPL/SPH, TCNT1L/TCNT1H,
...) :
ldi temp1,HIGH(RAMEND)
out SPH,temp1 ; Latch wird beschrieben
ldi temp1,LOW(RAMEND)
out SPL,temp1 ; temp1 geht zusammen mit dem Latchinhalt ins
Register
und zum lesen :
in temp1,SPL ; LOW-Byte, High-Byte geht in ein Latch
in temp2,SPH ; HIGH-Byte, Latch wird gelesen
Dann sollte es eigentlich auch mit deinem Programm funktionieren, da
bei deinem Fehler der Stack auf 005F initialisiert wurde (SP und Latch
beim Anschalten : 00, dann LOW-Byte von RAMEND in den SP : 005F)
005F liegt lt. Datenblatt im IO-Bereich. Sprich : mit jedem Call/Push
überschreibst du ein IO-Register. Das konnte nicht gut gehen.
Hallo!
Also mit dem Stackpointer das habe ich jetzt umgeändert. Aber das
Programm spinnt immernoch. Bleibt zwar nicht mehr hängen, aber auf dem
LCD wird jetzt "Ffb" ausgegeben anstatt "Hallo!". Hab den Eindruck,
dass je nachdem wo und welche Unterprogramme man aufruft, der Ablauf des
Programmes durcheinander kommt. Für sich alleine funktionieren die
Unterprogramme alle. Hab das Programm jetzt mal angehängt. Vielleicht
findet ja einer nen Fehler, der das verursachen könnte. Ich sitze da
jetzt schon 2 Tage dran und verzweifel so langsam.
Vielen Dank für die Hilfe!
MFG Dominik
Wie ich sehe hast du die Displayroutinen auch aus einem Tutorial
übernommen. Dabei musst du aber auch drauf achten, dass du die Routinen
wie Delay, Wait50µs und eigentlich alles, was mit Delays zu tun hast
anpasst.
Wenn du Beispielsweise den Code, der für ein 4MHz Quarz (nur ein
Beispiel) entwickelt wurde mit einem 16MHz AVR ausprobierst, wird das
Timing auch 4x schneller. Das könnte beim Display dann Probleme geben.
Achte darauf einfach nochmal, oder schreib die Routinen zum Warten von
50µs, 5ms, usw. für deinen Takt selbst.
Bsp. für ein 1MHz Quarz.
Call-Sprung zur Routine braucht 4 Zyklen, ret ebenfalls, daher muss man
992 Zyklen Delay einbauen
Wait1ms:
ldi LOOP,248
WAIT_LOOP:
subi LOOP,1
nop
brne WAIT_LOOP ; für die Schleife 4 Zyklen bei Sprung, 3 wenn
weiter
ret ; 248 * 4 = 992, + 8 = 1000 (1ms bei 1MHz)
Das einfach an deine Taktfrequenz anpassen, schon gehts (hoffentlich
;-)
Also wenn die Wartezeiten länger sind ist es doch nicht so schlimm oder?
Hab meinen auf 1 MHz laufen. Hab dann grad mal 4 MHz ausprobiert, wie im
Tutorial und bekomme das gleiche Ergebnis. Für sich alleine läuft die
LCD Ausgabe auch super. Alle Unterprogramme laufen für sich selber. Nur
wenn ich sie zusammenbastel, dann gibt es Probleme.
Grüße Dominik!
Hey ich habs. War wohl ein Fehler in einer der LCD routinen, den ich
anscheinend ausversehen eingebaut habe. Er hat immer das untere Nibbel
und obere Nibbel gleich ausgegeben. Also mit dem swap oder so hats wohl
nicht richtig hingehauen. Damit wäre mein erstes Problem schonmal
gelöst. Die Ausgabe läuft jetzt wunderbar. Arbeite mich jetzt mal
wieder weiter durch und hoffe, dass das jetzt mein einziges Problem war
und nicht noch wieder Probleme mit Unterprogrammen auftauchen.
Also erstmal vielen Dank für eure Mühe.
MFG Dominik