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
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
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
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.
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
Hi Horst, Du mußt nur am Anfang Deiner ISR die ISR-Flags zurücksetzen. MfG Michael
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
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
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
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
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
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
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
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.