ASM beim ATMega88 Stack verbiegen oder ganz anderst?

Gast #3112029
Lesenswert?

Guten Morgen,
eigentlich ein ganz einfache Sache die ich machen möchte. Ich möchte das 
ein Interrupt beim reti nicht da weiter macht wo er her gekommen ist, 
sondern das alle Rücksprungandressen gelöscht werden ( Stack leeren??? ) 
und an einem anderen Label zurück springen.

Beispiel:
1
.INCLUDE "m88def.inc"
2

3
.def Dummy1     = r16
4

5
.equ F_CPU = 8000000 ; Systemtakt in Hz
6
 
7
.org 0x000     ; kommt ganz an den Anfang des Speichers
8
  rjmp RESET   ; Interruptvektoren überspringen und zum Hauptprogramm
9

10
reti           ; $001 External Interrupt Request 0
11
rjmp Wechsel   ; $002 External Interrupt Request 1
12
reti           ; $003 Pin Change Interrupt Request 0
13
reti           ; $004 Pin Change Interrupt Request 0
14
reti           ; $005 Pin Change Interrupt Request 1
15
reti           ; $006 Watchdog Time-out Interrupt
16
reti           ; $007 Timer/Counter2 Compare Match A
17
reti           ; $008 Timer/Counter2 Compare Match A
18
reti           ; $009 Timer/Counter2 Overflow
19
reti           ; $00A Timer/Counter1 Capture Event
20
reti           ; $00B Timer/Counter1 Compare Match A
21
reti           ; $00C Timer/Counter1 Compare Match B
22
reti           ; $00D Timer/Counter1 Overflow
23
reti           ; $00E TimerCounter0 Compare Match A
24
reti           ; $00F TimerCounter0 Compare Match B
25
reti           ; $010 Timer/Couner0 Overflow
26
reti           ; $011 SPI Serial Transfer Complete
27
reti           ; $012 USART Rx Complete
28
reti           ; $013 USART, Data Register Empty
29
reti           ; $014 USART Tx Complete
30
reti           ; $015 ADC Conversion Complete
31
reti           ; $016 EEPROM Ready
32
reti           ; $017 Analog Comparator
33
reti           ; $018 Two-wire Serial Interface
34
reti           ; $019 Store Program Memory Read
35

36
RESET:         ; Hier beginnt das Hauptprogramm 
37

38
; ***********************************************************************
39
; * Stackpointer initialisieren                                         *
40
; ***********************************************************************
41
    ldi Dummy1, high(RAMEND) 
42
    out SPH,Dummy1           
43
    ldi Dummy1, low(RAMEND)
44
    out SPL,Dummy1
45
; ***********************************************************************
46
; * Port instaliesieren                                                 *
47
; ***********************************************************************
48
    ldi  Dummy1, 0b00000000
49
    out DDRC,Dummy1 ; Port-C Eingang 
50
    ldi  Dummy1, 0b00000000
51
    out DDRB,Dummy1 ; Port-B Eingang
52
    ldi  Dummy1, 0b00000000
53
    out DDRD,Dummy1 ; Port-D Eingang PD3=Eingang Taster Int1
54
; ***********************************************************************
55
; * INT 1 PD.3 auf fallende Flanke konfigurieren                        *
56
; *********************************************************************** 
57
    ldi Dummy1, (1<<ISC11 | 0<<ISC10)
58
    sts EICRA, Dummy1
59
    ldi Dummy1, (1<<INT1)
60
    out EIMSK, Dummy1
61
; ***********************************************************************
62
; * Alle Interrups an                                                   *
63
; *********************************************************************** 
64
    sei
65
; ***********************************************************************
66

67

68
Loop_1:
69
rjmp Loop_1
70

71

72
Loop_2:
73
rjmp Loop_2
74

75
Wechsel:
76
reti

Das Programm rennt in Loop_1 (0x002A) soweit ok. Nun kommt einen 
fallende Flanke an INT1, das Programm springt zu Wechsel. Auch das ist 
OK, nun kommt es an reti und springt wieder zurück nach Loop_1 (0x002A) 
doch ich möchte das es zu Loop_2 springt (0x002B) und alle anderen 
Rücksprungadressen vergisst (rcall, reti, Pop, etc)

Mir ist ganz klar das man jene Entscheidungen im Loop_1 treffen sollte 
darum geht es aber hier gerade nicht. Meine Frage bezieht sich darauf 
wie ich den Stack zurücksetzen kann und eventuell die neue 
Rücksprungadresse eintragen.

Reicht es einfach:
1
Wechsel:
2
; ***********************************************************************
3
; * Stackpointer verbiegen                                              *
4
; ***********************************************************************
5
    ldi  Dummy1, high(RAMEND) 
6
    out  SPH,Dummy1           
7
    ldi  Dummy1, low(RAMEND)
8
    subi Dummy1,0x02
9
    out  SPL,Dummy1
10

11
    ldi  Dummy1,0x00
12
    sts  SPH, Dummy1
13
    ldi  Dummy1,0x2B
14
    sts  SPL, Dummy1
15
reti
Gast #3112093
Lesenswert?

Bei einem Programm, dass im Grunde genommen nichts macht, mag das ganze 
ja gehen. Vor allem in Assembler.
Stack zurücksetzen und jmp xxx. Das ist alles.

... aber eigentlich ist es ja recht sinnvoll, wenn eine beliebige 
Sequenz unterbrochen wird, die Arbeit an der UNTERBRECHUNGSSTELLE wieder 
aufzunehmen.
In diesem Falle dient der Stack sozusagen als Gedächtnis.
Auch ist der Prozessorstatus danach in unbedingt definiert. Ein bisschen 
von der Unterbrechung, ein bisschen von der Unterbrechung selbst.
#3112171
Lesenswert?

Holger P. schrieb:
> Aber ansonsten ist dagegen nix zu sagen?

Doch viel.
Das ist ne Lösung nur für den Eintagsprogrammierer.
Wenn Du aber länger programmieren willst und die Programme größer 
werden, schießt Du Dir damit irgendwann ins Knie.

Holger P. schrieb:
> Soll eine Art eigene Watchdog geben.

Was gefällt Dir an dem richtigen Watchdog nicht?
Gast #3112278
Lesenswert?

Peter Dannegger schrieb:
> Was gefällt Dir an dem richtigen Watchdog nicht?

Nun das ich nach einer bestimmten Zeit eine Bestimmte Routine anspringen 
möchte und kein Reset ausführen.

Ich bin in einer schleife gefangen die bei Normalfall verlassen wird. 
Aber im nicht normalen Fall würde sich mein kleiner Mega halt in dieser 
Schleife aufhängen.

Also dachte ich einen Timer gestartet, da die schleife nach 0,5Sekunden 
eigentlich beendet sein müsste. Ist dieses nicht der Fall so setzt der 
Timer ein, Fehlermeldung wird ausgegeben und ab zu meinem Main.
Gast #3112332
Lesenswert?

Hi

>Nun das ich nach einer bestimmten Zeit eine Bestimmte Routine anspringen
>möchte und kein Reset ausführen.

Ob der interne Watchdog einen Reset auslöst kann konfiguriert werden. Es 
sind auch noch Interrupt und Interrupt mit nachfolgendem Reset möglich. 
Außerdem kann beim Progammstart abgefragt werden, was den Reset 
ausgelöst hat. Steht im Register MCUSR.

>Ich bin in einer schleife gefangen die bei Normalfall verlassen wird.
>Aber im nicht normalen Fall würde sich mein kleiner Mega halt in dieser
>Schleife aufhängen.

>Also dachte ich einen Timer gestartet, da die schleife nach 0,5Sekunden
>eigentlich beendet sein müsste. Ist dieses nicht der Fall so setzt der
>Timer ein, Fehlermeldung wird ausgegeben und ab zu meinem Main.

Dann einfach einen Timer starten, der nach den 0,5s ein Flag setzt. Das 
wird abgefragt und entsprechend gehandelt.

Ich habe den Watchdog in 15 Jahren mit AVRs noch nicht einmal gebraucht.

MfG Spess
Gast #3112398
Lesenswert?

spess53 schrieb:
> Hi
>
>>Ja das war auch am Anfang meine Idee, doch habe ich in der Schleife
>>dafür keine Zeit mehr. Hatte ich schon versucht und  das Timing war im
>>A.....
>
> Als Flag kannst du z.B. auch das T-Flag in SREG nehmen. Dann langt ein
> zusätzliches brtc oder brts um deine Schleife zu verlassen.
>
> MfG Spess

Richtig das T-Flag hatte ich auch gefunden. Doch kostet mich auch die 
brtc bzw. brts zu viel Zeit.
#3112404
Lesenswert?

Holger P. schrieb:

> Richtig das T-Flag hatte ich auch gefunden. Doch kostet mich auch die
> brtc bzw. brts zu viel Zeit.

Zeig mal Code.
Irgendwie kommt mir das spanisch vor, wenn du einerseits eine Schleife 
mit einem Timeout beenden willst, es aber auf der anderen Seite auf 
jeden Taktzyklus ankommt.

Es gibt natürlich solche Fälle, bei denen es tatsächlich auf jeden 
Taktzyklus ankommt, aber im Regelfall (wir reden hier immerhin über 
Mykro-Sekunden) ist das kein Problem.
Gast #3112410
Lesenswert?

>Ich bin in einer schleife gefangen

Soso. Dann könnte es aber auch sein, dass Dein Problem ganz woanders 
liegt als in Deinem Unwissen darüber, wie man den Stack verbiegt, 
nämlich hier:

Was ist das für eine Schleife, die Deinen ATmega gefangennimmt? Muss sie 
das unbedingt tun und wenn ja: Aus welchem Grund?

>Richtig das T-Flag hatte ich auch gefunden. Doch kostet mich auch die
>brtc bzw. brts zu viel Zeit.

Diese Schleife muss etwas ganz Besonderes sein.
Gast #3112462
Lesenswert?

Hi,

Holger P. schrieb:
> ich möchte das es zu Loop_2 springt (0x002B) und alle anderen
> Rücksprungadressen vergisst (rcall, reti, Pop, etc)


...wenn du den Stack eh löschst, brauchst du am Ende deiner ISR auch 
kein reti. Das reti restauriert ja nur den P.C. mit der, beim Aufruf der 
ISR auf den Stack gelegten, Adresse.

Das ist aber dirty coding...


loop_1:
rjmp loop_1


Loop_2:
rjmp loop_2


Wechsel:
   ldi r16,high(RAMEND)
   out SPH,r16
   ldi r16,Low(RAMEND)
   out SPL,r16

  rjmp loop_2


Falls ich dich richtig verstanden habe...
Mike
Gast #3112466
Lesenswert?

Peter II schrieb:
> Holger P. schrieb:
>> Wo oder wie könnte ich das verkürzen?
>
> warum nicht den Pinchage interrupt dafür verwenden und dann ein flag
> setzen. auf diesen kannst du dann warten.
>
> Oder ist es wichtig das du "sofort" nach dem low etwas machst?

Dieses habe ich auch schon versucht. Zum einen sind es 8 Signale die ich 
hintereinander abfragen möchte. ( zu wenig Interrupt beim Mega88 ) und 
zum anderen kostet mich das zu viel Zeit.

Ich habe 8 Signalleitungen die alle mal ganz kurz low werden. Es ist 
alles OK wenn diese innerhalb von 0,5Sek mal low waren.

Also habe ich 8 von diesen Schleifen hintereinander gebaut.

Also
1. Taster wird gedrückt
2. Alle 8 Leitung auf low testen.
3. waren alle Leitung mal low alles OK

Klappt so auch 100% nur wenn mal eine Leitung defekt ist oder ???? so 
würde ich aus diesem Test nie wieder zurück kommen. Deswegen ein Timer 
1Sek vor den Schleifen starten. und nach den Schleifen wieder anhalten.

Schlägt der Timer zu so Fehlermeldung und ab wieder zum Main.
Gast #3112469
Lesenswert?

Diese Schleife ist exakt genauso schnell, wird aber verlassen sobald das 
T-Flag gesetzt ist:

1
   clt
2
Wait_Start_1:
3
   sbic  PIND,PIND2   ; Überspringe den nächsten Befehl, fals Bit 2 in PIND low ist
4
   brtc  Wait_Start_1 ; T=0 --> loopen, T wird beim Timeout in der Timer-ISR gesetzt

>Ein brbs kostet mich 631Hz was bei dieser Aufgabenstellung...

Solche Aufgabenstellungen sind (natürlich) nicht ausgeschlossen, aber in 
der Praxis selten.
Gast #3112479
Lesenswert?

Hi

>Ein brbs kostet mich 631Hz was bei dieser Aufgabenstellung dazu führt
>das ich diesen kurzen low Impuls nicht immer sicher erkenne.

Nein.
1
   ...
2
   clt
3
   ...
4

5
Wait_Start_1:
6
   sbic  PIND,PIND2
7
   brtc  Wait_Start_1 
8
   brts Main 
9
   ...
10

11
Interrupt:
12
   set
13
reti
Das kostet dich lediglich einen Takt nach der Schleife wenn ein Inpuls 
erkannt wurde.

MfG Spess
Gast #3112489
Lesenswert?

spess53 schrieb:
> Hi
>
>>Ein brbs kostet mich 631Hz was bei dieser Aufgabenstellung dazu führt
>>das ich diesen kurzen low Impuls nicht immer sicher erkenne.
>
> Nein.   ...
>    clt
>    ...
>
> Wait_Start_1:
>    sbic  PIND,PIND2
>    brtc  Wait_Start_1
>    brts Main
>    ...
>
> Interrupt:
>    set
> reti
> Das kostet dich lediglich einen Takt nach der Schleife wenn ein Inpuls
> erkannt wurde.
>
> MfG Spess

Jou aber springt man nun nicht immer in Main?
Sollte Pin Low sein geht es weiter mit dem nächsten Pin dabei so wenig 
Zeit wie es geht zu verlieren.

Aber ich werde es mal versuchen. Danke
Gast #3112493
Lesenswert?

1
Wait_Start_1:
2
   sbic  PIND,PIND0   ; Überspringe den nächsten Befehl, fals Bit 0 in PIND low ist
3
   rjmp  Wait_Start_1 
4

5
Wait_Start_2:
6
   sbic  PIND,PIND1   ; Überspringe den nächsten Befehl, fals Bit 1 in PIND low ist
7
   rjmp  Wait_Start_2 
8

9
Wait_Start_3:
10
   sbic  PIND,PIND2   ; Überspringe den nächsten Befehl, fals Bit 2 in PIND low ist
11
   rjmp  Wait_Start_3 
12

13
Wait_Start_4:
14
   sbic  PIND,PIND3   ; Überspringe den nächsten Befehl, fals Bit 3 in PIND low ist
15
   rjmp  Wait_Start_4 
16

17
Wait_Start_5:
18
   sbic  PIND,PIND4   ; Überspringe den nächsten Befehl, fals Bit 4 in PIND low ist
19
   rjmp  Wait_Start_5 
20

21
Wait_Start_6:
22
   sbic  PIND,PIND5   ; Überspringe den nächsten Befehl, fals Bit 5 in PIND low ist
23
   rjmp  Wait_Start_6 
24

25
Wait_Start_7:
26
   sbic  PIND,PIND6   ; Überspringe den nächsten Befehl, fals Bit 6 in PIND low ist
27
   rjmp  Wait_Start_7 
28

29
Wait_Start_8:
30
   sbic  PIND,PIND7   ; Überspringe den nächsten Befehl, fals Bit 7 in PIND low ist
31
   rjmp  Wait_Start_8 
32

33

34
ALLES OK
#3112501
Lesenswert?

Holger P. schrieb:

> ALLES OK

Das bedeutet aber auch, dass deine Low-Pulse in genau der richtigen 
Reihenfolge kommen müssen.
Davon war aber bei

> . waren alle Leitung mal low alles OK

noch nicht die Rede.

Und es erklärt immer noch nicht, wo diese ultrkurzen Pulse eigentlich 
herkommen.

Würde es was helfen, alle 8 Eingänge gemeinsam parallel abzufragen?

   ldi  r16, 0xFF
loop:
   in   r17, PIND
   and  r16, r17
   brne loop         ; noch nicht auf allen eine 0 gesehen

die Schleife ist zwar ein wenig länger aber dafür ist die Reihenfolge 
egal.

Aber der wichtigste Punkt scheint mir immer noch zu sein: wo kommen die 
Pulse her bzw. machst du dir hier nicht eigentlich selbst ein Problem.
Gast #3112523
Lesenswert?

Karl Heinz Buchegger schrieb:
> Aber der wichtigste Punkt scheint mir immer noch zu sein: wo kommen die
>
> Pulse her bzw. machst du dir hier nicht eigentlich selbst ein Problem.

Das ganze Problem aufzuzeigen wäre echt Arbeit. Nehmen wir doch mal an 
es ist so wie ich es sage. Also das Problem ist so wie hier getippt.

Deswegen bin ich ja auf die Idee mit dem Stack gekommen.
Gast #3112529
Lesenswert?

spess53 schrieb:
> Hi
>
>>Jou aber springt man nun nicht immer in Main?
>
> Nein. Nur wenn das T-Flag gesetzt ist (Timeout) springt er aus der
> Schleife und mit brts in deine Main oder wo du sonst hin willst. Ist das
> T-Flag nicht gesetzt wird 'brts Main' ignoriert.
>
> MfG Spess

Aja eben habe ich es verstanden. Das werde ich mal versuchen ob mich der 
eine Takt nicht killt.

Aber sieht so oder so nicht schlecht aus und vor allem wieder was 
gelernt.
Gast #3112548
Lesenswert?

Hi

>Aja eben habe ich es verstanden. Das werde ich mal versuchen ob mich der
>eine Takt nicht killt.

Den Sprung zur Main brauchst du nur nach

>Wait_Start_8:
>   sbic  PIND,PIND7
>   rjmp  Wait_Start_8

Die Teile davor werden mit gesetztem T-Flag einfach durchlaufen.

Allerdings ist die Variante von Karl-Heinz eleganter. Wie lang sind die 
Impulse und mit welchem Takt läuft dein Controller?

MfG Spess
#3112599
Lesenswert?

spess53 schrieb:

> Wie lang sind die
> Impulse und mit welchem Takt läuft dein Controller?

Das will er ja nicht sagen.
Mein Bauch sagt trotzdem, dass er das 'falsche Problem' löst.
Und sei es nur, dass er einen ungeeigneten Controller nimmt um 
Nano-sekunden Pulse festzustellen, bzw. dort auf Software setzt wo 
eigentlich schon Hardware angebracht wäre.

Aber ist ok. Des Menschen Wille ist sein Himmelreich.

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