mikrocontroller.net

Forum: Compiler & IDEs MSP430: Auswertung Interrupt-Flags


Autor: kai (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Habe eine Frage an euch. Ich verwende einen MSP430F2619 und bin gerade 
dabei die ISR von der DMA zu schreiben (in C).
Das sieht so aus:
#pragma vector = DMA_VECTOR
__interrupt void DMA_ISR(void)
{
  do
  {
    if(DMAIV & DMAIV_DMA0IFG)
    {
      /* DMA0 Interrupt */
      if(DMA0Interrupt_CB != NULL)
      {
        DMA0Interrupt_CB();
      }
    }
    if(DMAIV & DMAIV_DMA1IFG)
    {
      /* DMA1 Interrupt */
      if(DMA1Interrupt_CB != NULL)
      {
        DMA1Interrupt_CB();
      }
    }
    if(DMAIV & DMAIV_DMA2IFG)
    {
      /* DMA2 Interrupt */
      if(DMA2Interrupt_CB != NULL)
      {
        DMA2Interrupt_CB();
      }
    }
  } while (DMAIV);
}

Beim anschauen des Anwenderhandbuchs ist mir der Assemblercode dazu 
aufgefallen:
;Interrupt handler for DMA0IFG, DMA1IFG, DMA2IFG Cycles
DMA_HND ... ; Interrupt latency 6
ADD &DMAIV,PC ; Add offset to Jump table 3
RETI ; Vector 0: No interrupt 5
JMP DMA0_HND ; Vector 2: DMA channel 0 2
JMP DMA1_HND ; Vector 4: DMA channel 1 2
JMP DMA2_HND ; Vector 6: DMA channel 2 2
RETI ; Vector 8: Reserved 5
RETI ; Vector 10: Reserved 5
RETI ; Vector 12: Reserved 5
RETI ; Vector 14: Reserved 5
DMA2_HND ; Vector 6: DMA channel 2
... ; Task starts here
RETI ; Back to main program 5
DMA1_HND ; Vector 4: DMA channel 1
... ; Task starts here
RETI ; Back to main program 5
DMA0_HND ; Vector 2: DMA channel 0
... ; Task starts here
RETI ; Back to main program 5

Der Code sieht wesentlich kompakter aus, als meine If-Abfragen in der 
ISR.

Mache ich da etwas grundlegend Falsch?

Danke für eure konstruktive Kritik!

Gruß
Kai

P.S.:
Um es gleich zu sagen: Ich kann kein Assembler! Schon gar nicht in 
Assembler entwickeln!

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die machen da den MSP430-ISR Trick. Die Interrupt Flags bei den mehrfach 
belegten IFGs sind so gestaltet, dass man einfach das gaze IFG Register 
auf den Programmcounter addieren kann. Ist kein Interrupt anstehend, 
gehts dann mit dem Befehl direkt danach weiter, weil 0 addiert wurde. 
Ist einer anstehend, gehts mit einem der (im obigen Beispiel 3) Befehlen 
weiter, die danach kommen. Das spart jede Menge Latenz. Natürlich klappt 
das mit deinem C-Code nicht, weil du ja erst (wieso überhaupt?) 
überprüfst, ob die ISR Funktion vorhanden ist....wenn du die Abfrage 
weglässt, wird das der Compiler entsprechend umsetzen.

Autor: kai (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian R. schrieb:
> Natürlich klappt
> das mit deinem C-Code nicht, weil du ja erst (wieso überhaupt?)
> überprüfst, ob die ISR Funktion vorhanden ist....wenn du die Abfrage
> weglässt, wird das der Compiler entsprechend umsetzen.

Und wie müsste ich den Code schreiben, dass das so gemacht wird?

Außerdem überprüfe ich ja nicht beim Betreten der ISR ob sie vorhanden 
ist, sondern welches Flag gesetzt ist. Im DMAIV steht doch drin, welcher 
DMA-Interrupt aufgetreten ist. Und es kann ja sein, das wärend ich die 
ISR abarbeite eine zweite DMA fertig ist und wieder einen Interrupt 
auslöst. Dann muss ich nicht erst die ISR verlassen und wieder betreten, 
sonden bleibe in der ISR, bis auch dieser Interrupt abgearbeitet ist.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
kai schrieb:
> Und wie müsste ich den Code schreiben, dass das so gemacht wird?

Mit einem Array von Funktionspointern, dessen Startadresse Du auf void* 
castest, den Inhalt des IFG draufaddierst und das Ergebnis wieder zu 
einem Funktionspointer machst, den Du dann aufrufst.

Wichtig ist, daß das Array ausreichend groß dimensioniert ist -- im 
Assemblerbeispiel enthält die Sprungtabelle 8 Einträge.

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei IAR gibt es die intrinsische Funktion __even_in_range,
die zumindest bei TAIV, TBIV, usw. funktioniert. Ob's auch bei DMAIV 
funktioniert müsstest Du mal näher untersuchen

Autor: kai (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rufus Τ. Firefly schrieb:
> Mit einem Array von Funktionspointern, dessen Startadresse Du auf void*
> castest, den Inhalt des IFG draufaddierst und das Ergebnis wieder zu
> einem Funktionspointer machst, den Du dann aufrufst.
>
> Wichtig ist, daß das Array ausreichend groß dimensioniert ist -- im
> Assemblerbeispiel enthält die Sprungtabelle 8 Einträge.

Dauert das Verwenden von Funktionspointern nicht länger?
Bis ich das Element berechnet habe und da hinspringe (wobei hierbei 
wieder der ganze Stack und so gesichert werden müssten) vergeht doch 
mehr Zeit, wie wenn ich das Register maskiere und auf > 0 abfrage, oder 
nicht!?
Davon abgesehen, dass ein Array mit Funktionspointer mehr Speicherplatz 
braucht. Hier wären es 4 Byte * 8 = 32 Byte ...

Stefan schrieb:
> Bei IAR gibt es die intrinsische Funktion __even_in_range,
> die zumindest bei TAIV, TBIV, usw. funktioniert. Ob's auch bei DMAIV
> funktioniert müsstest Du mal näher untersuchen

Ich verwende CCE und nicht IAR.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
kai schrieb:
> Dauert das Verwenden von Funktionspointern nicht länger?

Wieso sollte es das tun?

> Davon abgesehen, dass ein Array mit Funktionspointer mehr Speicherplatz
> braucht.

Verwendest Du einen MSP430X? Dann ja, sonst nein, ein Funktionspointer 
ist auch nur 16 Bit groß.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Frage ist, ob DMAIV eine Bitmaske oder eine Nummer ist.
Dein &-Test macht nur Sinn, wenn es eine Bitmaske ist und dann ist aber 
eine Sprungtabelle Unsinn.

Ist es dagegen eine Nummer, dann ist der &-Test Unsinn und man nimmt 
einfach ein switch/case.
Dann entscheidet der Compiler automatisch, ob ein Vergleich oder eine 
Sprungtabelle besser ist.
Ein Sprungtabelle lohnt sich nämlich erst ab einer größeren Zahl und bei 
aufeinanderfolgenden Case.

Dein zusätzlicher Test der Funktionsadresse auf Null ist in der Tat sehr 
merkwürdig.
Entweder eine Funktion existiert nicht, dann meckert der Linker oder sie 
existiert und dann ist sie immer != Null.
Auf der Adresse 0x0000 kann keine Funktion stehen.


Peter

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:
> Dein zusätzlicher Test der Funktionsadresse auf Null ist in der Tat sehr
> merkwürdig.
> Entweder eine Funktion existiert nicht, dann meckert der Linker oder sie
> existiert und dann ist sie immer != Null.
> Auf der Adresse 0x0000 kann keine Funktion stehen.

Genau das meine ich, wenn du den Quatsch weglässt und statt dessen das 
Switch-Case nimmst wie in den Beispielcodes von TI, macht der Compiler 
da automatisch die Tabelle draus. Jedenfalls klappt das bei den Timer 
Interrupts wunderbar.

Autor: kai (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Abrüfen auf Null muss deswegen erfolgen, weil die Funktionspointer 
zur Programmlaufzeit gesetzt und auch wieder gelöscht werden können.
Wenn es keinen Registrierte Funktion auf einen DMA-Event gibt, dann 
steht eben Null drin und dann darf ich auch nicht springen...

Autor: kai (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rufus Τ. Firefly schrieb:
> Verwendest Du einen MSP430X? Dann ja, sonst nein, ein Funktionspointer
> ist auch nur 16 Bit groß.

Guckst du oben: MSP430F2619

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dann deaktivier doch beim Löschen des Funktionspointers einfach den 
entsprechenden DMA Kanal. Bringt ja dann auch nix.

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.