CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

GPS buffer garbage

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
michaelb



Joined: 28 Nov 2005
Posts: 17

View user's profile Send private message

GPS buffer garbage
PostPosted: Tue Dec 13, 2005 1:32 pm     Reply with quote

Hi,

I know this topic has been done a lot, but I couldn't find an answer to this specific problem. I'm trying to buffer NMEA sentences from a GPS to eventually extract the lat/long. At the moment I'm merely trying to send the first 5 characters of the sentence to the PC.

The problem I'm having seems to down to mistiming. The first sentence is outputted correctly, but subsequent ones are not. Here is my code:

Code:

/*
GPS Stream Reader/Parser
Read GPS NMEA stream over serial interface.
GPS RX: C7
PC TX: C6


*/

#if defined(__PCM__)
   #include <16F877.h> //PIC16F877A Device
   #device *=16  //Use 16 Bit Pointers
   #fuses HS,NOWDT,NOPROTECT,NOLVP
   #use delay(clock=20000000) //20MHz Clock
   #use rs232(baud=4800, xmit=PIN_C6, rcv=PIN_C7, ERRORS) //Configure RS232 Comms
#endif

#include <lcd.c>

#define  esc 0x1B //Terminal Escape Character

//Function Prototypes
void cls();

//Global Variables
int line_complete;    //Flag to show NMEA sentence complete
int data_valid;       //Flag to show incoming data stream to be added to sentence
int buffer_pointer;   //Points to next available buffer space
char gps_buffer[82];  //82 Byte buffer - maximum lenfth of an NMEA sentence

#INT_RDA //Serial RX Interrupt
RDA_isr()
{
   char char_rcvd; //To store received char

   char_rcvd = getc(); //Store received char

   if(char_rcvd == '$') //$ Marks beginning of a NMEA sentence
   {
      data_valid = true; //Add incoming chars to the buffer
      buffer_pointer = 0; //Reset buffer pointer
   }

   if(data_valid)
   {
      gps_buffer[buffer_pointer] = char_rcvd;   //Add char to buffer
      buffer_pointer++;                         //Advance buffer pointer

      if((char_rcvd == '\r') || (char_rcvd == '\n')) //If end of NMEA sentence
      {
         data_valid = FALSE;
      }
      if(buffer_pointer >= 82) //If buffer is full
      {
         data_valid = FALSE;
      }
      if(!data_valid) //If data stream ended
      {
         line_complete = TRUE; //Flag as sentence completed
      }
   }
}

void main()
{
   int i;
   
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   setup_spi(FALSE);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);

   lcd_init();
   delay_ms(6);
   cls();
   lcd_putc("GPS Parser");
   
   line_complete = FALSE;
   enable_interrupts(GLOBAL);
   printf("Ready\n\r");
   enable_interrupts(INT_RDA);

   while(1)
   {
      while(!line_complete) //Wait for sentence to be completed
      {
         #asm
            NOP
         #endasm
      }

      if(line_complete) //If sentence is complete
      {
         disable_interrupts(INT_RDA);
         for(i=0; i <6;i++) //Print first 5 chars to terminal
         {
            putc(gps_buffer[i]);
         }
         printf("\r\n");
         line_complete = FALSE;
         enable_interrupts(INT_RDA); //Get next sentence
      }
   }


}

void cls(void)
{
   printf("%c[2J",esc);
}


Here is the terminal output for 2 sequences:
Code:

$GPRMC
$B,V,,
$A,,,,
$A,A,1
$V,3,1
$V,3,2
$V,3,3
$L,,,,
$D,,T,
$E,,M,
$Z,,f,
$E,1,1
$GPRMC
$B,V,,
$A,,,,
$A,A,1
$V,3,1
$V,3,2
$V,3,3
$L,,,,
$D,,T,
$E,,M,
$Z,,f,
$E,1,1


This is what the GPS is actually outputting (in one sequence):

Code:

$GPRMC,,V,,,,,,,251105,3.3,W,N*28
$GPRMB,V,,,,002,5223.700,N,00133.648,W,,,,V,N*15
$GPGGA,,,,,,0,00,,,M,,M,,*66
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPGSV,3,1,12,03,83,272,00,08,10,335,00,11,00,242,00,15,53,064,00*7F
$GPGSV,3,2,12,16,46,181,00,18,40,074,00,19,46,285,00,21,20,058,00*71
$GPGSV,3,3,12,22,41,128,00,26,08,024,00,27,19,297,00,29,07,013,00*71
$GPGLL,,,,,,V,N*64
$GPBOD,,T,,M,002,*75
$PGRME,,M,,M,,M*00
$PGRMZ,,f,1*29
$GPRTE,1,1,c,*37


As you can see the number of sentences is the same - but the data is corrupt. Any help would be greatly appreciated. I've been trying this all day and it's driving me insane.

Kind Regards,

Michael
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Dec 13, 2005 2:02 pm     Reply with quote

The problem is that the NMEA sentences come in right after each other,
without any spacing. When you get one sentence, you then disable
interrupts. So you miss several characters from the next sentence.

Perhaps you should use an interrupt-driven transmit buffer, as shown
in the CCS example file EX_STISR.C.
michaelb



Joined: 28 Nov 2005
Posts: 17

View user's profile Send private message

PostPosted: Tue Dec 13, 2005 2:31 pm     Reply with quote

Thanks for that. I'll have a look through that example.
I was thinking it shouldn't matter though, as a new sentence is only ever created when a $ is detected, and the data following that should then be intact. It will only start putting together a new sentence from the beginning - by looking for the first $ after the interrupt has been enabled again. This may mean that not all sentences are read, but the ones that are should be intact. I'd be intested if you had any ideas on this.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Dec 13, 2005 2:54 pm     Reply with quote

This is what's happening in detail, I believe:

You declare the first sentence has been received when you get
the carriage return. Shorty after that (maybe within 10 us), you
disable interrupts in your main loop.

However, there is also a linefeed character at the end of the first
sentence, that comes in. It gets loaded into the 2-deep output fifo
of the UART receiver. This fifo is in hardware. Then the next sentence
starts coming in immediately. The '$' char at the start of that sentence
get shifted in, and put into the 2nd free location in the 2-deep receive
fifo. Now the receive fifo is full. Any further characters that come
in while interrupts are disabled will just roll right over each other in
the input shift register and cause overrun errors. Because you have
the ERRORS directive in your #use rs232() statement, these errors will
be cleared. You'll still lose the chars, though.

While this is going on, you are sending 6 (not 5) characters with your
putc() statement. The UART transmitter will accept 2 characters
without delay. That's because it has the output shift register, and a
1-deep transmit "fifo", which feeds the shift register. So even though
you're sending 6 characters to the transmitter, putc() only has to wait
in a polling loop for 4 of them. Well, if you look at your list of displayed
characters, you'll notice that you're missing exactly 4 chars from the
2nd sentence. But anyway, after a delay of 4 char times, you
re-enable interrupts, and start executing the isr again.

Your code in the RDA_isr() ignores the linefeed left over from the last
sentence. It sees the '$' char from the 2nd sentence, because it was
in the 2nd slot in the hardware receive fifo. But since interrupts
disabled for 4 char times, you lost the next 4 chars after the '$' in the
2nd sentence. So instead of seeing this "$GPRMB", you see this "$B,V,,"
because you have lost the "GPRM".

That's why I suggest that you must do this in a way that doesn't shut
off interrupts.
michaelb



Joined: 28 Nov 2005
Posts: 17

View user's profile Send private message

PostPosted: Tue Dec 13, 2005 3:06 pm     Reply with quote

Thanks very much for that detailed explanation - helped a lot. I'll have a look at doing this as you mentioned beforehand.
michaelb



Joined: 28 Nov 2005
Posts: 17

View user's profile Send private message

PostPosted: Tue Dec 13, 2005 3:15 pm     Reply with quote

Just had a thought - is there a way of clearing the receiver FIFO? Clearing RCREG perhaps? Seems to be an easier solution.
Douglas Kennedy



Joined: 07 Sep 2003
Posts: 755
Location: Florida

View user's profile Send private message AIM Address

PostPosted: Tue Dec 13, 2005 3:23 pm     Reply with quote

It's unlikely you'll get this to work reliably without a circular buffer.
What I've done in the past is to select the sentence of interest ..don't let
anything get into the buffer unless it is $GPGLL for example.
The RDA triggers char by char but until you see $ followed by G P G L L
it doesn't take up space in your buffer.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Dec 13, 2005 3:33 pm     Reply with quote

http://www.ccsinfo.com/forum/viewtopic.php?t=1571&highlight=clear+uart+buffer
michaelb



Joined: 28 Nov 2005
Posts: 17

View user's profile Send private message

PostPosted: Tue Dec 13, 2005 3:49 pm     Reply with quote

Thanks both. I've used the clear_usart_receiver() function and it receives the first sentence fine, but the interrupt does not seem to come back on. I've use d the clear function just before enabling the interrupt again in main(), and I've determined it gets past enabling the interrupt (by printing a char after that statement). I know that the interrupt does not seem to reactivate as I added a putc statement in the ISR to print a every time it's run. This happens before it displays the $GPRMC bit, but not after re-enabling the interrupt again. As i'm using RS232 with 'ERRORS' i assume there are no flags i need to clear to enable reception again?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Dec 13, 2005 4:02 pm     Reply with quote

http://www.ccsinfo.com/forum/viewtopic.php?t=6649&highlight=resetuart
michaelb



Joined: 28 Nov 2005
Posts: 17

View user's profile Send private message

PostPosted: Tue Dec 13, 2005 4:14 pm     Reply with quote

I've tried using that function now, but it hasn't fixed it I'm afraid. I'll tinker some more.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Dec 13, 2005 4:15 pm     Reply with quote

At this point, I feel that I've given all the answers that I can
on this thread.
michaelb



Joined: 28 Nov 2005
Posts: 17

View user's profile Send private message

PostPosted: Tue Dec 13, 2005 4:21 pm     Reply with quote

Thanks very much for you help. I'll let you know if I get anywhere - might try the aforementioned alternative method.
Bart



Joined: 12 Jul 2005
Posts: 49

View user's profile Send private message

PostPosted: Tue Dec 13, 2005 4:21 pm     Reply with quote

Can this example help you ?
http://www.ccsinfo.com/forum/viewtopic.php?t=24716

It is working at my site but it gets/gives only the selected string (not all GPS strings)
_________________
I like Skype (www.skype.com), my username is BplotM
michaelb



Joined: 28 Nov 2005
Posts: 17

View user's profile Send private message

PostPosted: Tue Dec 13, 2005 5:46 pm     Reply with quote

After resetting the CREN bit too, it finally works. Thanks to everyone for your help. I'm off to bed.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group