Eingang/Ausgang von unsynchronisiertem ADC/DAC

HAFTUNGSAUSSCHLUSS : Diese Frage hängt irgendwie mit dieser anderen Frage von mir zusammen , aber letztere hatte keine zufriedenstellende Antwort.

Ich arbeite an einem Audio-DSP-Projekt mit dem STM32F4xx und verwende 4 Audioeingänge und 1 Audioausgang .

Ich muss - jeden Eingang lesen - das Signal jedes Eingangs verarbeiten, - die verarbeiteten Signale zusammenmischen - das Ergebnis ausgeben.

Der Eingang wird über einen der 3 internen DACs des STM32 erhalten , 1 Kanal für jeden Eingang (dh 4 Kanäle zum Scannen insgesamt) und unter Verwendung von DMA in einem Puffer gespeichert .

Die Ausgabe wird durch einen Codec unter Verwendung eines I2S-Busses bei 48 kHz konvertiert.

Jedes Mal, wenn der Codec einen Puffer (oder genauer gesagt einen halben Puffer) fertig konvertiert hat, löst er eine Callback-Funktion aus , in der ich derzeit den gesamten DSP-Code habe. In der Schleife werden die Ausgangsabtastwerte berechnet und an den Halbpuffer gesendet, um unter Verwendung von DMA an I2S ausgegeben zu werden.

Angenommen, ich sample meinen Eingang mit der gleichen Rate wie meinen Ausgang (48 kHz, was bedeutet, dass mein DAC mit 4 * 48 kHz = 192 kHz getaktet sein muss), wie kann ich den ADC und die DAC-Konvertierung synchronisieren ?

Ich habe an einen FIFO zwischen dem Eingang und der DSP-Routine gedacht, der jedes Mal, wenn ich einen verarbeiten muss, einen Abtastwert in der Warteschlange auswählt. Aber ich bin mir nicht sicher, wie ich das machen soll, wenn ich mit Datenblöcken arbeite (ein Puffer hat eine Tiefe von 64 Samples).

Eine andere Lösung wäre, eine Eingangspuffertiefe von nur 1 Sample zu haben und dieses Sample in der DSP-Routine zu lesen, aber ich bin mir nicht sicher, ob dies funktionieren würde.

Weiß jemand wie man das am besten macht? Oder noch besser, wie synchronisiert man den ADC des STM32 mit einem externen Codec?

BEARBEITEN : Ich habe auch daran gedacht, den DAC im "One-Shot"-Modus zu verwenden, dh jedes Mal, wenn mein Codec sein Flag "Ich möchte Samples" setzt, eine Konvertierung von 64 Samples für alle Kanäle auszulösen. Funktioniert das?

EDIT2 : Auf Anfrage von @Neil_UK ist hier ein anschauliches Diagramm dessen, was passiert:Geben Sie hier die Bildbeschreibung ein

4 Eingänge werden vom internen ADC des STM32 abgetastet. Jeder muss eine Abtastrate von 48 kHz haben, da die Konvertierung der ADC-Kanäle nicht parallel erfolgt, ergibt sich eine Gesamtabtastfrequenz von 192 kHz (korrigieren Sie mich, wenn ich falsch liege).

Dann werden die konvertierten Samples jedes Eingangs in einem Ringpuffer von jeweils 64 Samples gespeichert und jedes Mal, wenn ein halber Puffer gefüllt wurde (dh 32*4 Samples wurden gespeichert), wird ein Interrupt-Flag gesetzt.

Auf der anderen Seite gibt es einen Codec, der kontinuierlich Samples, die ihm per I2S zugesendet werden, aus dem DMA des STM32 umwandelt. Es wird auch jedes Mal ein Interrupt ausgelöst, wenn der halbe I2S-Puffer geleert wurde. Zwischen den 2 gibt es eine DSP-Routine, die die Eingabe lesen, filtern und in den Ausgabepuffer legen soll.

Das Problem : Ich habe 2 Interrupts:

  • Das vom Codec (DAC) ausgelöste "Ich bin fertig mit der Konvertierung" ;
  • Das vom internen ADC ausgelöste "I'm done converting".

Wenn ich mit 192 kHz scanne, sollten diese Interrupts zumindest synchron sein (außer vielleicht etwas Jitter), aber die Phase kann völlig unterschiedlich sein. Das bedeutet, dass ich meinen DAC bemerken lassen kann, dass alle Samples gesendet werden, während mein ADC noch mitten in der Konvertierung der Eingänge ist. Und diese Phasendifferenz kann möglicherweise jedes Mal anders sein, wenn ich das Board zurücksetze, sodass ich sie nicht wirklich mit einem Offset kompensieren kann.

EDIT3 : Es scheint, als wäre das SAI-Modul eine gute Möglichkeit, dies zu tun. Wenn jemand Erfahrung mit SAI hat, hätte ich gerne einige Tipps und Hilfe zur Verwendung, um den internen DAC mit einem externen Codec zu verbinden

Zeichne ein Diagramm. Sie haben 3 ADCs, vier Eingänge, einen DAC-Ausgang über I2S. Sie alle haben eine Abtastrate, die entweder 48k oder 192k sein könnte, aber es ist nicht klar, welche. Wenn Sie, wie Sie andeuten, in der Lage sind, über I2S DMA auf ein Gerät zu übertragen und ADCs zu lesen, und Ihre Abtastraten ganzzahlige Vielfache voneinander sind, bin ich mir nicht sicher, wo Ihre Schwierigkeit liegt. Ihre Filterlängen legen eine minimale Größe für Ihre Puffer fest, Ihre Ziellatenz eine maximale Größe, der ganze Rest ist nur Hausarbeit, um keine Samples zu verlieren und Ihren Code ohne „off by one“-Fehler laufen zu lassen.
Hinweis: Wenn Sie dieses Diagramm nicht zeichnen können, verstehen Sie Ihre Anwendung und Ressourcen noch nicht genug.
Mache es gerade. Es scheint, als wäre ich in meinem OP nicht klar genug gewesen, ich verwende nur 1 der 3 ADC, aber 4 der Kanäle dieses ADC. Wenn man bedenkt, dass ich möchte, dass jeder Kanal mit 48k abgetastet wird, ergibt das eine ADC-Abtastrate von 4*48k = 192kHz. Mein Problem ist die Phase zwischen den Konvertierungen, dh die end_of_conversionFlags werden nicht gleichzeitig gehisst. EDIT: Eigentlich muss ich gehen, ich werde meinen Beitrag so schnell wie möglich bearbeiten
@Neil_UK Ich habe die Bearbeitung gerade zu meinem OP hinzugefügt, es tut mir leid, dass es einige Zeit gedauert hat, und ich hoffe, mein Problem macht jetzt mehr Sinn
Was ist die akzeptable Verzögerung zwischen Eingang und Ausgang? Verarbeiten Sie Daten Byte für Byte oder in Blöcken?
@Andrés Ich habe mit Puffern von 64 Samples gearbeitet und hatte eine akzeptable Latenz unter 1,5 ms. Aber ich landete mit einem FIFO und es funktionierte gut

Antworten (1)

Es gibt keine gute Möglichkeit, dies über den integrierten ADC / DAC zu tun. Sie müssten die DAC-Konvertierung im ADC-Interrupt auslösen, aber Sie könnten die Raten bei Verwendung von DMA nicht richtig einstellen, sodass Sie Sample für Sample vorgehen müssten. Das ist mit viel Overhead verbunden, und obwohl es funktionieren könnte, würde Ihnen nicht viel CPU für den DSP übrig bleiben.

Die bessere Lösung ist die Verwendung der I2S- oder SAI-Schnittstelle mit einem dedizierten Audio-Codec. Sie können entweder zwei Codecs verwenden oder einen Codec erhalten, der sowohl Eingabe- als auch Ausgabefähigkeit hat.

Danke für deine Antwort! Am Ende habe ich einen FIFO zwischen den ADC und die DSP-Routine gesetzt und es hat gut funktioniert ...