Inversión de onda con Arduino DUE

Hola a todos, estoy tratando de obtener mediante un micrófono audio y con un arduino DUE invertir la onda y luego reproducirla por unos cascos para hacer una cancelación activa de sonido, SI, se que con un euro en componentes se puede hacer pero esto es un proyecto propuesto por un profesor y he de utilizar la placa DUE.

Hace años que no toco arduino y no me acuerdo demasiado pero con un poco de investigación por aquí y por allá he conseguido montar este código que me permite leer perfectamente una onda sinusoidal de 20kHz, el problema es que lee la entrada del pin 0 un momento y luego te hace el display de 1001 valores(creo), no es una lectura y display continua, le pregunté al profesor y me dio que buscase un método llamado First In First Out pero todo lo que veo es un buffer de x logitud de bits que es leído, guardado y luego reproducido, sin embargo esto ha de ser en vivo, tan simple como leer un solo valor, multiplicarlo por -1 y devolverlo sin guardarlo ni nada, tal como haría un opamp en modo inversor unitario , también tengo al duda de como declarar la salida ya que yo solo he trabajado con analogwrite y digitalwrite pero esto precisa de valores de tensión determinados.

Alguna idea?



Este es el código que he estado utilizando, tiene comentado el apartado del plotter ya que solo lo usé para comprobar que leía correctamente hasta 20kHz

C:
unsigned long start_time;
unsigned long stop_time;
unsigned long values[1000]; /guarda 1001 valores?

void setup() {       
  Serial.begin(9600); 
  ADC->ADC_MR |= 0x80;  //Activa el modo libre en el ADC
  ADC->ADC_CHER = 0x80; //Activa el ADC en el pin A0 ( adc7???)
  //pinMode(13, OUTPUT);           // Declara pin como salida
 // digitalWrite(13, HIGH);       // Determina el estado inicial del pin
}
/*ADC->ADC_CDR[7]; //esto lee los datos mediante el adc
*/
void loop() {
  unsigned int i;
    
  start_time = micros();
  for(i=0;i<1000;i++){
    while((ADC->ADC_ISR & 0x80)==0); // espera a la conversión
    values[i]=ADC->ADC_CDR[7]; //obtiene los valores en el adc7
    //pin13!=pin13;    
    //pin13=estado                   por hacer    tratar de hacer onda cuadrada que con cada cambio de estado muestre cuando hace una adquisición de datos para saber la velocidad.
    //digitalWrite(13, estado);   por hacer
  }
//  stop_time = micros();
//
//  Serial.print("Tiempo total: ");
//  Serial.println(stop_time-start_time);
//  Serial.print("Tiempo medio por conversion: ");
//  Serial.println((float)(stop_time-start_time)/1000);
//
//  Serial.println("Valores: ");
//  for(i=0;i<1000;i++) {
//    Serial.println(values[i]);
//  }
// 
//  delay(2000);
}
 
Para empezar revisa la velocidad del ADC que en Arduino es absurdisimamente re ultra super lento .
No sé la velocidad del ADC del DUE


Puede que nada más empezar no tengas velocidad

La normal creo que es de unas 10k samples lo cual podría dar para reproducir voz con muy mala calidad.
 
Última edición:
Una sinusoidal de 20kHz la capta perfectamente con bastantes medidas por periodo, inicialmente se propuso limitar el ancho de banda desde 100 hasta 8000 Hz para facilitar la adquisición de audio pero no va a ser necesario ya que el espectro completo de audio se capta sin problemas.
 
Supuestamente el uC es un AT91SAM3X8E (ARM Cortex-M3) y el ADC es capaz de 1Msample/s, lo mismo que el DAC. Para 20kHz debería alcanzar.

Sobre el tratamiento de la señal:

1- El ADC debe recibir una señal positiva de 0 a 3,3v, por lo tanto la salida del micrófono necesita una tensión de offset (idealmente 1,65V).

2- Una vez convertida la señal analógica, el procesamiento de ese dato para la inversión de la señal, no debería ser multiplicar por -1, sino obtener el complementario.

Ejemplos de complementarios:

3,3v => 0v
0v => 3,3v
2v => 1,3v
...etc

Resumiendo, el cálculo debería ser:

Vout=-(Vin-Voffset)+Voffset

Una forma de evitar esa cuenta todo el tiempo por cada valor entrante, es usar algo llamado LUT (lookup table), que básicamente es un vector del tamaño de todos los posibles valores de entradas que reflejen el valor de salida deseado. Por ej. en un ADC de 8 bits, tenés 256 posibilidades, por lo tanto el vector debe ser de ese tamaño. En un ADC de 12bits, tenés 4096 posibilidades; si el programa y el uC lo permiten, te podés dar el lujo de pedir esos 4096 bytes en RAM.

La LUT te conviene hacerlo con los niveles del DAC y luego convertirlo a tensión; porque sino la LUT de flotantes tiene un peso 4 veces mayor.

Finalmente con un capacitor en serie a la salida, podés quitar el offset agregado previamente.
 
Una cosa es lo que haga el chip y otra lo que haga la capa Arduino, el ADC que yo usaba hace 25 años tardaba 14μs con un cuarzo de 12MHz pero el Arduino normal a 16MHz tarda no recuerdo que tiempo absurdo en convertir creo que 100μs por alguna incomprensible razón. Eso da 10kHz que corresponde a una onda de 5kHz como mucho para más o menos imaginar la forma de onda.
Se ve que hay librerías que convierten ese valor a algo más cuerdo.

En el caso del DUE no lo había investigado. Debería de sobrar por todos los lados pero no me hubiera sorprendido algún otro valor de conversión incomprensible.
 
Muchas gracias por el aporte Cosmefulanito04,

Ya he visto que el propio due tiene un DAC y ya he visto como hacerlo funcionar a 12 bits, lo que no entiendo es por que sería mas rápido la LUT que el cálculo ya que no se muy bien como funciona, de todas formas como ya el ADC tiene 12 bits no sería mas fácil esto?


Código:
 analogWriteResolution(12);// cambia la resolución del DAC de 8bits por defecto a 12bits
 newvalor=4095-valor;
 analogWrite(DAC0, newvalor );
El único "inconveniente" es que por lo que he leído la salida máx de tensión por el DAC del due es de 2,8v y no se si eso significa que esos 4096 bits están en esos 2,8v o que la onda se va a ver recortada por arriba.
 
De hecho hay una librería para el due para reproducir audio por los DACs que tiene dos.
No recortará, saldrá más pequeña.


La puedes amplificar después si es necesario.
 
Muchas gracias por el aporte Cosmefulanito04,

Ya he visto que el propio due tiene un DAC y ya he visto como hacerlo funcionar a 12 bits, lo que no entiendo es por que sería mas rápido la LUT que el cálculo ya que no se muy bien como funciona, de todas formas como ya el ADC tiene 12 bits no sería mas fácil esto?
Tal vez en este caso no influye tanto, porque la operación que se debe realizar es relativamente sencilla. Pero si fuera más compleja, la ventaja del uso de una LUT es que hacés el cálculo solo una vez (al generar la tabla) y te quedan guardado en memoria RAM los resultados, por lo tanto es más rápido leer en memoria que realizar el proceso cada vez que te llega un dato.

No todos los procesos se pueden realizar con una LUT, por ej. aquellos que requieran de valores anteriores o posteriores (filtros digitales).

El único "inconveniente" es que por lo que he leído la salida máx de tensión por el DAC del due es de 2,8v y no se si eso significa que esos 4096 bits están en esos 2,8v o que la onda se va a ver recortada por arriba.
Es correcto, según la hoja de datos la salida del DAC es 5/6*Vref. Tendrías que probar si el rango de 0 a 4095 es equivalente al de 0 a 2,8v o 0 a 3,3v. Sería un derroche de niveles que sea de 0 a 3,3v.
 
hola, les consulto algo:
el arduino , si posee 5 pines A/D , puese usarlso a la vez ?
o adentro es solo 1 conversor A/D que trabaja secuencialmente ??

digo, por que si es tema de velocidad, podria usar 5 pines ala vez y va "capturando" la señal y procesando .
 
Existen los conversores "paralelo" en la que cada entrada lleva el suyo, pero son raros. Lo normal es que lleve un solo conversor y un multiplexor.
 
y ese conversor hasta que no termina con su trabajo, no toma otro dato imagino ??
es asi ??
imagino que debe usar un flag ?
alguna vez lei, que si el ruido es repetitivo, o sea un ruido.
NO ruidos que cambian, como voces y cosas asi.
sino por ejemplo una sirena, o el motor de un avion, es siempre el mismo ruido.

si el A/D demora digamos 100 us en teoria no podria mas que convertir cada 100 us , pero eso no es asi.
puedo incluso convertir cada 1 us
solo necesito detectar el inicio de el ciclo de la onda.
 
y ese conversor hasta que no termina con su trabajo, no toma otro dato imagino ??
es asi ??
Es así.

imagino que debe usar un flag ?
Normalmente tiene un flag en el registro de estado del ADC que indica que terminó la conversión.

alguna vez lei, que si el ruido es repetitivo, o sea un ruido.
NO ruidos que cambian, como voces y cosas asi.
sino por ejemplo una sirena, o el motor de un avion, es siempre el mismo ruido.
Esto no lo entendí.

si el A/D demora digamos 100 us en teoria no podria mas que convertir cada 100 us , pero eso no es asi.
puedo incluso convertir cada 1 us
solo necesito detectar el inicio de el ciclo de la onda.
Si el ADC tarda 100uS (10kHz), es lo que tarda. Normalmente suelen ir de 100kHz a 1MHz, dependiendo del micro y del fabricante. Supongo que los DSP deben ir a mayor velocidad (nunca los usé).

Después tenés ADC independientes (un integrado propio) que puede alcanzar velocidades mucha mayores.
 
El conversor puede activar una interrupción o un flag para indicar que ha terminado.
En mi caso como sabía que tardaba 14μs y programaba en ensamblador, mandaba leer, ejecutaba 18 instrucciones de 1μs de otra cosa y leía sin mirar ni flag ni interrupción.
Arduino por defecto detiene la ejecución 100μs lo que ya no sé es si en ese intervalo permite interrupciones etc. Imagino que si.
 
Si. Un analogRead(pin) tarda 100μs en un Arduino UNO y similares.
Desconozco el por qué de esa brillante idea.
Según la documentación es "Para dar más estabilidad", como el que siembra delays estabilizadores.

Hay quien reconfigura el chip y consigue una velocidad normal, pero por defecto está así.


En un Arduino normal el código sería:

analogWrite(pinSalida, 255-analogRead(pinEntrada)/4);

Más o menos


En el Arduino fue tras leer la documentación:
En el setup:
Analogwritesetresolution(10)

En la función
analogWrite(DAC0, 1023-analogRead(pinEntrada);
Y ya está.

Si ajustas las dos resoluciones a lo mismo no hay que convertir nada.

No he buscado si el ADC se puede hacer de 12 bits
 
Última edición:

Arriba