Entrada/salida de ADC/DAC no sincronizado

DESCARGO DE RESPONSABILIDAD : esta pregunta está relacionada de alguna manera con esta otra pregunta mía , pero esta última no tuvo ninguna respuesta satisfactoria.

Estoy trabajando en un proyecto de DSP de audio con el STM32F4xx, usando 4 entradas de audio y 1 salida de audio .

Necesito - leer cada entrada - procesar la señal de cada entrada, - mezclar las señales procesadas juntas - generar el resultado.

La entrada se obtiene a través de uno de los 3 DAC internos del STM32 , 1 canal para cada entrada (es decir, 4 canales para escanear en total) y se almacena en un búfer mediante DMA .

La salida se convierte a través de un códec usando un bus I2S, a 48kHz.

Cada vez que el códec ha terminado de convertir un búfer (o, más precisamente, un medio búfer), activa una función de devolución de llamada en la que actualmente tengo todo el código DSP. En el bucle, las muestras de salida se calculan y se envían al medio búfer para que se envíen mediante DMA a I2S.

Dado que muestreo mi entrada a la misma velocidad que mi salida (48kHz, lo que significa que mi DAC debe tener una frecuencia de reloj de 4 * 48kHz = 192kHz), ¿cómo puedo sincronizar el ADC y la conversión de DAC ?

He pensado en un FIFO entre la entrada y la rutina DSP, seleccionando una muestra en la cola cada vez que necesito procesar una. Pero no estoy seguro de cómo hacerlo cuando trabajo con fragmentos de datos (un búfer tiene una profundidad de 64 muestras).

Otra solución sería tener una profundidad de búfer de entrada de solo 1 muestra y leer esta muestra en la rutina DSP, pero no estoy seguro de que esto funcione.

¿Alguien sabe cuál es la mejor manera de hacerlo? O mejor aún, ¿cómo sincronizar el ADC del STM32 con un códec externo?

EDITAR : También pensé en usar el DAC en modo "one shot", es decir, activar una conversión de 64 muestras para todos los canales cada vez que mi códec levanta el indicador "Quiero muestras". Funcionaría eso?

EDIT2 : a pedido de @Neil_UK, aquí hay un diagrama ilustrativo de lo que está sucediendo:ingrese la descripción de la imagen aquí

El ADC interno del STM32 está muestreando 4 entradas. Cada uno debe tener una frecuencia de muestreo de 48 kHz, por lo que, dado que la conversión de los canales ADC no se realiza en paralelo, eso nos da una frecuencia de exploración total de 192 kHz (corríjame si me equivoco).

Luego, las muestras convertidas de cada entrada se almacenan en un búfer circular de 64 muestras cada una y se activa una bandera de interrupción cada vez que se llena la mitad del búfer (es decir, se han almacenado 32*4 muestras).

Por otro lado, hay un códec que convierte continuamente las muestras que se le envían a través de I2S, desde el DMA del STM32. También se activa una interrupción cada vez que se vacía la mitad del búfer I2S. Entre los 2 hay una rutina DSP que se supone que lee la entrada, la filtra y la coloca en el búfer de salida.

El problema : tengo 2 interrupciones:

  • El "Terminé de convertir" generado por el códec (DAC);
  • El "Terminé de convertir" planteado por el ADC interno.

Si escaneo a 192 kHz, estas interrupciones al menos deberían estar sincronizadas (excepto quizás por alguna fluctuación) pero la fase puede ser completamente diferente. Eso significa que puedo hacer que mi DAC me notifique que todas las muestras se envían mientras mi ADC todavía está en medio de la conversión de las entradas. Y esta diferencia de fase puede ser diferente cada vez que restablezco la placa, por lo que realmente no puedo compensarla con una compensación.

EDIT3 : parece que el módulo SAI es una buena manera de hacerlo, si alguien tiene experiencia con SAI, me encantaría tener algunos consejos y ayuda sobre cómo usarlo para conectar el DAC interno con un códec externo

Dibuja un diagrama. Tiene 3 ADC, cuatro entradas, una salida DAC a través de I2S. Todos tienen una frecuencia de muestreo que puede ser de 48k o 192k, pero no está claro cuál. Si, como insinúa, es competente para DMA a un dispositivo a través de I2S y para leer ADC, y sus frecuencias de muestreo son múltiplos enteros entre sí, entonces no estoy seguro de dónde radica su dificultad. Las longitudes de su filtro pondrán un tamaño mínimo en sus búferes, su latencia objetivo un tamaño máximo, todo lo demás es solo limpieza para no dejar caer muestras y hacer que su código se ejecute sin errores de 'apagado por uno'.
Sugerencia, si no puede dibujar ese diagrama, aún no comprende lo suficiente su aplicación y sus recursos.
Haciéndolo ahora mismo. Parece que no fui lo suficientemente claro en mi OP, uso solo 1 de los 3 ADC pero 4 de los canales de este ADC. Teniendo en cuenta que quiero que cada canal se muestree a 48k, eso me da una tasa de escaneo ADC de 4*48k = 192kHz. Mi problema es la fase entre las conversiones, es decir, las end_of_conversionbanderas no se levantan al mismo tiempo. EDITAR: en realidad tengo que irme, editaré mi publicación lo antes posible
@Neil_UK Acabo de agregar la edición a mi OP, lamento haber tomado tiempo y espero que mi problema tenga más sentido ahora
¿Cuál es el retraso aceptable entre la entrada y la salida? ¿Está procesando datos byte por byte o en fragmentos?
@Andrés I estaba operando por buffers de 64 muestras y tenía una latencia aceptable por debajo de 1.5ms. Pero terminé usando un FIFO y funcionó bien.

Respuestas (1)

No hay una buena manera de hacer esto a través del ADC/DAC integrado. Tendría que activar la conversión de DAC en la interrupción de ADC, pero no podría establecer las tasas correctamente cuando use DMA, por lo que tendría que ir muestra por muestra. Eso implica muchos gastos generales y, si bien podría funcionar, no te dejaría con una gran cantidad de CPU sobrante para el DSP.

La mejor solución es usar la interfaz I2S o SAI con un códec de audio dedicado. Puede usar dos códecs u obtener un códec que tenga capacidad de entrada y salida.

¡Gracias por tu respuesta! Terminé poniendo un FIFO entre el ADC y la rutina DSP y funcionó bien...