MSP430: Auswertung Interrupt-Flags

Gast #2057945
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:
1
#pragma vector = DMA_VECTOR
2
__interrupt void DMA_ISR(void)
3
{
4
  do
5
  {
6
    if(DMAIV & DMAIV_DMA0IFG)
7
    {
8
      /* DMA0 Interrupt */
9
      if(DMA0Interrupt_CB != NULL)
10
      {
11
        DMA0Interrupt_CB();
12
      }
13
    }
14
    if(DMAIV & DMAIV_DMA1IFG)
15
    {
16
      /* DMA1 Interrupt */
17
      if(DMA1Interrupt_CB != NULL)
18
      {
19
        DMA1Interrupt_CB();
20
      }
21
    }
22
    if(DMAIV & DMAIV_DMA2IFG)
23
    {
24
      /* DMA2 Interrupt */
25
      if(DMA2Interrupt_CB != NULL)
26
      {
27
        DMA2Interrupt_CB();
28
      }
29
    }
30
  } while (DMAIV);
31
}

Beim anschauen des Anwenderhandbuchs ist mir der Assemblercode dazu 
aufgefallen:
1
;Interrupt handler for DMA0IFG, DMA1IFG, DMA2IFG Cycles
2
DMA_HND ... ; Interrupt latency 6
3
ADD &DMAIV,PC ; Add offset to Jump table 3
4
RETI ; Vector 0: No interrupt 5
5
JMP DMA0_HND ; Vector 2: DMA channel 0 2
6
JMP DMA1_HND ; Vector 4: DMA channel 1 2
7
JMP DMA2_HND ; Vector 6: DMA channel 2 2
8
RETI ; Vector 8: Reserved 5
9
RETI ; Vector 10: Reserved 5
10
RETI ; Vector 12: Reserved 5
11
RETI ; Vector 14: Reserved 5
12
DMA2_HND ; Vector 6: DMA channel 2
13
... ; Task starts here
14
RETI ; Back to main program 5
15
DMA1_HND ; Vector 4: DMA channel 1
16
... ; Task starts here
17
RETI ; Back to main program 5
18
DMA0_HND ; Vector 2: DMA channel 0
19
... ; Task starts here
20
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!
#2057988
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.
Gast #2058026
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.
Persönliche Seite #2058031
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.
Gast #2058063
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.
#2058221
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
#2058282
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.
Gast #2058359
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...

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