Hallo zusammen, für mich ist FIFO im Hardwarekontext ein Puffer, wo die Bits sequentiell reingespeichert werden und dann bei erwünschtem Befüllungsgrad wieder ausgelesen/weiterverarbeitet werden sollen. Doch gerade bin ich dabei, das Serial Audio Interface(SAI) für ein STM32 Controller aufzustellen und habe da doch Verständnisprobleme. Und zwar das SAI hat eine Pufferlänge von 8 Wörter, also 8x32bits, s. Bilder. Aber das Datenregister SAI_xDR, das als FIFO Buffer dienen sollte, ist nur 1 Wort groß (=32bits) Die Interrupt Generation bezieht sich auch auf den Befüllungsgrad vom Register SAI_xDR, s.Bild. Worauf beziehen sich also diese 8 Wörter? Bzw. wie kann ich das handhaben, dass ich tatsächlich in 8-Wörter langes FIFO habe, das z.B. alle 4 Wörter ein DMA auslöst? (Was vom Datenblatt auch versprochen wird) Im Datenblatt steht folgendes: A write to this register loads the FIFO provided the FIFO is not full. A read from this register empties the FIFO if the FIFO is not empty. Also kontrolliert man über dieses Register nur das FIFO bzw. schiebt wortweise Daten rein und liest raus? Was ist die Adresse des FIFO-Puffers? Kann mir jemand bitte erklären, wie das ganze genau funktioniert? Danke und viele Grüße
Solocan Z. schrieb: > Hallo zusammen, > > für mich ist FIFO im Hardwarekontext ein Puffer, wo die Bits sequentiell > reingespeichert werden und dann bei erwünschtem Befüllungsgrad wieder > ausgelesen/weiterverarbeitet werden sollen. > Doch gerade bin ich dabei, das Serial Audio Interface(SAI > Aber das Datenregister SAI_xDR, das als FIFO Buffer dienen sollte, ist > nur 1 Wort groß (=32bits) > > Die Interrupt Generation bezieht sich auch auf den Befüllungsgrad vom > Register SAI_xDR, s.Bild. Worauf beziehen sich also diese 8 Wörter? Bzw. Ich habe das DB jetzt nicht gelesen aber das FIFO, dein Puffer ist 8x32 bit gross. Die Daten die du erhältst schreibst du ins Datenregister DR. Von Dort aus werden sie in den Puffer geschrieben. Spätestens nach dem 8.Datensatz ist der Puffer voll u du verlierst Daten, wenn du ihn nicht leerst. Sprich die Dma faul rum sitzt. > wie kann ich das handhaben, dass ich tatsächlich in 8-Wörter langes FIFO > habe, das z.B. alle 4 Wörter ein DMA auslöst? (Was vom Datenblatt auch > versprochen wird) Du kannst die DMA so einstellen, dass nachdem immer das Register DR geschrieben wurde die Daten immer transferiert werden durch die DMA, aber auch so dass sie das nur dann macht wenn du das DMA enable bit immer per Software aktivierst, wenn 4 Datensaetze gekommen sind. Macht für mich aber keinen Sinn. Lies dazu das Ref Man zur DMA am Besten. > Im Datenblatt steht folgendes: > A write to this register loads the FIFO provided the FIFO is not full. > A read from this register empties the FIFO if the FIFO is not empty. > > Also kontrolliert man über dieses Register nur das FIFO bzw. schiebt > wortweise Daten rein und liest raus? Was ist die Adresse des > FIFO-Puffers? Schau im Ref man ganz am Anfang nach der Basis Adresse memory organization. iwas 0x4001 xxxx bis 0x4001 yyyy. Also 0x4001 + Offset SAI_BDR in deinem Bild. Kann mir jemand bitte erklären, wie das ganze genau > funktioniert? > > Danke und viele Grüße
Beim SAI darf das FIFO nie leer laufen, dann dann "Stockt" die Soundausgabe. Um das zu gewährleisten gibt es ein FIFO in der Peripherie SAI. Du musst nur das eine Datenregister beschreiben, jedes Schreiben tut die Peripherie automatisch in das FIFO legen. Nun gibt es ein Interrupt, den kann man auslösen wenn z.B. nur noch 4 Elemente im FIFO drin sind. -> Periphere möchte dass man mehr Daten liefert. Die 4 bedeutet, dass man noch diese 4 Plätze Zeit hat um Daten zu liefern und der Datenstrom nicht abreißt. Dann macht man das FIFO voll und verlässt den Interrupt. So geht die "Händische" Programmierung. Etwas komplexer ist die Soundausgabe mit DMA. Hier wird die Schwelle den DMA triggern und dieser kopiert die Daten in den FIFO. Ist der DMA zu Ende, so generiert dieser ein Interrupt und nun muss man den nächsten DMA Auftrag für den nächsten RAM Bereich zur Soundausgabe senden aktivieren. Während der DMA die Daten aus gibt kann man in einem zweiten RAM Bereich die neuen Sound-Daten vorbereiten. So werden im Prinzip immer 2 RAM Bereich für die Sound Ausgabe umgeschaltet.
Markus M. schrieb: > > Etwas komplexer ist die Soundausgabe mit DMA. > Hier wird die Schwelle den DMA triggern und dieser kopiert die Daten in > den FIFO. Ist der DMA zu Ende, so generiert dieser ein Interrupt und nun > muss man den nächsten DMA Auftrag für den nächsten RAM Bereich zur > Soundausgabe senden aktivieren. > Meiner Meinung nach geschieht die Portierung in das FIFO automatisch. Das sagt ja auch der englische Text weiter oben. Dazu benötigst du keine DMA. Die DMA holt sich die Daten aus dem FIFO (Adresse der Quelle) und transportiert sie an die Zieladresse. Die Quell- und die Zieladresse muss man der DMA auch in der Initialisierung entsprechend bekannt geben. Ich kann mich aber auch täuschen, da ich das DB nicht gelesen habe.
bastler schrieb: > Markus M. schrieb: > >> >> Etwas komplexer ist die Soundausgabe mit DMA. >> Hier wird die Schwelle den DMA triggern und dieser kopiert die Daten in >> den FIFO. Ist der DMA zu Ende, so generiert dieser ein Interrupt und nun >> muss man den nächsten DMA Auftrag für den nächsten RAM Bereich zur >> Soundausgabe senden aktivieren. >> > > Meiner Meinung nach geschieht die Portierung in das FIFO automatisch. > Das sagt ja auch der englische Text weiter oben. Dazu benötigst du keine > DMA. > Die DMA holt sich die Daten aus dem FIFO (Adresse der Quelle) und > transportiert sie an die Zieladresse. Die Quell- und die Zieladresse > muss man der DMA auch in der Initialisierung entsprechend bekannt geben. > Ich kann mich aber auch täuschen, da ich das DB nicht gelesen habe. Solocan Z. schrieb: > SAI_FIFO.png Ach hier steht es ja: Das Schreiben des DR füllt das FIFO und das Lesen entleert das FIFO Also muss die DMA Quelladresse das SAI_BDR sein.
Lesen muss man bei SAI nur dann wenn man ein Sound einlesen möchte (LineIn, Mikrofon), geht es nur um Soudausgabe (Musik-Player/Pip-Ausgabe), dann kann man darauf verzichten. Man kann die SAI Ausgabe / SAI Einlesen fast wie 2 getrennte Peripherie Einheiten betrachten und kann man getrennt voneinander nutzen.
Vielen Dank für die Antworten! Es geht schon in die Richtung, die ich verstehen wollte. Vieles deckt sich auch mit meinem Verständnis. Aber eine Frage bleibt für mich offen: Muss ich jetzt die DMA alle 4 Wörter in einer Interruptroutine triggern oder soll SAI Peripherie jedes mal automatisch ein DMA starten? Nehmen wir ein Beispiel: Ich möchte kontinuierlich ein 1ms langes Sample ausgeben: Wie macht man das am sinnvollsten? Option A: 1) Signal definiert (Samplelänge=48 Wörter bei 48kHz und 1ms) 2) DMA und SAI so konfigurieren, dass es mir bei halber Befüllung ein Interrupt auslöst. 3) Schicke erst mal 8 Wörter mit einem DMA Request und befüll das FIFO vollständig. 4) Irgendwann wird das "Halbvoll-Interrupt" ausgelöst, wenn wieder die Hälfte leer ist und in dieser Interrupt-Routine werden die nächsten 4 Wörter mit einem neuen DMA-Request geschickt und so weiter... (Option A wäre also "interrupt-gesteuert und die Interruptroutine müsste alle 4 Wörter einen neuen DMA-Request starten, weil sich ja die DMA-Quelladdresse ändert.) Option B: 1) Gleich wie oben. 2) DMA und SAI so konfigurieren, dass es mir bei halber Befüllung ein DMA-Request startet und nehme als Quelladdresse einen 4-Wörter langen selbsterzeugten Speicherbereich (&buf). 3) Schicke erst mal 8 Wörter mit einem DMA Request und befüll das FIFO vollständig. 4) Ich kopiere die nächsten 4 Wörter in den "&buf" 5) Bei halber Befüllung wird ein DMA-Request getriggert. DMA holt den Inhalt von &buf und schiebt in die Peripherie. 6) Wenn DMA-Transfer fertig ist, wird ein "DMA-Transfer complete" ausgelöst. In dieser Routine kopiere ich die nächsten 4 Wörter von meinem Sample in den "&buf". 7) Zurück zu 5). Nachteil Option A: Alle 4 Wörter wird ein neuer DMA request mit geänderter Adresse gestartet. (viel Overhead) Nachteil Option B: Ich muss alle 4 Wörter lang 4 Wörter in &buf kopieren. (Pointer kann ich ja nicht ändern, weil DMA guckt ja nur unter der gegebenen Adresse und nimmt das, was sich darunter befindet) Also wie sollte ich vorgehen?
Ne, das geht anders - und eimfacher. SAI wird mit dem DMA verbunden. Ein RAM Buffer mit den 48 Worten vorbereiten. DMA starten. Warten bis der DMA fertig ist -> Interrupt vom DMA nicht vom SAI. Der DMA weiß von alleine dass der SAI noch platz im FIFO hat und schiebt den kompletten Buffer da rein, ganz von alleine.
Wow, das klingt gut. Mal blöd gefragt: Wie macht man das? Wenn ich DMA starte mit 48 Wörtern, dann gibt's gleich die Warnung, FIFO voll und nach 8 Wörtern kommt nichts mehr an, oder?
Der DMA wartet auf die Anforderung der Peripherie. Der ist klug genug das zu wissen.
Ok. Jetzt habe ich es soweit, dass DMA meinen beliebig langen Array automatisch in Schleife ins FIFO schiebt. Danke euch nochmal, ich bin definitiv ein Schritt weiter. Nur, ich bekomme nun keinen "Transfer complete" callbacks. Kämpfe gerade daran, dass ich irgendwelche Callbacks vom DMA abzapfen kann. Kann es sein, dass im circular mode transfer nie beendet wird? Na ja wahrscheinlich komme ich wieder zurück mit einem neuen Thread..
Auf der RAM Seite sollte man den Circular Mode nicht aktivieren, denn man will ja einen nächsten Ton-Abschnitt senden und nicht ein Endlos-Pipen haben - außer man will endlos pipen ;-) Wenn dann der DMA fertig ist sollte es ein Interrupt geben und man kann den DMA erneut starten mit den nächsten Daten aus einem anderen RAM Bereich. Ich hatte das einmal bei einem LPC4351 programmiert, sollte beim STM ähnlich funktionieren.
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.


