Hallo da draußen,
ich probiere in meinem Design eine Interrupt-Routine zu starten. Leider
springt die nicht an.
Deshalb wollte ich bitten, ob nicht jmd einen Blick auf meinen Code
werfen kann, ob da alles richtig ist.
1
XIntcInterruptController;/* Instance of the Interrupt Controller */
2
3
voidroutine(){
4
xil_printf("I N T E R R U P T routine\n\r");
5
while(1);
6
}
7
8
intmain()
9
{
10
//* * Interrupt initialization * *//
11
intStatus;
12
/* Initialize the interrupt controller driver so that it is ready to use. */
Der Interrupt werfende IP-Core funktioniert in der Simulation. Dort wird
Interupt für einen Takt sequentiell oben gehalten; so wie im
Xilinx-Beispiel.
Woran liegt's? C oder VHD?
Warum gewagt?
Interrupt heißt doch, daß der aktuelle Prozess unterbrochen wird und man
in die angegebene Funktion springt.
Eigentlich soll dann mehrfach der PLB ausgelesen werden.
Also, wenn das oben richtig ist, muss es wohl am IP-Core liegen.
Sollte ich den Interrupt vielleicht kombinatorisch statt sequentiell
werfen?
Hallo nochmal,
ich habe gelesen, man kann, wenn man nur einen Interrupt hat, den
Interrupt-Controller auch weglassen.
Leider habe ich wenig dazu gefunden. Geht das wirklich?
Und wenn, wie setze ich im C-Code dann dir interrupt-routine(), die dem
Fall aufgerufen wird?
In dem Code oben setze ich die interrupt-routine() ja mit Hilfe des
Interrupt-Controllers:
XIntc_Connect(&InterruptController,XPAR_INTC_IPCORE_VEC_ID,
(XInterruptHandler) interrupt-routine, NULL);
Hat jmd einen Code-Schnippsel für mich?
olpo schrieb:> ist es so richtig?
Funktionierts, oder funktionierts nicht?
Würde für mich richtig ausschauen.
Standalone BSP dazugebunden?
Schau aber nochmals die Definition für eine XInterruptHandler kompatible
Funktion an. Ich könnte mir vorstellen, dass sie einen Parameter void *
bekommt.
void meine_routine(void * ptr)
{
}
Kennst Du XAPP778 ?
Klaus Falser schrieb:> Kennst Du XAPP778 ?
Ja, daher habe ich microblaze_register_handler(...);
> Funktionierts, oder funktionierts nicht?
Natürlich funktioniert's nicht. Ich habe grade alles ausprobiert: Mit
(void)*Pointer und ohne. Einmal werfe ich den Interrupt kombinatorisch
und einmal sequentiell. Ich habe in der Simulation und mittels LED
überprüft, ob denn überhaupt Interrupts geworfen werden. Das tut es.
Gibt es beim Microblaze nicht solche Error-Register? Müsste da nicht
etwas zu finden sein, wenn ich mir sicher bin, daß der Interrupt
geworfen wird?
Ich habe bereits ein mdm-Modul mitsynthetisiert und bei dem Microblaze
"Enable Debug" eingestellt. Nur, wie greif ich auf die Error-Register
zu, oder wie bediene ich das mdm?
- Wie ist der Interrupt-pin beim Microblaze definiert?
Edge sensitive oder Level sensitive?
Apropos,
wieso versuchst Du nicht einmal einen Timer als Interrupt-Quelle?
olpo schrieb:> Einmal werfe ich den Interrupt kombinatorisch> und einmal sequentiell.
Was meinst Du damit?
olpo schrieb:> wie bediene ich das mdm?
Das macht man normalerweise nicht manuell.
Der MDM kommuniziert mit XDM und dieser mit dem debugger gdb.
Wenn man im SDK debugged, wird alles automatisch gestartet.
Klaus Falser schrieb:> - Wie ist der Interrupt-pin beim Microblaze definiert?> Edge sensitive oder Level sensitive?
Also, wenn ich in XPS auf Configure-IP ( Microblaze) drücke, sehe ich in
"Erweitert" einen Reiter "Interrupt und Reset".
Komischerweise ist das zum Interrupt "ausgegraut" und nicht anklickbar.
Deshalb schreibe ich mal, wie's da aussieht:
Interrupt
Sense Interrupt on Edge vs. Level [ ]
Sense Interrupt on Rising vs. Falling Edge [x]
> olpo schrieb:>> Einmal werfe ich den Interrupt kombinatorisch>> und einmal sequentiell.>> Was meinst Du damit?
Na, ich habe zwei IP-Cores probiert. Der eine wirft den Interrupt
getaktet ( sequentiell), der andere kombinatorisch. Beides mal für einen
Takt. Im Xilinx Beispiel war's sequentiell für einen Takt.
olpo schrieb:> Komischerweise ist das zum Interrupt "ausgegraut" und nicht anklickbar.
Könnte sein, dass das EDK die Konfiguration automatisch berechnet.
Hast Du im MPD Deines Cores angegeben, dass das Ausgangssignal ein
Interrupt ist und dass es auf die steigende Flanke reagieren soll?
Wenn dein Interrupt Signal nur einen Takt lang kommt, dann brauchts Du
einen flankengetriggerten Interrupt.
Vielleicht gibt es aber noch sonstige Anforderungen an einen solchen
Puls, warum probierts Du ihn nicht länger zu machen?
Was hältst Du von der Idee mit dem xps_timer core?
Nachtrag :
olpo schrieb:> Interrupt> Sense Interrupt on Edge vs. Level [ ]
Dieses Kästchen disabled heißt, dass du einen LEVEL getriggerten
Interrupt pin hast.
Ich habe mir das Referenzdesign zu diesem Board angeguckt. Dort sind
mehrere Interrupt-Quellen an einem Interrupt-Controller angeschlossen.
Auch dort ist Configure-IP ( Microblaze) -> Interrupt ausgegraut.
> Dieses Kästchen disabled heißt, dass du einen LEVEL getriggerten> Interrupt pin hast.
Das heißt doch, das mein Interrupt-Signal gar nicht zu kurz anliegen
kann, oder?
olpo schrieb:> Ich habe mir das Referenzdesign zu diesem Board angeguckt. Dort sind> mehrere Interrupt-Quellen an einem Interrupt-Controller angeschlossen.> Auch dort ist Configure-IP ( Microblaze) -> Interrupt ausgegraut.
Das XPS erkennt aus dem MPD der angeschlossenen Interrupt-Quellen welche
Art eingestellt werden muss und konfiguriert den Microblaze deshalb
autonom.
Man kann es deshalb nicht ändern.
Der INTC erzeugt fast sicher eine Interrupt Request Signal für Level
Triggerung.
>> Dieses Kästchen disabled heißt, dass du einen LEVEL getriggerten>> Interrupt pin hast.> Das heißt doch, das mein Interrupt-Signal gar nicht zu kurz anliegen> kann, oder?
Kann es sein, dass Dir der Unterschied zwischen Pegel und
Flankentriggerung nicht klar ist?
- Edge Triggerung heißt, dass jede Flanke einen Interrupt auslöst und
eignet sich gut, wenn nur eine Quelle bedient werden muss.
Kommt eine weitere Flanke, bevor der 1. Interrupt bedient ( d.h. bevor
die ISR ausgeführt wurde), dann geht der 2. Interrupt verloren.
- Bei Pegeltriggerung wird ein dass Interrupt Request Signal angelegt,
und bleibt solange angelegt bis der Interrupt bedient ist. In der ISR
wird durch Schreiben oder Lesens eines Register die Hardware dazu
veranlasst, das Interrupt Signal zurückzunehmen. Liegt nach der ISR der
Interrupt Pin weiterhin auf High, wird die ISR wieder angesprungen.
Ein Zurücknehmen des Interrupt Signals (so wie in deinem Fall) bevor die
ISR ausgeführt ist, ist eigentlich nicht vorgesehen und kann dazu
führen, dass der Interrupt wieder gelöscht wird.
Moin nochmal,
also, ich habe wieder einen Interrupt-Controller angeschlossen und daran
GPio Drückknöpfe und meinen Custom-IP.
Tatsächlich funktioniert der Interrupt mit GPio, aber nicht mit meinem
Custom-IP. Die Initialisierung auf SW-Seite scheint also noch nicht
richtig zu sein. Ich habe für meinen IP probiert die gleiche Methodik zu
verwenden wie beim GPio.
Das einzige, das ich sehe, ist, daß ich keine Instanz von ip-core habe.
XIntc_Connect bekommt aus letztes Argument einen Instanzpointer aus
GPio_push. Ich hab's jetzt mit NULL und &baseaddr anstelle des
Instanzpointers versucht. Beides geht nicht.
Hat noch jmd eine Idee?
olpo schrieb:> Hat noch jmd eine Idee?
Ja, falsche Triggerung Level/Edge.
Aber du schreibst ja nicht ob du das kontrolliert, bzw. geändert hast.
olpo schrieb:> XIntc_Connect bekommt aus letztes Argument einen Instanzpointer aus> GPio_push
Nein, XIntc_Connect bekommt einen Parameter, der beim Aufruf an die ISR
routine weitergereicht wird. Damit kann man die selbe Routine für
mehrere Interrupts verwenden.
> Ja, falsche Triggerung Level/Edge.> Aber du schreibst ja nicht ob du das kontrolliert, bzw. geändert hast.
Ich glaube, das verstehe ich nicht ganz.
Den xps_intc habe ich überprüft; der sagt:
IRQ Output Use Level [ Level ]
The Sense of IRQ Output [ Rising/High ]
Oder soll ich meine IP-Core überprüfen? Immerhin importiert der eine
Bibliothek:
library interrupt_control_v2_01_a;
use interrupt_control_v2_01_a.interrupt_control;
Der IP-Core hängt an einem PLB und als ich den Core erstellt habe, gab
es noch "Interrupt Control" auszuwählen. Das habe ich gemacht und im
folgenden Dialogfenster [1] ausgewählt ( siehe Anhang). ([2] zeigt
andere Option).
Oder soll ich die iterrupt library wegschmeißen und das Ausgangssignal
einfach an den xps_intc hängen?
olpo schrieb:> Der IP-Core hängt an einem PLB und als ich den Core erstellt habe, gab> es noch "Interrupt Control" auszuwählen. Das habe ich gemacht und im> folgenden Dialogfenster [1] ausgewählt ( siehe Anhang). ([2] zeigt> andere Option).
Meiner Meinung nach passt das eben mit deiner Beschreibung weiter oben
nicht zusammen, weil Du schreibst dass dein IRQ Signal nur einen Takt
lang aktiv ist.
Dein Interrupt Service Mechanismus ist aber für Pegel (Level)
konfiguriert und das erfordert, dass das IRQ Signal deines Cores solange
aktiv bleiben muss, bis die ISR ausgeführt wird.
In der ISR muss dann das IRQ Signal zurückgenommen werden, z.B. indem Du
ein bestimmtes Register Deines Cores beschreibst.
Du kannst aber auch den Capture Mode "Positive Edge detect " aktivieren,
dann verschiebt sich dies in den IP ISC.
In diesem Fall musst Du in der ISR die Register des IP ISC bedienen.
In jedem Fall musst Du das Global Interrupt Enable Register schreiben,
das den in der Zeichnung angegeben ist.
Bitte drücke den Knopf, wo "data sheet" steht und versuche das Ganze zu
verstehen.
Also, ich habe gerade ohne die interrupt library synthetisiert. Es wird
also einfach eine 1b Leitung an xps_intc gehängt. Und siehe da, es
funktioniert.
Aber...jetzt ist da noch die Sache mit dem Pegel-/Kante-Kram und so.
Ist das jetzt sicher, wenn ich nur von einen Takt das Signal oben lasse?
olpo schrieb:> Ist das jetzt sicher, wenn ich nur von einen Takt das Signal oben lasse?
Jein.
a) Du solltest im MPD deines Cores dein signal explizit als Interrupt
kennzeichnen und den Typus auf Flankengetriggert setzen.
b) Du mußt garantieren, dass die ISR abgearbeitet wird, bevor der
nächste Interrupt kommt.
Ich habe die Doku von xps_intc durchgelesen.
Fragezeichen bleiben...
Also, anhand des Interrupt-Status-Register ( ISR ) ist wohl zu erkennen,
welche Interrupts gesetzt sind, aber noch nicht abgearbeitet.
1.) Wie kann ich als IP-Core auf das Register zugreifen?
2.) Wie ist das Ablaufprotokoll beim Microblaze? ( Ist wichtig wegen
einer Studienarbeit).
Also, sobald Micorblaze einen Interrupt erkennt, sichert er seinen
Instruction-Stack und springt dann zu Register 0x10. Was findet er da?
Woher weiß Microblaze, welche Routine es aufrufen soll bzw. wer den
Interrupt geworfen hat.
Wäre super wenn mir das jmd beantworten könnte.
olpo schrieb:> 1.) Wie kann ich als IP-Core auf das Register zugreifen?
Ja und nein.
Was willst Du denn mit dem Register machen?
> 2.) Wie ist das Ablaufprotokoll beim Microblaze? ( Ist wichtig wegen> einer Studienarbeit).> Also, sobald Micorblaze einen Interrupt erkennt, sichert er seinen> Instruction-Stack und springt dann zu Register 0x10. Was findet er da?> Woher weiß Microblaze, welche Routine es aufrufen soll bzw. wer den> Interrupt geworfen hat.
Dann mußt Du in Register 0x10 die Adresse Deiner Interruptroutine
ablegen.
Die muß dann im Statusregister (oder bei den einzelnen IP-Cores)
nachschauen, woher der Interrupt kommt und ihn ggf. zurücksetzen.
Außerdem müssen natürlich die Softwareaktionen gestartet werden, die auf
den Interrupt reagieren sollen (Flag setzen, Scheduler ausführen, neue
Berechnung starten, Ergebnisse in Puffer schreiben etc. pp.)
Duke
Duke Scarring schrieb:> olpo schrieb:>> 1.) Wie kann ich als IP-Core auf das Register zugreifen?> Ja und nein.> Was willst Du denn mit dem Register machen?>
Der IP-Core, zumindest die Hardware des IP-Cores hat mit diesem Register
nichts zu schaffen.
Wenn man die standalone platform verwendet, dann ist alles schon
vorbereitet.
>> 2.) Wie ist das Ablaufprotokoll beim Microblaze? ( Ist wichtig wegen>> einer Studienarbeit).>> Also, sobald Micorblaze einen Interrupt erkennt, sichert er seinen>> Instruction-Stack und springt dann zu Register 0x10. Was findet er da?>> Woher weiß Microblaze, welche Routine es aufrufen soll bzw. wer den>> Interrupt geworfen hat.
Der Microblaze weiss überhaupt nichts. Er springt zur Adresse die in
0x10 angegeben ist. Das nennt man Interrupt Vektor.
Dies ist die primäre ISR, die vom standalone Framework zur Verfügung
gestellt wird und Teil des Interrupt Controller Cores ist.
Diese primäre ISR sichert die Register und liest das ISR des INTC.
Die ISR verfügt über eine interne Tabelle, in der für jeden
konfigurierten Interrupt wiederum die Adresse der sekundären ISR
abgelegt ist.
Diese Adresse wird durch die Funktion XINTC_connect() gesetzt.
Die primäre ISR schaut alle interrupt Quellen durch ob sie aktiv sind,
und führt die sekundäre ISR aus.
Dann wird der Hardware des INTC gemeldet, dass der Interrupt nun bedient
ist, und das Bit im Status register wird deaktiviert.
Das Verhalten der primären ISR ist aber z.T. konfigurierbar.
Nachdem die sekundäre ISR ihre Arbeit verrichtet hat, dann stellt die
primäre ISR die Register wieder her und springt aus den Interrupt
heraus.
Das geschieht alles in SW !!
> Dann mußt Du in Register 0x10 die Adresse Deiner Interruptroutine> ablegen.
Nur wenn Du auf den Interrupt controller oder auf die standalone
platform verzichtest. Dann kannst Du aber nur eine Interrupt Quelle
haben.
> Die muß dann im Statusregister (oder bei den einzelnen IP-Cores)> nachschauen, woher der Interrupt kommt und ihn ggf. zurücksetzen.> Außerdem müssen natürlich die Softwareaktionen gestartet werden, die auf> den Interrupt reagieren sollen (Flag setzen, Scheduler ausführen, neue> Berechnung starten, Ergebnisse in Puffer schreiben etc. pp.)>> Duke
Uff, so ganz passt das für mich noch nicht zusammen.
( Aber schon mal Danke für die Mühe.)
Ich arbeite ja jetzt mit INTC.
Wenn jetzt ein Interrupt erkannt wird, dann steht wohl in 0x10: "Schau
mal nach was INTC von dir will". Richtig?
Aber, steht in INTC jetzt die Adresse der Interrupt-Routine, oder schaut
Microblaze nur nach "wer" den Interupt geworfen hat?
In dem INTC-Dokument konnte ich keine Register finden, die
Instruction-Adressen speichern. So wie ich's verstanden habe, steht im
ISR jedes Bit für einen angeschlossenen Interrupt-Werfer.
olpo schrieb:> Uff, so ganz passt das für mich noch nicht zusammen.> ( Aber schon mal Danke für die Mühe.)>> Ich arbeite ja jetzt mit INTC.> Wenn jetzt ein Interrupt erkannt wird, dann steht wohl in 0x10: "Schau> mal nach was INTC von dir will". Richtig?>
Richtig.
Die ISR, deren Adresse an 0x10 steht wird ausgeführt.
> Aber, steht in INTC jetzt die Adresse der Interrupt-Routine, oder schaut> Microblaze nur nach "wer" den Interupt geworfen hat?>
Der Microblaze sieht nur einen Interrupt, nicht mehr und
beginnt die ISR auszuführen.
Diese ISR muss nun so geschrieben sein, dass sie zur HW passt und in
Deinem Fall ist das eine ISR zur Bedienung des IntC.
Wenn Du das SDK verwendest, dann enthalten die SW Platformen schon eine
fertige ISR dazu. Man könnte aber auch selbst eine schreiben, aber wozu?
Das Ganze ist ein Zusammenspiel von HW in dazu passender SW.
> In dem INTC-Dokument konnte ich keine Register finden, die> Instruction-Adressen speichern. So wie ich's verstanden habe, steht im> ISR jedes Bit für einen angeschlossenen Interrupt-Werfer.
Dieses Dokument beschreibt nur die HW, der Rest ist SW und kann nach
Gutdünken implementiert werden.
Die von mir beschriebene Tabelle existiert nur im von Xilinx zur
Verfügung gestellten Treiber. Dazu gibt es meines Wissens keine
besonders gute Dokumentation. Man liest am Besten den Quell-Kode
(xintc_l.c).
Aber wie gesagt, das ist SW.
Wenn Du willst kannst Du dir auch eine ISR bauen, die komplett anders
funktionert.