TODOPIC

Microcontroladores PIC => dsPIC => Mensaje iniciado por: jafema en 19 de Mayo de 2009, 07:43:43

Título: Recepcion datos modulo UART, problemas y dudas
Publicado por: jafema en 19 de Mayo de 2009, 07:43:43
Hola, me llamo Javier. Antetodo quería presentarme a ustedes puesto que soy nuevo en el foro y creo que es la mejor forma de empezar. Necesito de su consejo.

Estoy intentando realizar una recepción de datos utilizando el módulo de comunicaciones  UART, con un dsPIC30F4011. Para ello envio los datos a través de una aplicación similar al hyperterminal de windos llamada Terminal.  Estoy desarrollando el código en C, utilizando el compliador C30 de Microchip, y mi versión de MPLAB es la 8.20, el dsp se encuentra en la placa de prueba dsPICDEM 2 del fabricante Microchip.

He estado leyendo varios post en este foro sobre el módulo UART y también en otra fuentes, me han ayudado bastante a entender algunos fallos que tenía pero sigo encontrado algún que otro problema y también tengo alguna duda. Así que les agredecería mucho si me pudieran ayudar, les voy a explicar lo mejor posible lo que sucede para no robarles mucho de su valioso tiempo.

Bueno voy a empezar por lo que hace el programa. Como dije antes es una recepción de datos utilizando el módulo de comunicaciones  UART, para ello he utilizado la librería UART.h de Microchip, lo que quiero hacer es ir recibiendo los datos e ir almacenandolos en un buffer de cuatro elementos (más tarde con esos cuatro elementos construiré un único dato, pero eso no está incluido en el programa), una vez se ha completado el buffer se vuelve a puntar al primer elemento de este para volver a utilizarlo. He configurado para que se produzca la interrupción cada vez que se recive un caracter.

Problemas con los que me encuentro:

Cuando estoy haciendo el debug e inicializo el programa el primer caracter que mando no se almacena en el buffer, entra en la interrupción y automáticamente el registro U1RXREG se borra y me almacena un dato vacio en el buffer. Y así sucesivamente hasta que llego al cuarto caracter, el cual si se me almacena en el buffer. La explicación a todo esto que sucede, en mi opinión, es que al irse almacenando los datos en la pila FIFO de recepción (pila de 4 niveles), hasta que un dato no llega al nivel más alto de la pida no es apto para su manipulación.

También he probado configurando la interrupción para que se produzca cuando se completa el buffer, para eso tengo que mandandar los datos de cuatro en cuatro pero sólo me coge el primer elemento de la pila, pues esta al no estar direccionada no puede ser recorrida y por lo tanto no puedo acceder a los otros datos a no ser que lleguen más que hagan que los ya almacenados se desplacen.

Por lo tanto no tengo muy claro el funcionamiento de la pila y la interrupciones, puesto según entiendo yo si configuro para que se me produzca la interrupción cada vez que se recive un dato no tendría porque completar el resto de la pila, esta quedaría como una de un solo nivel, digamoslo así. Y si configuro la interrupción para que sea cuando se me complete el buffer una vez que leo el primer dato debería actualizarse la pila porque sigue teniendo datos en ella y el primer nivel se ha quedado libre.

Otro problema que tengo, es que la comunicación la estoy haciendo utilizando los pines U1ALTRX Y U1ALTTX, y se comunica con los anteriores problemas citados, pero si cambio la comunicacíon para realizarla con los pines normales de la UART, habiendo cambiado la configuración el los registros, es decir, puesto a 0 el bit ALTIO del registro U1MODE, la cominicación se me vuelve loca, no recive nada y de hecho me envia datos extraños, lo cual es raro porque solo estoy haciendo la recepción, aquí estoy más perdido y no he podido llegar a ninguna conclusión, he leído el manual de la placa y la he configurado para cambiar a los pines normales, era sólo cambiar un jumper por otro, así que eso no tiene misterio.

Decir que el programa me compila correctamente, no me genera ni errores ni warnings, que he incluido las librerias del dsPIC libc-coff.a libp30F4011-coff.a, libpic30-coff.a, el correspondiente Linker Script p30f4011.gld, y los header Files p30f4011.h, uart.h, stdlib.h

También he probado a hacerlo mismo sin utilizar la libreria uart.h y el comportamiento es el mismo.

Espero que me puedan hechar un cable porque llevo ya muchos días con esto y ya he agotado todas las ideas......... :( pero no la fe  :)

Les dejo el código para que le heche un vistazo, he puesto bastantes comentarios pero si necesitan alguna aclaración no duden en preguntar.

Muchas gracias por su ayuda y valioso tiempo.


Código: [Seleccionar]
//***********************************************************************************
//
// PROGRAMA:
// Obtener datos enviados por computador a traves de comunicacion RS232,
// los datos se estan enviando atraves de una aplicacion software llamada terminal
// similar al hyperterminal de windows, pero con mejores caracteristicas
//
// Entorno de programacion: MPLAB v8.20
// Compilador: C30
// Dispositivo: dsPIC30F4011
//  Placa desarrollo: dsPICDEM2
//
//***********************************************************************************

#include <p30f4011.h>
#include <uart.h>
#include <stdlib.h>

//Macros for Configuration Fuse Registers:
//Invoke macros to set up  device configuration fuse registers.
//The fuses will select the oscillator source, power-up timers, watch-dog
//timers, BOR characteristics etc. The macros are defined within the device
//header files. The configuration fuse registers reside in Flash memory.
_FOSC(CSW_FSCM_OFF & XT_PLL8);  //Run this project using an external crystal
                                //routed via the PLL in 8x multiplier mode
                                //For the 7.3728 MHz crystal we will derive a
                                //throughput of 7.3728e+6*8/4 = 14.74 MIPS(Fcy)
                                //,~67nanoseconds instruction cycle time(Tcy).
_FWDT(WDT_OFF);                 //Turn off the Watch-Dog Timer.
_FBORPOR(MCLR_EN & PWRT_OFF);   //Enable MCLR reset pin and turn off the
                                //power-up timers.
_FGS(CODE_PROT_OFF);            //Disable Code Protection

//Defines for System Clock Timing -
//For oscillator configuration XT x PLL8 mode,
//Device Throughput in MIPS = Fcy = 7372800*8/4 = ~14.74 MIPS
//Instruction Cycle time = Tcy = 1/(Fcy) = ~68 nanoseconds
#define XTFREQ          7372800         //On-board Crystal frequency
#define PLLMODE         8               //On-chip PLL setting
#define FCY             XTFREQ*PLLMODE/4        //Instruction Cycle Frequency

#define BAUDRATE        9600                     //Designamos rango de baudios
#define BRGVAL          (((FCY/BAUDRATE)/16)-1)   //Formula para registro U1BRG, obtenida del manual
                                                //dsPIC30F Family Reference Manual

/*****************
 **  PROTOTIPOS  **
 *****************/
void UART_Init (void);
void __attribute__((__interrupt__)) _U1RXInterrupt(void);
int main (void);


/****************
 **  GLOBALES  **
 ****************/
unsigned char bufferRX[4]; //buffer donde voy almacenar los elementos de la pila
unsigned char *Ptro_bufferRX=NULL; //inicializacion del buffer
unsigned char index=0; //contador que me indica las veces que se ha leido un dato


/*****************
 **  FUNCIONES  **
 *****************/ 
void UART_Init (void)
{
unsigned int U1MODEvalue;
unsigned int U1STAvalue;

CloseUART1(); //Turn off UART1module

//Configuramos interrupciones de UART1, recepcion
ConfigIntUART1(UART_TX_INT_DIS & UART_RX_INT_EN & UART_RX_INT_PR7);

//configuramos los registros UMODE y USTA
U1MODEvalue= UART_EN & UART_IDLE_CON & UART_DIS_WAKE & UART_DIS_ABAUD & UART_ALTRX_ALTTX &
                 UART_DIS_LOOPBACK & UART_ODD_PAR_8BIT & UART_1STOPBIT;

    U1STAvalue= UART_INT_TX & UART_INT_TX_BUF_EMPTY & UART_TX_PIN_NORMAL & UART_TX_DISABLE &
UART_INT_RX_CHAR & UART_ADR_DETECT_DIS & UART_RX_OVERRUN_CLEAR;   
               
OpenUART1(U1MODEvalue, U1STAvalue, BRGVAL); //activamnos el uart con la configuracion seleccionada

Ptro_bufferRX= &bufferRX[0];  //el puntero apunta al primer elemento del buffer
}    



/*********************
 ** Interrupciones  **
 *********************/

// This is UART1 receive ISR
void __attribute__((__interrupt__,no_auto_psv)) _U1RXInterrupt(void)
{
    IFS0bits.U1RXIF = 0; //borramos flag de interrupcion
   
    if((U1STAbits.PERR==0) && (U1STAbits.FERR==0)) //compruebo errores
    {
    (*(Ptro_bufferRX)++)=U1RXREG;    
}   
if(U1STAbits.OERR) U1STAbits.OERR=0; //si hay error de overflow es borrado



/***********
 ** main  **
 ***********/
int main (void)
{

UART_Init(); //iniciamos las configuracion de UART

while(1) //bucle infinito, loop main
{
if(index==4) //se acede cuando se han leido cuatro bytes
{
Ptro_bufferRX= &bufferRX[0]; //vuelvo apuntar al primer elemento del buffer
index=0; //inicializo contador
}
}


CloseUART1(); //si por alguan circunstacia se abandona loop main se cierra el dispostivo UART

return 0;
}
//main



 


 
Título: Re: Recepcion datos modulo UART, problemas y dudas
Publicado por: blackcat en 19 de Mayo de 2009, 20:27:20
Hola!

Bienvenido al foro de TODOPIC ...

Hay dos cosas que creo que debes revisar:

1-) Nunca he usado la libreria de UART.h .. yo suelo hacerlo de forma manual. Creo que es mas sencillo; sin embargo, no veo la configuración de los puertos, ya que hay que poner el pin RX como input y el pin TX como output ... bueno C30 asume como entradas aquellos pines que no se cofiguran .. ¿Estará incluido en el init?

2-) Tambien veo que la siguiente linea: (*(Ptro_bufferRX)++)=U1RXREG; un poco extraña ... porque no haces la prueba asi:

Código: C
  1. *(Ptro_bufferRX) = U1RXREG;
  2. Ptro_bufferRX++;

Puede que de la forma que lo pones esté correcto, .. sin embargo, tengo dudas ... me da a entender que el valor que apunta Ptro_bufferRX esta siendo incrementado en uno ... y no el puntero ... voy a verificarlo.

Pregunta: ¿En que punto de codigo estás deteniendo el debug? ¿un breakpoint?... creo que es mejor que envies el dato .. esperes unos segundo, luego le das pausa y ves el valor en el buffer a ver si llego.

Saludos!
Título: Re: Recepcion datos modulo UART, problemas y dudas
Publicado por: jafema en 20 de Mayo de 2009, 09:02:02
Hola, muchas gracias por responder blackcat.

Respondiendo a tu pregunta, estoy haciendo el debug paso a paso, nada más dar a animate le doy a pause, y voy ejecuntando todo instrucción a instrucción, viendo en el  Watch el contenido de los registros  U1BRG, U1MODE, U1STA Y U1RXREG, así como el contenido de mi buffer y también el puntero para comprobar donde apunta.

Lo del puerto no había caído en la cuenta, porque además creo que usando las funciones de la uart.h ya lo configuran, además si no fuera así no me llegaría nada, y si me llegan datos pero la uart se comporta de manera extraña, aun así lo he comprobado también y lo he incluido en mi código por si acaso, pero siguió comportándose de la misma manera.

He cambiado el código y lo hecho de forma manual, y sigue comportándose de la misma forma, lo dejo aquí a ver si lo he configurado de la misma forma que haces tu.

Saludos y muchas gracias por tu tiempo.

Código: [Seleccionar]
//***********************************************************************************
//
// PROGRAMA:
// Obtener datos enviados por computador a traves de comunicacion RS232,
// los datos se estan enviando atraves de una aplicacion software llamada terminal
// similar al hyperterminal de windows, pero con mejores caracteristicas
//
// Entorno de programacion: MPLAB v8.20
// Compilador: C30
// Dispositivo: dsPIC30F4011
//  Placa desarrollo: dsPICDEM2
//
//***********************************************************************************

#include <p30f4011.h>
#include <stdlib.h>

//Macros for Configuration Fuse Registers:
//Invoke macros to set up  device configuration fuse registers.
//The fuses will select the oscillator source, power-up timers, watch-dog
//timers, BOR characteristics etc. The macros are defined within the device
//header files. The configuration fuse registers reside in Flash memory.
_FOSC(CSW_FSCM_OFF & XT_PLL8);  //Run this project using an external crystal
                                //routed via the PLL in 8x multiplier mode
                                //For the 7.3728 MHz crystal we will derive a
                                //throughput of 7.3728e+6*8/4 = 14.74 MIPS(Fcy)
                                //,~67nanoseconds instruction cycle time(Tcy).
_FWDT(WDT_OFF);                 //Turn off the Watch-Dog Timer.
_FBORPOR(MCLR_EN & PWRT_OFF);   //Enable MCLR reset pin and turn off the
                                //power-up timers.
_FGS(CODE_PROT_OFF);            //Disable Code Protection

//Defines for System Clock Timing -
//For oscillator configuration XT x PLL8 mode,
//Device Throughput in MIPS = Fcy = 7372800*8/4 = ~14.74 MIPS
//Instruction Cycle time = Tcy = 1/(Fcy) = ~68 nanoseconds
#define XTFREQ          7372800         //On-board Crystal frequency
#define PLLMODE         8               //On-chip PLL setting
#define FCY             XTFREQ*PLLMODE/4        //Instruction Cycle Frequency

#define BAUDRATE        9600                     //Designamos rango de baudios
#define BRGVAL          (((FCY/BAUDRATE)/16)-1)   //Formula para registro U1BRG, obtenida del manual
                                                //dsPIC30F Family Reference Manual

/*****************
 **  PROTOTIPOS  **
 *****************/
void UART_Init (void);
void __attribute__((__interrupt__)) _U1RXInterrupt(void);
int main (void);


/****************
 **  GLOBALES  **
 ****************/
unsigned char bufferRX[4]; //buffer donde voy almacenar los elementos de la pila
unsigned char *Ptro_bufferRX=NULL; //inicializacion del buffer
unsigned char indice=0; //contador que me indica las veces que se ha leido un dato


/*****************
 **  FUNCIONES  **
 *****************/ 
void UART_Init (void)
{
U1MODE=0;
U1STA=0;  
   
    TRISCbits.TRISC14=1;  //configguramos el puerto poniendo como entrada la linea RX->RC14

//cargamos el valor BRGVAL en el registro U!BRG, sera el que nos indica la valocidad de comunicacion
    U1BRG=BRGVAL; //los valores serian: 95->9600 7->115200 47->19200 15->57600   PLLx8                         

IPC2bits.U1RXIP = 7; // establecmos prioridad de la interrupcion

//U1MODE
U1MODEbits.UARTEN=1; //Enable UART (implies reception)
U1MODEbits.USIDL=0;   
    U1MODEbits.ALTIO=1;
    U1MODEbits.WAKE = 0;
    U1MODEbits.LPBACK=0;
    U1MODEbits.ABAUD = 0; // Autobaud desactivado
    U1MODEbits.PDSEL = 0b10; // odd parity
    U1MODEbits.STSEL = 0; // 1-stop bit      
   
   
  //U1STA
    U1STAbits.URXISEL = 0b00; //indicamos tipo de interrupcion
    U1STAbits.ADDEN=0; //address detect mode desactivado
  U1STAbits.OERR=0; //borramos el overrun
 
 
    IFS0bits.U1RXIF = 0;  // borramos flag interrupcion
   
    IEC0bits.U1RXIE = 1;  //interrupcion recepcion activada
   
    Ptro_bufferRX= &bufferRX[0]; //inicializamos el puntero al primer elemento de la tabla

}    



/*********************
 ** Interrupciones  **
 *********************/

// This is UART1 receive ISR
void __attribute__((__interrupt__,no_auto_psv)) _U1RXInterrupt(void)
{
    IFS0bits.U1RXIF = 0; //borramos flag de interrupcion
   
    if((U1STAbits.PERR==0) && (U1STAbits.FERR==0)) //compruebo errores
    {
    (*(Ptro_bufferRX)++)=U1RXREG;
    indice++; //incremento el valor del indice cada vez que llega un dato    
}   
if(U1STAbits.OERR) U1STAbits.OERR=0; //si hay error de overflow es borrado



/***********
 ** main  **
 ***********/
int main (void)
{
UART_Init(); //iniciamos las configuracion de UART

while(1) //bucle infinito, loop main
{
if(indice==4) //se acede cuando se han leido cuatro bytes
{
Ptro_bufferRX= &bufferRX[0]; //vuelvo apuntar al primer elemento del buffer
indice=0; //inicializo contador
}
}


CloseUART1(); //si por alguan circunstacia se abandona loop main se cierra el dispostivo UART

return 0;
}
//main

Título: Re: Recepcion datos modulo UART, problemas y dudas
Publicado por: jafema en 20 de Mayo de 2009, 09:05:11
Hola yo otra vez, jejee

Se me había olvidado (*(Ptro_bufferRX)++)=U1RXREG;, funciona correctamente, es un post-incremento, primero almacena el dato en la dirección a la que apunta el puntero y luego incrementa en uno el valor de esta, en ese mismo orden, con lo cual al finalizar estas apuntado al siguiente elemento de la tabla.

Saludos
Título: Re: Recepcion datos modulo UART, problemas y dudas
Publicado por: blackcat en 20 de Mayo de 2009, 13:53:09
La ejecucion paso a paso no es conveniente pues el debugger esta controlando el clock del micro ... entonces el baud generator se deriva de ese clock ... si damos pausa mientra se recibe un dato no lo recibimos como es ... mejor hazlo primero como te dije ... pon un breakpoint en cualquier lugar del la rutina de servicio de la interrrupcion .. puede ser donde se borra el flag ... podes hacerlo dando doble click sobre la linea y aparecerá un punto rojo con una B en el centro justa al lado de la linea ... despues dale run .. y cuando envies el dato el debugger detendrá la ejecucion del micro en el breakpoint.

Saludos!
Título: Re: Recepcion datos modulo UART, problemas y dudas
Publicado por: jafema en 21 de Mayo de 2009, 07:57:19
He realizado el debugger como me has comentado y funciona perfectamente  :) :) y lo probé con la función uart.h y también me funcionó :)

Lo único que no he probado todavía ha sido a cambiar la comunicación de la UART por los pines ALT, a realizar la comunicación por los pines normales de la UART. Pero si me sigue dando problemas lo dejaré así porque me sirven para hacer la comunicación.

Voy a dejar el código aquí por si alguién se encuentra con los mismos problemas le sirva de ayuda, además me parece lo más lógico dejar la solución puesto que me me han ayudado.

es un código muy simple, configura la UART para la una comunicación a 9600 baudios (se puede modificar fácilmente), 8 bits, paridad impar, usa los pines ALT del módulo UART, está configurado para que se produzca una interrupción cuando se completa el buffer de recepcion de datos del dspic, y lee el buffer completo almacenando los datos en un buffer que le hemos indicado. Le envío los daots desde una aplicación llamada terminal, similar al hyperterminal de windows. El programa no realiza nada más, ahora depende de la imaginación de cada uno ir añadiendo funciones (y más quebraderos de cabeza :) )

Saludos y muchas gracias por todo,

Javi
Código: [Seleccionar]
//***********************************************************************************
//
// PROGRAMA:
// Obtener datos enviados por computador a traves de comunicacion RS232,
// los datos se estan enviando atraves de una aplicacion software llamada terminal
// similar al hyperterminal de windows, pero con mejores caracteristicas
//
// Entorno de programacion: MPLAB v8.20
// Compilador: C30
// Dispositivo: dsPIC30F4011
//  Placa desarrollo: dsPICDEM2
//
//***********************************************************************************

#include <p30f4011.h>
#include <uart.h>
#include <stdlib.h>

//Macros for Configuration Fuse Registers:
//Invoke macros to set up  device configuration fuse registers.
//The fuses will select the oscillator source, power-up timers, watch-dog
//timers, BOR characteristics etc. The macros are defined within the device
//header files. The configuration fuse registers reside in Flash memory.
_FOSC(CSW_FSCM_OFF & XT_PLL8);  //Run this project using an external crystal
                                //routed via the PLL in 8x multiplier mode
                                //For the 7.3728 MHz crystal we will derive a
                                //throughput of 7.3728e+6*8/4 = 14.74 MIPS(Fcy)
                                //,~67nanoseconds instruction cycle time(Tcy).
_FWDT(WDT_OFF);                 //Turn off the Watch-Dog Timer.
_FBORPOR(MCLR_EN & PWRT_OFF);   //Enable MCLR reset pin and turn off the
                                //power-up timers.
_FGS(CODE_PROT_OFF);            //Disable Code Protection

//Defines for System Clock Timing -
//For oscillator configuration XT x PLL8 mode,
//Device Throughput in MIPS = Fcy = 7372800*8/4 = ~14.74 MIPS
//Instruction Cycle time = Tcy = 1/(Fcy) = ~68 nanoseconds
#define XTFREQ          7372800         //On-board Crystal frequency
#define PLLMODE         8               //On-chip PLL setting
#define FCY             XTFREQ*PLLMODE/4        //Instruction Cycle Frequency

#define BAUDRATE        9600                     //Designamos rango de baudios
#define BRGVAL          (((FCY/BAUDRATE)/16)-1)   //Formula para registro U1BRG, obtenida del manual
                                                //dsPIC30F Family Reference Manual

/*****************
 **  PROTOTIPOS  **
 *****************/
void UART_Init (void);
void __attribute__((__interrupt__,no_auto_psv)) _U1RXInterrupt(void);
int main (void);


/****************
 **  GLOBALES  **
 ****************/
unsigned char bufferRX[4]; //buffer donde voy almacenar los elementos de la pila
unsigned char *Ptro_bufferRX=NULL; //inicializacion del buffer
unsigned char index_byte=0; //contador que me indica las veces que se ha leido un dato

/*****************
 **  FUNCIONES  **
 *****************/
/*==========================
 ==  INICIALIZACION UART  ==
 ==========================*/
void UART_Init (void)
{
unsigned int U1MODEvalue;
unsigned int U1STAvalue;

CloseUART1(); //Turn off UART1module

//Configuramos interrupciones de UART1, recepcion
ConfigIntUART1(UART_TX_INT_DIS & UART_RX_INT_EN & UART_RX_INT_PR7);

//configuramos los registros UMODE y USTA
U1MODEvalue= UART_EN & UART_IDLE_CON & UART_DIS_WAKE & UART_DIS_ABAUD & UART_ALTRX_ALTTX &
                 UART_DIS_LOOPBACK & UART_ODD_PAR_8BIT & UART_1STOPBIT;

    U1STAvalue= UART_INT_TX & UART_INT_TX_BUF_EMPTY & UART_TX_PIN_NORMAL & UART_TX_DISABLE &
UART_INT_RX_BUF_FUL & UART_ADR_DETECT_DIS & UART_RX_OVERRUN_CLEAR;   
               
OpenUART1(U1MODEvalue, U1STAvalue, BRGVAL); //activamnos el uart con la configuracion seleccionada

Ptro_bufferRX= &bufferRX[0];  //el puntero apunta al primer elemento del buffer

}    

/*********************
 ** INTERRUPCIONES  **
 *********************/
// This is UART1 receive ISR
void __attribute__((__interrupt__,no_auto_psv)) _U1RXInterrupt(void)
{
    IFS0bits.U1RXIF = 0; //borramos flag de interrupcion
   
    if((U1STAbits.PERR==0) && (U1STAbits.FERR==0)) //compruebo errores
    {
    while(U1STAbits.URXDA==1) //lee mientras haya datos en la pila este bit indica que hay datos y pueden ser leidos
    {
    (*(Ptro_bufferRX)++)= U1RXREG;
    index_byte++; //se incrementa
}    
}   

if(U1STAbits.OERR) U1STAbits.OERR=0; //si hay error de overflow es borrado



/************
 **  MAIN  **
 ************/
int main (void)
{
UART_Init(); //iniciamos las configuracion de UART

while(1) //bucle infinito, loop main
{
if(index_byte==4) //se acede cuando se han leido cuatro bytes
{
Ptro_bufferRX= &bufferRX[0]; //vuelvo apuntar al primer elemento del buffer
index_byte=0; //inicializo contador
}
}


CloseUART1(); //si por alguan circunstacia se abandona loop main se cierra el dispostivo UART

return 0;
}
//main



 
Título: Re: Recepcion datos modulo UART, problemas y dudas
Publicado por: blackcat en 21 de Mayo de 2009, 11:59:24
Que bien !  :mrgreen:

Gracias por dejar el código, mucha gente pregunta por ejemplos para UART

Saludos!