Forum: Mikrocontroller und Digitale Elektronik Einfügen von Unterprogrammen führen zu hängen des Program


von Dominik L (Gast)


Lesenswert?

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?

von Hartmut Gröger (Gast)


Lesenswert?

Hi

1.Hast Du den Stack initialisiert.
2.wenn du push/pop Befehle benutzt,überprüfe,ob all gepushten Register
wieder gepopt werden.

Mfg HG

von Dominik L (Gast)


Lesenswert?

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 ?

von Jadeclaw (Gast)


Lesenswert?

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.

von Dominik L (Gast)


Lesenswert?

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

von Hartmut Gröger (Gast)


Lesenswert?

Hi

was für einen AVR benutzt Du?

Mfg HG

von Dominik L (Gast)


Lesenswert?

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

von Ancalagon (Gast)


Lesenswert?

Bei mir steht:
.INCLUDE "m16def.inc"
...

    ldi  rTemp1,  HIGH( RAMEND )
    out  SPH,  rTemp1
    ldi  rTemp1,  LOW(  RAMEND )
    out  SPL,  rTemp1

funktioniert einwandfrei.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

@Dominik:

Bist Du Dir sicher, daß die obere Endadresse Deines RAMs 0x00FF ist?
Dann hätte IMHO Dein Controller ziemlich wenig RAM ...

von Jadeclaw (Gast)


Lesenswert?

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.

von Christoph W. (christoph)


Lesenswert?

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.

von Dominik L (Gast)


Angehängte Dateien:

Lesenswert?

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

von Christoph W. (christoph)


Lesenswert?

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

von Dominik L (Gast)


Lesenswert?

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!

von Dominik L (Gast)


Lesenswert?

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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.