Forum: Mikrocontroller und Digitale Elektronik Assembler Stack Overflow


von Tobi (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe hier ein Programm geschrieben wo ich einfach nur einen Pin in 
Regelmäßigen Abständen schalten will.

Irgendwie gibt mir AVR-Studio immer StackOverflow.

Ich rufe das Programm auf ...

Beim Timer2CompareMatch Interrupt springt er in das Unterprogramm, 
löscht die Sprungadresse welche durch den Interrupt erstellt wurde.

Dann Springt er zum durch den Z Pointer gezeigten Unterprogramm.

Da macht er n bissle was, verändert den Z-Pointer und springt zu next.

Hier wird die durch den ijmp erstellte Adresse aus dem Stack gelöscht 
und er springt wieder in die Warteschleife.

Bereits beim zweiten Timer Interrupt bekomme ich einen Stack Overflow.
1
.include "m8def.inc"
2
3
   
4
.def      Temp1     =    r16
5
.def      Temp      =    r16
6
.def      Temp2     =    r17
7
.def      Temp3     =    r18
8
9
10
Interrupt:
11
12
.org 0x0000
13
     rjmp      Init
14
     
15
.org 0x0003
16
     rjmp      Timer2Compare     
17
18
Init:
19
20
; Initialisierung Stackpointer
21
     ldi       Temp,     LOW(RAMEND)
22
     out       SPL,      Temp
23
     ldi       Temp,     HIGH(RAMEND)
24
     out       SPH,      Temp
25
26
; Initialisierung I/O Pins
27
     clr       Temp
28
     out       DDRC,     Temp
29
     ldi       Temp,     0x03
30
     out       PORTC,    Temp
31
     
32
     clr       Temp
33
     out       PORTB,    Temp
34
     ldi       Temp,     0x1F
35
     out       DDRB,     Temp
36
37
; Initialisierung Timer0 for Clock
38
     ldi       Temp,     39                                                               ; Compare at x
39
     out       OCR2,     Temp
40
     ldi       Temp,     (1<<OCIE2)
41
     out       TIMSK,    Temp
42
43
;Initialisierung LCD Display
44
     rcall     lcd_init
45
     rcall     lcd_clear
46
     rcall     lcd_home
47
     
48
49
OneShot:
50
51
     ldi       ZL,       LOW(Programm)
52
     ldi       ZH,       HIGH(Programm)
53
54
     ldi       Temp,     0x03
55
     out       DDRC,     Temp
56
57
     ldi       Temp,     (1<<WGM21) | (0<<WGM20) | (0<<CS22) | (1<<CS21) | (0<<CS20)      ; Divided by 1024 /Start Timer
58
     out       TCCR2,    Temp
59
60
     sei
61
62
63
Loop:
64
65
     rjmp      Loop
66
67
68
Programm:
69
     
70
     
71
     ; Gaanz viel Rumgestelle     
72
73
74
75
76
toLoop:
77
     
78
     rjmp      Loop
79
     
80
81
82
83
Timer2Compare:
84
     
85
     pop       Temp
86
     pop       Temp
87
     ijmp
88
89
Next:
90
     pop       Temp
91
     pop       Temp
92
     sei
93
     rjmp      Loop
94
95
.include "C:\lcd-routines.asm"

von Stefan E. (sternst)


Lesenswert?

Tobi schrieb:
> Hier wird die durch den ijmp erstellte Adresse aus dem Stack gelöscht

???
Ein ijmp erzeugt keine Adresse auf dem Stack.

von Tobi (Gast)


Lesenswert?

Stefan Ernst schrieb:
> Tobi schrieb:
>> Hier wird die durch den ijmp erstellte Adresse aus dem Stack gelöscht
>
> ???
> Ein ijmp erzeugt keine Adresse auf dem Stack.


Verdammt.

Danke, war der Meinung (festen Meinung) das auch ein ijmp einen Eintrag 
erstellt.
Wird sicher nicht nochmal vorkommen

von Purzel H. (hacky)


Lesenswert?

Und die Interrupt routine ?

Timer2Compare:
     pop       Temp
     pop       Temp
     ijmp


kann's ja wohl nicht sein.

von Tobi (Gast)


Lesenswert?

Warum kanns das nicht sein?

Lösche die durch den Interrupt erstellte Adresse im Stack
Springe zu dem durch den Z-Pointer angegebenen Programm


Wie würdest du das lösen?

von Purzel H. (hacky)


Lesenswert?

Ein Hardware Interrupt muss wie ein Hardware Interrupt behandelt werden. 
Dazu erst mal das Manual konsultieren. Ueblicherweise solte man die 
Bedingung loesen, zB den Counter auslesen, dann wird so das betreffende 
Interrupt flag geloescht, am Ende kommt dann noch ein iret. Ein jump an 
die gleiche Stelle ist nicht dasselbe.

von Tobi (Gast)


Lesenswert?

Der Springt immer an andere Stellen

von holger (Gast)


Lesenswert?

>Der Springt immer an andere Stellen

P1:

     ldi       Temp,     0x03
     out       DDRC,     Temp
     out       PORTC,    Temp
     ldi       ZL,       LOW(P2)

Wo sorgst du dafür das der Interrupt nicht genau hier ausgelöst wird?

     ldi       ZH,       HIGH(P2)
     rjmp      Next

von Tobi (Gast)


Lesenswert?

Damit das der Interrupt 320 Takte braucht bis er wieder auslöst und dort 
die 320 Takte nochnicht erreicht sind.

Ausserdem wird er erst direkt vor dem Rücksprung wieder aktiviert:
1
Next:
2
     ;pop       Temp
3
     ;pop       Temp
4
     sei
5
     rjmp      Loop

von spess53 (Gast)


Lesenswert?

Hi

Hör mit diesem Stackgefummel auf. Das es nur etwas für Leute, die sich 
100%-tig damit auskennen. Und gerade die vermeiden so etwas. Nur 
Anfänger denken das wäre elegant oder notwendig.

In deinem Fall reicht es im Interrupt ein Flag zu setzen, das im 
Hauptprogramm ausgewertet wird.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Tobi schrieb:
> Warum kanns das nicht sein?
>
> Lösche die durch den Interrupt erstellte Adresse im Stack
> Springe zu dem durch den Z-Pointer angegebenen Programm
>
>
> Wie würdest du das lösen?

Gar nicht.
Ich würde nach den Regeln spielen.
Ein Interrupt wurde ausgelöst, als Folge davon eine ISR aufgerufen also 
hat diese ISR auch wieder mit einem reti zurückzukehren.
Das bringt den Stack nicht in eine Bredullie und sorgt auch bei dem 
Interrupteten Code für kein Bauchweh, weil der sich dann auch ein paar 
Dinge auf den Stack pushen und poppen kann, OHNE dass Gefahr droht, dass 
der Stack überläuft.

Wie gesagt: Spiele nach den Regeln. Meist lebt es sich damit viel 
besser.

von Tobi (Gast)


Lesenswert?

Hab grad n bissle Überlegt...

Son Register was bei jedem Interrupt hochgezählt wird und wo dann auf 
eine Sprungtabelle hingelinkt wird +Zähler = Sprung zu Routine?

Muss ich morgen mal schauen wie das funktioniert

übrigens: ursprüngliches Programm läuft, nun bin ich grad dabei es etwas 
einfacher zu schreiben bis es am besten nurnoch ein rcall ist und alles 
im Hintergrund abläuft

von Peter D. (peda)


Lesenswert?

Statt diesem Rumgehopse, schau Dir mal den LPM-Befehl an.
Damit kann man Werte aus einer Tabelle lesen.


Peter

von spess53 (Gast)


Lesenswert?

Hi

>alles im Hintergrund abläuft

Auf einem AVR läuft nichts im Hintergrund.

MfG Spess

von Purzel H. (hacky)


Lesenswert?

Was soll das Ganze ueberhaupt ? Ich arbeit nun schon seit Jahren mit den 
AVR, teilweise auch mit ASM, und hatte noch nie das Beduerftnis fuer 
sowas.

von Julian R. (tuefftler)


Lesenswert?

Dekad Oschi schrieb:
> Was soll das Ganze ueberhaupt ? Ich arbeit nun schon seit Jahren mit den
> AVR, teilweise auch mit ASM, und hatte noch nie das Beduerftnis fuer
> sowas.

Ich hab sowas auch noch nie gebraucht.
Wenn man mit Interrupts arbeitet, sollte ein Int.-Prog. immer so 
aussehen:
1
ORG $000
2
  rjmp Reset
3
ORG $xxx
4
  rjmp Interrupt
5
6
Reset:
7
  ;Stack init
8
  rcall init_Interrupt
9
  rcall init_IOs
10
11
  ;Sonstiges machen und Initialisieren
12
13
loop:
14
  ;Irgendwelche Flags checken und dann reagieren
15
  rjmp loop
16
17
18
Interrupt:
19
  push  r16
20
  ;Mach was...
21
  pop   r16
22
  reti
23
  ;Ab hier wird der Interrupt verlassen, und danach das I-Flag gesezt!
So machs ich seit einiger Zeit; Um die Interrupts möglichst kurz zu 
halten lager ich noch ein paar sachen in die Endlosschleife aus.
Der Vorteil daran ist, dass man eben nicht ständig ein Flag checken 
muss,
und dadurch mehr Zeit für anderes hat. Also lass es, solange du nicht 
auf Platz und Zeit im ns-Bereich achten musst.

julian

von Tobi (Gast)


Lesenswert?

spess53 schrieb:
> Hi
>
>>alles im Hintergrund abläuft
>
> Auf einem AVR läuft nichts im Hintergrund.
>
> MfG Spess

Ja .. im Hintergrund ist falsch beschrieben.

Sagen wir, das ich nurnoch ein Unterprogramm aufrufen muss welches mir 
ein Flag setzt sobald es fertig ist und wo in der Wartezeit immer das 
Hauptprogramm frisch fröhlich weiterläuft.

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.