Hallo, ich arbeite mit dem UART1-Modul in einem dsPIC33FJ128GP802, aber es funktioniert nicht wie erwartet mit dem XC16-Compiler. Hier ist mein Initialisierungscode und meine Interrupt-Routine, die Makros debug()
und printNumericDebug()
Makros senden nur Daten zu Debugging-Zwecken an das UART2-Modul:
Haupt 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);
}
Definitionen.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
Wenn ich also mein erstes Byte über UART1 sende, funktioniert es korrekt, wenn ich die Routine unterbreche und diese Funktion im Schalterfall eingebe:
case LOGIC_ANALIZER:
vLogicAnalizer();
mode = NO_MODE;
break;
Hier funktioniert alles genau richtig, aber wenn ich eintrete, vLogicAnalizer()
treten Probleme auf, hier ist der Code von 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
}
Ich bekomme das 'L'
Zeichen wie erwartet von TX von UART1, dann lösche ich den UART1-Puffer, indem ich alle verfügbaren Daten lese, und ich erhalte ein oder zwei Daten, die den Wert 0 enthalten. NACH diesem Interrupt wird sofort gefeuert, auch wenn ich keine Daten sende und die gelesenen Daten 0 sind.
Ich habe versucht, sie zu entfernen sleepWait()
und nur auf eingehende Daten zu warten, mReadUART1()
aber ich bekomme auch sofort den Wert 0.
Warum passiert das, wenn ich diese Funktion aufrufe? Wenn Sie mehr Quellcode benötigen, kann ich die vollständigen Dateien für Sie hochladen. Vielen Dank für Ihre Hilfe!
BEARBEITEN: Eine andere Sache, die mir aufgefallen ist, ist, dass manchmal ein Interrupt ausgelöst wird, aber keine Daten empfangen werden (U1STA.URXDA-Bit ist 0), warum?
Ok nach ein paar Tagen konnte ich es endlich lösen und es ist ein sehr dummes Problem. Grundsätzlich stelle ich bei der Eingabe vLogicAnalizer()
meinen TRISB ein:
TRISB = 0xFF00;
Dies wirkte sich auf meine UART Tx- und Rx-Pins aus. Um dies zu lösen, muss ich nur Folgendes tun:
TRISB |= 0xFF00;
Adam Lawrence
Andreas