Welche Cortex-M3 Interrupts kann ich für allgemeine Arbeiten verwenden?

7

Ich hätte etwas Code, der als Ergebnis eines bestimmten ablaufenden Interrupts ausgeführt werden muss.

Ich möchte es nicht im Kontext des Interrupts selbst ausführen, aber ich möchte auch nicht, dass es im Thread-Modus ausgeführt wird.

Ich möchte es mit einer Priorität ausführen, die niedriger ist als der High-Level-Interrupt, der seine Ausführung ausgelöst hat, aber auch eine Priorität, die höher ist als die Thread-Ebene (und auch einige andere Interrupts).

Ich denke, ich muss einen der anderen Interrupt-Handler verwenden.

Welche sind die am besten zu verwenden und was ist der beste Weg, sie aufzurufen?

Im Moment plane ich, nur die Interrupt-Handler für einige Peripheriegeräte zu verwenden, die ich nicht verwende, und sie aufzurufen, indem ich Bits direkt über die NVIC setze, aber ich hoffte, dass es einen besseren, offiziellen Weg gibt.

>

Danke,

    
Captain NedD 02.05.2010, 01:23
quelle

5 Antworten

15

ARM Cortex unterstützt eine spezielle Ausnahme namens PendSV. Es scheint, dass Sie diese Ausnahme genau verwenden könnten, um Ihre Arbeit zu erledigen. Praktisch alle präemptiven RTOS für ARM Cortex verwenden PendSV, um den Kontextwechsel zu implementieren.

Damit es funktioniert, müssen Sie PendSV niedrig priorisieren (schreiben Sie 0xFF in das PRI_14-Register in der NVIC). Sie sollten auch alle IRQs über dem PendSV priorisieren (niedrigere Nummern in die entsprechenden Prioritätsregister im NVIC schreiben). Wenn Sie bereit sind, die gesamte Nachricht zu verarbeiten, lösen Sie den PendSV aus dem ISR mit der hohen Priorität aus:

%Vor%

Die ARM-Cortex-CPU beendet dann Ihre ISR und alle anderen ISRs, die möglicherweise von der ARM-Cortex-CPU ausgeschlossen wurden, und schließlich wird sie an die PendSV-Ausnahme angehängt. Hier sollte der Code zum Parsen der Nachricht sein.

Bitte beachten Sie, dass PendSV von anderen ISRs ausgeschlossen werden kann. Das ist alles in Ordnung, aber Sie müssen sich natürlich daran erinnern, alle freigegebenen Ressourcen durch einen kritischen Codeabschnitt zu schützen (kurzes Deaktivieren und Aktivieren von Interrupts). In ARM Cortex deaktivieren Sie Interrupts, indem Sie __asm ​​("cpsid i") ausführen und Interrupts durch __asm ​​("cpsie i") aktivieren. (Die meisten C-Compiler bieten eingebaute intrinsische Funktionen oder Makros für diesen Zweck.)

    
Miro Samek 02.05.2010, 22:31
quelle
3

Verwenden Sie ein RTOS? Im Allgemeinen würde diese Art von Sache gehandhabt werden, indem man einen Thread mit hoher Priorität hat, der signalisiert wird, etwas Arbeit durch den Interrupt zu machen.

Wenn Sie kein RTOS verwenden, haben Sie nur ein paar Aufgaben, und die Arbeit, die durch den Interrupt ausgelöst wird, ist nicht zu ressourcenintensiv. Es könnte am einfachsten sein, Ihre Arbeit mit hoher Priorität im Kontext der Unterbrechungshandler. Wenn diese Bedingungen nicht erfüllt sind, dann wäre das Implementieren, von dem Sie sprechen, der Beginn eines grundlegenden Multitasking-Betriebssystems selbst. Das kann ein interessantes Projekt sein, aber wenn Sie nur Arbeit erledigen wollen, sollten Sie ein einfaches RTOS in Betracht ziehen.

Da Sie einige Besonderheiten Ihrer Arbeit erwähnt haben, hier eine Übersicht darüber, wie ich in der Vergangenheit ein ähnliches Problem behandelt habe:

Zum Behandeln empfangener Daten über eine UART-Methode, die ich bei einem einfacheren System verwendet habe, das keine volle Unterstützung für das Tasking hat (dh die Tasks werden in einer einfachen while -Schleife round-robined) ist eine gemeinsam genutzte Warteschlange für Daten, die vom UART empfangen werden. Wenn ein UART-Interrupt ausgelöst wird, werden die Daten vom RDR (Receive Data Register) des UART gelesen und in die Warteschlange gestellt. Der Trick, dies so zu behandeln, dass die Warteschlangenzeiger nicht beschädigt sind, besteht darin, die Warteschlangenzeiger vorsichtig flüchtig zu machen und sicherzustellen, dass nur der Interrupt-Handler den Endzeiger und nur die Vordergrundaufgabe, die Daten liest, modifiziert Aus der Warteschlange wurde der Kopfzeiger geändert. Ein Überblick auf hoher Ebene:

  • producer (der UART-Interrupt-Handler):

    1. lies queue.head und queue.tail in Einheimische;
    2. erhöht den lokalen Tail-Zeiger ( nicht den tatsächlichen queue.tail -Zeiger). Wickeln Sie es an den Anfang des Warteschlangenpuffers, wenn Sie nach dem Ende des Warteschlangenpuffers inkrementiert haben.
    3. vergleichen local.tail und local.head - wenn sie gleich sind, ist die Warteschlange voll, und Sie müssen tun, was auch immer Fehlerbehandlung angemessen ist.
    4. Andernfalls können Sie die neuen Daten in local.tail punkte
    5. schreiben
    6. Nur jetzt können Sie queue.tail == local.tail
    7. festlegen
    8. von der Unterbrechung zurückkommen (oder andere UART-bezogene Aufgaben behandeln, wie z. B. das Lesen aus einer Sendewarteschlange)
  • Consumer (die Vordergrundaufgabe)

    1. lies queue.head und queue.tail in Einheimische;
    2. wenn local.head == local.tail die Warteschlange leer ist; kehren Sie zurück, um die nächste Aufgabe erledigen zu lassen
    3. lese das Byte, auf das von local.head gezeigt wird
    4. inkrement local.head und bei Bedarf umbrechen;
    5. festlegen queue.head = local.head
    6. gehe zu Schritt 1

Stellen Sie sicher, dass queue.head und queue.tail volatile sind (oder schreiben Sie diese Bits in Assembly), um sicherzustellen, dass keine Sequenzierungsprobleme auftreten.

Stellen Sie jetzt sicher, dass Ihre UART-Datenwarteschlange so groß ist, dass sie alle Bytes enthält, die empfangen werden können, bevor die Vordergrundaufgabe ausgeführt werden kann. Die Vordergrundaufgabe muss die Daten aus der Warteschlange in ihre eigenen Puffer ziehen, um die Nachrichten zu erstellen, die der Aufgabe "Nachrichtenprozessor" übergeben werden sollen.

    
Michael Burr 02.05.2010 01:28
quelle
1

Der "offiziellere Weg" oder eher die konventionelle Methode besteht darin, einen prioritätsbasierten präemptiven Multitasking-Scheduler und das "Deferred Interrupt Handler" -Muster zu verwenden.

    
Clifford 02.05.2010 10:50
quelle
1

Was Sie verlangen, ist beim Cortex-M3 ziemlich einfach. Sie müssen das STIR-Register aktivieren, damit Sie die ISR mit niedriger Priorität mit Software auslösen können. Wenn der ISR mit hoher Priorität mit dem kritischen Zeug fertig ist, löst er nur den Interrupt mit niedriger Priorität aus und wird beendet. Die NVIC wird dann an den Handler mit niedriger Priorität anschließen, wenn nichts Wichtigeres passiert.

    
Robert Sexton 24.11.2010 00:20
quelle
0

Überprüfen Sie Ihre Prozessordokumentation. Einige Prozessoren werden unterbrochen, wenn Sie das Bit schreiben, das Sie normalerweise innerhalb des Interrupts löschen müssen. Ich verwende derzeit ein SiLabs c8051F344 und im Datenblatt Abschnitt 9.3.1:

"Die Software kann einen Interrupt simulieren, indem sie ein Interrupt-Flag auf logisch 1 setzt. Wenn Interrupts für das Flag aktiviert sind, wird eine Interrupt-Anforderung generiert und die CPU wird an die ISR-Adresse des Interrupt-Pending Flags übertragen . "

    
Jim Tshr 04.05.2010 16:01
quelle

Tags und Links