Forum: Digitale Signalverarbeitung / DSP / Machine Learning periodischer Interrupt


von Horst (Gast)


Lesenswert?

Hallo zusammen,

ich möche eine Interruptstruktur programmieren. Ein Interrupt soll
periodisch alle 200µs ausgelöst werden. Als Timer wird der GP Timer 1
von Event Manager A genutzt. Der Interrupt, der ausgelöst werden soll
ist: T1UFINT (INT2.6). Die Routine, die ausgeführt werden soll, wenn
der Interrupt angestoßen wird, lautet: v_Regelung()

So weit bin ich gekommen:

  EvaRegs.EVAIMRA.bit.T1UFINT = 1;
  PieCtrlRegs.PIEIFR2.bit.INTx6 = 1;
  PieCtrlRegs.PIEIER2.bit.INTx6 = 1;
  PieCtrlRegs.PIEACK.all = 0;

  PieCtrlRegs.PIECRTL.bit.ENPIE = 1;
  IFR |= 0x0002;
  IER |= 0x0002;

  EALLOW;
     GpioMuxRegs.GPAMUX.all = 0x00FF;
    EDIS;

    EALLOW;
    PieVectTable.T1UFINT = &T1UFINT_ISR;
    EDIS;

    EINT;
    ERTM;

_________________________________________________

Die ISR von Interrupt 2.6 sieht folgendermaßen aus:

// INT2.6
interrupt void T1UFINT_ISR(void)   // EV-A
{
  // Insert ISR Code here
  v_Regelung();

  // To receive more interrupts from this PIE group, acknowledge this
  // interrupt
  PieCtrlRegs.PIEACK.all = PIEACK_GROUP2;

  // Next two lines for debug only to halt the processor here
  // Remove after inserting ISR Code
  // asm ("      ESTOP0");
  // for(;;);
}

Infos habe ich mir aus spru078c.pdf und dem Module 4/5 aus dem
Zwickau-Projekt geholt. Leider funktioniert das ganze nicht, wie
gewünscht: Vermutlich wird der gewünschte Interrupt einmal ausgeführt,
anschießend bleibt die CPU in der ISR von INT14 hängen...

Kann mir jemand sagen, ob ich in dem o.g. Code einen Fehler habe, bzw.
wo ich weitere Infos bekommen kann?

vielen Dank, für Eure Hilfe

von Andreas Fertl (Gast)


Lesenswert?

Ich kenns so dass INT Routinen meißt mit einem #pragma makiert werden
müssen und irgendow auch noch zugeordnet sind. Mehr oder weniger einen
Fixen Namen haben.
z.B.
#pragma T1UFINT
interrupt void T1UFINT_ISR(void)   // EV-A
{
}
Wär möglich das es bei dir auch so wäre.
Hast keinen Debugger? Sonnst würd sichs anbieten einmal nen Breakpoint
in die ISR zu legen.

Grüße Andreas

von Michael (Gast)


Angehängte Dateien:

Lesenswert?

Hi Horst,

schau Dir mal meine Routine an. Kannste fast übernehmen. Ist nur für
Timer1_Overflow_ISR...

Dir fehlen ein paar Einstellungen. Vor allem mußt Du die Interruptflags
immer manuell zurücksetzen...

Schau Dir lieber das spru065c.pdf an.

Hast Du keinen Debugger? Wie bekommst Du Deinen Code auf den DSP?

Michael

von Horst (Gast)


Lesenswert?

Hallo,

danke für Eure Hilfe. Mit Hilfe des Beispielcodes konnte ich mein
Problem lösen. Ich benutze den Code Composer (Integrated Development
Version: 2.20.0). Mit dem Debugger gehe ich Schritt für Schritt den
Code durch und lasse mir ein paar Bits anzeigen, um das ganze ein wenig
nachvollziehen zu können.

Vielen Dank nochmal, bin also weitergekommen. Falls ich nochmal
irgendwo Fragen habe, melde ich mich.

Gruß, Horst.

von Horst (Gast)


Lesenswert?

Hallo,

ich nutze inzwischen einen 2. Interrupt: T2UFINT

In SPRU078C.PDF habe ich gelesen (Seite 6-16), daß die Gruppe INT2 eine
höhere CPU Priorität hat, als die Gruppe INT3 zu der ja der T2UFINT
gehört. Durch Tests habe ich aber bemerkt, daß immer die ISR
vollständig ausgeführt wird, die zuerst aufgerufen wurde. Eigentlich
möchte ich aber, daß der eine Interrupt (welcher, ist egal, z.B.
T1UFINT) den anderen während dessen Ausführung unterbrechen kann. Muß
ich da noch irgend etwas freischalten?

Viele Grüße, Horst

von Michael (Gast)


Lesenswert?

Hi Horst,

Du mußt nur am Anfang Deiner ISR die ISR-Flags zurücksetzen.

MfG Michael

von Horst (Gast)


Lesenswert?

Hallo Michael,

hab gerade Deinen Vorschlag probiert. Allerdings ändert sich nichts am
Verhalten. Ich poste hier mal den Quellcode, vielleicht erkennst Du
meinen Fehler....

// INT2.6
interrupt void T1UFINT_ISR(void)         // EV-A
{
   IFR = 0x0000;                         // ISR Flag zurückgesetzt
   GpioDataRegs.GPBDAT.bit.GPIOB6 = 1;   // Testpin, um Start der
                                         // T1UFINT_ISR am Oszilloskop
                                         // beobachten zu können
   GpioDataRegs.GPBDAT.bit.GPIOB7 = 0;   // Testpin von T2UFINT (um
                                         // Unterbrechnung von T2UFINT
                                         // durch T1UFINT beobachten
                                         // zu können
   EvaRegs.EVAIFRA.bit.T1UFINT = 1;   // Reset Interrupt lokales
                                         // Flag
   PieCtrlRegs.PIEACK.bit.ACK2 = 1;   // Interrupt Flag
                                         // zurücksetzen

   v_Regelung();                         // Routine, die im Kontext
                                         // dieses Interrupts laufen
                                         // soll

   GpioDataRegs.GPBDAT.bit.GPIOB6 = 0;   // Testpin, um Ende der
                                         // T1UFINT_ISR am Oszilloskop
                                         // beobachten zu können
}

// INT3.3
interrupt void T2UFINT_ISR(void)         // EV-A
{
   GpioDataRegs.GPBDAT.bit.GPIOB7 = 1;   // Testpin, um Start der
                                         // T2UFINT_ISR am Oszilloskop
                                         // beobachten zu können
   GpioDataRegs.GPBDAT.bit.GPIOB6 = 0;   // Testpin von T1UFINT (um
                                         // Unterbrechnung von T1UFINT
                                         // durch T2UFINT beobachten
                                         // zu können
   EvaRegs.EVAIFRB.bit.T2UFINT = 1;   // Reset Interrupt lokales
                                         // Flag
   PieCtrlRegs.PIEACK.bit.ACK3 = 1;   // Interrupt Flag
                                         // zurücksetzen

   v_Steuerung();                        // Routine, die im Kontext
                                         // dieses Interrupts laufen
                                         // soll

   GpioDataRegs.GPBDAT.bit.GPIOB7 = 0;   // Testpin, um Ende der
                                         // T2UFINT_ISR am Oszilloskop
                                         // beobachten zu können
}

Ich bin dabei davon ausgegangen, daß INT2.6 die höhere Priorität hat.
Und (wenn ich Deinen Beitrag richtig verstanden habe) mit IFR = 0x0000
das "ISR-Flag" zurückgesetzt werden kann.
Nachdem die ISR mit der niederen Priorität unterbrochen und die ISR mit
der höheren Priorität ausgeführt wurde, soll die ISR mit der niederen
Priorität an der "Unterbrechungsstelle" weitergeführt werden.

Viele Grüße, Horst

von Michael (Gast)


Lesenswert?

Du setzt in beiden ISR's die Flags zurück. So wird dann natürlich jeder
Interrupt den anderen ablösen. Das Zurücksetzen ist vergleichbar mit
"Jetzt ist der DSP wieder Interrupt fähig". Folglich kann ein
niederpriorer Interrupt einen höherprioren Interrupt ablösen. :-) :-(

Für Dich bedeutet das, dass Du die ISR mit der niedriegen Priorität
sofort wieder freigibst. Bei dem mit der hohen Priroität erst am Ende
der ISR wieder die Flags zurücksetzt.

Schwierig wird es wenn Du mehr als nur zwei Interrupte nutzen willst.
Aber wenn Du das Prinzip verstanden hast, dann sollte auch das nicht
allzu schwer sein...

Michael

von Horst (Gast)


Lesenswert?

Hallo,

ich habe Dich leider nicht ganz verstanden. Was meinst Du mit:

"Du setzt in beiden ISR's die Flags zurück."?

Ich dachte eigenltich, Du meintest das IFR. Dieses habe ich nur in der
T1UFINT_ISR zurückgesetzt.

Da ich nun noch einen dritten Interrupt nutzen möchte, sollte ich das
Prinzip wirklich verstanden haben, wie Du bereits sagtest. Dieser
Interrupt soll allerdings nicht von einem Timer gestartet werden,
sondern nur laufen, wenn keiner der anderen beiden läuft. Gibt es da
schon was? Oder welches Ereignis könnte diesen Interrupt anstoßen?

Viele Grüße und vielen Dank!

Horst

von Michael (Gast)


Lesenswert?

Hi Horst,

v_Steuerung soll von v_Regelung unterbrochen werden können, oder?

Dann darfst Du doch nicht schon vor v_Regelung schreiben:

   EvaRegs.EVAIFRA.bit.T1UFINT = 1;
PieCtrlRegs.PIEACK.bit.ACK2 = 1; // Gebe Interrupt frei
   // Ab hier können alle(!) anderen Interrupts diese ISR
   // ablösen !!!
   v_Regelung();

Sondern richtig:
   v_Regelung();
   // Bis hier, nun ist keine ISR Ablösung möglich.
   EvaRegs.EVAIFRA.bit.T1UFINT = 1;
   PieCtrlRegs.PIEACK.bit.ACK2 = 1;


Ich hoffe das hilft Dir weiter,
Michael

von Horst (Gast)


Lesenswert?

Ah wunderbar! Ich habe das falsche Register gemeint! Dann ists klar!

Aber ich hatte noch eine Frage wegen dem 3. Interrupt:
Dieser soll nicht von einem Timer gestartet werden,
sondern nur laufen, wenn keiner der anderen beiden läuft. Gibt es da
schon was? Oder welches Ereignis könnte diesen Interrupt anstoßen?

Viele Grüße, Horst

von Horst (Gast)


Lesenswert?

Hallo,

ich dachte, ich hätte es verstanden, aber es funktioniert trotzdem
nicht so, wie es soll. Ich poste nochmal meine beiden ISR:


// INT2.6
interrupt void T1UFINT_ISR(void)   // EV-A
{
  int a;
  double b;
  v_Regelung();
  EvaRegs.EVAIFRA.bit.T1UFINT = 1;  // Reset Interrupt lokales
                                        // Flag
  PieCtrlRegs.PIEACK.bit.ACK2 = 1;  // Interrupt Flag zurücksetzen
  EINT;
}


// INT3.3
interrupt void T2UFINT_ISR(void)    // EV-A
{
  int c;
  double d;
  EvaRegs.EVAIFRB.bit.T2UFINT = 1;  // Reset Interrupt lokales
                                        // Flag
  PieCtrlRegs.PIEACK.bit.ACK3 = 1;  // Interrupt Flag zurücksetzen
  EINT;
  v_Steuerung();
}

Beim INT2.6 habe ich darauf geachtet, daß die beiden Zeilen:

  EvaRegs.EVAIFRA.bit.T1UFINT = 1;  // Reset Interrupt lokales
                                        // Flag
  PieCtrlRegs.PIEACK.bit.ACK2 = 1;  // Interrupt Flag zurücksetzen

NACH dem Aufruf von v_Regelung(); stehen. Beim INT3.3 ist es genau
umgekehrt. Es ist aber tatsächlich immer noch so, daß keiner der beiden
Interrupts den anderen wirklich unterbricht.
Gibt es noch eine andere "Schraube" an der ich drehen könnte?

Viele Grüße und Dankeschön,

Horst

von Horst (Gast)


Lesenswert?

Hallo  zusammen,

so langsam werde ich das Gefühl nicht los, daß sich entweder zwei
Interrupts aus vereschiedenen INT-Gruppen nicht gegenseitig
unterbrechen können, oder daß irgendwo ein Hardware-, Software oder
Denkfehler vorliegt. Denkfehler wäre mir am liebsten, da er am
einfachsten zu beheben wäre...
Nach weiteren zeitintensiven Untersuchungen habe ich folgendes
entdeckt:
(ich beziehe mich auf meinen geposteten Code vom 7.8.)
- angenommen, die Ausführung befindet sich innerhalb von T2UFINT_ISR.
(Zur Erinnerung: der Interrupt mit der geringeren Priorität)
- Mit Hilfe des Watch Windows sehe ich, daß innerhalb der Routine
v_Steuerung() (die von T2UFINT_ISR aus aufgerufen wird) folgendes
gilt:

IER=2
PieCtrlRegs.PIEACK.bit.ACK2=0
PieCtrlRegs.PIEACK.bit.ACK3=0
IFR=2

Da IFR und IER gesetzt sind, sowie EINT (Rücksetzen von INTM)
ausgeführt wird, sind meiner Meinung alle Bedingungen erfüllt, damit
das Interruptsignal für den höherpriorisierten Interrupt T1UFINT zum
CPU Kern weitergeleitet werden kann.
Aber: erst nachdem T2UFINT_ISR komplett ausgeführt wurde, startet
T1UFINT_ISR.
Inzwischen weiß ich nicht mehr, was ich noch probieren könnte, bzw. wo
ich noch nachlesen könnte.
Die TI Discussion Groups habe ich auch schon rauf und runter gelesen.

Viele Grüße.... und Danke!

Horst

von Michael (Gast)


Lesenswert?

Hi Horst,

seltsam, dass die Interruptablösung nicht funktioniert. Versuch doch
mal folgende unkonventionelle Vorgehensweise.

1) Ersetze Deinen Funktionsaufruf v_Steuerung() durch while (1).

2) Lass Dein Programm laufen

3) interrupt void T1UFINT_ISR(void){...; da setzt Du einen Breakpunkt
  rein.

Du kannst dann absolut sicher sein, wenn Du auf den Breakpunkt läufst,
aus der ISR abgelöst worden zu sein.

Läufst Du nicht drauf, setze & rücksetze sämtliche in Frage kommenden
Flags und Bits (IFR, IER, INTM)

Michael

PS: Sorry, aber einen besseren Vorschlag habe ich nicht.

von Andreas Wiese (Gast)


Lesenswert?

Hallo,

also ich benutzte auch zwei periodische Interrupts, einen mit 20 und
einem mit 100kHz. Die ISR im 20er Interrupt ist sehr lang, daher muss
er in jedem Fall unterbrochen werden, um den 100-Takt zu ermöglichen.
Das klappt bei mir auch ohne Probleme. Das sieht bei mir so aus:


interrupt void eva_timer1_isr(void)//20kHz Interrupt
{
  EINT;   // zeitkritischere Interrupts ermöglichen


Inhalt der ISR




     // Note: To be safe, use a mask value to write to the entire
     // EVAIFRA register.  Writing to one bit will cause a
read-modify-write
     // operation that may have the result of writing 1's to clear
     // bits other then those intended.
     EvaRegs.EVAIFRA.all = BIT7;

  // Acknowledge interrupt to receive more interrupts from PIE group 2
  PieCtrlRegs.PIEACK.all = PIEACK_GROUP2;

}
interrupt void eva_timer2_isr(void){//100kHz Interrupt


Inhalt der ISR



     // Note: To be safe, use a mask value to write to the entire
     // EVAIFRA register.  Writing to one bit will cause a
read-modify-write
     // operation that may have the result of writing 1's to clear
     // bits other then those intended.
     EvaRegs.EVAIFRB.all = BIT0;

  // Acknowledge interrupt to receive more interrupts from PIE group 3
   PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;

}

Der Unterschied, den ich erkenne liegt eigentlich nur im EINT der
langsameren Routine.

Ist allerdings ne Weile her, bin in dem Thema nicht mehr ganz drin.

Gruß
Andreas

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.