Forum: Mikrocontroller und Digitale Elektronik interrupt LowPowerMode MSP430F449


von Fabio S. (codehamster)


Lesenswert?

Hallo zusammen,

ich glaube ich habe einen Denkfehler in meiner Interruptrotine.
Kann mir jemand auf die Sprünge helfen?
Ich möchte wenn am Port1.3 ein Interrupt ansteht einen Zähler erhöen und 
danach den MSP sofort wieder schlafen legen. Jedoch komme ich nach dem 
ersten Interrupt nie mehr in die Interruptroutine...
1
#pragma interrupt_handler port1_isr:PORT1_VECTOR
2
void port1_isr(void)
3
{
4
    if(get_bit(P1IFG, BIT3)){
5
        if(get_bit(P1IES, BIT3)){
6
            // Interrupt wurde durch eine negative Flanke ausgelöst
7
            LPM3_EXIT;
8
        if(flow_counter >= 65535){
9
          flow_counter_old = 0;
10
          flow_counter = 1;
11
          LPM3;
12
        }else{
13
          flow_counter++;
14
          LPM3;
15
        }
16
        }
17
    }
18
    P1IFG = 0;
19
}

Bin um jede Hilfe dankbar.

MFG Fabio

von slw (Gast)


Lesenswert?

Dein Code paßt nicht zu Deiner Aussage, dass Du nie mehr aus der ISR 
rauskommst. Ich bin mir fast sicher dass Du immer wieder diese Routine 
ausführst. Denn es fehlt ein "Clear Interrupt Flag" befehl! Sprich wenn 
ein IRQ Flag gesetzt bleibt, läuft die ISR in einer "Endlos Schleife" 
ab.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Soll das wirklich so sein?
1
void port1_isr(void)
2
{
3
  if (get_bit(P1IFG, BIT3))
4
  {
5
    if (get_bit(P1IES, BIT3))
6
    {
7
      // Interrupt wurde durch eine negative Flanke ausgelöst
8
      LPM3_EXIT;
9
      if (flow_counter >= 65535)
10
      {
11
        flow_counter_old = 0;
12
        flow_counter = 1;
13
        LPM3;
14
      }
15
      else
16
      {
17
        flow_counter++;
18
        LPM3;
19
      }
20
    }
21
  }
22
  P1IFG = 0;
23
}

Irgendwie habe ich das Gefühl, daß Du da mit den Klammern und Deiner 
Sourcecodeformatierung durcheinandergekommen bist.

von Fabio S. (codehamster)


Lesenswert?

Danke erstmal für eure Antworten:

@slw

Du meinst wenn ich das LPM3 flag setze wird das P1IFG = 0; nie mehr 
ausgeführt und somit bleibe ich endlos in dieser Routine gefangen?

@ Rufus Τ. Firefly

ich denke ja, aber kann sein dass ich etwas übersehe. Ich versuchs mal 
zu erklären.

1. IF-Abfrage ist ein Interrupt an Port1.3 aufgetreten
2. IF-Abfrage war es eine negative Flanke, falls ja, CPU hochfahren --> 
LPM3_EXIT;

3. IF-Abfage flow_counter auf Überlauf prüfen
4. Alle Interrupt-Flags des Port1 zurücksetzen.

Ich habe eine Anwendung in der ich möglichst wenig Strom verbrauchen 
soll, da Batteriebetrieben. Ein Geber sendet mir auf Port1.3 sporadisch 
Flanken. Diese Flanken will ich zählen. Über den Basic_Timer fahre ich 
alle 30min externe Speisungen hoch und setze per RF ein Telegramm ab.

Ich steh heute wohl auf der Leitung.

von slw (Gast)


Lesenswert?

ich kenne die genaue Bezeichnungen von den einzelnen Flags nicht, jedoch 
das erste was passieren soll, wenn ein ISR ausgeführt wird, Flag zu 
löschen, der für das anspringen der ISR verantwortlich ist. Wie dieser 
zurück gesetzt wird, steht sicherlich im DB, schau nochmal genau nach.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Auf LPM3_EXIT folgt in Deinem Code unweigerlich ein LPM3 -- ich habe 
Deinen Code nur umformatiert, aber nicht inhaltlich geändert.

Deswegen frage ich ja, ob Du Dir da wirklich sicher bist.

von Erik (Gast)


Lesenswert?

Hallo codehamster,

ich verstehe eins nicht ; wenn  ein interrupt an PortX
warum den "If " Handling ?
bei Assembler wird der interrupt handling ausgeführt und dann
weiter in der Hauptschleife.
Ich mache nur assembler ist das bei C anders?

mfg Erik

von Fabio S. (codehamster)


Lesenswert?

Hallo zusammen,

@slw:
jep da bin ich grundsätzlich deiner Meinung! ev. wäre es besser die 
einzelnen Flags zurückzusetzen, anstatt am Ende der ISR alle Flags 
gleichzeitig.

@Rufus Τ. Firefly:
ich hab gemekrt dass du "nur" umformatiert hast. Auf deine Bemerkung 
dass unweigerlich auf LPM3_EXIT ein LPM3 kommt kann ich nur sagen dass 
ich mir eben nicht sicher bin ob dass so funktionieren kann.
Dazu stellen sich zwei Fragen. Die 1. hat slw schon angesprochen, 
Interruptflags gleich löschen sobald die Bearbeitungsroutine anspringt.
Die 2. Frage die sich mir stellt, gibt es ein minimale Dauer die es 
abzuwarten gilt bis die CPU, und diverse Clocks wieder hochgefahren 
sind, oder ist nach LPM3_EXIT der Prozessor schon wieder bereit 
Arithmetische operationen durchzuführen.
Nach meinen Überlegungen ist ja die Arbeit nach dem inkrementieren, bzw. 
Rücksetzen der Zählerstände erledigt. Desshalb sofort wieder in den 
LPM3.
Aber ich vermute dass da der Hund begraben liegen könnte.

@Erik:
das P1IFG ist das Port 1 Interrupt Flag Register. Wenn an einem der 
Pin's von diesem Port welche für Interrupts freigegeben sind anspricht, 
wird in diese ISR gesprungen. Die IF's sind dazu da um herauszubekommen 
welcher der 8 möglichen Pin's des Ports den Interrupt ausgelöst hat. Man 
hat ja nicht 8 mögliche Interruptquellen wenn eine reichen würde.
Nach Beendigung der ISR wird wieder in der Hauptschleife 
weitergearbeitet, das ist in C nicht anders als in Assembler.

Vielen Dank für Eure Feedbacks, ev. habt Ihr noch einen Tipp für mich, 
ich werde auf jeden Fall nochmal den User-Guide wälzen.

MFG Fabio

von Stefan (Gast)


Lesenswert?

Bei einem Interrupt wird der MSP430 automatisch aufgeweckt und nach 
Beendigung der Interrupt Service Routine auch wieder schlafen gelegt 
wenn er vorher in einem low power mode war. LPM3_EXIT und LPM3 
Anweisungen brauchts dafür nicht.

Mit P1IES (Port 1 interrupt edge select) wird festgelegt ob eine 
positive Flanke (0) oder eine negative Flanke (1) am Pin den Interrup 
auslösen können soll.
P1IES muss entsprechend initialisiert werden, am besten bevor Interrupts 
erlaubt werden.
Eine Prüfung von P1IES in der ISR sollte normalerweise nicht notwendig 
sein.

von Christian R. (supachris)


Lesenswert?

Eine Prüfung, welche Flanke den Interrupt ausgelöst hat ist auch gar 
nicht möglich. Der MSP430 kann nur ent oder weder. Und das muss man 
vorher einstellen. Das LPM3_EXIT braucht man, wenn der MSP nach der ISR 
noch wach sein soll. IFG löschen ist richtig, soweit ich mich erinnere, 
werden die Port-IFGs nicht automatisch gelöscht.

von Fabio S. (codehamster)


Lesenswert?

Guten Morgen,

danke für eure Ausführungen! Hab auch nochmal im User-Guide gestöbert.
Also kurz zusmamengefasst:
- Das Abfragen des EdgeSelectRegisters ist unnötig.
- Ein Interrupt (sofern Freigegeben) weckt die CPU und nach Beendigung 
der ISR wird wieder in den ursprünglichen "Operating Mode" gegangen.

Somit bleibt noch die Frage Interuptflag löschen, am Ende der ISR oder 
beim Beginn der ISR?
1
void port1_isr(void)
2
{
3
  if (get_bit(P1IFG, BIT3))
4
  {
5
    if (flow_counter >= 65535)
6
    {
7
      flow_counter_old = 0;
8
      flow_counter = 1;
9
    }
10
    else
11
    {
12
      flow_counter++;
13
    }
14
    clr_bit(P1IFG, BIT3);
15
  }
16
}

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Fabio S. schrieb:
> if (flow_counter >= 65535)

Was für einen Datentyp hat denn bitte flow_counter?

von codehamster (Gast)


Lesenswert?

unsigned int16

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Hmm. Kann ein unsigned int16 größer werden als 65535?

von Fabio S. (codehamster)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Hmm. Kann ein unsigned int16 größer werden als 65535?

nein =), das geht somit auch kürzer! Danke für den Hinweis.

somit wären alle Fragen geklärt.
Danke für eure Hilfe.

MFG Fabio

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Dann bleibt die Frage, was Du eigentlich mit Deiner Funktion bezweckst. 
Geht es um die Erkennung eines Overflow?

von Fabio S. (codehamster)


Lesenswert?

Hallo Rufus,

Fabio S. schrieb:
> Ich habe eine Anwendung in der ich möglichst wenig Strom verbrauchen
> soll, da Batteriebetrieben. Ein Geber sendet mir auf Port1.3 sporadisch
> Flanken. Diese Flanken will ich zählen. Über den Basic_Timer fahre ich
> alle 30min externe Speisungen hoch und setze per RF ein Telegramm ab.

Also bezwecke ich damit nichts anderes als Interruptgesteuert einen 
Zähler zu bedienen. Kann kürzer behandelt werden als in meinem 
Codeschnippsel, wie du ja bereits bemerkt hast.

Es geht darum dass in einer gewissen Zeit eine gewisse anzahl Impulse 
gezählt werden müssen. Da das System Batteriebetrieben wird, Zählen per 
Interrupt. Ansonsten soll der MSP schlafen und alle xmin ein Telegramm 
absetzen.

von Christian R. (supachris)


Lesenswert?

Na hoffentlich hast du das Zählsignal ordentlich entprellt...

von Fabio S. (codehamster)


Lesenswert?

hab ich =)

bin ja zum Glück nicht mehr ganz so grün hinter den Ohren.
Aber trotzdem musste ich feststellen das ich im Thema Interrupt und 
Operating-Modes des MSP430 noch einiges zu lernen habe.

Danke für eure Feedbacks.
wünsche einen schönen Tag.

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.