Hallo Leute,
hat schon irgendwer einen Ringpuffer gebaut, der über USART Daten
empfängt und per DMA in den Puffer schreibt? Oder denke ich gar zu
kompliziert?
Meine Idee war erst wie folgt:
Ich erstelle einen Puffer. Sagen wir mal 100 Bytes.
Dann konfiguriere ich einen DMA-Kanal so, dass er byteweise vom
USART.DATA-Register inkrementell in den Puffer schreibt. Am Anfang sage
ich dem DMA, dass er 100 Bytes transferieren darf.
Wenn jetzt Bytes über den USART rein kommen, dann transferiert der DMA
diese automatisch nach und nach in den Puffer. Ich hab's zwar bisher so
noch nicht ausprobiert, sollte aber klappen.
Das Problem ist jetzt, dass ich in der Zeit, in der so nach und nach die
Bytes eintrudeln, nicht weiß wie weit der Puffer schon gefüllt ist. Das
heißt ich bekomme erst einen Interrupt vom DMA ausgelöst, wenn die 100
Bytes komplett voll sind.
Da die Befehle, die rein kommen, aber meistens nur wenige Bytes lang
sind, ist das recht unpraktisch. Jetzt könnte ich ja den Puffer klein
genug machen, sodass der Interrupt öfter ausgelöst wird, aber da stellt
sich mir dann die Frage, ob ich den DMA überhaupt noch brauche. Das
heißt da könnte ich gleich auf den Received-Interrupt vom USART
reagieren und DMA ganz lassen.
Was meint ihr?
Ich frage deswegen, weil ich nicht das Rad neu erfinden möchte und ich
bisher nur eine fertige Ringpuffer-Implementierung in die andere
Richtung gefunden habe. Also Puffer -> DMA -> Usart transmit. In die
Richtung macht es auch viel mehr Sinn, finde ich.
@Nicolas G. (ntq)
>Ich erstelle einen Puffer. Sagen wir mal 100 Bytes.>Dann konfiguriere ich einen DMA-Kanal so, dass er byteweise vom>USART.DATA-Register inkrementell in den Puffer schreibt. Am Anfang sage>ich dem DMA, dass er 100 Bytes transferieren darf.
Zuviel. Nimm lieber 10x10 oder so.
>Das Problem ist jetzt, dass ich in der Zeit, in der so nach und nach die>Bytes eintrudeln, nicht weiß wie weit der Puffer schon gefüllt ist. Das>heißt ich bekomme erst einen Interrupt vom DMA ausgelöst, wenn die 100>Bytes komplett voll sind.
Jo. Aber danach kannst du dem DMA sagen, wieviel Bytes er bis zum
nächsten Interrupt schreiben darf. Das kann man aus der Anzahl Bytes im
FIFO berechnen.
>Da die Befehle, die rein kommen, aber meistens nur wenige Bytes lang>sind, ist das recht unpraktisch. Jetzt könnte ich ja den Puffer klein>genug machen, sodass der Interrupt öfter ausgelöst wird,
Den Puffer nicht, aber die DMA-Größe.
>aber da stellt>sich mir dann die Frage, ob ich den DMA überhaupt noch brauche. Das>heißt da könnte ich gleich auf den Received-Interrupt vom USART>reagieren und DMA ganz lassen.
Sicher. DMA braucht man nur, wenn man höchste Baudraten mit maximaler
Perfomance verarbeiten muss. Im "Handbetrieb" per Interrupt und CPU
schaufelt so ein AVR immer noch eine beachtliche Menge. Schau dir die
diversen DMX512 Projekte an, dort werden 250kbaud gefahren und bei
gescheiter Programmierung ist immer nocht massig CPU-Leistung verfügbar.
>Was meint ihr?>Ich frage deswegen, weil ich nicht das Rad neu erfinden möchte und ich>bisher nur eine fertige Ringpuffer-Implementierung in die andere>Richtung gefunden habe. Also Puffer -> DMA -> Usart transmit. In die>Richtung macht es auch viel mehr Sinn, finde ich.
Jo. RX geht aber auch. Siehe oben.
MFG
Falk
Die Verwendung des normalen Usart Receive Interrupts ist meist besser
als die entsprechende DMA Variante (im Gegensatz zum Transmit). Man
spart den Pufferspeicher, ggf. Aufwand zur Extraktion gesuchter Daten
daraus, vor allem aber kann man im Usart-Interrupt gleich in "Echtzeit"
auf gesuchte Daten reagieren bzw. diese sofort verwerfen.
Falk Brunner schrieb:>>Das Problem ist jetzt, dass ich in der Zeit, in der so nach und nach die>>Bytes eintrudeln, nicht weiß wie weit der Puffer schon gefüllt ist. Das>>heißt ich bekomme erst einen Interrupt vom DMA ausgelöst, wenn die 100>>Bytes komplett voll sind.>> Jo. Aber danach kannst du dem DMA sagen, wieviel Bytes er bis zum> nächsten Interrupt schreiben darf. Das kann man aus der Anzahl Bytes im> FIFO berechnen.>>>Da die Befehle, die rein kommen, aber meistens nur wenige Bytes lang>>sind, ist das recht unpraktisch. Jetzt könnte ich ja den Puffer klein>>genug machen, sodass der Interrupt öfter ausgelöst wird,>> Den Puffer nicht, aber die DMA-Größe.
Achso, logisch. Ich könnte den Puffer bei 100 Bytes lassen, aber dem DMA
sagen, dass er immer nur 10 Bytes oder weniger übertragen soll. Dann
bekomme ich alle 10 Bytes einen Interrupt und kann dann den writeIndex
aktualisieren, sodass die receiveBuffer-Methode beim nächsten Aufruf
weiß, dass was neues drin ist.
Klar. So mach ich es. Ich muss dann nur mein Protokoll auf der PC-Seite
etwas anpassen, sodass ein Datenchunk immer genau 10 Bytes oder ein
Vielfaches davon groß sein muss, auch wenn mal nur weniger übertragen
werden müsste. Das reicht mir aber vollkommen.
@ Nicolas G. (ntq)
>Klar. So mach ich es. Ich muss dann nur mein Protokoll auf der PC-Seite>etwas anpassen, sodass ein Datenchunk immer genau 10 Bytes oder ein>Vielfaches davon groß sein muss, auch wenn mal nur weniger übertragen>werden müsste.
Nein, das musst du nicht. Der RX DMA kann beliebig "dumm" die Daten in
den FIFO schreiben. Nur deine Auswertung muss halt ab und annmal
schauen, wieviele Daten im FIFO sind und dann etnsprechend reagieren.
Falk Brunner schrieb:> Nur deine Auswertung muss halt ab und annmal> schauen, wieviele Daten im FIFO sind und dann etnsprechend reagieren.
Woran sehe ich weit ein bestimmter DMA-Kanal bereits geschrieben hat?
Ändert sich DMA.CHx.DESTADDR während eines Schreibvorgangs? Das hab ich
noch nie ausprobiert?
Sorry, falls ich mich jetzt etwas dumm anstelle. :/