Autor Tema: Problema con el puerto serie en dsPIC33FJ256GP710-I/PF-ND  (Leído 1948 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado padag

  • PIC10
  • *
  • Mensajes: 13
Problema con el puerto serie en dsPIC33FJ256GP710-I/PF-ND
« en: 20 de Abril de 2021, 06:24:51 »
Buenos días a todos!!

Me presento, soy Pablo y trabajo como investigador en el laboratorio de telecomunicaciones marinas de la Universidad de Cádiz (España).

Estoy trabajando desde hace un tiempo con el dsPIC33FJ256GP710-I/PF-ND, ya que después de investigar llegué a la conclusión de que para temas de telecomunicaciones, estos son bastante eficientes. Os presento mi problema actual (mucho texto incoming):


Tengo a uno de los ADCs del dsPIC configurado para que muestree una señal (en principio es una CC, luego será una senoidal), a una velocidad de muestreo de 256KHz (según datasheet, este en concreto puede muestrear hasta a 1.1 Msps, así que la que estoy utilizando no debería ser ningún problema). La configuración del ADC quedaría así (os voy adjuntando el código según vaya hablando de él, y finalmente os adjunto el fichero completo):


void ADCInit() {
    AD1PCFGLbits.PCFG10 = 0; // Se configura el ADPCFG para que el único pin
    // usado analógicamente sea el AN10
    AD1CON1bits.SSRC = 0b111;
    AD1CON1bits.ASAM = 1; 
    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;
    AD1CON3bits.ADCS = 12;
}

Esa función sería para la configuración, y posteriormente tengo esta otra que lo único que hace es encender el ADC:

void ADCStart() {
    AD1CON1bits.ADON = 1; // Enciende el ADC
}

Una de las posibles preguntas que os haréis es: ¿Ese valor para el ADCS? La fórmula para sacar este valor viene en el datasheet y es:

Tcy · (ADCS<7:0> +1) = Tad

Teniendo en cuenta que estoy utilizando un cristal de 20MHz para, obtener utilizando PLLs, una Fcy de 40MHz, me sale un resultado tal que:

(1/40x10^6) · (12 + 1 ) = 3.25x10^-7s = Tad.

Hasta ahí creo que sin problema. En el datasheet también se indica que para que el proceso de captura y conversión se realice sin errores, es necesario un tiempo total (para una resoluciónde 10bits, que es lo que estoy utilizando) un tiempo total de 12·Tad. Por lo tanto:

12 · Tad = 12 · 3.25x10^-7 = 3.9x10^-6 s = 3.9 us.

Como os he comentado, la frecuencia de muestreo que quiero es de 256KHz, lo que equivale a:

1/256x10^3 = 3.90625x10^-6 s = 3.9 us.

Según entiendo, con las configuraciones que os acabo de exponer, el ADC debería trabajar sin problemas a una frecuencia de 256KHz.

Pues bien, una vez configurado el módulo ADC, en el que CREO que está todo correcto, paso a configurar el módulo UART, ya que la transmisión de los datos al PC lo hago a través del puerto serie. La configuración de este registro quedaría tal que así:

void Configurar_UART() {//uart 2
    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 = 9; //BAUD Rate Setting for 1.000.000
    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
}

De aquí lo más conflictivo creo que es la selección del BAUD Rate, el cual lo he fijado en 1.000.000, obteniendo un valor de 9 para U2BRG. Este valor se obtiene, de nuevo gracias a datasheet, a través de la siguiente fórmula:

U2BRG = (Fcy / (4 · BAUDRATE )) -1 = (40x10^6 / (4 · 1.000.000)) -1 = 9

Finalmente, utilizo los timers 2 y 3 concatenados (timer 32bits) con un preescaler 1:256 para poder ver que distancia temporal hay entre la recepción de una muestra y otra. Os dejo aquí la configuración de sus registros:

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;
}

Como veis, utilizo una interrupción para que cuando este timer llegue al valor establecido (en este caso 10 segundos), deje de enviar los datos por el puerto serie. Os dejo aquí su interrupción:

void __attribute__((__interrupt__, __auto_psv__)) _T3Interrupt(void) {
    AD1CON1bits.ADON = 0;
    T1CONbits.TON = 0;
    T2CONbits.TON = 0;
    while (1) {
    }
    return 0;
    _T3IF = 0; /* Ponemos a 0 el Flag de la Int del Timer 3 */
}

En el main, lo único que hago es capturar el valor del ADC y enviarlo por el puerto serie junto con el valor actual del TMR3 y el TMR2, para poder observar la distancia temporal que hay entre cada recepción, obteniendo algo tal que así:

Sin-t-tulo" border="0

Siendo los valores:

Voltaje--TMR3:TMR2 (En esa prueba no estoy inyectando ninguna señal, por eso todos los valores a cero)

Bien, si nos quedamos con los dos últimos valores de TMR2 tenemos una diferencia de ciclos de 55119 - 55065 = 54 ciclos de reloj.

Como la Fcy= 40MHz, esto querría decir que con un preescaler 1:1, tendríamos 40.000.000 de ciclos en un segundo, pero al tener el preescaler 1:256 en el timer, tenemos que:

40MHz / 256 = 156250 ciclos/s.

Por lo tanto, si tengo una diferencia de 54 ciclos entre una muestra y otra, eso quiere decir que hay una diferencia temporal de (haciendo una simple regla de tres):

54/156250 =3.456x10^-4 s .

Y ahí mi problema, que debería tener una diferencia temporal entre una muestra y otra de 3.9 us aproximadamente, pero como podéis ver está bastante lejos. No sé si el cuello de botella está en el USB, ya que debería de estar recibiendo 256000 muestras por segundo, y no sé si el monitor serie de Arduino es capaz de mostrar semejante cantidad de datos, o si estoy haciendo algo mal en la configuración del dsPIC.

Muchas gracias a todos de antemano y perdonad por el "mucho texto", pero quería explicarlo todo para que no queden dudas.


Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5878
    • Picuino
Re:Problema con el puerto serie en dsPIC33FJ256GP710-I/PF-ND
« Respuesta #1 en: 20 de Abril de 2021, 10:58:18 »
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
  1. // DSPIC33FJ256GP710 Configuration Bit Settings
  2.  
  3. // 'C' source line config statements
  4.  
  5. // FBS
  6. #pragma config BWRP = WRPROTECT_OFF     // Boot Segment Write Protect (Boot Segment may be written)
  7. #pragma config BSS = NO_FLASH           // Boot Segment Program Flash Code Protection (No Boot program Flash segment)
  8. #pragma config RBS = NO_RAM             // Boot Segment RAM Protection (No Boot RAM)
  9.  
  10. // FSS
  11. #pragma config SWRP = WRPROTECT_OFF     // Secure Segment Program Write Protect (Secure Segment may be written)
  12. #pragma config SSS = NO_FLASH           // Secure Segment Program Flash Code Protection (No Secure Segment)
  13. #pragma config RSS = NO_RAM             // Secure Segment Data RAM Protection (No Secure RAM)
  14.  
  15. // FGS
  16. #pragma config GWRP = OFF               // General Code Segment Write Protect (User program memory is not write-protected)
  17. #pragma config GSS = OFF                // General Segment Code Protection (User program memory is not code-protected)
  18.  
  19. // FOSCSEL
  20. #pragma config FNOSC = PRIPLL           // Oscillator Mode (Primary Oscillator (XT, HS, EC) w/ PLL)
  21. #pragma config IESO = ON                // Two-speed Oscillator Start-Up Enable (Start up with FRC, then switch)
  22.  
  23. // FOSC
  24. #pragma config POSCMD = NONE            // Primary Oscillator Source (Primary Oscillator Disabled)
  25. #pragma config OSCIOFNC = OFF           // OSC2 Pin Function (OSC2 pin has clock out function)
  26. #pragma config FCKSM = CSDCMD           // Clock Switching and Monitor (Both Clock Switching and Fail-Safe Clock Monitor are disabled)
  27.  
  28. // FWDT
  29. #pragma config WDTPOST = PS32768        // Watchdog Timer Postscaler (1:32,768)
  30. #pragma config WDTPRE = PR128           // WDT Prescaler (1:128)
  31. #pragma config WINDIS = OFF             // Watchdog Timer Window (Watchdog Timer in Non-Window mode)
  32. #pragma config FWDTEN = ON              // Watchdog Timer Enable (Watchdog timer always enabled)
  33.  
  34. // FPOR
  35. #pragma config FPWRT = PWR128           // POR Timer Value (128ms)
  36.  
  37. // FICD
  38. #pragma config ICS = PGD1               // Comm Channel Select (Communicate on PGC1/EMUC1 and PGD1/EMUD1)
  39. #pragma config JTAGEN = OFF             // JTAG Port Enable (JTAG is Disabled)
  40.  
  41. // #pragma config statements should precede project file includes.
  42. // Use project enums instead of #define for ON and OFF.
  43.  
  44. /*******librerias******************/
  45. #include "xc.h"
  46. #include <stdlib.h>
  47. #include <stdio.h>
  48. #include <string.h>
  49. #include <math.h>
  50. #include "p33FJ256GP710.h"
  51. /**********************************/
  52.  
  53.  
  54. /**********************************/
  55. #define Fcy 40000000
  56. #define delay_ms(x) __delay32((Fcy/1000)*x) //delay en milisegundos
  57.  
  58. /**********************************/
  59.  
  60.  
  61. /*DECLARACION DE FUNCIONES*/
  62. void Configurar_UART();
  63. void Configurar_IO();
  64. void OscConfig();
  65. void ADC_Data();
  66. void ADCStart();
  67. void ADCInit();
  68. void Serial_SendString(char *str);
  69. void Serial_PutChar(char Ch);
  70. void Configurar_Timer1();
  71. void Configurar_Timer32();
  72. /**************************/
  73. float temp1 = 0;
  74. char Salto[] = "\n";
  75. char trama[28];
  76.  
  77. void __attribute__((__interrupt__, __auto_psv__)) _T3Interrupt(void) {
  78.     AD1CON1bits.ADON = 0;
  79.     T1CONbits.TON = 0;
  80.     T2CONbits.TON = 0;
  81.     while (1) {
  82.     }
  83.     return 0;
  84.     //T1CONbits.TON = 0;
  85.     _T3IF = 0; /* Ponemos a 0 el Flag de la Int del Timer 1 */
  86. }
  87.  
  88.  
  89. /****************************************/
  90. /* Función de Interrupción de Recepción */
  91.  
  92. /****************************************/
  93.  
  94. void __attribute__((__interrupt__, no_auto_psv)) _U2RXInterrupt(void) {
  95.     U2TXREG = U2RXREG; //se trasmite lo que se recibe
  96.     _U2RXIF = 0; // Borramos flag.
  97. }
  98. /*********************/
  99. /* Función Principal */
  100.  
  101. /*********************/
  102.  
  103. int main(void) {
  104.     //ADPCFG = 0xffff;
  105.     OscConfig();
  106.     Configurar_IO();
  107.     ADCInit(); // Inicializamos el conversor A/D
  108.     Configurar_UART();
  109. //    Configurar_Timer1();
  110.     Configurar_Timer32();
  111.     while (OSCCONbits.LOCK != 1);
  112.     ADCStart(); // Encendemos el ADC
  113. //    T1CONbits.TON = 1;
  114.     T2CONbits.TON = 1;
  115.     while (1) {
  116.         while (!IFS0bits.AD1IF);
  117.         IFS0bits.AD1IF = 0;
  118.         ADC_Data(); //Dato almacenado en la variable temp1
  119.         temp1 = (temp1 * (3.313)) / 1023.0;
  120.         sprintf(trama, "%.2f--", (double) temp1);
  121.         Serial_SendString(trama);
  122.         sprintf(trama, "%.0f:", (double) TMR3);
  123.         Serial_SendString(trama);
  124.         sprintf(trama, "%.0f", (double) TMR2);
  125.         Serial_SendString(trama);
  126.         Serial_SendString(Salto);
  127.     }
  128.     return 0;
  129. }
  130. /*************************************/
  131. /* Función de Configuración del UART */
  132.  
  133. /*************************************/
  134. void Configurar_UART() {//uart 1
  135.     U2MODEbits.BRGH = 1;
  136.     U2MODEbits.PDSEL = 0b00; // No Parity, 8 data bits
  137.     U2MODEbits.STSEL = 0; // 1 Stop bit    
  138.     U2MODEbits.UEN = 0b00;
  139.     U2MODEbits.ABAUD = 0; // Auto-Baud Disabled    
  140.     //U2BRG = 21 ; //BAUD Rate Setting for 115200
  141.     //U2BRG = 10; //BAUD Rate Setting for 230400
  142.     //U2BRG = 259; // BAUD Rate Setting for 9600
  143.     //U2BRG = 9; //BAUD Rate Setting for 2.000.000
  144.     U2BRG = 9;
  145.     U2STAbits.URXISEL = 0; // Interrupt after one RX character is received
  146.     IFS1bits.U2RXIF = 0; // Clear the Recieve Interrupt Flag
  147.     IEC1bits.U2RXIE = 1; // Enable Recieve Interrupts
  148.     U2MODEbits.UARTEN = 1; // Enable UART
  149.     U2STAbits.UTXEN = 1; // Enable UART TX
  150. }
  151.  
  152. void Configurar_IO() {
  153.     TRISB = 0; /*       Puerto B como salida */
  154.     TRISF = 0xFFF7;
  155. }
  156. // Send a string out to the serial interface.
  157.  
  158. void OscConfig() {
  159.     //CONFIGURACION PARA OBTENER UNA Fcy=40MHz
  160.     //Fosc = Fin * M/(N1*N2), Fcy = Fosc/2
  161.     //Fosc = 20MHz * 16/(2*2) = 80MHz para una entrada de reloj de 20MHz
  162.     CLKDIV = 0x0000; // N1=2 Y N2=2
  163.     PLLFBD = 0x000E; // M=16
  164.     OSCTUN = 0; // Desactivar afinado del oscilador FRC, si está activo
  165.     RCONbits.SWDTEN = 0; //Desactivar Watch Dog Timer
  166. }
  167.  
  168. void ADCInit() {
  169.     AD1PCFGLbits.PCFG10 = 0; // Se configura el ADPCFG para que el único pin
  170.     // usado analógicamente sea el AN10
  171.     AD1CON1bits.SSRC = 0b111; // selección de la muestra después que la conversión termina
  172.     AD1CON1bits.ASAM = 1; // Formato del resultado entero, Comienzo de la conversión automático,
  173.     AD1CON1bits.AD12B = 0; //10 bits resolución
  174.     AD1CHS0bits.CH0SA = 0b1010; //  Entrada positiva AN10 para la entrada de la muestra
  175.     AD1CHS0bits.CH0NA = 0; // Entrada negativa se usa el VR-
  176.     AD1CON2bits.VCFG = 0b000; // Referencias: AVDD y AVSS,
  177.     AD1CON2bits.BUFM = 0; //Se selecciona nivel de buffer 16*1 y
  178.     AD1CON3bits.ADCS = 12;
  179. }
  180.  
  181. void ADCStart() {
  182.     AD1CON1bits.ADON = 1; // Prende el ADC
  183. }
  184.  
  185. void ADC_Data() {
  186.     unsigned long int temp;
  187.     temp = ADCBUF0;
  188.     temp1 = temp;
  189. }
  190.  
  191. void Serial_PutChar(char Ch) { // wait for empty buffer
  192.     while (U2STAbits.UTXBF == 1);
  193.     U2TXREG = Ch;
  194. }
  195.  
  196. // Send a string out to the serial interface.
  197.  
  198. void Serial_SendString(char *str) {
  199.     char * p;
  200.     p = str;
  201.     while (*p)
  202.         Serial_PutChar(*p++);
  203. }
  204.  
  205. //void Configurar_Timer1() {
  206. //    PR1 = 0xFFFF;
  207. //    //PR1 = 1 / (int) (((float) (Fcy) * 1)*0.000001 * tmicro);
  208. //    T1CON = 0; // Resetear el timer
  209. //    T1CONbits.TCKPS = 0b00; //Preescaler 1:1
  210. //    TMR1 = 0;
  211. //    //IPC0bits.T1IP = 1; // Interrupción con prioridad 1
  212. //    //IFS0bits.T1IF = 0; // Interrupción cuando llega a 0
  213. //    //IEC0bits.T1IE = 1; //Habilitar interrupción del timer1
  214. //    //T1CONbits.TON = 1; //Activar el timer1
  215. //}
  216.  
  217. void Configurar_Timer32() {
  218.     T3CONbits.TON = 0;
  219.     T2CONbits.TON = 0;
  220.     T2CONbits.T32 = 1;
  221.     T2CONbits.TCS = 0;
  222.     T2CONbits.TGATE = 0;
  223.     T2CONbits.TCKPS = 0b11;
  224.     TMR3 = 0;
  225.     TMR2 = 0;
  226.     PR3 = 0x0017;
  227.     PR2 = 0xD784;
  228.     IPC2bits.T3IP = 1;
  229.     IFS0bits.T3IF = 0;
  230.     IEC0bits.T3IE = 1;
  231. }

Main cambiado para probar solo el envío por UART:
Código: C
  1. int main(void) {
  2.     //ADPCFG = 0xffff;
  3.     OscConfig();
  4.     Configurar_IO();
  5.     ADCInit(); // Inicializamos el conversor A/D
  6.     Configurar_UART();
  7. //    Configurar_Timer1();
  8.     Configurar_Timer32();
  9.     while (OSCCONbits.LOCK != 1);
  10.     ADCStart(); // Encendemos el ADC
  11. //    T1CONbits.TON = 1;
  12.     T2CONbits.TON = 1;
  13.     while (1) {
  14.         temp1 = (100 * (3.313)) / 1023.0;
  15.         sprintf(trama, "%.2f--", (double) temp1);
  16.         Serial_SendString(trama);
  17.         sprintf(trama, "%.0f:", (double) TMR3);
  18.         Serial_SendString(trama);
  19.         sprintf(trama, "%.0f", (double) TMR2);
  20.         Serial_SendString(trama);
  21.         Serial_SendString(Salto);
  22.     }
  23.     return 0;
  24. }

Un saludo.
« Última modificación: 20 de Abril de 2021, 11:01:40 por Picuino »

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Re:Problema con el puerto serie en dsPIC33FJ256GP710-I/PF-ND
« Respuesta #2 en: 20 de Abril de 2021, 11:22:53 »
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.
 
« Última modificación: 20 de Abril de 2021, 17:17:50 por remi04 »

Desconectado padag

  • PIC10
  • *
  • Mensajes: 13
Re:Problema con el puerto serie en dsPIC33FJ256GP710-I/PF-ND
« Respuesta #3 en: 21 de Abril de 2021, 04:42:28 »
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
  1. // DSPIC33FJ256GP710 Configuration Bit Settings
  2.  
  3. // 'C' source line config statements
  4.  
  5. // FBS
  6. #pragma config BWRP = WRPROTECT_OFF     // Boot Segment Write Protect (Boot Segment may be written)
  7. #pragma config BSS = NO_FLASH           // Boot Segment Program Flash Code Protection (No Boot program Flash segment)
  8. #pragma config RBS = NO_RAM             // Boot Segment RAM Protection (No Boot RAM)
  9.  
  10. // FSS
  11. #pragma config SWRP = WRPROTECT_OFF     // Secure Segment Program Write Protect (Secure Segment may be written)
  12. #pragma config SSS = NO_FLASH           // Secure Segment Program Flash Code Protection (No Secure Segment)
  13. #pragma config RSS = NO_RAM             // Secure Segment Data RAM Protection (No Secure RAM)
  14.  
  15. // FGS
  16. #pragma config GWRP = OFF               // General Code Segment Write Protect (User program memory is not write-protected)
  17. #pragma config GSS = OFF                // General Segment Code Protection (User program memory is not code-protected)
  18.  
  19. // FOSCSEL
  20. #pragma config FNOSC = PRIPLL           // Oscillator Mode (Primary Oscillator (XT, HS, EC) w/ PLL)
  21. #pragma config IESO = ON                // Two-speed Oscillator Start-Up Enable (Start up with FRC, then switch)
  22.  
  23. // FOSC
  24. #pragma config POSCMD = NONE            // Primary Oscillator Source (Primary Oscillator Disabled)
  25. #pragma config OSCIOFNC = OFF           // OSC2 Pin Function (OSC2 pin has clock out function)
  26. #pragma config FCKSM = CSDCMD           // Clock Switching and Monitor (Both Clock Switching and Fail-Safe Clock Monitor are disabled)
  27.  
  28. // FWDT
  29. #pragma config WDTPOST = PS32768        // Watchdog Timer Postscaler (1:32,768)
  30. #pragma config WDTPRE = PR128           // WDT Prescaler (1:128)
  31. #pragma config WINDIS = OFF             // Watchdog Timer Window (Watchdog Timer in Non-Window mode)
  32. #pragma config FWDTEN = ON              // Watchdog Timer Enable (Watchdog timer always enabled)
  33.  
  34. // FPOR
  35. #pragma config FPWRT = PWR128           // POR Timer Value (128ms)
  36.  
  37. // FICD
  38. #pragma config ICS = PGD1               // Comm Channel Select (Communicate on PGC1/EMUC1 and PGD1/EMUD1)
  39. #pragma config JTAGEN = OFF             // JTAG Port Enable (JTAG is Disabled)
  40.  
  41. // #pragma config statements should precede project file includes.
  42. // Use project enums instead of #define for ON and OFF.
  43.  
  44. /*******librerias******************/
  45. #include "xc.h"
  46. #include <stdlib.h>
  47. #include <stdio.h>
  48. #include <string.h>
  49. #include <math.h>
  50. #include "p33FJ256GP710.h"
  51. /**********************************/
  52.  
  53.  
  54. /**********************************/
  55. #define Fcy 40000000
  56. #define delay_ms(x) __delay32((Fcy/1000)*x) //delay en milisegundos
  57.  
  58. /**********************************/
  59.  
  60.  
  61. /*DECLARACION DE FUNCIONES*/
  62. void Configurar_UART();
  63. void Configurar_IO();
  64. void OscConfig();
  65. void ADC_Data();
  66. void ADCStart();
  67. void ADCInit();
  68. void Serial_SendString(char *str);
  69. void Serial_PutChar(char Ch);
  70. void Configurar_Timer1();
  71. void Configurar_Timer32();
  72. /**************************/
  73. float temp1 = 0;
  74. char Salto[] = "\n";
  75. char trama[28];
  76.  
  77. void __attribute__((__interrupt__, __auto_psv__)) _T3Interrupt(void) {
  78.     AD1CON1bits.ADON = 0;
  79.     T1CONbits.TON = 0;
  80.     T2CONbits.TON = 0;
  81.     while (1) {
  82.     }
  83.     return 0;
  84.     //T1CONbits.TON = 0;
  85.     _T3IF = 0; /* Ponemos a 0 el Flag de la Int del Timer 1 */
  86. }
  87.  
  88.  
  89. /****************************************/
  90. /* Función de Interrupción de Recepción */
  91.  
  92. /****************************************/
  93.  
  94. void __attribute__((__interrupt__, no_auto_psv)) _U2RXInterrupt(void) {
  95.     U2TXREG = U2RXREG; //se trasmite lo que se recibe
  96.     _U2RXIF = 0; // Borramos flag.
  97. }
  98. /*********************/
  99. /* Función Principal */
  100.  
  101. /*********************/
  102.  
  103. int main(void) {
  104.     //ADPCFG = 0xffff;
  105.     OscConfig();
  106.     Configurar_IO();
  107.     ADCInit(); // Inicializamos el conversor A/D
  108.     Configurar_UART();
  109. //    Configurar_Timer1();
  110.     Configurar_Timer32();
  111.     while (OSCCONbits.LOCK != 1);
  112.     ADCStart(); // Encendemos el ADC
  113. //    T1CONbits.TON = 1;
  114.     T2CONbits.TON = 1;
  115.     while (1) {
  116.         while (!IFS0bits.AD1IF);
  117.         IFS0bits.AD1IF = 0;
  118.         ADC_Data(); //Dato almacenado en la variable temp1
  119.         temp1 = (temp1 * (3.313)) / 1023.0;
  120.         sprintf(trama, "%.2f--", (double) temp1);
  121.         Serial_SendString(trama);
  122.         sprintf(trama, "%.0f:", (double) TMR3);
  123.         Serial_SendString(trama);
  124.         sprintf(trama, "%.0f", (double) TMR2);
  125.         Serial_SendString(trama);
  126.         Serial_SendString(Salto);
  127.     }
  128.     return 0;
  129. }
  130. /*************************************/
  131. /* Función de Configuración del UART */
  132.  
  133. /*************************************/
  134. void Configurar_UART() {//uart 1
  135.     U2MODEbits.BRGH = 1;
  136.     U2MODEbits.PDSEL = 0b00; // No Parity, 8 data bits
  137.     U2MODEbits.STSEL = 0; // 1 Stop bit    
  138.     U2MODEbits.UEN = 0b00;
  139.     U2MODEbits.ABAUD = 0; // Auto-Baud Disabled    
  140.     //U2BRG = 21 ; //BAUD Rate Setting for 115200
  141.     //U2BRG = 10; //BAUD Rate Setting for 230400
  142.     //U2BRG = 259; // BAUD Rate Setting for 9600
  143.     //U2BRG = 9; //BAUD Rate Setting for 2.000.000
  144.     U2BRG = 9;
  145.     U2STAbits.URXISEL = 0; // Interrupt after one RX character is received
  146.     IFS1bits.U2RXIF = 0; // Clear the Recieve Interrupt Flag
  147.     IEC1bits.U2RXIE = 1; // Enable Recieve Interrupts
  148.     U2MODEbits.UARTEN = 1; // Enable UART
  149.     U2STAbits.UTXEN = 1; // Enable UART TX
  150. }
  151.  
  152. void Configurar_IO() {
  153.     TRISB = 0; /*       Puerto B como salida */
  154.     TRISF = 0xFFF7;
  155. }
  156. // Send a string out to the serial interface.
  157.  
  158. void OscConfig() {
  159.     //CONFIGURACION PARA OBTENER UNA Fcy=40MHz
  160.     //Fosc = Fin * M/(N1*N2), Fcy = Fosc/2
  161.     //Fosc = 20MHz * 16/(2*2) = 80MHz para una entrada de reloj de 20MHz
  162.     CLKDIV = 0x0000; // N1=2 Y N2=2
  163.     PLLFBD = 0x000E; // M=16
  164.     OSCTUN = 0; // Desactivar afinado del oscilador FRC, si está activo
  165.     RCONbits.SWDTEN = 0; //Desactivar Watch Dog Timer
  166. }
  167.  
  168. void ADCInit() {
  169.     AD1PCFGLbits.PCFG10 = 0; // Se configura el ADPCFG para que el único pin
  170.     // usado analógicamente sea el AN10
  171.     AD1CON1bits.SSRC = 0b111; // selección de la muestra después que la conversión termina
  172.     AD1CON1bits.ASAM = 1; // Formato del resultado entero, Comienzo de la conversión automático,
  173.     AD1CON1bits.AD12B = 0; //10 bits resolución
  174.     AD1CHS0bits.CH0SA = 0b1010; //  Entrada positiva AN10 para la entrada de la muestra
  175.     AD1CHS0bits.CH0NA = 0; // Entrada negativa se usa el VR-
  176.     AD1CON2bits.VCFG = 0b000; // Referencias: AVDD y AVSS,
  177.     AD1CON2bits.BUFM = 0; //Se selecciona nivel de buffer 16*1 y
  178.     AD1CON3bits.ADCS = 12;
  179. }
  180.  
  181. void ADCStart() {
  182.     AD1CON1bits.ADON = 1; // Prende el ADC
  183. }
  184.  
  185. void ADC_Data() {
  186.     unsigned long int temp;
  187.     temp = ADCBUF0;
  188.     temp1 = temp;
  189. }
  190.  
  191. void Serial_PutChar(char Ch) { // wait for empty buffer
  192.     while (U2STAbits.UTXBF == 1);
  193.     U2TXREG = Ch;
  194. }
  195.  
  196. // Send a string out to the serial interface.
  197.  
  198. void Serial_SendString(char *str) {
  199.     char * p;
  200.     p = str;
  201.     while (*p)
  202.         Serial_PutChar(*p++);
  203. }
  204.  
  205. //void Configurar_Timer1() {
  206. //    PR1 = 0xFFFF;
  207. //    //PR1 = 1 / (int) (((float) (Fcy) * 1)*0.000001 * tmicro);
  208. //    T1CON = 0; // Resetear el timer
  209. //    T1CONbits.TCKPS = 0b00; //Preescaler 1:1
  210. //    TMR1 = 0;
  211. //    //IPC0bits.T1IP = 1; // Interrupción con prioridad 1
  212. //    //IFS0bits.T1IF = 0; // Interrupción cuando llega a 0
  213. //    //IEC0bits.T1IE = 1; //Habilitar interrupción del timer1
  214. //    //T1CONbits.TON = 1; //Activar el timer1
  215. //}
  216.  
  217. void Configurar_Timer32() {
  218.     T3CONbits.TON = 0;
  219.     T2CONbits.TON = 0;
  220.     T2CONbits.T32 = 1;
  221.     T2CONbits.TCS = 0;
  222.     T2CONbits.TGATE = 0;
  223.     T2CONbits.TCKPS = 0b11;
  224.     TMR3 = 0;
  225.     TMR2 = 0;
  226.     PR3 = 0x0017;
  227.     PR2 = 0xD784;
  228.     IPC2bits.T3IP = 1;
  229.     IFS0bits.T3IF = 0;
  230.     IEC0bits.T3IE = 1;
  231. }

Main cambiado para probar solo el envío por UART:
Código: C
  1. int main(void) {
  2.     //ADPCFG = 0xffff;
  3.     OscConfig();
  4.     Configurar_IO();
  5.     ADCInit(); // Inicializamos el conversor A/D
  6.     Configurar_UART();
  7. //    Configurar_Timer1();
  8.     Configurar_Timer32();
  9.     while (OSCCONbits.LOCK != 1);
  10.     ADCStart(); // Encendemos el ADC
  11. //    T1CONbits.TON = 1;
  12.     T2CONbits.TON = 1;
  13.     while (1) {
  14.         temp1 = (100 * (3.313)) / 1023.0;
  15.         sprintf(trama, "%.2f--", (double) temp1);
  16.         Serial_SendString(trama);
  17.         sprintf(trama, "%.0f:", (double) TMR3);
  18.         Serial_SendString(trama);
  19.         sprintf(trama, "%.0f", (double) TMR2);
  20.         Serial_SendString(trama);
  21.         Serial_SendString(Salto);
  22.     }
  23.     return 0;
  24. }

Un saludo.



Hola Picuino!!

Ya probé el ir función por función, pero aun así no me acercaba al valor que esperaba. Creo que seguramente sea lo que dice nuestro compi remi04, y no sea posible hacer todas estas operaciones en tan poco tiempo... :(

Muchas gracias por tu rápida respuesta y, si se te ocurre alguna otra solución, estaré encantado de escucharla  :) :)

Gracias de nuevo!!
« Última modificación: 21 de Abril de 2021, 04:49:45 por padag »

Desconectado padag

  • PIC10
  • *
  • Mensajes: 13
Re:Problema con el puerto serie en dsPIC33FJ256GP710-I/PF-ND
« Respuesta #4 en: 21 de Abril de 2021, 04:48:27 »
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 Remi!

Donde puedo ver esa información de los tiempos que me dices? he estado mirando en los datasheet y los manuales de referencia pero no veo nada en concreto que se refiera a los tiempos de transmisión de la UART.

El proyecto en sí consiste en captar una senoidal de 256KHz, digitalizarla con el dsPIC, hacerle la FFT y conseguir finalmente el desfase de la señal (todo esto dentro del dsPIC). Tal y como entiendo en base a tu comentario, esto no sería posible hacerlo con el dsPIC? Llevo ya varias semanas peleándome con este bicho y había llegado a la misma conclusión que tu me expones, que es imposible hacer todas esas operaciones en tan poco tiempo, pero al ser nuevo en este mundillo, me gustaría tener una opinión de alguien mas formado en el tema  :oops:.

Muchas gracias de antemano!!

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Re:Problema con el puerto serie en dsPIC33FJ256GP710-I/PF-ND
« Respuesta #5 en: 21 de Abril de 2021, 05:36:29 »
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 trama 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.
« Última modificación: 21 de Abril de 2021, 16:09:16 por remi04 »

Desconectado padag

  • PIC10
  • *
  • Mensajes: 13
Re:Problema con el puerto serie en dsPIC33FJ256GP710-I/PF-ND
« Respuesta #6 en: 21 de Abril de 2021, 06:39:53 »
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!

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5878
    • Picuino
Re:Problema con el puerto serie en dsPIC33FJ256GP710-I/PF-ND
« Respuesta #7 en: 21 de Abril de 2021, 06:43:24 »
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

Desconectado padag

  • PIC10
  • *
  • Mensajes: 13
Re:Problema con el puerto serie en dsPIC33FJ256GP710-I/PF-ND
« Respuesta #8 en: 21 de Abril de 2021, 06:46:48 »
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!!

Desconectado padag

  • PIC10
  • *
  • Mensajes: 13
Re:Problema con el puerto serie en dsPIC33FJ256GP710-I/PF-ND
« Respuesta #9 en: 21 de Abril de 2021, 07:04:04 »
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!!
« Última modificación: 21 de Abril de 2021, 07:32:28 por padag »

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Re:Problema con el puerto serie en dsPIC33FJ256GP710-I/PF-ND
« Respuesta #10 en: 21 de Abril de 2021, 09:07:39 »
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!

  Según la captura del terminal que tu pusiste, una línea cualquiera de esa trata sería por ejemplo:

0.00--23:53655

Ahí falta un CR y un LF que no se ven, pero están ahí, es decir, un salto de línea y un retorno de carro para que la siguiente te aparezca debajo y no a continuación. 

Para que te llegue eso a la terminal, el pic está enviando por orden, la siguiente lista de caracteres ASCII:
0  = Byte 1
. = Byte 2
0 = Byte 3
0 = byte 4
- = byte 5
- = byte 6
2 = Byte 7
3 = byte 8
: = byte 9
5 = byte 10
3 = byte 11
6 = byte 12
5 = byte 13
5 = byte 14
CR = byte 15
LF = byte 16

  Cada carácter ocupa 8 bits = 1 byte.

 Un saludo.

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Re:Problema con el puerto serie en dsPIC33FJ256GP710-I/PF-ND
« Respuesta #11 en: 21 de Abril de 2021, 09:18:16 »
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.
« Última modificación: 21 de Abril de 2021, 09:21:24 por remi04 »

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5878
    • Picuino
Re:Problema con el puerto serie en dsPIC33FJ256GP710-I/PF-ND
« Respuesta #12 en: 21 de Abril de 2021, 13:48:10 »
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!!

Entonces para esa aplicación que comentas no vale un Lock-in Amplifier, pero estudiar cómo funciona te puede ayudar a calcular desfases de manera más rápida que con una FFT.

Saludos.

Desconectado padag

  • PIC10
  • *
  • Mensajes: 13
Re:Problema con el puerto serie en dsPIC33FJ256GP710-I/PF-ND
« Respuesta #13 en: 23 de Abril de 2021, 05:36:51 »
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.

Pues tal y como decías, he probado a cuantificar el tiempo que transcurre hasta que coge las 256k muestras y el ADC trabaja a la velocidad establecida. Coge una cada 3.9us, por lo que este módulo está perfecto.

El cuello de botella está en la comunicación UART que ahora, gracias a tu explicación entiendo el por qué de este retraso  :-/ :-/.

Así que he optado directamente por olvidarme de transmitir los datos por el puerto serie, ya que solo era para comprobar que el ADC funcionaba correctamente, y pasar a hacer la FFT de los datos que capto con el ADC.

¿Sabéis donde puedo encontrar algún código actualizado para implementar la FFT? He encontrado este que proporcionan en este hilo (https://forum.mikroe.com/viewtopic.php?t=61823)(que casualmente es para el mismo modelo de dsPIC que estoy utilizando), pero he estado leyendo que el utilizar los parámetros YDATA está algo desfasado, por lo que creo que debería haber nuevas formas de implementarla. Además, la máxima frecuencia para este ejemplo es de 35KHz, y como os he explicado anteriormente la intención es trabajar con 256KHz...

También, como es la primera vez que voy a hacer algo relacionado con la FFT, me cuesta bastante desencriptar qué hace exactamente ese código, así que cualquier cable que me podáis echar me vendría súper bien.

Muchas gracias de nuevo!!

Desconectado Eduardo2

  • PIC24F
  • *****
  • Mensajes: 941
Re:Problema con el puerto serie en dsPIC33FJ256GP710-I/PF-ND
« Respuesta #14 en: 23 de Abril de 2021, 09:34:04 »
No entiendo qué esperás conseguir haciendo la FFT.   
La fase que vas a sacar es respecto al momento de iniciar la adquisición, los 4 DSpics deberían trabajar sincronizados con diferencias menores del microsegundo para que sirva de algo. 
Y si se comunican para sincronizarse... para eso analizá la dierencia de tiempos entre flancos en lugar de hacer una FFT.