Author Topic: PIC4520 - Recieving data from GPS  (Read 2985 times)

0 Members and 1 Guest are viewing this topic.

Offline Puffie40Topic starter

  • Regular Contributor
  • *
  • Posts: 54
  • Country: ca
  • Irregular Logic
PIC4520 - Recieving data from GPS
« on: April 23, 2016, 06:55:16 am »
I'm trying to pull data from a Maestro A2255 by UART, on a 4520, and I am having a heck of a time getting it to read.

Code: [Select]
#include <stdio.h>
#include "UART.h"
//#include "GPS.h"
#define _XTAL_FREQ   8000000    //required for __delay_ms(time) function
#define CR 0x0D                 //Carriage Return - end of NEMA sentance
#define LF 0x0A                 //Line feed       - end of NEMA sentance

unsigned char charRead;       /* char read from COM port */
unsigned char stringRead[100];
unsigned int i = 0;         /* Number of chars read per GPS message string */

//Function prototypes
void wait_sec(unsigned int x);

void main(){
    TRISD = 0;
    LATD = 0;
    setup_USART();
    wait_sec(1);
    USARTWriteLine("Hello! If you can read this, I am working!");

    while(1){
    USARTWriteLine("Read");
    charRead = USARTReadByte();
//    USARTWriteLine("done reading");
    if(BAUDCONbits.ABDOVF == 1){
        PORTD = 0x01;}

    if(RCSTAbits.FERR == 1){
        PORTD = 0x03;
    }

     if(RCSTAbits.OERR == 1){
        PORTD = 0x08;
        RCSTAbits.OERR = 0;
    }

    //USARTWriteByte(charRead);
    }
//        for( i=0; i < 10; i++){
//      charRead = USARTReadByte();
//             stringRead[i] = charRead;
//        }
//    USARTWriteLine("done reading");
//        for( i=0; i < 10; i++){
//        USARTWriteByte(stringRead[i]);
//        }
    }

//wait function set up to wait x seconds
void wait_sec(unsigned int x){
  unsigned int time = (x * 20);
  for (unsigned int m=0; m<time; m++)
        {
            __delay_ms(50);
        }
}

UART.h has this code

Code: [Select]
//Setup procedure for UART
void setup_USART(void){

//    //pin setup
    TRISCbits.RC6 = 1;          //Ensures RC6 is a input
    TRISCbits.RC7 = 1;          //Ensures RC7 is a input

    //RX Setup
    RCSTAbits.SPEN = 1;         //Enables USART Module
    RCSTAbits.CREN = 1;         //Enables UART Continuous Reception

    //TX Setup
    TXSTAbits.TXEN = 1;         //Enables UART Transmission
    TXSTAbits.SYNC = 0;         //Setting Asynchronous Mode

    //Configure Baud Rate Generator
    SPBRG = 25;                 //4800 buad rate w/ 4MHz crystal
                                //BRG = |((Fosc/Baud)/64)-1|

    SPBRGH = 0;                  //MSB for BRG.  should be incremented when
                                //SPBRG is > 255

    BAUDCONbits.BRG16 = 0;
//    //interrupts
//    INTCONbits.GIE = 1;         //enables general interrupts
//    INTCONbits.PEIE = 1;        //enables peripheral interrupts
//    PIE1bits.RCIE = 1;          //enables USART RX interrupt
//    PIE1bits.TXIE = 1;          //enables USART TX Interrupt

    //BAUDCON = 0x00;
}

void USARTWriteByte(char ch)
{
    RCSTAbits.OERR = 0;
//Wait for TXREG Buffer to become available
while(!TXIF);

//Write data
TXREG=ch;
}

void USARTWriteString(const char *str)
{
while((*str)!='\0')
{
//Wait for TXREG Buffer to become available
while(!TXIF);

//Write data
TXREG=(*str);

//Next goto char
str++;
}
}

/*

Writes a line of text to USART and goes to new line
The new line is Windows style CR/LF pair.

This will work on Hyper Terminal Only NOT on Linux

*/

void USARTWriteLine(const char *ln)
{
USARTWriteString(ln);
USARTWriteString("\r\n");
}

void USARTWriteInt(int val,unsigned char field_length)
{
if(val<0)
{
USARTWriteByte('-'); //Write '-' sign for negative numbers.
val=(val*(-1)); //Make it positive.
}

//Convert Number To String and pump over Tx Channel.
char str[5]={0,0,0,0,0};
int i=4,j=0;
while(val)
{
str[i]=val%10;
val=val/10;
i--;
}
if(field_length>5)
while(str[j]==0) j++;
else
j=5-field_length;

for(i=j;i<5;i++)
{
USARTWriteByte('0'+str[i]);
}
}

//checks flag to see if data is ready
char UART_Data_Ready(){
  return RCIF;
}

//reads recieved register
unsigned char USARTReadByte(){
while(!RCIF); //Wait for a byte

return RCREG;
}

Right now, I'd be happy if it could continuously read, but the code hangs after reading the second letter. Checking the error registers suggests a overrun error has occurred, but I have not found anything on google regarding how to fix this.  I tried a 8Mhz crystal on the off chance it might be a speed issue, but I can't get past the second character.
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 5319
  • Country: gb
Re: PIC4520 - Recieving data from GPS
« Reply #1 on: April 23, 2016, 09:31:05 am »
I just tried your code on a slightly different chip (PIC18F2620, more memory and in a smaller package, so no PORTD), and it seems fine when sending characters from a keyboard manually.

However if I paste a string of characters into my terminal emulator (putty), you get a buffer overrun. this is because you have blocking code while you're sending out "Read" so the read buffer overruns while you're still sending out characters.

I didn't know what your hardware setup was so I had to guess that, and there were no config bits set either. My hardware and modified version of code to run on my device is below.



Code: [Select]
#include <xc.h>

// CONFIG1H
#pragma config OSC = INTIO7     // Oscillator Selection bits (Internal oscillator block, CLKOUT function on RA6, port function on RA7)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

// CONFIG2L
#pragma config PWRT = OFF       // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = SBORDIS  // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
#pragma config BORV = 3         // Brown Out Reset Voltage bits (Minimum setting)

// CONFIG2H
#pragma config WDT = OFF        // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H
#pragma config CCP2MX = PORTC   // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = OFF     // PORTB A/D Enable bit (PORTB<4:0> pins are configured as digital I/O on Reset)
#pragma config LPT1OSC = OFF    // Low-Power Timer1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config MCLRE = ON       // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF        // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

// CONFIG5L
#pragma config CP0 = OFF        // Code Protection bit (Block 0 (000800-003FFFh) not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 (004000-007FFFh) not code-protected)
#pragma config CP2 = OFF        // Code Protection bit (Block 2 (008000-00BFFFh) not code-protected)
#pragma config CP3 = OFF        // Code Protection bit (Block 3 (00C000-00FFFFh) not code-protected)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block (000000-0007FFh) not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 (000800-003FFFh) not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 (004000-007FFFh) not write-protected)
#pragma config WRT2 = OFF       // Write Protection bit (Block 2 (008000-00BFFFh) not write-protected)
#pragma config WRT3 = OFF       // Write Protection bit (Block 3 (00C000-00FFFFh) not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot Block (000000-0007FFh) not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 (000800-003FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 (004000-007FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF      // Table Read Protection bit (Block 2 (008000-00BFFFh) not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF      // Table Read Protection bit (Block 3 (00C000-00FFFFh) not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot Block (000000-0007FFh) not protected from table reads executed in other blocks)

#include <stdio.h>
#include "UART.h"
//#include "GPS.h"
#define _XTAL_FREQ   8000000    //required for __delay_ms(time) function
#define CR 0x0D                 //Carriage Return - end of NEMA sentance
#define LF 0x0A                 //Line feed       - end of NEMA sentance

unsigned char charRead;       /* char read from COM port */
unsigned char stringRead[100];
unsigned int i = 0;         /* Number of chars read per GPS message string */

//Function prototypes
void wait_sec(unsigned int x);

void main(){
    TRISB = 0;
    LATB = 0;
    //hl
    OSCCONbits.IRCF=0b111; // 8MHz intosc
   
    setup_USART();
    wait_sec(1);
    USARTWriteLine("Hello! If you can read this, I am working!");

    while(1)
    {
        USARTWriteLine("Read");
        charRead = USARTReadByte();
    //    USARTWriteLine("done reading");
        if(BAUDCONbits.ABDOVF == 1){
            PORTB = 0x01;
        }

        if(RCSTAbits.FERR == 1){
            PORTB = 0x03;
        }

         if(RCSTAbits.OERR == 1){
            PORTB = 0x08;
            RCSTAbits.OERR = 0;
        }

        //USARTWriteByte(charRead);
    //hl    }
    //        for( i=0; i < 10; i++){
    //      charRead = USARTReadByte();
    //             stringRead[i] = charRead;
    //        }
    //    USARTWriteLine("done reading");
    //        for( i=0; i < 10; i++){
    //        USARTWriteByte(stringRead[i]);
    //        }
    }
}

//wait function set up to wait x seconds
void wait_sec(unsigned int x){
  unsigned int time = (x * 20);
  for (unsigned int m=0; m<time; m++)
        {
            __delay_ms(50);
        }
}


UART.c
Code: [Select]
#include <xc.h>
#include "UART.h"

//Setup procedure for UART
void setup_USART(void){

//    //pin setup
    TRISCbits.RC6 = 1;          //Ensures RC6 is a input
    TRISCbits.RC7 = 1;          //Ensures RC7 is a input

    //RX Setup
    RCSTAbits.SPEN = 1;         //Enables USART Module
    RCSTAbits.CREN = 1;         //Enables UART Continuous Reception

    //TX Setup
    TXSTAbits.TXEN = 1;         //Enables UART Transmission
    TXSTAbits.SYNC = 0;         //Setting Asynchronous Mode

    //Configure Baud Rate Generator
    SPBRG = 25;                 //4800 buad rate w/ 4MHz crystal
                                //BRG = |((Fosc/Baud)/64)-1|

    SPBRGH = 0;                  //MSB for BRG.  should be incremented when
                                //SPBRG is > 255

    BAUDCONbits.BRG16 = 0;
//    //interrupts
//    INTCONbits.GIE = 1;         //enables general interrupts
//    INTCONbits.PEIE = 1;        //enables peripheral interrupts
//    PIE1bits.RCIE = 1;          //enables USART RX interrupt
//    PIE1bits.TXIE = 1;          //enables USART TX Interrupt

    //BAUDCON = 0x00;
}

void USARTWriteByte(char ch)
{
    RCSTAbits.OERR = 0;
//Wait for TXREG Buffer to become available
while(!TXIF);

//Write data
TXREG=ch;
}

void USARTWriteString(const char *str)
{
while((*str)!='\0')
{
//Wait for TXREG Buffer to become available
while(!TXIF);

//Write data
TXREG=(*str);

//Next goto char
str++;
}
}

/*

Writes a line of text to USART and goes to new line
The new line is Windows style CR/LF pair.

This will work on Hyper Terminal Only NOT on Linux

*/

void USARTWriteLine(const char *ln)
{
USARTWriteString(ln);
USARTWriteString("\r\n");
}

void USARTWriteInt(int val,unsigned char field_length)
{
if(val<0)
{
USARTWriteByte('-'); //Write '-' sign for negative numbers.
val=(val*(-1)); //Make it positive.
}

//Convert Number To String and pump over Tx Channel.
char str[5]={0,0,0,0,0};
int i=4,j=0;
while(val)
{
str[i]=val%10;
val=val/10;
i--;
}
if(field_length>5)
while(str[j]==0) j++;
else
j=5-field_length;

for(i=j;i<5;i++)
{
USARTWriteByte('0'+str[i]);
}
}

//checks flag to see if data is ready
char UART_Data_Ready(){
  return RCIF;
}

//reads recieved registeroooooooooooooooo
unsigned char USARTReadByte(){
while(!RCIF); //Wait for a byte

return RCREG;
}


UART.h
Code: [Select]
extern void setup_USART(void);
extern void USARTWriteByte(char ch);
extern void USARTWriteString(const char *str);
extern void USARTWriteLine(const char *ln);
extern void USARTWriteInt(int val,unsigned char field_length);
extern char UART_Data_Ready();
extern unsigned char USARTReadByte();
 

Offline Puffie40Topic starter

  • Regular Contributor
  • *
  • Posts: 54
  • Country: ca
  • Irregular Logic
Re: PIC4520 - Recieving data from GPS
« Reply #2 on: April 24, 2016, 01:52:15 am »
I realize the code is rather sketchy, I was trying to find out where the code was hanging.

Is there a procedure for reading a string off UART?  All the examples I found online only show how to receive a single byte.
 

Offline Kilrah

  • Supporter
  • ****
  • Posts: 1852
  • Country: ch
Re: PIC4520 - Recieving data from GPS
« Reply #3 on: April 24, 2016, 04:15:19 am »
You first have to define what a string is in your context (delimited with e.g. CRLF? just a "block of text that comes in one go"?) - then see about handling it appropriately.
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 5319
  • Country: gb
Re: PIC4520 - Recieving data from GPS
« Reply #4 on: April 24, 2016, 07:41:14 am »
In its simplest form, you can do as kilrah suggests, or even simpler, just wait for a CR (0x0D) and throw away the LF (0x0A) in your string parser.

If you want your device to be able to do things while that string's being received, or when the GPS isn't connected, then you need to look at how to deal with that.

Typically this is done in a "super loop" where main() has a while (1) loop which is continually checking the receive buffer for characters, and also doing other things, but key is that it doesn't block waiting for those characters. If there's a character, it adds it to a string, but it will always yield. If the character was a CR, it can parse the string, but it needs to be quick, it should not then sit around waiting to pump out characters for example.

You might have another task that flashes an LED for example, toggling it when a timer has reached a preset point, but again that task doesn't block, it only toggles if the timer state has reached that point since the last time it was polled.

Another way to do this is to implement the receiver in an interrupt service routine (ISR) triggered by an incoming character. It is generally considered good practice to keep the code in an ISR to a minimum, so although adding a character to a line buffer is a reasonable thing to do, parsing that string probably isn't, and I'd do that in my main super loop using a volatile flag set in the ISR when a CR is found. In this case I'd also operate two line buffers and flip between them so that the line that's being parsed isn't overwritten by new incoming characters.

In practice you'll usually find a combination of super loop and interrupts in all but the most trivial embedded real time implementations.


 
The following users thanked this post: Kilrah

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9890
  • Country: us
Re: PIC4520 - Recieving data from GPS
« Reply #5 on: April 24, 2016, 04:28:04 pm »
You will come to find that the only way this will ever be reliable is if you receive chars in an interrupt routine.
You know how long a GPS sentence is (or at least the max sentence) so you could arrange to have the interrupt routine build up an array of complete sentences and notify the mainline that another sentence is available.  You can keep full/empty flags for each sentence in the array.  Two sentences would be a minimum, three or four would probably be better.  What you do when the array is full and the mainline isn't reading them fast enough is up to you.  I might take the position that I won't bother to process the next sentence if the array is full.

You need some way to indicate to both the interrupt handler and the mainline that a sentence in the array is ready to process.  The first byte of a sentence could be a flag.  The data starts in the second byte.  When a sentence is complete (<CR> received), the interrupt routines terminates the sentence string with a '\0' (no point in passing the CR or LF) and sets the first byte of the array to '1'.  The mainline, after processing the sentence, resets the first byte to '0'.  The interrupt handler only puts data into array sentences when the first byte is '0'.  Something like that...
 

Offline Puffie40Topic starter

  • Regular Contributor
  • *
  • Posts: 54
  • Country: ca
  • Irregular Logic
Re: PIC4520 - Recieving data from GPS
« Reply #6 on: April 27, 2016, 06:20:10 pm »
I managed to find some example code that used a interrupt to receive a string and echo it back when you pressed enter.

with that, I started implementing it to read from my GPS:

Code: [Select]
// PIC18F4520 Configuration Bit Settings

// 'C' source line config statements

#include <xc.h>

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

// CONFIG1H
#pragma config OSC = XT         // Oscillator Selection bits (XT oscillator)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

// CONFIG2L
#pragma config PWRT = OFF       // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = SBORDIS  // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
#pragma config BORV = 3         // Brown Out Reset Voltage bits (Minimum setting)

// CONFIG2H
#pragma config WDT = OFF         // Watchdog Timer Enable bit (WDT enabled)
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H
#pragma config CCP2MX = PORTC   // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = ON      // PORTB A/D Enable bit (PORTB<4:0> pins are configured as analog input channels on Reset)
#pragma config LPT1OSC = OFF    // Low-Power Timer1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config MCLRE = ON       // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = ON         // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

// CONFIG5L
#pragma config CP0 = OFF        // Code Protection bit (Block 0 (000800-001FFFh) not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 (002000-003FFFh) not code-protected)
#pragma config CP2 = OFF        // Code Protection bit (Block 2 (004000-005FFFh) not code-protected)
#pragma config CP3 = OFF        // Code Protection bit (Block 3 (006000-007FFFh) not code-protected)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block (000000-0007FFh) not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 (000800-001FFFh) not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 (002000-003FFFh) not write-protected)
#pragma config WRT2 = OFF       // Write Protection bit (Block 2 (004000-005FFFh) not write-protected)
#pragma config WRT3 = OFF       // Write Protection bit (Block 3 (006000-007FFFh) not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot block (000000-0007FFh) not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 (000800-001FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 (002000-003FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF      // Table Read Protection bit (Block 2 (004000-005FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF      // Table Read Protection bit (Block 3 (006000-007FFFh) not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot block (000000-0007FFh) not protected from table reads executed in other blocks)

#include <pic18f4520.h>         // Header file for PIC18F4520
#include <stdio.h>
#include "UART.h"
//#include "GPS.h"
//#include <ctype.h>  /* required for the isalnum function */
#define _XTAL_FREQ   4000000    //required for __delay_ms(time) function
#define CR 0x0D                 //Carriage Return - end of NEMA sentance
#define LF 0x0A                 //Line feed       - end of NEMA sentance

unsigned char MessageBuffer[100];
int i=0;
void SetupClock(void);
void Delay1Second(void);

void main(void) {

    setup_USART();
    __delay_ms(100);

    TRISCbits.RC6 = 1; //TX pin set as output
    TRISCbits.RC7 = 1; //RX pin set as input
   
    __delay_ms(100);
    //TX line test
    //USARTWriteLine("Hi! I must be working if you can read this!");
   
    //SiRF Star iv Commands
    //USARTWriteLine("$PSRF103,04,01,30,00*23");
    //USARTWriteLine("$PSRF103,00,6,00,0*23");
    //USARTWriteByte(CR);
    __delay_ms(100);


    PIE1bits.RCIE = 1;          //enables USART RX interrupt

    while(1) //infinite loop
    {

    }
}

void interrupt Interrupt(){
    //check if the interrupt is caused by USART RX pin
    if(PIR1bits.RCIF == 1){
        //if(i<100){ //our buffer size
            MessageBuffer[i] = USARTReadByte(); //read the byte from rx register
           
            if(MessageBuffer[i] == 0x0D){ //check for return key

                RCSTAbits.CREN = 0;           //shuts off USART RX for printing

                USARTWriteString(MessageBuffer);
                USARTWriteLine("");

                //for(;i>0;i--)
                //    MessageBuffer[i] = 0x00; //clear the array
                i=0; //for sanity
                RCSTAbits.CREN = 1;           //enables USART RX
                return;

                //sentance recieved. check if its the NEMA Sentance we want.
//                if(MessageBuffer[4] == 'R' && MessageBuffer[5] == 'M' && MessageBuffer[6] == 'C') {
//                    USARTWriteString(MessageBuffer); //write string to TX serial
//                    USARTWriteLine("");
//
//                    //pChar = stringRead;   //save string
//                    //StringRXF = 1 //let the code know a string has been recieved
//
//                    for(i;i>0;i--)
//                        MessageBuffer[i] = 0x00; //clear the array
//                    i=0; //for sanity
//
//                    RCSTAbits.CREN = 1;           //enables USART RX
//                    return;
//                }
//
//                else{   //sentance is not what we want.  get rid of it.
//                    USARTWriteLine("1");
//                    for(i;i>0;i--)
//                        MessageBuffer[i] = 0x00; //clear the array
//                    i=0; //for sanity
//
//                    RCSTAbits.CREN = 1;           //enables USART RX
//                    return;
//                }
            }
        //}

//        else{
//            USARTWriteString(MessageBuffer); //string is too big. get rid of it.
//            for(i;i>0;i--){
//                MessageBuffer[i] = 0x00; //clear the array
//            }
//            i=0; //for sanity
//            return;
//            }
       
        i++;
        PIR1bits.RCIF = 0; // clear rx flag
    }
}

I have attached what my terminal shows with this running.  I'm switching receive off while the code processes the string.

the problem I have is dealing with the flood of messages the GPS gives me. Since the Maestro uses a SiRFStar iv chipset, I have tried transmitting some commands to limit the flow to RMC only, but I don't know if the GPS read it.

I admit I am currently working with the gps not having a fix, and I understand the GPS receiver floods you with sentances until it has a fix.
 

Offline Wilksey

  • Super Contributor
  • ***
  • Posts: 1329
Re: PIC4520 - Recieving data from GPS
« Reply #7 on: April 27, 2016, 07:58:52 pm »
OK, looking very briefly at your code, I am assuming you are new to PIC programming?
The interrupt should be serviced then returned as quick as possible, with minimal processing, none preferably, otherwise you could miss interrupts and the internal buffer may overflow.  You have to also reset the receiver on a overflow error.

I have implemented a GPS receiver based on a PIC24 and Maestro A2100 without any issues, it's commercial so unfortunately I cannot share it, but you flag a process message on a CRLF then check the beginning $GPXXXX message, if it's one you want then you process it, if not, drop it from the buffer.

You can look up circular buffers also.
 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9890
  • Country: us
Re: PIC4520 - Recieving data from GPS
« Reply #8 on: April 27, 2016, 08:08:22 pm »
The only job the interrupt routine should perform is to grab the chars and stick them in a circular buffer.  The buffer needs to be large enough that regardless of what the main code is doing, the buffer won't overflow.

Earlier I mentioned implementing the circular queue as an array of sentence length buffers.  The index into the array works in a circular fashion and there is some kind of flag to indicate whether a sentence is yet to be processed or whether it is now available for new data.  To make index wrap-around easy to perform, buffers are of some length which is a power of 2.  8 buffers takes 3 bits so every time you increment the index, you simply & the result with 0x07.  No modulo arithmetic required, no testing for the final index, none of that stuff.

The code that looks at the sentences can parse enough information to decide whether the sentence contains useful data and should be processed further or whether it is nonsense and just move on.

Grabbing a single character by way of an interrupt is not the way to handle data when you can't control the flow.  Can you control the flow?  Does the GPS serial port honor flow control?  Hardware flow control?  Software flow control?
 

Offline Puffie40Topic starter

  • Regular Contributor
  • *
  • Posts: 54
  • Country: ca
  • Irregular Logic
Re: PIC4520 - Recieving data from GPS
« Reply #9 on: April 28, 2016, 07:37:22 am »
Quote
OK, looking very briefly at your code, I am assuming you are new to PIC programming?
The interrupt should be serviced then returned as quick as possible, with minimal processing, none preferably, otherwise you could miss interrupts and the internal buffer may overflow.  You have to also reset the receiver on a overflow error.
Yes, I am quite new at this. :-[  I'd like to say I have an okay understanding of basic C++ programming, but so far the project I'm doing is proving more challenging and frustrating than anticipated.

I'll move some of those data operations out of the interrupt.

Grabbing a single character by way of an interrupt is not the way to handle data when you can't control the flow.  Can you control the flow?  Does the GPS serial port honor flow control?  Hardware flow control?  Software flow control?

There is no flow control with the UART.  there's some NEMA commands in the SiRFStar IV datasheet that suggest the data output can be configured, including time between outputs, but I have not figured any of that out.
 

Online hans

  • Super Contributor
  • ***
  • Posts: 1640
  • Country: nl
Re: PIC4520 - Recieving data from GPS
« Reply #10 on: April 28, 2016, 08:17:52 am »
GPS receivers will likely transmit their NMEA data in 1 quick burst. So if you shut down the receiver of your UART and reprint your message buffer from the interrupt (which is blocking), you will miss the next line/a set of bytes.

Like others said; buffer data in a circular buffer. Interrupts should be short and to the point.
If you want to output what is in your buffer for debugging, do it in main loop.
If you want to debug an interrupt, an oscilloscope/logic analyzer is a very valuable tool to measure states/timings on GPIO pins. You can sometimes use a debugger; but remember that you will miss interrupts by doing so and will likely cause the state of your application to corrupt (which can also be a good thing to see if your system recovers gracefully).
 

Offline Wilksey

  • Super Contributor
  • ***
  • Posts: 1329
Re: PIC4520 - Recieving data from GPS
« Reply #11 on: April 28, 2016, 12:03:30 pm »
There's your problem...C not C++!  ;D
Remember, it's not desktop programming!

Think about what the micro has to do, it's single tasked not multi-threaded, and slow, you need to help it out by allowing it to service other interrupts and the way to do that is to return as quickly as possible from one and back to the "main loop".

Set processing flags and check them in the main loop then process them in there, that way the interrupts can still work.

Think about what a GPS message consists of, you can filter out each sentence from the receiver, it's delimited with CRLF, so every time you see a CRLF you know the next character is probably a $ - start of a new GPS "sentence".  Increment the char pointer through the buffer, you can get helper functions for circular buffers, just look on-line, they don't have to be specific to the compiler, standard ANSI C code will work.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf