Muestreo de señal de audio con dsPIC

Que tal:

Uso un 30f2010 y no se que pasa con mi sistema pero no arroja lo que la simulación hace.
podrían ayudarme a revisar mi código y decirme si está bien programado?
quiero muestrear una señal de audio por AN2 con una frecuencia de muestreo de 2400Hz aprox.
uso el ADC con TIMER3 y pretendo llenar 64 muestras del buffer para mandarlos a una funcion fft.
el codigo está aquí:

Código:
#define _NOPSV  __attribute__((no_auto_psv))
# include <p30f2010.h>
# include <math.h>
_FOSC(CSW_FSCM_OFF & XT_PLL8); 
_FBORPOR(PBOR_OFF & MCLR_EN);
_FGS(CODE_PROT_OFF);

# define M_PI 3.141592654
unsigned char flag=0;
unsigned AdcValue=0;
void Iniciar_Adc(void);
unsigned char i=0,ind=0;
int *apunta;
int buf[64];
int  P[64];
*apunta=&buf[0];
int interval[6];
volatile int liminf,c=0,prom=0,ii=0,k,p,j=0;
double long   sum=0,sum1=0;
 void _ISR _NOPSV _ADCInterrupt(void)
	{

	IFS0bits.ADIF=0;
	AdcValue=ADCBUF0;
	flag=1;
	}
main()
{
TRISE=0;
Iniciar_Adc();	
Init_Timer();
IFS0bits.ADIF=0;
IEC0bits.ADIE=1;
ADCON1bits.ADON=1;
T3CONbits.TON=1;
while(1)
if(flag==1){
flag=0;
*apunta=ADCBUF0-512;
*apunta++;
ind++;
if(ind==64){
ind=0;
ADCON1bits.ADON=0;
T3CONbits.TON=0;
fft();
apunta=0x800;
*apunta=&buf[0];

ADCON1bits.ADON=1;

T3CONbits.TON=1;
}
}
}
void Init_Timer(void)
{
T3CONbits.TCKPS=3;
T3CONbits.TON=0;
PR3=31;
TMR3=0;

}
void Iniciar_Adc(void)
{
ADCON1bits.SSRC=2;//Autosample
ADCON1bits.FORM=0;
ADCON2bits.SMPI=0;
//ADCON3bits.ADCS=63;
//ADCON3bits.SAMC=31;
ADCHS=0x0002;
ADCSSL=0;
ADPCFG =0;      
ADCON1bits.ASAM=1;
ADCON2bits.VCFG=0;
}

Gracias.
 
Creo que el uso de un dspic esta muy sobrado para aplicaciones de voz, puedes hacer una prueba muy sencilla antes de comenzar a guardar tus datos, lo que hice fue usar el adc de un 16f873 y pasar los datos directamente al PWM que tiene el pic amplificandola un poco para que pueda escucharse bien con una bocina, con un reloj de 4 MHz tiene la suficiente velocidad de muestreo para lograr un reconocimiento de palabra, intenta hacerlo de esta forma, te dara buenos resultado.

Exito.
 
Y qué es lo que no te anda en particular?: las muestras no se toman bien, o no se guardan en memoria como esperabas, o el CAD te da valores inesperados, etc.

Me llaman la atención este par de líneas:

Código:
*apunta=ADCBUF0-512;
*apunta++;

Ahí le estás restando 512 al resultado de la conversión y guardando en apunta, que apunte a un int del vector buf. Hasta ahí bien.
Pero no será que la segunda línea en vez de ser "*apunta++; " debiera ser "apunta++; " para incrementar el puntero y no el valor al que apunta?

Lo mismo más arriba con *apunta=&buf[0]; ahí estás diciendo que se guarde la dirección de buf[0] en el int del que tiene la dirección apunta (por no poner el int al que apunta apunta), que ya de entrada es un lugar de la memoria indefinido.

Creo que debería ser "apunta=&buf[0]" sin *.

Este par de líneas:
Código:
apunta=0x800;
*apunta=&buf[0];

No entiendo para que está ese par de líneas ahí, es para usar la fft?. Pero en tal caso debería estar antes de llamar a fft().
Lo que me parece raro es guardar una dirección en el registro al que apunta apunta (este juego de palabras ya me marea). Estarías guardando la dirección de buf[0] en el registro ram que tiene dirección 0x800.

unsigned AdcValue=0; acá debería llevar un int (unsigned int...)

En fin, creo que en resumen, estás teniendo problemas con el manejo de punteros, acordate que el * es el operador de indirección y el & te da la dirección de la variable a la que se aplica.

Y si los punteros están bien, entonces no tengo ni idea de que hace el programa .

Saludos y suerte, contanos tu sufrimiento. .

PD: cuando hagas un post en el que metas código usá la etiqueta "Código" al redactar el mensaje, queda más claro y te respeta los espacios. Podés editar el mensaje anterior y corregirlo para que quede mejor.
 
*apunta=ADCBUF0-512;
*apunta++;
Esta parte del codigo resta 2.5volts de una señal de offset que tengo metida antes del ADC.
*apunta++ lo que hace es mover sobre el vector buf un lugar para recibir el siguiente valor.
*apunta=&buf[0];
lo que hace apunta este apuntando al primer lugar del vector buf
apunta=0x800;
esta instruccion es para regresar el puntero a su localidad d ememoria inicial ya que conforme se repite le ciclo de llenado del ADC, el puntero sigue incrmentando su valor generando errores de localidad d ememoria en la simulación por lo que lo corregí regresando a "apunta" a la localidad inicial, una vez haciendo esto, dispongo a que "apunta" apunte al lugar 0 del vector buf.

*apunta=&buf[0];
mi simulación corre bien pero a mi tambien me hizo ruido eso del *Y el & por lo que revisaré de nuevo la simulación y comentaré mis resultados.
Por cierto , encuentras algo mal en la config del ADC? no s eporque no funciona el sistema físicamente.
gracias.
 
Si la simulación en el mplab te anduvo bien, entonces voy a tener que retomar práctica.
Mi versión es la que sigue

Vamos a hacer lo siguiente, a partir de ahora soy el compilador C30 del mplab :LOL:

Esta primera parte no la comento, no sirve para ilustrar mi punto
#define _NOPSV __attribute__((no_auto_psv))
# include <p30f2010.h>
# include <math.h>
_FOSC(CSW_FSCM_OFF & XT_PLL8);
_FBORPOR(PBOR_OFF & MCLR_EN);
_FGS(CODE_PROT_OFF);

# define M_PI 3.141592654

unsigned char flag=0;
//bueno, acá tengo que meter un char que se llama flag en algún lugar de la memoria ram, que a mí, el compilador, me guste
// me parece linda la dirección 0x900 (esto en realidad depende del archivo .lkr, pero como nadie nunca tiene
//necesidad de abrirlo, bien lo podemos suponer aleatorio)
//a partir de ahora cada que encuentre flag, lo reemplazo por 0x900
//Ah!, casi me olvido, me dijo que de entrada meta un 0 en 0x900, hecho

unsigned AdcValue=0;

//similar a lo anterior, ahora es un unsigned, acá la verdad no estoy seguro de que es lo que haría el compilador
//por eso te decía de ponerle un int, ya que lo usás para leer el adc que te da un int:
//unsigned AdcValue=0;
//bueno, como yo tengo el poder digo que AdcValue va a ser la dirección 0x902
//pero también me reservo 0x903, ya que se trata de un int, de dos bytes

void Iniciar_Adc(void);

//ajá, voy a buscar la definición de Iniciar_Adc más adelante

unsigned char i=0,ind=0;

// decreto que i va a estar en la dirección 0x904, e ind en la dirección 0x905
//además de entrada cargo el registro 0x904 con valor 0 al igual que 0x905

int *apunta;

//ahora tengo que reservar una variable que apunta a otra variable
//creo que son un par de bytes (ya no soy tan poderoso)
//la variable apunta tendrá la dirección 0x906, y se reservará 0x907 por ser de 2 bytes
//no tiene ningún valor de inicialización así que va a ser (uno aleatorio o por default)
//0x1234

int buf[64];

//ufff, tengo que reservar 64 int's, decreto que buff va a empezar de 0x908 y el vector ocupará
//los registros desde esa dirección hasta 0x908 + 64 . 2 (0x40)= 0x948

int P[64];

//otro vector, ubico a P en 0x950 y llegará a 0x990

*apunta=&buf[0];

// ajá, el miembro de la derehca me pide aa dirección de donde empieza buf, que ya dije antes
//que es 0x908.
//apunta es el registro en 0x906, pero como está el * me dice que tome el contenido de apunta,
//que es aleatorio y vale 0x1234
//por lo tanto escribo el valor 0x908 en el registro 0x1234
//(se nota el dilema?)

//bueno, las variables que siguen no revisten mayor interés para lo que quiero exponer
//vamos a la parte donde se trabaja con apunta

int interval[6];
volatile int liminf,c=0,prom=0,ii=0,k,p,j=0;
double long sum=0,sum1=0;[/code]
void _ISR _NOPSV _ADCInterrupt(void)
{

IFS0bits.ADIF=0;
AdcValue=ADCBUF0;
flag=1;
}
main()
{
TRISE=0;
Iniciar_Adc();
Init_Timer();
IFS0bits.ADIF=0;
IEC0bits.ADIE=1;
ADCON1bits.ADON=1;
T3CONbits.TON=1;
while(1)
if(flag==1){
flag=0;
*apunta=ADCBUF0-512;

//bien, ya llegué acá a ver que tenemos....
//del lado de la derecha hago la cuenta, me puede dar positivo o negativo, pero si es un offset
//el resultado va a ser positivo
//hice la cuenta, me dió 165 (por decir algo)
//eso lo tengo que guardar en *apunta
//apunta es 0x906
//pero está el asterisco, me dice que lo guarde en el registro cuya dirección es el valor de apunta
//por lo tanto lo guardo en el registro de dirección 0x1234
//por lo tanto el registro 0x1234 ahora guarda el valor 165

*apunta++;

//en realidad no estoy muy seguro de como interpreta esto el compilador, yo creo que
//lo que hace tomar es como si fuera (*apunta)++
//entonces incrementa el registro 0x1234 en 1
// que ahora tendrá un valor de 166

ind++;
if(ind==64){
ind=0;
ADCON1bits.ADON=0;
T3CONbits.TON=0;
fft();
apunta=0x800;

//ahora apunta, que antes tenía el valor 0x906 pasa a tener el valor 0x800


*apunta=&buf[0];

//el lado derecho es la dirección de buff[0]
//el lado izquierdo me dice que lo guarde en el registro cuya dirección es el valor de apunta
//por lo tanto guardo 0x908 en el registro 0x800 (no en apunta)


ADCON1bits.ADON=1;

T3CONbits.TON=1;
}
}
}
void Init_Timer(void)
{
T3CONbits.TCKPS=3;
T3CONbits.TON=0;
PR3=31;
TMR3=0;

}
void Iniciar_Adc(void)
{
ADCON1bits.SSRC=2;//Autosample
ADCON1bits.FORM=0;
ADCON2bits.SMPI=0;
//ADCON3bits.ADCS=63;
//ADCON3bits.SAMC=31;
ADCHS=0x0002;
ADCSSL=0;
ADPCFG =0;
ADCON1bits.ASAM=1;
ADCON2bits.VCFG=0;
}

------------------

En la configuración del ADC no ví nada malo a priori (configurar un cad de un dspic cuesta el doble o el triple que el de un pic18 o pic16).
Si no te muestrea nada físicamente, no sé, tenés conectados AVdd y AVss?
AVdd en lo posible que venga de una referencia de tensión.
Para ver si es algo de hard te diría que pongas el circuito.

Bueno, eso es lo que yo creo que hay que corregir, puede ser que me equivoque (50 y 50 te diría), pero si lo solucionás no dejes de comentarlo así queda claro.

Saludos
 
Ok entiendo el punto y de acuerdo a la simulación se puedo definir lo siguiente.
apunta adress 0x800 donde buff[0] es 0x800
cuando hago *apunta++; apunta se va a 0x802; que está el buf[1] eso arroja la simulación.
cuando termino el llenado de buf, apunta invade localidades de memoria que arrojan error por lo que al terminar regreso apunta a la dirección 0x800 para que regrese a la posicion buf[0] de hecho el segundo *apunta=&buf[0] es redundante.
y puedo quitarlo.
me gustaría hablar contigo si es que tu puedes para que me ayudes podríamos hablar por messenger o skype para que podamos hablar fluido.
De verdad agradezco mucho tu ayuda y ah! adjunto mi circuito en el siguiente post
 
Uff bueno, yo te diría que para estar seguros de que buf tiene la dirección 0x800, la declares de esta forma:

int buf[64] __attribute__ ((address(0x800)));

Puede ser que el compilador empiece a guardar las variables en 0x800 por default, pero no hay garantía de que al declarar nuevas variables no te cambie la dirección.
Bueno, cerramos entonces el tema de los punteros, puede ser que sea yo el que tiene que revisar el uso de los operadores.

¿Qué es lo que no te hace el pic?, ¿el programa arranca o ni siquiera eso?, ¿ejecuta el código?,¿el cristal lo pusiste sin capacitores?.

En cuanto a lo del messenger, mandame un mensaje privado con tu cuenta y yo te contacto; con la condición de que después volquemos acá lo hablado.

Saludos y suerte.
 
La simulacion va d emaravilla hace lo que debe de hacer pero fisicamente no lo hace , no se si sea algo de config del ADC o que rayos con el circuito
el compilador le asigna una dirección a apunta sin embargo yo hago que apunte a la dirección 0x800 que es donde esta el buf[0]
 
He seguido con pruebas y no logro entender que pasa, ardagon que puedo estar haciendo mal,
tu revisaste mi diagrama?
la señal de offset está bien pare evitar quemar el ADC no?
simule el programa con señales generadas del adobe audition y la fft arroja el resultado correcto pero mi sistema fisicamente no.
como puedo saber si queme el ADC?
gracias.
 
Bueno, ese circuito para meter un offset a la señal de audio.... yo de audio mucho no entiendo más allá de que es una señal cuyo rango de frecuencias de interés es de 0 a 20 KHz :) .

Y ese circuito distorsiona apreciablemente la señal de audio (ver adjunto, eso es en amplitud, y en fase será mucho peor).

Para meterle el offset usaría un operacional (no sé cual se usa para audio) en configuración sumador.

Le pusiste capacitores al cristal de 10 MHz?.

Que amplitud pico a pico tiene la señal de audio?, cuidado que no se vaya (con offset y todo) arriba de +5V o abajo de 0V (el PIC corre peligro).

El PIC funciona bien más allá de lo del ADC?, ejecuta código?.
 

Adjuntos

  • audio_414.gif
    audio_414.gif
    50.6 KB · Visitas: 62
El circuito porque distorsiona?
yo probe el circuito con el sonoscope y no presenta distorsion sino una atenuación en frecuencias por encima de 2kHz por lo que el filtro no es del todo preciso pero no distorsiona.
La prueba para el filtro fue realiada con ruido rosa del adobe audition.
La señal pico pico es de 1V y la señal de offset es de 2.5V por lo que 2.5VRMS mas .7Vrms me dan 3.2 V con los cuales no excedo especificaciones del dsPIc.
los valores del divisor de tensi´n (4.7K) es porque la impedancia recomendada de entrada al ADC es de 5 kOhm y la impedancia de un reproductor mp3 es de 30 ohm.
Consideras que deba cambiar algo del circuito ?
Que sugieres son bienvenidas todas las sugerecias!1
gracias!
PD. Ando en línea.
 
Bueno, dije que no entiendo mucho de audio, pero el filtrado de agudos se nota al oído. Adjunto imágenes de señal de entrada y de salida.

Por otro lado, es la impedancia de entrada máxima de 5Kohm según la hoja de datos.

Hoja datos dspic30f2010 dijo:
the maximum recommended source imped-
ance, RS, is 5 kohm

Si es menos que eso mucho mejor.

No me respondiste si le pusiste capacitores al cristal, y si el PIC te ejecuta código, no dejes de contestarlo para la próxima.
 

Adjuntos

  • entrada_495.gif
    entrada_495.gif
    81.4 KB · Visitas: 19
  • frec_entrada_150.gif
    frec_entrada_150.gif
    31.9 KB · Visitas: 15
  • salida_167.gif
    salida_167.gif
    86 KB · Visitas: 22
  • frec_salida_731.gif
    frec_salida_731.gif
    27.1 KB · Visitas: 27
ok disculpa mi omisión a tu pregunta, el cristal tiene 2 cap. de 22pF a tierra.
el código en mplab corre bien y me da las mismas amplitudes que el matlab. no se si te refieras a eso con "el pic ejecuta el codigo"
como comento , la simulacion corre bien, aunque muy lento my fft jaja pero funciona.
Segun yo mi ADC configurado para recibir 2400 muestras por segundo aprox.
por la terminal AN2 (configurada como analogica), conectado Avdd a Vdd y Avss a Vss y configurado los pines de referencia, el CHOSA, el PR3, TMR y simulo con un stimulus workbook usando un "injection trace" para simular los valores del ADC en la ejecución del código
 
Al preguntar si el PIC ejecuta código, me refiero a el PIC físicamente hablando. Es decir, meterle un programa sencillo (encender un led por ejemplo) y ver si lo hace (en una protoboard); para saber si el PIC no está quemado, o si se programa bien.
 
En rojo se destacan los valores recientemente actualizados. Si uno ejecuta paso a paso y ejecuta una instrucción PORTA = 0xF0; por ejemplo, entonces si ese registro esta en la ventana watch pasa a rojo.
 
ok ok entendido .
de verdad aprecio mucho tu ayuda y sigo buscando errores en el codigo o en el circuito para hacer que esto funcione.
has encontrado alguna anomalía, me sería de mucha ayuda tu experiencia.

Gracias.
 
Si, ando medio complicado estos días, y parece que va a ser así hasta fin de año; el foro lo veo cuando puedo.
No te creas que tengo tanta experiencia, con los PIC empecé hace año y medio (a programarlos), a armar algo en la vida real hace poco menos de 1 año....

En fin, volviendo a lo tuyo, de hardware ya dije que en mi lugar metería con algún operacional; y por otro lado meteria un zener con un operacional (puede ser un chip con dos operacionales para la señal y el zener) para que sea referencia del CAD (pin AVdd). Esto porque la alimentación digital (Vdd) es de por sí bastante "polucionada" (variaciones de nivel por la activación/desactivación de entradas/salidas o señales internas del mismo PIC). Y se requiere que el AVdd sea lo más estable porque el AD usa esa tensión para hacer la conversión, su precisión/exactitud si descartamos los errores propios del CAD será tan buena como la tensión AVdd.
Me habías dicho que la señal variaba entre -1V y 1V; el CAD convertiría (con el offset incluído) tensiones entre 1.5V y 3.5V. Ahí estamos aprovechando solo el 40% de rango del operacional -> perdemos más de 1 bit de resolución

Bueno, en cuanto a probar con el CAD, podrías probar si convierte el offset (en hard) adecuadamente para empezar. Que usás para programar el dspic?, tenés un depurador "in circuit"?.

Ahora reviso la configuración del CAD...
 
Atrás
Arriba