www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik MSP430 aus Interrupt springen Hilfe!


Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Servus,

Ich sitze gerade an einem größeren Projekt für den MSP430F169 und bin 
auf ein Problem gestoßen:

Ich muss (Und ich hab mir das echt lange überlegt; Polling in main ist 
nicht drin!) aus einer Port-Interrupt-Funktion an eine bestimmte Stelle 
in meinem Main-Programm springen.

Ich habe das jetzt über einen Inline-Asembler-Code gelöst, welcher den 
PC manipuliert, um so gezielt die entsprechende Zeile erreichen zu 
können.

Das Verfahren klappt auch perfekt. Aber leider nur ein einziges mal!!!
Danach wird der Interrupt gar nicht mehr ausgelöst, auch wenn der IE 
noch aktiv ist und ich alle Flags vorher gelöscht habe.

Da ich Assembler nie gelernt habe: Weiß jemand, woher das kommen könnte? 
Hängt das mit meiner frechen Manipulation der Core-Register zusammen?

Für eine Antwort wäre ich echt dankbar!!!

Markus

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus schrieb:

> aus einer Port-Interrupt-Funktion an eine bestimmte Stelle
> in meinem Main-Programm springen.

Böser Fauxpas. Auch dann, wenn man von Assembler Ahnung hat. So 
programmiert man nicht.

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das habe ich mir fast schon gedacht, danke!!!

Aber gibt es auch eine andere Lösung für dieses Problem?

Gruß,

Markus

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In Interrupt-Handlern wird irgendein Status gesetzt, der in der Mainloop 
abgefragt wird.

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Polling/Abfragen von Status-Bits ist leider nicht möglich :(

Deshalb bin ich ja auf diese verquere Lösung gekommen!

Der Interrupt soll zu einem "kontrollierten Reset" führen und eine 
Stelle in main anfahren ohne einen wirklichen Hardware-Rest zu benutzen, 
das Variablen erhalten bleiben müssen!

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das was du vorhast, setzt beinahe voraus, dass du Compiler und Library 
selbst geschrieben hast. Weil du ganz genau wissen musst, was beide in 
allen Lebenslagen tun.

Da dies offensichlich nicht der Fall ist, kann ich nur die dringende 
Empfehlung abgeben, dieses Konzept komplett in die Tonne zu kippen.

Wenn bestimmte Variablen einen Reset überleben sollen, dann gibt es 
evtl. Möglichkeiten, sie entsprechend zu deklarieren oder den sie 
initialisierenden Startup-Code entsprechend zu modifizieren/ersetzen.

Es gibt zwar mit setjmp/longjmp antike Mechanismen für non-local gotos, 
aber wenn man das in einem Interrupt-Handler macht, dann drohen trotzdem 
einige Überrschungen.

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stellt sich eher die Frage, wieso Polling nicht möglich ist? Musst halt 
entsprechend oft pollen, quasi nach jeder Funktion in der Main-Schleife 
das Bit, was die ISR setzt, überprüfen.

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Polling ist extrem schwierig bis unmöglich, da der Sprung zurück an eine 
bestimmt Main-zeile aus mehreren Funktionen in mehreren C-Modulen 
(Dateien) kommen können muss! Deshalb ja der gescheiterte Versuch mit 
dem Inline-Assembler. Ich wollte mir tausende von if(polling) Abfragen 
ersparen, zumal die Applikation sehr Timing-sensitiv ist!

Das ist alles sehr unbefriediegend!

Aber trotzdem schonmal allen danke für die Antworten!

Und falls es noch Ideen gibt: Her damit!!!

Autor: mal_so (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kannst Du deine Reset-Routine 'diese Stelle in Main' nicht als Funktion 
/ Unterprogramm ausführen welches von Main und auch deiner 
Interruptroutine angesprungen wird ?

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gute Idee!

Aber das Problem ist nicht, dass ich eine spezifische Operation, welche 
schon mal in main vorgekommen ist, nochmal ausführen will, sondern dass 
das ganze Programm nochmal von vorne starten soll (Halt nur ohne das 
Setup). Und dieser Sprung muss halt IMMER und von ÜBERALL möglich sein, 
weil in meiner Applikation ein Reset IMMER und ÜBERALL kommen kann und 
das Programm SOFORT reagieren können muss und nicht erst beim nächsten 
Polling.

Dumme Sache, was?

Ich bin weiterhin für alles offen! Super Hilfsbereitschaft!!!!!!

Autor: mal_so (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dann setz doch in Main alle Register (ausser PC) so wie sie beim 
Hard-Reset /Power-on gesetzt werden (Sprungmarke main_2 für die 
Interruptroutine). Davor main_1 welche beim Power_on angesprungen wird - 
zur Initialisierung...

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klingt gut!
Hab ich aber nicht verstanden!

Wäre ein Anschauungsbeispeil möglich???

(Fehlerhaftes) Prinzip im Moment:

Variablen.....

main()
{
  Initialisierung........
  Assembler-Code (PC speichern)
  Programm.......
}

Interrupt-Funktion
{
   Assembler-Code (Ersetzte PC durch gespeicherten Wert)
}

Ergebniss: Murks!

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Ergebniss: Murks!

Du hast eigentlich die ganze zeit um den heißen Brei herumgeredet z.B. 
Warum muss man aus jeder Programmstelle an eine bestimmte andere 
springen?

Ausser deiner Meinung, das es nicht anders geht, hast du noch keinen 
triftigen Grund genannt.

>Ergebniss: Murks!

eher: Konzept Murks.

MfG Spess

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tschuldigung, ich wollte nicht gleich mit allen Details nerven!
Habs ja nur einfach halten wollen!

Mein Prozessor soll zum 1-Wire-Slave werden und eine Kommunikation mit 
anderen 1-Wire Devices ermöglichen. Da diese Schnittstelle rein auf 
Timing basiert und jede Flanke damit entscheidend ist, muss ich 
Interrupt-Funktion für jeden Befehl nutzen können. Dies bedeutet auch, 
dass mal auf einen Interrupt gewartet werden muss, zb, wenn mehr als ein 
bit erwartet wird!
Nun wollte ich vermeiden, dass sich das Programm beim Verlust eines Bits 
oder einer Flanke (Aus welchem grund auch immer) aufhängt. Also: Es muss 
immer ein Reset möglich sein, ganz egal, wo das Programm gerade ist, ob 
in main oder sonst wo!

Zufrieden?

Wenn ja, ich bin weiterhin am Suchen für eine Lösung!

MfG,

Markus

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, du müsstest den StackPointer auch wieder zurück stellen, denn beim 
Srpung in die ISR wird der PC und das SR auf den Stack gerettet. Dann 
wird sicherlich der C-Compiler auch noch einige Pushs eingebaut haben, 
um seine Register zu retten. Das alles musst du wieder per pop 
zurückholen. Außerdem musst du alles das abhandeln, was ein RETI 
eigentlich macht. Flags löschen, GIE wieder einschalten usw. damit es 
wirklich so ist, als wärest du aus der ISR wieder heraus gesprungen. 
Dann könnte es klappen, obwohl es eine wirkliche Schweinerei ist die 
ganze Sache. Du wolltest das Konzept nochmal überdenken, es geht 
garantiert auch ohne diese Kankheit.

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK, mir ist klar geworden, dass es so nicht gehen kann!
Aber anscheinend gibt es auch keine bessere Lösung in diesem einfachen 
Sinne.
Vielleicht mache ich doch einen Totalen Hardware-Reset und speichere mir 
vorher die wichtigen Variablen im Flash!

Schade aber auch! Eine schnelle und korrekte Lösung für mein Problem 
scheint es echt nicht zu geben!

Trotzdem allen Vielen Dank! Falls jemandem doch noch was einfällt, wäre 
ich überaus dankbar, wenn er/sie es mir noch mitteilen könnte!

Gruß,

Markus

Autor: Jörg S. (joerg-s)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab's mir jetzt nicht im detail durchgelesen, aber wenn es darum geht 
nach dem Reset einen Code-Teil zu überspringen, müsste das doch mit dem 
Watchdog möglich sein. Wenn ich mich recht erinnere kann man doch 
feststellen ob der Reset durch Power on oder Watchdog ausgelöst wurde.
Also muss man beim booten nur schauen ob's ein Watchdog war und wenn ja 
den Code Teil überspringen den er nicht ausführen soll.

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, ihm gehts ja aber drum, alle Variablen-Inhalte zu belassen. Dazu 
müsste er die StartUp Codes ändern, die ja alle Variablen 
initialisieren.

Autor: Flo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
1-wire-Slave würd ich eher mit Timerinterrupts programmieren als über 
irgendwelche Flankenerkennungen, da du ja 0 und 1 nur über 
unterschiedlich lange Low-Phasen codierst, kann man ja im Timerinterrupt 
den Pinstatus mitzählen, von mir aus 4 mal low = 0 und 10 mal low = 1.
dann die Zeitlich außeinanderliegenden Abtastwerte in ein Datenwort 
zusammenschieben und auswerten.

Autor: Nobody (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus schrieb:
> Nun wollte ich vermeiden, dass sich das Programm beim Verlust eines Bits
> oder einer Flanke (Aus welchem grund auch immer) aufhängt.

Sowas geschieht ja nicht grundlos und falls man den Grund nicht als 
irrelevant betrachtet, hat das den Vorteil das man ihn kennt und 
vermeiden kann.
Gefühlsmäßig beruht die Fragestellung des TO auf der Unsicherheit 
darüber welche Gründe es für das übersehen von Flanken gibt. Das sollte 
man zuerst angehen und erst wenn man die Gründe kennt eine Abhilfe 
überlegen.
Es ist IMHO besser die Ursachen anzugehen und nicht die Symptome.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Es gibt zwar mit setjmp/longjmp antike Mechanismen für non-local gotos,
> aber wenn man das in einem Interrupt-Handler macht, dann drohen trotzdem
> einige Überrschungen.

Schau in der Compiler-Doku oder im "setjmp.h" nach.
Z.B. beim AVR-GCC geht es.


Eine andere Möglichkeit ist, den Main-Code als Statemachine 
(Switch/Case) aufzubauen, statt als ellenlangen Spaghetticode.
Dann brauchst Du immer nur zu Beginn des Switch das Flag abtesten.
Oder der Interrupt setzt Deine Statevariable ganz brutal auf 0 und schon 
geht alles automatisch von vorne los.
Es wird maximal noch der gerade laufende State beendet.


Peter

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier mal ein Beispiel für eine Statemachine für 1-Wire Master im 
Hintergrund per Timerinterrupt auf nem 8051:

State 20, 19: Reset
State 18 .. 11: sende Byte
State 8 .. 1: lese Byte
State 0: fertig

onwi_write: Anzahl der zu sendenden Bytes
onwi_read: Anzahl der zu lesenden Bytes

void t0_handler( void ) interrupt INT_T0
{
  ONWI_IO = 1;                          // pin = 1

  if( --onwi_state >= ONWI_START )
    return;                             // used as start delay counter

  TR0 = 0;
  TL0 = LOAD60us;
  TH0 = LOAD60us >> 8;                  // 60µs = 200 cycle

  switch( onwi_state ){

    case 20:                            // 480us low
      ONWI_IO = 0;                      // pin = 0

    case 19:                            // 480us high
      TL0 = LOAD480us;
      TH0 = LOAD480us >> 8;
      break;

    case 10:                            // 1. command byte finished
    case 18:
      if( onwi_write ){
        onwi_write--;
        onwi_state = 18;                // write bit 0

    case 17:                            // write bit 1
    case 16:
    case 15:
    case 14:
    case 13:
    case 12:
    case 11:                            // write bit 7
        ONWI_IO = 0;                    // pin = 0
        delay();
        if( onwi_buff[onwi_write] & 1 )
          ONWI_IO = 1;                  // pin = 1
        onwi_buff[onwi_write] >>= 1;
        break;
      }
    case 0:
      if( onwi_read == 0 ){             // all reading done

    default:
        return;                         // leave TR0 = 0: one wire finished
      }
      onwi_read--;
      onwi_state = 8;                   // read bit 0

    case 7:                             // read bit 1
    case 6:
    case 5:
    case 4:
    case 3:
    case 2:
    case 1:                             // read bit 7
      ONWI_IO = 0;
      delay();
      ONWI_IO = 1;                      // 6 cycle = 1.8µs
      onwi_buff[onwi_read] >>= 1;
      if( ONWI_IO )                     // 18 cyle = 5.7µs
        onwi_buff[onwi_read] |= 0x80;
  }
  TR0 = 1;
}

Peter

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Flo schrieb:
> 1-wire-Slave würd ich eher mit Timerinterrupts programmieren als über
> irgendwelche Flankenerkennungen, da du ja 0 und 1 nur über
> unterschiedlich lange Low-Phasen codierst, kann man ja im Timerinterrupt
> den Pinstatus mitzählen, von mir aus 4 mal low = 0 und 10 mal low = 1.

Schon klar, ich zähle ja auch Zeiten und keine Flanken (Nur nicht über 
Timer, sondern über Delay-Cycles, die sind genauer). Nur für den Start, 
also das loslassen der Timer, brauche ich die Flankendetektierung. (Und 
das bei jedem Bit auf neue!)

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nobody schrieb:
> Gefühlsmäßig beruht die Fragestellung des TO auf der Unsicherheit
> darüber welche Gründe es für das übersehen von Flanken gibt. Das sollte
> man zuerst angehen und erst wenn man die Gründe kennt eine Abhilfe
> überlegen.

Es gibt dafür bei mir nur einen Grund: Hardware zu langsam.
Alles andere habe ich beseitigt!

Den Fehler kann ich im Moment nicht beheben, da Übertakten und Austausch 
im Moment nicht in Frage kommen.

Aber grundsätzlich stimme ich dem Statement voll und ganz zu!!!!!

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:
> Hier mal ein Beispiel für eine Statemachine für 1-Wire Master im
> Hintergrund per Timerinterrupt auf nem 8051:
>
> State 20, 19: Reset
> State 18 .. 11: sende Byte
> State 8 .. 1: lese Byte
> State 0: fertig

Guuuuuut! Vielen Dank für den Hinweis!

Allerdings ist die sache nicht ganz so einfach:
Weiterhin gilt: Reset muss immer möglich sein und der Slave-Code 
beschränkt sich nicht nur aufs andauernde lesen und schreiben, sodass 
durchaus mal Flanken verloren gehen können (Siehe: Hardware zu langsam) 
Das ist bei mir aber echt nur die Ausnahme. Die Sicherheit in Sachen 
aufhängen muss halt nur immer gegeben sein. Und falls mal eine erste (!) 
Flanke verloren geht, ist halt ohne möglichen Reset Ende!

Aber ich werde die Sache mit der Satemachine weiter verfolgen! 
vielleicht lässt sich das verwerten! Danke!

Autor: ralf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eigentlich brauchst du nur im IRQ den den SP neu zu initialisieren, GIE 
setzen und ohne reti direkt zu der Main-zeile springen.

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und wie in die entsprechende Main-Zeile springen?
Da liegt ja mein Problem!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.