Assembler Stack Overflow

Gast #2329252
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"
Angehängte Dateien:
#2329282
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.
Gast #2329297
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
Gast #2329312
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
Gast #2329349
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
#2329360
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.
Gast #2329372
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
#2329533
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
Gast #2329607
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren