Hola Pablo, bienvenido al foro.
En este tipo de problemas conviene separar entre sí las diferentes funciones y probarlas una a una. Yo te recomendaría que comenzases por probar en envío de texto por serial. Creo que es lo que está consumiendo más tiempo.
La función sprintf() que utilizas no es una buena idea a la hora de ahorrar tiempo. Es muy potente, pero también consume bastantes ciclos formateando la salida y más si utilizas variables de tipo double. Intenta manejar datos de tipo entero que son mucho más rápidos.Código: C
// DSPIC33FJ256GP710 Configuration Bit Settings // 'C' source line config statements // FBS #pragma config BWRP = WRPROTECT_OFF // Boot Segment Write Protect (Boot Segment may be written) #pragma config BSS = NO_FLASH // Boot Segment Program Flash Code Protection (No Boot program Flash segment) #pragma config RBS = NO_RAM // Boot Segment RAM Protection (No Boot RAM) // FSS #pragma config SWRP = WRPROTECT_OFF // Secure Segment Program Write Protect (Secure Segment may be written) #pragma config SSS = NO_FLASH // Secure Segment Program Flash Code Protection (No Secure Segment) #pragma config RSS = NO_RAM // Secure Segment Data RAM Protection (No Secure RAM) // FGS #pragma config GWRP = OFF // General Code Segment Write Protect (User program memory is not write-protected) #pragma config GSS = OFF // General Segment Code Protection (User program memory is not code-protected) // FOSCSEL #pragma config FNOSC = PRIPLL // Oscillator Mode (Primary Oscillator (XT, HS, EC) w/ PLL) #pragma config IESO = ON // Two-speed Oscillator Start-Up Enable (Start up with FRC, then switch) // FOSC #pragma config POSCMD = NONE // Primary Oscillator Source (Primary Oscillator Disabled) #pragma config OSCIOFNC = OFF // OSC2 Pin Function (OSC2 pin has clock out function) #pragma config FCKSM = CSDCMD // Clock Switching and Monitor (Both Clock Switching and Fail-Safe Clock Monitor are disabled) // FWDT #pragma config WDTPOST = PS32768 // Watchdog Timer Postscaler (1:32,768) #pragma config WDTPRE = PR128 // WDT Prescaler (1:128) #pragma config WINDIS = OFF // Watchdog Timer Window (Watchdog Timer in Non-Window mode) #pragma config FWDTEN = ON // Watchdog Timer Enable (Watchdog timer always enabled) // FPOR #pragma config FPWRT = PWR128 // POR Timer Value (128ms) // FICD #pragma config ICS = PGD1 // Comm Channel Select (Communicate on PGC1/EMUC1 and PGD1/EMUD1) #pragma config JTAGEN = OFF // JTAG Port Enable (JTAG is Disabled) // #pragma config statements should precede project file includes. // Use project enums instead of #define for ON and OFF. /*******librerias******************/ #include "xc.h" #include <stdlib.h> #include <stdio.h> #include <string.h> #include <math.h> #include "p33FJ256GP710.h" /**********************************/ /**********************************/ #define Fcy 40000000 #define delay_ms(x) __delay32((Fcy/1000)*x) //delay en milisegundos /**********************************/ /*DECLARACION DE FUNCIONES*/ void Configurar_UART(); void Configurar_IO(); void OscConfig(); void ADC_Data(); void ADCStart(); void ADCInit(); void Serial_SendString(char *str); void Serial_PutChar(char Ch); void Configurar_Timer1(); void Configurar_Timer32(); /**************************/ float temp1 = 0; char Salto[] = "\n"; char trama[28]; void __attribute__((__interrupt__, __auto_psv__)) _T3Interrupt(void) { AD1CON1bits.ADON = 0; T1CONbits.TON = 0; T2CONbits.TON = 0; while (1) { } return 0; //T1CONbits.TON = 0; _T3IF = 0; /* Ponemos a 0 el Flag de la Int del Timer 1 */ } /****************************************/ /* Función de Interrupción de Recepción */ /****************************************/ void __attribute__((__interrupt__, no_auto_psv)) _U2RXInterrupt(void) { U2TXREG = U2RXREG; //se trasmite lo que se recibe _U2RXIF = 0; // Borramos flag. } /*********************/ /* Función Principal */ /*********************/ int main(void) { //ADPCFG = 0xffff; OscConfig(); Configurar_IO(); ADCInit(); // Inicializamos el conversor A/D Configurar_UART(); // Configurar_Timer1(); Configurar_Timer32(); while (OSCCONbits.LOCK != 1); ADCStart(); // Encendemos el ADC // T1CONbits.TON = 1; T2CONbits.TON = 1; while (1) { while (!IFS0bits.AD1IF); IFS0bits.AD1IF = 0; ADC_Data(); //Dato almacenado en la variable temp1 temp1 = (temp1 * (3.313)) / 1023.0; Serial_SendString(trama); Serial_SendString(trama); Serial_SendString(trama); Serial_SendString(Salto); } return 0; } /*************************************/ /* Función de Configuración del UART */ /*************************************/ void Configurar_UART() {//uart 1 U2MODEbits.BRGH = 1; U2MODEbits.PDSEL = 0b00; // No Parity, 8 data bits U2MODEbits.STSEL = 0; // 1 Stop bit U2MODEbits.UEN = 0b00; U2MODEbits.ABAUD = 0; // Auto-Baud Disabled //U2BRG = 21 ; //BAUD Rate Setting for 115200 //U2BRG = 10; //BAUD Rate Setting for 230400 //U2BRG = 259; // BAUD Rate Setting for 9600 //U2BRG = 9; //BAUD Rate Setting for 2.000.000 U2BRG = 9; U2STAbits.URXISEL = 0; // Interrupt after one RX character is received IFS1bits.U2RXIF = 0; // Clear the Recieve Interrupt Flag IEC1bits.U2RXIE = 1; // Enable Recieve Interrupts U2MODEbits.UARTEN = 1; // Enable UART U2STAbits.UTXEN = 1; // Enable UART TX } void Configurar_IO() { TRISB = 0; /* Puerto B como salida */ TRISF = 0xFFF7; } // Send a string out to the serial interface. void OscConfig() { //CONFIGURACION PARA OBTENER UNA Fcy=40MHz //Fosc = Fin * M/(N1*N2), Fcy = Fosc/2 //Fosc = 20MHz * 16/(2*2) = 80MHz para una entrada de reloj de 20MHz CLKDIV = 0x0000; // N1=2 Y N2=2 PLLFBD = 0x000E; // M=16 OSCTUN = 0; // Desactivar afinado del oscilador FRC, si está activo RCONbits.SWDTEN = 0; //Desactivar Watch Dog Timer } void ADCInit() { AD1PCFGLbits.PCFG10 = 0; // Se configura el ADPCFG para que el único pin // usado analógicamente sea el AN10 AD1CON1bits.SSRC = 0b111; // selección de la muestra después que la conversión termina AD1CON1bits.ASAM = 1; // Formato del resultado entero, Comienzo de la conversión automático, AD1CON1bits.AD12B = 0; //10 bits resolución AD1CHS0bits.CH0SA = 0b1010; // Entrada positiva AN10 para la entrada de la muestra AD1CHS0bits.CH0NA = 0; // Entrada negativa se usa el VR- AD1CON2bits.VCFG = 0b000; // Referencias: AVDD y AVSS, AD1CON2bits.BUFM = 0; //Se selecciona nivel de buffer 16*1 y AD1CON3bits.ADCS = 12; } void ADCStart() { AD1CON1bits.ADON = 1; // Prende el ADC } void ADC_Data() { unsigned long int temp; temp = ADCBUF0; temp1 = temp; } void Serial_PutChar(char Ch) { // wait for empty buffer while (U2STAbits.UTXBF == 1); U2TXREG = Ch; } // Send a string out to the serial interface. void Serial_SendString(char *str) { char * p; p = str; while (*p) Serial_PutChar(*p++); } //void Configurar_Timer1() { // PR1 = 0xFFFF; // //PR1 = 1 / (int) (((float) (Fcy) * 1)*0.000001 * tmicro); // T1CON = 0; // Resetear el timer // T1CONbits.TCKPS = 0b00; //Preescaler 1:1 // TMR1 = 0; // //IPC0bits.T1IP = 1; // Interrupción con prioridad 1 // //IFS0bits.T1IF = 0; // Interrupción cuando llega a 0 // //IEC0bits.T1IE = 1; //Habilitar interrupción del timer1 // //T1CONbits.TON = 1; //Activar el timer1 //} void Configurar_Timer32() { T3CONbits.TON = 0; T2CONbits.TON = 0; T2CONbits.T32 = 1; T2CONbits.TCS = 0; T2CONbits.TGATE = 0; T2CONbits.TCKPS = 0b11; TMR3 = 0; TMR2 = 0; PR3 = 0x0017; PR2 = 0xD784; IPC2bits.T3IP = 1; IFS0bits.T3IF = 0; IEC0bits.T3IE = 1; }
Main cambiado para probar solo el envío por UART:Código: C
int main(void) { //ADPCFG = 0xffff; OscConfig(); Configurar_IO(); ADCInit(); // Inicializamos el conversor A/D Configurar_UART(); // Configurar_Timer1(); Configurar_Timer32(); while (OSCCONbits.LOCK != 1); ADCStart(); // Encendemos el ADC // T1CONbits.TON = 1; T2CONbits.TON = 1; while (1) { temp1 = (100 * (3.313)) / 1023.0; Serial_SendString(trama); Serial_SendString(trama); Serial_SendString(trama); Serial_SendString(Salto); } return 0; }
Un saludo.
Hola. Un saludo desde Chiclana de la Frontera. Estamos cerquita. ((:-))
Ahí lo que veo es que tomas una muestra y estás enviando 16 bytes a la terminal a 1 Mbps. Cada byte lleva 1 start bit, 8 bits de datos y 1 stop bit. (Son 10 en total) es decir, necesitas 160 baudios para transmitir esos 16 bytes.
En tu caso 1 byte va a necesitar 10 uS para salir por el puerto físico.
Teniendo en cuenta que tienes un FIFO de 4 bytes, si envías los 16 bytes del tirón, tienes que tener en cuenta que los 4 primeros se cargan sin demoras, pero a partir del quinto byte vas a tener que esperar espacio libre en buffer, es decir, 10 uS por byte adicional hasta que salgan los 16. Esto es 16-4= 12 bytes * 10 uS cada uno = 120 uS.
Si le sumas lo que tarda la adquisición adc que en tu caso Tad = 3,9 uS son 124 uS entre instrucciones y demás..
Y luego en la siguiente adquisición seguramente cuando vayas a volver a enviar la siguiente trama todavía aún así al fifo no le habrá dado ni tiempo de terminar de enviarte los 4 últimos de la anterior trama, por lo que la espera total va a alcanzar los 165 uS.
Eso son 6060 operaciones por segundo vs las 250.000 que esperabas.
Si lo que quieres es saber que tiempo transcurre entre una adquisición y otra simplemente pon el timer 2/3 de 32 bits que usas para medir a cero y toma unas cuantas muestras ADC, por ejemplo 100 o 1000 muestras, o incluso las 250.000 y una vez tomadas, lee el Timer 2/3 y envía su información a la terminal. Entonces ahí verás lo que realmente demora cada adquisición por una simple regla de tres.
No puedes pretender adquirir 250.000 muestras adc y enviarlas a 1 mbps en serie todo eso en 1 segundo. Es que es imposible salvo que tengas un fifo de 4 Mb y ni aún así.
Un saludo.
Hola. Un saludo desde Chiclana de la Frontera. Estamos cerquita. ((:-))
Ahí lo que veo es que tomas una muestra y estás enviando 16 bytes a la terminal a 1 Mbps. Cada byte lleva 1 start bit, 8 bits de datos y 1 stop bit. (Son 10 en total) es decir, necesitas 160 baudios para transmitir esos 16 bytes.
En tu caso 1 byte va a necesitar 10 uS para salir por el puerto físico.
Teniendo en cuenta que tienes un FIFO de 4 bytes, si envías los 16 bytes del tirón, tienes que tener en cuenta que los 4 primeros se cargan sin demoras, pero a partir del quinto byte vas a tener que esperar espacio libre en buffer, es decir, 10 uS por byte adicional hasta que salgan los 16. Esto es 16-4= 12 bytes * 10 uS cada uno = 120 uS.
Si le sumas lo que tarda la adquisición adc que en tu caso Tad = 3,9 uS son 124 uS entre instrucciones y demás..
Y luego en la siguiente adquisición seguramente cuando vayas a volver a enviar la siguiente trama todavía aún así al fifo no le habrá dado ni tiempo de terminar de enviarte los 4 últimos de la anterior trama, por lo que la espera total va a alcanzar los 165 uS.
Eso son 6060 operaciones por segundo vs las 250.000 que esperabas.
Si lo que quieres es saber que tiempo transcurre entre una adquisición y otra simplemente pon el timer 2/3 de 32 bits que usas para medir a cero y toma unas cuantas muestras ADC, por ejemplo 100 o 1000 muestras, o incluso las 250.000 y una vez tomadas, lee el Timer 2/3 y envía su información a la terminal. Entonces ahí verás lo que realmente demora cada adquisición por una simple regla de tres.
No puedes pretender adquirir 250.000 muestras adc y enviarlas a 1 mbps en serie todo eso en 1 segundo. Es que es imposible salvo que tengas un fifo de 4 Mb y ni aún así.
Un saludo.
Los tiempos de la USART salen del baudrate que has configurado. En tu caso 1 Mbps. Significa que vas a poder transmitir 1.000.000 de bits en un segundo, es decir, 1 baudio en 1 us en este caso. 1/1Mhz = 1 us.
Calculando el volumen de bits que quieres enviar en cada trata y multiplicándolo por el tiempo por baudio requerido obtienes el tiempo total necesario para transmitir una trama.
Por otro lado. La FFT, sabemos el sample rate que quieres, que sería 250 Khz, pero es importante conocer también su tamaño. Tienes 30 Kb de RAM en el pic. Tal vez, si te cabe, te convenga construir la FFT entera en la ram del pic y una vez concluida haces todas las operaciones de análisis que necesitas y las transmites.
Para la transmisión puedes barajar también la posibilidad de usar SPI que puede alcanzar velocidades de 40 Mhz en ese micro. Hay adaptadores de SPI hasta 48 Mhz a USB. Por ejemplo este:
https://diolan.com/usb-spi-adapters
Otra cosa es que ese micro tiene 2 Kb de RAM casadas con funciones DMA que bien utilizado en una buena simbiosis entre funciones puede ser muy potente.
Por ejemplo, puedes ir metiendo en esos 2 Kb datos de las muestras a la misma vez que las vas tomando y esos datos pueden ir saliendo por el SPI automáticamente sin intervención de la CPU.
Creo que poderse hacer lo que quieres es posible. Simplemente se trata de analizar bien todo el hardware disponible y medirlo todo bien en cuanto al FFT, especialmente Sample rate, tamaño y periodicidad. Ajustar al máximo el tamaño de la información a transmitir, transmitiendo solo lo justo y necesario para que el dispositivo que va a recibir esos datos pueda interpretarlos. obviando lo que no sea necesario.
Un saludo.
Para calcular el desfase de una senoidal no es necesario calcular la FFT.
La FFT de una senoidal de frecuencia fija es un solo valor, se puede calcular simplemente simplificando la FFT a un detector de fase. Yo creo que lo que realmente quieres hacer es un Lock-in amplifier:
https://en.wikipedia.org/wiki/Lock-in_amplifier
https://www.microchip.com/wwwAppNotes/AppNotes.aspx?appnote=en532447
Hola. Un saludo desde Chiclana de la Frontera. Estamos cerquita. ((:-))
Ahí lo que veo es que tomas una muestra y estás enviando 16 bytes a la terminal a 1 Mbps. Cada byte lleva 1 start bit, 8 bits de datos y 1 stop bit. (Son 10 en total) es decir, necesitas 160 baudios para transmitir esos 16 bytes.
En tu caso 1 byte va a necesitar 10 uS para salir por el puerto físico.
Teniendo en cuenta que tienes un FIFO de 4 bytes, si envías los 16 bytes del tirón, tienes que tener en cuenta que los 4 primeros se cargan sin demoras, pero a partir del quinto byte vas a tener que esperar espacio libre en buffer, es decir, 10 uS por byte adicional hasta que salgan los 16. Esto es 16-4= 12 bytes * 10 uS cada uno = 120 uS.
Si le sumas lo que tarda la adquisición adc que en tu caso Tad = 3,9 uS son 124 uS entre instrucciones y demás..
Y luego en la siguiente adquisición seguramente cuando vayas a volver a enviar la siguiente trama todavía aún así al fifo no le habrá dado ni tiempo de terminar de enviarte los 4 últimos de la anterior trama, por lo que la espera total va a alcanzar los 165 uS.
Eso son 6060 operaciones por segundo vs las 250.000 que esperabas.
Si lo que quieres es saber que tiempo transcurre entre una adquisición y otra simplemente pon el timer 2/3 de 32 bits que usas para medir a cero y toma unas cuantas muestras ADC, por ejemplo 100 o 1000 muestras, o incluso las 250.000 y una vez tomadas, lee el Timer 2/3 y envía su información a la terminal. Entonces ahí verás lo que realmente demora cada adquisición por una simple regla de tres.
No puedes pretender adquirir 250.000 muestras adc y enviarlas a 1 mbps en serie todo eso en 1 segundo. Es que es imposible salvo que tengas un fifo de 4 Mb y ni aún así.
Un saludo.
Oye Remi, otra preguntita con esto que me pones aquí.
Me dices que estoy enviando 16 bytes a 1Mbps. ¿No serían 16bits? pregunto ya que el registro U2TXREG realmente tiene 16bits, y no sé si ha sido fallo tuyo o confusión mía al no conocer exactamente como funciona la transmisión.
Gracias de nuevo!
Los tiempos de la USART salen del baudrate que has configurado. En tu caso 1 Mbps. Significa que vas a poder transmitir 1.000.000 de bits en un segundo, es decir, 1 baudio en 1 us en este caso. 1/1Mhz = 1 us.
Calculando el volumen de bits que quieres enviar en cada trata y multiplicándolo por el tiempo por baudio requerido obtienes el tiempo total necesario para transmitir una trama.
Por otro lado. La FFT, sabemos el sample rate que quieres, que sería 250 Khz, pero es importante conocer también su tamaño. Tienes 30 Kb de RAM en el pic. Tal vez, si te cabe, te convenga construir la FFT entera en la ram del pic y una vez concluida haces todas las operaciones de análisis que necesitas y las transmites.
Para la transmisión puedes barajar también la posibilidad de usar SPI que puede alcanzar velocidades de 40 Mhz en ese micro. Hay adaptadores de SPI hasta 48 Mhz a USB. Por ejemplo este:
https://diolan.com/usb-spi-adapters
Otra cosa es que ese micro tiene 2 Kb de RAM casadas con funciones DMA que bien utilizado en una buena simbiosis entre funciones puede ser muy potente.
Por ejemplo, puedes ir metiendo en esos 2 Kb datos de las muestras a la misma vez que las vas tomando y esos datos pueden ir saliendo por el SPI automáticamente sin intervención de la CPU.
Creo que poderse hacer lo que quieres es posible. Simplemente se trata de analizar bien todo el hardware disponible y medirlo todo bien en cuanto al FFT, especialmente Sample rate, tamaño y periodicidad. Ajustar al máximo el tamaño de la información a transmitir, transmitiendo solo lo justo y necesario para que el dispositivo que va a recibir esos datos pueda interpretarlos. obviando lo que no sea necesario.
Un saludo.
Mi idea era comprobar primero que tomo las muestras necesarias (256K muestras/s) antes de meterme con la FFT, ya que si no estoy tomando ese número de muestras concretas y con una distancia temporal entre ellas similar, la FFT no me va a arrojar valores correctos. Voy a investigar un poco más sobre el tema de la RAM, a ver si consigo avanzar con esto.
Al final, con las ideas que me estás dando voy a deberte una cerveza!!
Muchas gracias!!
Para calcular el desfase de una senoidal no es necesario calcular la FFT.
La FFT de una senoidal de frecuencia fija es un solo valor, se puede calcular simplemente simplificando la FFT a un detector de fase. Yo creo que lo que realmente quieres hacer es un Lock-in amplifier:
https://en.wikipedia.org/wiki/Lock-in_amplifier
https://www.microchip.com/wwwAppNotes/AppNotes.aspx?appnote=en532447
UUUU esto podría ser exactamente lo que buscaba, sí. El proyecto final es tener 4 dsPICs equidistantes (un cuadrado) que reciben la misma señal de manera inalámbrica desde un quinto dsPIC que estará colocado en un lugar aleatorio X dentro de este cuadrado. Al recibir estas señales, los dsPICs calculan los desfases y, en función a estos, se puede estimar con una buena precisión la posición del 5 dsPIC dentro del cuadrado.
Entiendo que con esto que me pasas podría almacenar en una variable los desfases, no?
Gracias Picuino!!
Los tiempos de la USART salen del baudrate que has configurado. En tu caso 1 Mbps. Significa que vas a poder transmitir 1.000.000 de bits en un segundo, es decir, 1 baudio en 1 us en este caso. 1/1Mhz = 1 us.
Calculando el volumen de bits que quieres enviar en cada trata y multiplicándolo por el tiempo por baudio requerido obtienes el tiempo total necesario para transmitir una trama.
Por otro lado. La FFT, sabemos el sample rate que quieres, que sería 250 Khz, pero es importante conocer también su tamaño. Tienes 30 Kb de RAM en el pic. Tal vez, si te cabe, te convenga construir la FFT entera en la ram del pic y una vez concluida haces todas las operaciones de análisis que necesitas y las transmites.
Para la transmisión puedes barajar también la posibilidad de usar SPI que puede alcanzar velocidades de 40 Mhz en ese micro. Hay adaptadores de SPI hasta 48 Mhz a USB. Por ejemplo este:
https://diolan.com/usb-spi-adapters
Otra cosa es que ese micro tiene 2 Kb de RAM casadas con funciones DMA que bien utilizado en una buena simbiosis entre funciones puede ser muy potente.
Por ejemplo, puedes ir metiendo en esos 2 Kb datos de las muestras a la misma vez que las vas tomando y esos datos pueden ir saliendo por el SPI automáticamente sin intervención de la CPU.
Creo que poderse hacer lo que quieres es posible. Simplemente se trata de analizar bien todo el hardware disponible y medirlo todo bien en cuanto al FFT, especialmente Sample rate, tamaño y periodicidad. Ajustar al máximo el tamaño de la información a transmitir, transmitiendo solo lo justo y necesario para que el dispositivo que va a recibir esos datos pueda interpretarlos. obviando lo que no sea necesario.
Un saludo.
Mi idea era comprobar primero que tomo las muestras necesarias (256K muestras/s) antes de meterme con la FFT, ya que si no estoy tomando ese número de muestras concretas y con una distancia temporal entre ellas similar, la FFT no me va a arrojar valores correctos. Voy a investigar un poco más sobre el tema de la RAM, a ver si consigo avanzar con esto.
Al final, con las ideas que me estás dando voy a deberte una cerveza!!
Muchas gracias!!
Como ya te dije, eso sería muy fácil hacerlo.
Coges el timer 2/3 como hiciste de 32 bits y lo pones a cero. Inmediatamente haces las 250.000 capturas dentro de un bucle for por ejemplo.
Una vez terminadas las 250.000 capturas lees el valor de 32 bits del timer 2/3. Ya tienes ahí el tiempo que ha tardado en producirse las 250.000 capturas.
Envias por usart el valor del timer para que puedas calcular el tiempo real. Se calcula según la configuración que le hayas dado al timer. En tu caso, lo conectas a TCY de modo que tu timer va a contar de 0 a 40.000.000 en un segundo.
(40.000.000 / resultado del timer) = Tiempo en segundos que ha tardado en producirse las 250.000 muestras.
Un saludo.
Nada más. Te va a dar tal vez un poco más por que se tienen que producir 250.000 iteracciones FOR, con 250.000 incrementos del índice y poco más. Pero te sirve perfectamente.