Hola, estoy trabajando con el módulo UART1 en un dsPIC33FJ128GP802 pero no funciona como se espera con el compilador XC16. Aquí está mi código de inicialización y la rutina de interrupción, las macros debug()
y printNumericDebug()
simplemente envían datos al módulo UART2 para propósitos de depuración:
Main.c
/*
* File: Main.c
* Author: Andres Torti
*
* Created on 24 de mayo de 2012, 21:15
*/
/* Definiciones */
#include "definitions.h"
#include "mylibs.h"
/* Includes generales */
#include <libpic30.h> // Libreria para delays
#include <stdio.h>
#include <stdlib.h>
#include <uart.h>
/* Cabeceras de funciones */
#include "LogicAnalizer.h"
#include "Frecuencimetro.h"
#if DEBUG_ISIS == TRUE
#include <p33FJ32MC204.h>
// 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)
// 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 = OFF // Internal External Switch Over Mode (Start-up device with user-selected oscillator source)
// FOSC
#pragma config POSCMD = HS // Primary Oscillator Source (HS Oscillator Mode)
#pragma config OSCIOFNC = OFF // OSC2 Pin Function (OSC2 pin has clock out function)
#pragma config IOL1WAY = OFF // Peripheral Pin Select Configuration (Allow Multiple Re-configurations)
#pragma config FCKSM = CSDCMD // Clock Switching and Monitor (Both Clock Switching and Fail-Safe Clock Monitor are disabled)
// FWDT
#pragma config WDTPOST = PS256 // Watchdog Timer Postscaler (1:256)
#pragma config WDTPRE = PR128 // WDT Prescaler (1:128)
#pragma config WINDIS = OFF // Watchdog Timer Window (Watchdog Timer in Non-Window mode)
#pragma config FWDTEN = OFF // Watchdog Timer Enable (Watchdog timer enabled/disabled by user software)
// FPOR
#pragma config FPWRT = PWR2 // POR Timer Value (2ms)
#pragma config ALTI2C = OFF // Alternate I2C pins (I2C mapped to SDA1/SCL1 pins)
// 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)
#else
#include <p33FJ128GP802.h>
// 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 = OFF // Internal External Switch Over Mode (Start-up device with user-selected oscillator source)
// FOSC
#pragma config POSCMD = HS // Primary Oscillator Source (HS Oscillator Mode)
#pragma config OSCIOFNC = OFF // OSC2 Pin Function (OSC2 pin has clock out function)
#pragma config IOL1WAY = OFF // Peripheral Pin Select Configuration (Allow Multiple Re-configurations)
#pragma config FCKSM = CSDCMD // Clock Switching and Monitor (Both Clock Switching and Fail-Safe Clock Monitor are disabled)
// FWDT
#pragma config WDTPOST = PS256 // Watchdog Timer Postscaler (1:256)
#pragma config WDTPRE = PR128 // WDT Prescaler (1:128)
#pragma config WINDIS = OFF // Watchdog Timer Window (Watchdog Timer in Non-Window mode)
#pragma config FWDTEN = OFF // Watchdog Timer Enable (Watchdog timer enabled/disabled by user software)
// FPOR
#pragma config FPWRT = PWR2 // POR Timer Value (2ms)
#pragma config ALTI2C = OFF // Alternate I2C pins (I2C mapped to SDA1/SCL1 pins)
// 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)
#endif
/* RAM contigua para buffer */
__attribute__((far,aligned)) unsigned char Buffer[BUFFER_SIZE];
volatile unsigned int mode = NO_MODE; // Modo para el USART
void debugUARTInit (void){
#if DEBUG_ISIS == FALSE
// Configuración UART 2
U2MODEbits.USIDL = 1; // Continúa operando en modo IDLE
U2MODEbits.IREN = 0; // IrDa deshabilitado
U2MODEbits.RTSMD = 1; // Pin RTS no se utiliza
U2MODEbits.UEN = 0b00; // Pines RTS y CTS no se usan, solo TX y RX
U2MODEbits.WAKE = 1; // UART habilitado en sleep
U2MODEbits.LPBACK = 0; // No usa modo Loop-back
U2MODEbits.ABAUD = 0; // Auto-Baud apagado
U2MODEbits.BRGH = SPEED_MODE;
U2BRG = BRGVal;
U2MODEbits.PDSEL = 0b00; // 8 bits no parity
U2MODEbits.STSEL = 0; // 1 bit de stop
U2STAbits.UTXINV = 0; // Estado IDLE a 1
U2STAbits.UTXISEL0 = 0; // Deshabilitada interrupción por envío
U2STAbits.UTXISEL1 = 0;
U2STAbits.UTXEN = 1; // Pin TX habilitado
U2STAbits.URXISEL = 0b00; // Con solo un caracter la interrupcion por recepcion es lanzada
U2STAbits.ADDEN = 0; // Address mode apagado
U2STAbits.URXISEL = 0b00;
U2MODEbits.UARTEN = 1; // Módulo UART habilitado
#endif
}
/**
* Interrupcion de recepcion de dato en el UART 1 que es el que se comunica
* con el modulo bluetooth
*/
void __attribute__((interrupt, no_auto_psv)) _U1RXInterrupt(void){
IFS0bits.U1RXIF = 0;
debug("\r\nInterrupt");
if(DataRdyUART1() && mode == NO_MODE){ // Compruebo por las dudas de que en verdad halla un dato
mode = ReadUART1(); // Leo el dato desde el UART
printNumericDebug("\r\nIData: ", mode);
}
if(U1STAbits.OERR) U1STAbits.OERR = 0;
//U1MODEbits.WAKE = 1; // UART habilitado en sleep
}
int main (void) {
// Configuración del oscilador para usar un cristal de 4MHz y lograr 40MIPS
PLLFBDbits.PLLDIV = 78; // M=80
CLKDIVbits.PLLPOST = 0; // N1=2
CLKDIVbits.PLLPRE = 0; // N2=2
OSCTUN = 0; // Tune FRC oscillator, if FRC is used
RCONbits.SWDTEN = 0; // WDT desactivado
while(!OSCCONbits.LOCK); // Espero que se estabilize el PLL
__IOUNLOCK
#if DEBUG_ISIS == TRUE
RPINR18bits.U1RXR = 0b11001; // RX en RP25
RPOR12bits.RP24R = 0b00011; // TX en RP24
#else
RPINR18bits.U1RXR = 0b110; // RX en RP6
RPOR3bits.RP7R = 0b00011; // TX en RP7
RPOR0bits.RP0R = 0b00101; // TX2 en RP0
RPINR19bits.U2RXR = 1; // RX2 en RP1
#endif
__IOLOCK
TRISAbits.TRISA1 = 0; // Pin de dirección del buffer
PORTAbits.RA1 = 0; // Puerto B del buffer como entrada y A como salida (A <- B)
PORTB = 0xFF00; // Parte del buffer como entrada para evitar problemas
TRISBbits.TRISB2 = 0;
LATBbits.LATB2 = 0;
toggle(LATBbits.LATB2);
__delay_ms(500);
toggle(LATBbits.LATB2);
__delay_ms(500);
toggle(LATBbits.LATB2);
__delay_ms(500);
toggle(LATBbits.LATB2);
__delay_ms(500);
toggle(LATBbits.LATB2);
// Configuración UART 1
U1MODEbits.USIDL = 1; // Continúa operando en modo IDLE
U1MODEbits.IREN = 0; // IrDa deshabilitado
U1MODEbits.RTSMD = 1; // Pin RTS no se utiliza
U1MODEbits.UEN = 0b00; // Pines RTS y CTS no se usan, solo TX y RX
U1MODEbits.WAKE = 1; // UART habilitado en sleep
U1MODEbits.LPBACK = 0; // No usa modo Loop-back
U1MODEbits.ABAUD = 0; // Auto-Baud apagado
U1MODEbits.BRGH = SPEED_MODE;
U1BRG = BRGVal;
U1MODEbits.PDSEL = 0b00; // 8 bits no parity
U1MODEbits.STSEL = 0; // 1 bit de stop
U1STAbits.UTXINV = 0; // Estado IDLE a 1
U1STAbits.UTXISEL0 = 0; // Deshabilitada interrupción por envío
U1STAbits.UTXISEL1 = 0;
U1STAbits.UTXEN = 1; // Pin TX habilitado
U1STAbits.URXISEL = 0b00; // Con solo un caracter la interrupcion por recepcion es lanzada
U1STAbits.ADDEN = 0; // Address mode apagado
IFS0bits.U1RXIF = 0; // Borro el flag de interrupción
U1STAbits.OERR = 0; // Borro el flag de error
IEC0bits.U1RXIE = 1; // Activo interrupción del UART
U1MODEbits.UARTEN = 1; // Módulo UART habilitado
debugUARTInit();
__delay_ms(50); // Pequeño delay de arranque para estabilizacion
__C30_UART = 1;
printf(" "); // Debo enviar algo por printf() para que el UART
// comienze a funcionar, de otro modo el UART jamas inicia
__C30_UART = 2;
printf(" ");
debug("Debugger Iniciado UART 2");
while(TRUE){
Idle(); // El PIC se mantiene en modo Idle esperando un dato del UART
printNumericDebug("\r\nDespertado de Idle modo: ", mode);
switch(mode){
case FRECUENCIMETER:
//vFrecuencimetro();
mode = NO_MODE;
break;
case LC_METER:
//vLC_Meter();
mode = NO_MODE;
break;
case VOLTMETER:
mode = NO_MODE;
break;
case LOGIC_ANALIZER:
vLogicAnalizer();
mode = NO_MODE;
break;
}
}
return (EXIT_SUCCESS);
}
Definitions.h
#define FCY 40000000UL // MIPS para calculos de delay
#define BaudRate 9600
#define START_BYTE 'S'
#define BUFFER_SIZE 16000
#define ACK 0x06
#define TRUE 1
#define FALSE 0
#define FRECUENCIMETER 0
#define LC_METER 1
#define LOGIC_ANALIZER 'L'
#define VOLTMETER 3
#define NO_MODE 4
#define INDUCTANCE_MODE 4
#define CAPACITOR_MODE 5
#define FlancoSubida 0
#define FlancoBajada 1
#define DEBUG_ISIS FALSE
Mylibs.h
#ifndef MYLIBS_H
#define MYLIBS_H
#include "definitions.h"
#include "uart.h"
#include "stdio.h"
#include "stdlib.h"
void float2str(int *buffer, float f);
void printNumber(unsigned int number);
/* Definiciones generales */
// No permite cambios en Peripheral Pin Select
#define __IOLOCK __builtin_write_OSCCONL(OSCCON | 0x40);
// Permite cambios en Peripheral Pin Select
#define __IOUNLOCK __builtin_write_OSCCONL(OSCCON & 0xDF);
#define toggle(bit) bit ^= 0x01;
#if DEBUG_ISIS == FALSE
// Macros para DEBUG por el UART2
#define debug(data) putsUART2((unsigned int *)data); while(BusyUART2());
#define printNumericDebug(data, x) debug(data); printNumber(x); while(BusyUART2());
#define printCharDebug(data, x) debug(data); putcUART2((char)x); while(BusyUART2());
#else
#define debug(data)
#define printNumericDebug(data, x)
#define printCharDebug(data, x)
#endif
/**
* Macro para el calculo de baudios automatico
* Hay que colocar el define BAUDIOS en la funcioón OpenUSART
* donde pide el valor de "spbrg" y SPEED_MODE donde pide modo
* high o low speed:
* SPEED_MODE hay que colcoarlo en donde se pide el modo de velocidad y BAUDIOS donde
* se pide el "spbrg"
*/
#if (((FCY/BaudRate)/16)-1) < 0xFFFF
#define SPEED_MODE 0
#define BRGVal (((FCY/BaudRate)/16)-1)
#elif (((FCY/BaudRate)/4)-1) < 0xFFFF
#define SPEED_MODE 1
#define BRGVal (((FCY/BaudRate)/4)-1)
#else
#error No se pudo establecer un baudrate correcto
#endif
/***********************************************************************************/
#endif
Entonces, cuando envío mi primer byte a través de UART1, funciona correctamente, voy a interrumpir la rutina e ingresar esta función en el caso del conmutador:
case LOGIC_ANALIZER:
vLogicAnalizer();
mode = NO_MODE;
break;
Aquí todo funciona correctamente, pero cuando entro a vLogicAnalizer()
comienzan a aparecer los problemas, aquí está el código de LogicAnalizer.c
:
LogicAnalizer.c
/* Includes */
#include "mylibs.h"
#include "definitions.h"
#include "RunLengthAlgorithm.h"
#include <uart.h>
#include <libpic30.h>
#include <stdlib.h>
#if DEBUG_ISIS == FALSE
#include <p33FJ128GP802.h>
#else
#include <p33FJ32MC204.h>
#endif
/* Definiciones */
#define F40MHz 'A'
#define F20MHz 'S'
#define F10MHz 'D'
#define F4MHz 'F'
#define F400KHz 'G'
#define F2KHz 'H'
#define F10Hz 'J'
#define noTrigger 'N'
#define simpleTrigger 'S'
#define bitTest(data, n) (data & (1 << n))
#define enableUARTInt() U1MODEbits.WAKE = 1; IFS0bits.U1RXIF = 0; IEC0bits.U1RXIE = 1;
#define disableUARTInt() IEC0bits.U1RXIE = 0;
#define sleepWait() enableUARTInt(); Idle(); disableUARTInt();
#define writeUART1(data) WriteUART1(data); while(BusyUART1());
/**
* Definimos la variable tipo extern que fue definida en Main.c
* Archivo 1:
* int VariableGlobal; // Definición
* void UnaFunción (void); // Declaración externa implícita
*
* int main() {
* VariableGlobal = 1;
* UnaFunción();
* return 0;
* }
*
* Archivo 2:
* extern int VariableGlobal; // Declaración externa
*
* void UnaFunción (void) {
* ++ VariableGlobal;
* }
*
* En este ejemplo la variable VariableGlobal es definida en el archivo 1.
* Para utilizar la misma variable en el archivo 2, tiene que ser declarada
* usando el keyword extern. Independientemente de la cantidad de archivos,
* una variable global solo se define una vez, sin embargo, tiene que ser declarada
* usando extern en cualquier archivo aparte de aquel que contiene la definición.
* Técnicamente, UnaFunción es también externa, pero en C y en C++ todas las funciones
* son consideradas externas por defecto y normalmente no necesitan ser declaradas.
*
* Fuente: http://es.wikipedia.org/wiki/Variable_externa
*/
__attribute__((far,aligned)) extern unsigned char Buffer[BUFFER_SIZE];
/**
* Espero un byte desde el USART 1 y lo devuelvo
* @return byte leido desde el USART
*/
unsigned int mReadUART1 (void){
while(!DataRdyUART1());
return ReadUART1();
}
void vLogicAnalizer(void){
unsigned int keepGoing = 0; // Determina si debe seguir o no el muestreo
unsigned int triggerType; // Tipo de trigger
unsigned int samplingFrequency; // Frecuencia de muestreo
unsigned int channelMask; // Máscara para filtrar los canales (un 1 en el canal que se desea el trigger, 0 de otro modo)
TRISB = 0xFF00; // Parte alta del puerto B como entrada
TRISAbits.TRISA1 = 0; // Pin de dirección del buffer
PORTAbits.RA1 = 0; // Puerto B del buffer como entrada y A como salida (A <- B)
CNPU1 = CNPU2 = 0; // Deshabilito pull-ups
disableUARTInt();
writeUART1(LOGIC_ANALIZER); // Envío el modo
debug("\r\nAnalizador Logico");
while(DataRdyUART1()){
printNumericDebug("\r\nDatos disponibles en el UART: ", ReadUART1());
}
// Leo el estado para saber si debo continuar o detenerme
sleepWait();
keepGoing = mReadUART1();
printNumericDebug("\r\nKeepGoing recibido: ", keepGoing);
while(keepGoing != 0){
if(keepGoing != 0){
debug("\r\nKeep Going!");
samplingFrequency = mReadUART1(); // Obtengo la frecuencia de muestreo
triggerType = mReadUART1(); // Obtengo el tipo de trigger
channelMask = mReadUART1(); // Obtengo la máscara
printCharDebug("\r\nSampling Frequency: ", samplingFrequency);
printNumericDebug("\r\nTrigger Type: ", triggerType);
printNumericDebug("\r\nChannel Mask: ", channelMask);
CNEN1 = CNEN2 = 0;
if(channelMask == 0) triggerType = noTrigger;
// De acuerdo al bit seteado en el Mask detecto o no el cambio de estado
// en el pin correspondiente
if(bitTest(channelMask, 7)) CNEN1bits.CN11IE = 1;
if(bitTest(channelMask, 6)) CNEN1bits.CN12IE = 1;
if(bitTest(channelMask, 5)) CNEN1bits.CN13IE = 1;
if(bitTest(channelMask, 4)) CNEN1bits.CN14IE = 1;
if(bitTest(channelMask, 3)) CNEN1bits.CN15IE = 1;
if(bitTest(channelMask, 2)) CNEN2bits.CN16IE = 1;
if(bitTest(channelMask, 1)) CNEN2bits.CN21IE = 1;
if(bitTest(channelMask, 0)) CNEN2bits.CN22IE = 1;
// Habilito interrupciones por cambio de estado en caso de usarlas
if(triggerType == simpleTrigger){
IEC1bits.CNIE = 1;
IFS1bits.CNIF = 0;
}
else IEC1bits.CNIE = 0;
}
else{
debug("\r\nAnalizador Logico BREAK");
break;
}
switch(samplingFrequency){
case F40MHz:
debug("\r\nSampling 40MHz");
if(triggerType == noTrigger) vSample40MHz((unsigned char *)&PORTB+1, Buffer, BUFFER_SIZE);
else if(triggerType == simpleTrigger) vSample40MHzTriggerSimple((unsigned char *)&PORTB+1, Buffer, BUFFER_SIZE, channelMask);
break;
case F20MHz:
debug("\r\nSampling 20MHz");
if(triggerType == noTrigger) vSample20MHz((unsigned char *)&PORTB+1, Buffer, BUFFER_SIZE);
else if(triggerType == simpleTrigger) vSample20MHzTriggerSimple((unsigned char *)&PORTB+1, Buffer, BUFFER_SIZE, channelMask);
break;
case F10MHz:
debug("\r\nSampling 10MHz");
if(triggerType == noTrigger) vSample10MHz((unsigned char *)&PORTB+1, Buffer, BUFFER_SIZE);
else if(triggerType == simpleTrigger) vSample10MHzTriggerSimple((unsigned char *)&PORTB+1, Buffer, BUFFER_SIZE, channelMask);
break;
case F4MHz:
debug("\r\nSampling 4MHz");
if(triggerType == noTrigger) vSample4MHz((unsigned char *)&PORTB+1, Buffer, BUFFER_SIZE);
else if(triggerType == simpleTrigger) vSample4MHzTriggerSimple((unsigned char *)&PORTB+1, Buffer, BUFFER_SIZE, channelMask);
break;
case F400KHz:
debug("\r\nSampling 400KHz");
if(triggerType == noTrigger) vSample400KHz((unsigned char *)&PORTB+1, Buffer, BUFFER_SIZE);
else if(triggerType == simpleTrigger) vSample400KHzTriggerSimple((unsigned char *)&PORTB+1, Buffer, BUFFER_SIZE, channelMask);
break;
case F2KHz:
debug("\r\nSampling 2KHz");
//vSample2KHz((char *)&PORTB+1, &Buffer, BUFFER_SIZE);
break;
case F10Hz:
debug("\r\nSampling 10Hz");
//vSample10Hz((char *)&PORTB+1, &Buffer, BUFFER_SIZE);
break;
default:
debug("\r\nSampling Default");
break;
}
writeUART1(START_BYTE); // Envío byte de Start
writeUART1(LOGIC_ANALIZER); // Envío proveniencia del dato
// Envío el buffer comprimido
RLEncodeSendBuffer(Buffer, BUFFER_SIZE);
// Dos 0xFF indican la terminación
writeUART1(0xFF);
writeUART1(0xFF);
}
debug("\r\nSale de Analizador Logico");
enableUARTInt(); // Habilito nuevamente las interrupciones UART
}
Obtengo el carácter 'L'
como se esperaba de TX de UART1, luego borro el búfer de UART1 leyendo todos los datos disponibles y obtengo uno o dos datos que contienen 0 valores. DESPUÉS, esta interrupción se activa inmediatamente, incluso si no envío datos y la lectura de los datos es 0.
Intenté eliminar sleepWait()
y solo esperé los datos entrantes con mReadUART1()
, pero también obtuve un valor de 0 de forma inmediata.
¿Por qué sucede esto cuando entro en esta función? Si necesita más código fuente, puedo cargar los archivos completos para usted. Muchas gracias por tu ayuda!
EDITAR: otra cosa que noté es que a veces se dispara una interrupción pero no se reciben datos (el bit U1STA.URXDA es 0), ¿por qué?