Ich verbringe letzten Monat viel Zeit damit, UART (für MIDI) dazu zu bringen, mit einem STM (STM32F103C8T6) unter Verwendung von Interrupts zu arbeiten, ohne großen Erfolg.
An diesem Abend mit DMA hat es jedoch ziemlich schnell funktioniert.
Da DMA meines Erachtens schneller ist und die CPU entlastet, warum nicht immer DMA zugunsten von Interrupts verwenden? Zumal es beim STM32 einige Probleme zu geben scheint.
Ich verwende STM32CubeMx / HAL.
uart
dma
stm32cubemx
stm32f103c8t6
Michel Keijzers
quelle
quelle
Antworten:
Während DMA die CPU entlastet und somit die Latenz anderer Interrupt-gesteuerter Anwendungen verringern kann, die auf demselben Kern ausgeführt werden, sind damit Kosten verbunden:
Es gibt nur eine begrenzte Anzahl von DMA-Kanälen und es gibt Einschränkungen hinsichtlich der Interaktion dieser Kanäle mit den verschiedenen Peripheriegeräten. Ein anderes Peripheriegerät auf demselben Kanal ist möglicherweise besser für die DMA-Verwendung geeignet.
Wenn Sie beispielsweise alle 5 ms eine I2C-Massenübertragung durchführen, scheint dies ein besserer Kandidat für DMA zu sein als ein gelegentlicher Debug-Befehl, der auf UART2 eintrifft.
Das Einrichten und Verwalten von DMA ist eine Kosten für sich. (Normalerweise wird das Einrichten von DMA als komplexer angesehen als das Einrichten einer normalen Interrupt-gesteuerten Übertragung pro Zeichen. Dies liegt an der Speicherverwaltung, mehr beteiligten Peripheriegeräten, der Verwendung von Interrupts durch DMA selbst und der Möglichkeit, dass Sie die ersten Zeichen außerhalb von DMA analysieren müssen wie auch immer, siehe unten.)
DMA kann zusätzliche Energie verbrauchen , da es sich um eine weitere Domäne des Kerns handelt, die getaktet werden muss. Auf der anderen Seite können Sie die CPU anhalten, während die DMA-Übertragung läuft, wenn der Kern dies unterstützt.
Für DMA sind Speicherpuffer erforderlich (es sei denn, Sie führen DMA von Peripheriegerät zu Peripheriegerät durch), sodass damit einige Speicherkosten verbunden sind.
(Die Speicherkosten können auch bei der Verwendung von Interrupts pro Zeichen anfallen, aber sie können auch viel kleiner sein oder überhaupt verschwinden, wenn die Nachrichten sofort innerhalb des Interrupts interpretiert werden.)
DMA erzeugt eine Latenz, da die CPU erst benachrichtigt wird, wenn die Übertragung abgeschlossen / halb abgeschlossen ist (siehe die anderen Antworten).
Außer beim Streamen von Daten in / aus einem Ringpuffer müssen Sie im Voraus wissen, wie viele Daten Sie empfangen / senden werden.
Dies kann bedeuten, dass die ersten Zeichen einer Nachricht mithilfe von Interrupts pro Zeichen verarbeitet werden müssen. Wenn Sie beispielsweise eine Schnittstelle zu einem XBee herstellen, lesen Sie zuerst den Pakettyp und die Paketgröße und lösen dann eine DMA-Übertragung in einen zugewiesenen Puffer aus.
Bei anderen Protokollen ist dies möglicherweise überhaupt nicht möglich, wenn sie nur Trennzeichen für das Ende der Nachricht verwenden: beispielsweise textbasierte Protokolle, die
'\n'
als Trennzeichen verwendet werden. (Es sei denn, das DMA-Peripheriegerät unterstützt das Abgleichen eines Zeichens.)Wie Sie sehen können, sind hier viele Kompromisse zu berücksichtigen. Einige beziehen sich auf Hardwareeinschränkungen (Anzahl der Kanäle, Konflikte mit anderen Peripheriegeräten, Übereinstimmung mit Zeichen), andere basieren auf dem verwendeten Protokoll (Trennzeichen, bekannte Länge, Speicherpuffer).
Um einige anekdotische Beweise hinzuzufügen, habe ich mich all diesen Kompromissen in einem Hobbyprojekt gestellt, bei dem viele verschiedene Peripheriegeräte mit sehr unterschiedlichen Protokollen verwendet wurden. Es gab einige Kompromisse, hauptsächlich aufgrund der Frage "Wie viele Daten übertrage ich und wie oft werde ich das tun?". Dies gibt Ihnen im Wesentlichen eine grobe Schätzung der Auswirkungen einer einfachen Interrupt-gesteuerten Übertragung auf die CPU. Ich habe daher der oben genannten I2C-Übertragung alle 5 ms Vorrang vor der UART-Übertragung alle paar Sekunden eingeräumt, bei der derselbe DMA-Kanal verwendet wurde. Eine andere UART-Übertragung, die häufiger und mit mehr Daten stattfindet, hat andererseits Vorrang vor einer anderen I2C-Übertragung, die seltener stattfindet. Es sind alles Kompromisse.
Natürlich hat die Verwendung von DMA auch Vorteile, aber darum haben Sie nicht gebeten.
quelle
Die Verwendung von DMA bedeutet normalerweise, dass Sie nicht mehr jedes Zeichen unterbrechen, sondern erst, nachdem ein "Puffer voller" Zeichen empfangen (oder gesendet) wurde. Dies erhöht die Latenz der Verarbeitung dieser Zeichen - das erste Zeichen wird erst verarbeitet, nachdem das letzte Zeichen im Puffer empfangen wurde.
Diese Latenz kann eine schlechte Sache sein, insbesondere in einer latenzempfindlichen Anwendung wie MIDI, bei der einige ms hier und da schwerwiegende Probleme mit der Spielbarkeit von Live-Auftritten verursachen können.
quelle
DMA ist kein Ersatz für Interrupts - sie werden normalerweise zusammen verwendet! Wenn Sie beispielsweise DMA zum Senden von Daten über einen UART verwenden, benötigen Sie immer noch einen Interrupt, um zu erfahren, wann der Sendevorgang abgeschlossen ist.
quelle
Die Verwendung von DMA wirft einige interessante Fragen und Herausforderungen auf, die über alle anderen Überlegungen zur Verwendung von UART-Peripheriegeräten hinausgehen. Ich gebe Ihnen einige Beispiele: Angenommen, Ihr uC sitzt mit anderen Geräten auf einem RS485-Bus (oder einem anderen Bus). Es gibt viele Nachrichten im Bus, einige sind für Ihre uC bestimmt, andere nicht. Nehmen Sie außerdem an, dass diese Busnachbarn alle ein anderes Datenprotokoll sprechen, was impliziert, dass die Nachrichtenlängen unterschiedlich sind.
Einige Fragen, die nur bei der Verwendung von DMA auftauchen, sind:
Jedenfalls nur Denkanstöße.
quelle
Auf der Empfangsseite (wie ich mich erinnere) endet DMA entweder bei einer Zeichenübereinstimmung oder bei der Terminalanzahl. Einige Protokolle und viele interaktive Anwendungen passen nicht einfach in dieses Modell, und Sie müssen wirklich Zeichen für Zeichen mit den Dingen umgehen. Die DMA-Techniken können auch spröde sein, wenn die Kommunikationsverbindung unzuverlässig ist. Wenn Sie ein einzelnes Zeichen im Stream verlieren, kann dies Ihre DMA-Zustandsmaschine leicht durcheinander bringen.
quelle
Ich habe den STM32CubeMx / HAL jetzt in einigen Projekten verwendet und festgestellt, dass die von ihm generierte UART-Handhabungssoftware auf der Empfangsseite deutliche Mängel aufweist.
Beim Senden möchten Sie normalerweise einen Datenblock oder eine Textzeile senden. In diesem Fall wissen Sie im Voraus, wie lange die Datenübertragung dauert, und daher ist die Verwendung des DMA eine naheliegende Lösung. Sobald die Übertragung abgeschlossen ist, erhalten Sie eine Unterbrechung und können mithilfe der UART TX-Rückruffunktion Ihrem Hauptcode anzeigen, dass die Übertragung abgeschlossen ist, und Sie können einen weiteren Datenblock senden.
Wenn es um den Datenempfang geht, setzen alle von ST bereitgestellten Funktionen voraus, dass Sie wissen, wie viele Zeichen das sendende Gerät Ihnen geben wird, bevor es mit dem Senden beginnt. Normalerweise ist dies nicht bekannt. Die Interrupt-Funktion legt die empfangenen Daten in einem Puffer ab und zeigt nur an, dass Daten verfügbar sind, wenn die vordefinierte Anzahl von Zeichen empfangen wurde. Wenn Sie versuchen, die DMA- oder Interrupt-Funktion zum Empfangen von Daten zu verwenden, indem Sie sequentielle Einzelzeichenübertragungen einrichten, bedeutet die Einrichtungszeit für jede dieser Funktionen, dass Sie Zeichen mit einer anderen als der langsamsten Datenrate (der Baudrate, die Sie erhalten) verlieren Der Beginn des Datenverlusts hängt von der Taktrate Ihres Prozessors ab und lädt den Prozessor übermäßig, sodass keine Befehlszyklen für eine andere Verarbeitung verbleiben
Um dies zu umgehen, habe ich meine eigene Interrupt-Handler-Funktion geschrieben, die die Daten in einem kleinen lokalen Ringpuffer speichert und eine Anzahl festlegt, die vom Hauptcode (einem RTOS-Zählsemaphor) gelesen wird, um anzuzeigen, dass empfangene Daten bereit sind. Der Hauptcode kann dann die Daten aus diesem Puffer nach Belieben erfassen. Es spielt keine Rolle, ob sich die Erfassung der Daten verzögert, vorausgesetzt, der lokale Puffer läuft nicht über, bevor die Daten erfasst werden.
quelle