Ultimate GPS breakout: Problems with Arduino Fio

Breakout boards, sensors, Drawdio, Game of Life, other Adafruit kits, etc.

Moderators: adafruit_support_bill, adafruit

Ultimate GPS breakout: Problems with Arduino Fio

Postby lax77 » Wed May 09, 2012 4:52 pm

Hi there

I just got my Ultimate GPS breakout and I tested it using the library and sample-sketch called "echo" from http://ladyada.net/products/ultimategps/. The GPS is running very well on my Arduino Uno. However, I would like to have it running on an Arduino Fio at the end... When connecting the GPS to the Fio, using exactly the same Sketch as mentioned before (even when using the slowest update rate), I'm getting weird errors in the serial-data obtained from the Arduino:
- very often, the \newline at the end of a $GP... signal is missing
- sometimes, a "@" is placed directly after $GPGGA
- commas are often replaced by a point or a "/"
(see sample below)

Is there anyone having similar problems with the GPS connected to an Arduino? Might this be a problem of handling too much data using SoftwareSerial? Do you have any idea, how I could get rid of these "wrong" sentences?

Many thanks for your help
lax11

example:
$GPGG@,214818.000,4731.8792,N,00735.0571,E,1,9,0.83,352.1,M,48.0,M,,*56
$GPRMC,214818.000,A,4731.8792,N,00735.0571,E,0.32,63.30,952,A5$GPGGA,214819.000,4731.8792,N,00735.0572,E,1,9,083,352.1,M,48.0,M,,*54
$GPRMC,214819.000,A,4731.8792,N,00735.0572,E,0.34,63.30,952,A5
$GPGGA.214820.000,4731.8792,N,00735.0574,E,1,9,0.83,352.1,M,48.0,M,,*58
$GPRLC,214820.000,A,4731.8792,N,00735.0574,E,0.37,63.30,952,A5$GPGGA,214821.000,4731.8793,N,00735.0575,E,1,9,0.83,352.1,M,48.0,M,,*59
GPRMC,214821.000,A,4731.8793,N,00735.0575,E,0.38,63.30,952,A5
$GPGGA/214822.000,4731.893,N,00735.0577,E,1,9,0.83,352.1,M,48.0,M,,*58
lax77
 
Posts: 3
Joined: Wed May 09, 2012 4:26 pm

Re: Ultimate GPS breakout: Problems with Arduino Fio

Postby adafruit_support_rick » Wed May 09, 2012 5:49 pm

can you please post the exact sample-sketch code you're using?
User avatar
adafruit_support_rick
 
Posts: 2905
Joined: Tue Mar 15, 2011 10:42 am
Location: Buffalo, NY

Re: Ultimate GPS breakout: Problems with Arduino Fio

Postby lax77 » Thu May 10, 2012 1:54 am

Sure, here's the code I used on both, Uno and Fio:
Code: Select all
// Test code for Adafruit GPS modules using MTK3329/MTK3339 driver
//
// This code just echos whatever is coming from the GPS unit to the
// serial monitor, handy for debugging!
//
// Tested and works great with the Adafruit Ultimate GPS module
// using MTK33x9 chipset
//    ------> http://www.adafruit.com/products/746
// Pick one up today at the Adafruit electronics shop
// and help support open source hardware & software! -ada

#include <Adafruit_GPS.h>

// these are for Arduino 1.0
#include <SoftwareSerial.h>
SoftwareSerial mySerial(3, 2);

// Connect the GPS Power pin to 5V
// Connect the GPS Ground pin to ground
// Connect the GPS TX (transmit) pin to Digital 3
// Connect the GPS RX (receive) pin to Digital 2
Adafruit_GPS GPS(&mySerial);

// Set GPSECHO to 'false' to turn off echoing the GPS data to the Serial console
// Set to 'true' if you want to debug and listen to the raw GPS sentences
#define GPSECHO  true

// this keeps track of whether we're using the interrupt
// off by default!
boolean usingInterrupt = false;

void setup() 
{   
  // connect at 115200 so we can read the GPS fast enuf and
  // also spit it out
  Serial.begin(115200);
  Serial.println("Adafruit GPS library basic test!");

  // 9600 NMEA is the default baud rate for MTK - some use 4800
  GPS.begin(9600);
 
  // You can adjust which sentences to have the module emit, below
 
  // uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  // uncomment this line to turn on only the "minimum recommended" data for high update rates!
  //GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
  // uncomment this line to turn on all the available data - for 9600 baud you'll want 1 Hz rate
  //GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_ALLDATA);
 
  // Set the update rate
  // 1 Hz update rate
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
  // 5 Hz update rate- for 9600 baud you'll have to set the output to RMC or RMCGGA only (see above)
  //GPS.sendCommand(PMTK_SET_NMEA_UPDATE_5HZ);
  // 10 Hz update rate - for 9600 baud you'll have to set the output to RMC only (see above)
  //GPS.sendCommand(PMTK_SET_NMEA_UPDATE_10HZ);

  // the nice thing about this code is you can have a timer0 interrupt go off
  // every 1 millisecond, and read data from the GPS for you. that makes the
  // loop code a heck of a lot easier!
  useInterrupt(true);
 
  delay(1000);
}

// Interrupt is called once a millisecond, looks for any new GPS data, and stores it
SIGNAL(TIMER0_COMPA_vect) {
  char c = GPS.read();
  // if you want to debug, this is a good time to do it!
  if (GPSECHO)
    if (c) UDR0 = c; 
    // writing direct to UDR0 is much much faster than Serial.print
    // but only one character can be written at a time.
}

void useInterrupt(boolean v) {
  if (v) {
    // Timer0 is already used for millis() - we'll just interrupt somewhere
    // in the middle and call the "Compare A" function above
    OCR0A = 0xAF;
    TIMSK0 |= _BV(OCIE0A);
    usingInterrupt = true;
  } else {
    // do not call the interrupt function COMPA anymore
    TIMSK0 &= ~_BV(OCIE0A);
    usingInterrupt = false;
  }
}


void loop()                     // run over and over again
{
   // do nothing! all reading and printing is done in the interrupt
}
lax77
 
Posts: 3
Joined: Wed May 09, 2012 4:26 pm

Re: Ultimate GPS breakout: Problems with Arduino Fio

Postby adafruit_support_bill » Thu May 10, 2012 5:11 am

Sounds like you are dropping characters. It may be due to the fact that the FIO runs at half the speed of the UNO. (8 MHz vs 16 MHz)
User avatar
adafruit_support_bill
 
Posts: 16063
Joined: Sat Feb 07, 2009 9:11 am

Re: Ultimate GPS breakout: Problems with Arduino Fio

Postby adafruit_support_rick » Thu May 10, 2012 8:59 am

You are certainly dropping characters. What's happening is that you are reading one character at a time in your Timer_COMPA interrupt routine, and that interrupt is occurring once every millisecond. However, at a rate of 9600 baud, the data are arriving from the GPS at very nearly one character per millisecond.

I'll assume that you have the Arduino IDE correctly configured for your FIO, and so the timer interrupt really is happening every millisecond. What must be happening is that the FIO at 8MHz just can't quite keep up with the 9600 baud data rate. Since the timer is not synchronized with the data, the interrupt drifts until it starts missing data, resulting in the garbage characters you're seeing. Then it drifts a little more, and you start getting good characters again.

Ladyada has essentially the same example code here, except it doesn't use the timer interrupts. Try it and see if it works better for you:
https://raw.github.com/adafruit/Adafruit-MTK3329-GPS-Module-Test-Sketch/master/Adafruit_MTK3329_GPS_Test.pde
User avatar
adafruit_support_rick
 
Posts: 2905
Joined: Tue Mar 15, 2011 10:42 am
Location: Buffalo, NY

Re: Ultimate GPS breakout: Problems with Arduino Fio

Postby lax77 » Mon May 14, 2012 3:35 pm

Thanks driverblock, your explenation makes sense.
I just checked the example code you mentioned which is not using the interrupts and it seems to work fine, as long as I'm requesting the GPS to send RMC-only. When it is set to PMTK_SET_NMEA_OUTPUT_ALLDATA however, I'm still dropping some characters, see example below (again using a rate of 1 Hz).
I decided to use an Arduino Uno for the moment, but if you have any idea how to get the GPS running properly on the Fio (if it is possible at all) I'd be glad to get a hint!

Output example:
Code: Select all
$GPGSA,A,1,,,,,,,,1E
V1,3,,8,,*$RM20,,,,,45,
PV0T0.,.N2$GPGGA,202603.091,,,,,0,0,,,M,,M,,*45
$GPGLL,,,,,202603.091,V,N*77
$GPGSA,A,1,,,,,,,,*E
S1,3,18,,5$RM0.V,,0040,3PV,,,.0.,2$GPGGA,202604.091,,,,,0,0,,,M,,M,,*42
$GPGLL,,,,,202604.091,V,N*70
$GPGSA,A,1,,,,,,,,1E$V0,32,,2,7GRC69,,00145N
PV0T.0,0N2$GPGGA,202605.091,,,,,0,0,,,M,,M,,*43
$GPGLL,,,,,202605.091,V,N*71
$GPGSA,A,1,,,,,,,,,E
G,,3,3,,52
RM25,,,0040,4GPG0M.00K2
$GPGGA,202606.091,,,,,0,0,,,M,,M,,*40
$GPGLL,,,,,202606.091,V,N*72
$GPGSA,A,1,,,,,,,,*E
S,,3,18,,*$RM20,,,,,45,
PV0,0.0.,2$GPGGA,202607.091,,,,,0,0,,,M,,M,,*41
$GPGLL,,,,,202607.091,V,N*73
$GPGSA,A,1,,,,,,,,1E$V,,32,,2,7GRM60,,,0,45,
PV,T0.0.N2$GPGGA,202608.091,,,,,0,0,,,M,,M,,*4E
$GPGLL,,,,,202608.091,V,N*7C
$GPGSA,A,1,,,,,,,,E
$V,,32,,2,7GRC69,,,0145N
PV0,0.,0N2$GPGGA,202609.091,,,,,0,0,,,M,,M,,*4F
$GPGLL,,,,,202609.091,V,N*7D
$GPGSA,A,1,,,,,,,,1E$V,,32,,2,7GRC69,,00145,
PV0T.0,0N2$GPGGA,202610.091,,,,,0,0,,,M,,M,,*47
$GPGLL,,,,,202610.091,V,N*75
$GPGSA,A,1,,,,,,,,*E
S1,3,18,,*$RM20,,,,045,
PV,,,.0.,2$GPGGA,202611.091,,,,,0,0,,,M,,M,,*46
$GPGLL,,,,,202611.091,V,N*74
$GPGSA,A,1,,,,,,,,E
$V,,32,,2,7GRM69,,,0145N
PV0,0.,0N2$GPGGA,202612.091,,,,,0,0,,,M,,M,,*45
$GPGLL,,,,,202612.091,V,N*77
$GPGSA,A,1,,,,,,,,*E
G1,3,32,53
RM0.V,,0040,3PV,0,.0.K2$GPGGA,202613.091,,,,,0,0,,,M,,M,,*44
$GPGLL,,,,,202613.091,V,N*76
$GPGSA,A,1,,,,,,,,1E$S,,3,1,2,*$RM20,,,,,40,
PV0T0.00,2$GPGGA,202614.091,,,,,0,0,,,M,,M,,*43
$GPGLL,,,,,202614.091,V,N*71
$GPGSA,A,1,,,,,,,,*E
S1,3,18,,*$RM20,,,,045,
PV,,,.0.,2$GPGGA,202615.086,,,,,0,0,,,M,,M,,*44
$GPGLL,,,,,202615.086,V,N*76
$GPGSA,A,1,,,,,,
P,3,,,,,3PC18,0015,
P,,,.0.,2
P25.6,,,,4G,,,10V,
S,1,,,,1G,,007,,,,0$G,66,,0.0,1N
$V.,M0N0N2$GPGGA,202616.306,,,,,0,0,,,M,,M,,*4C
$GPGLL,,,,,202616.306,V,N*7E
$GPGSA,A,1,,,,,,,,E
$,,,32,,2,7GRC60,,00141N
PV0,.0N0*2$GPGGA,202617.306,,,,,0,0,,,M,,M,,*4D
$GPGLL,,,,,202617.306,V,N*7F
$GPGSA,A,1,,,,,,,,*E
G1,3,38,51
RM0.V,,0040,BPV,,,.0.K2$GPGGA,202618.306,,,,,0,0,,,M,,M,,*42
$GPGLL,,,,,202618.306,V,N*70
$GPGSA,A,1,,,,,,,,1E
V1,3,18,,*$RM23,,,,,45,
PV,T,.,.N2$GPGGA,202619.306,,,,,0,0,,,M,,M,,*43
$GPGLL,,,,,202619.306,V,N*71
$GPGSA,A,1,,,,,,,,1E$S,,3,1,2,*$RM23,,,,040,5PVG,,.00,2$GPGGA,202620.306,,,,,0,0,,,M,,M,,*49
$GPGLL,,,,,202620.306,V,N*7B
$GPGSA,A,1,,,,,,,,,E
G,,3,32,59
RM0.V,,0040,4PVG0M.00K2$GPGGA,202621.091,,,,,0,0,,,M,,M,,*45
$GPGLL,,,,,202621.091,V,N*77
$GPGSA,A,1,,,,,,,,1E
V1,3,,8,,*$RM20,,,,,45,
PV0T0.0.N2$GPGGA,202622.091,,,,,0,0,,,M,,M,,*46
$GPGLL,,,,,202622.091,V,N*74
$GPGSA,A,1,,,,,,,,1E$V,,32,,2,7GRC69,,0,145N
PV0T0.,0N2$GPGGA,202623.091,,,,,0,0,,,M,,M,,*47
$GPGLL,,,,,202623.091,V,N*75
$GPGSA,A,1,,,,,,,,1E
S1,3,18,,*$RM20,,,,,40,
PV,T,.0.,2$GPGGA,202624.091,,,,,0,
lax77
 
Posts: 3
Joined: Wed May 09, 2012 4:26 pm

Re: Ultimate GPS breakout: Problems with Arduino Fio

Postby adafruit_support_rick » Mon May 14, 2012 4:20 pm

Try changing the loop function to this:
Code: Select all
void loop()                     // run over and over again
{

  while (mySerial.available()) {
      Serial.print((char)mySerial.read());
  }
  while (Serial.available()) {
      mySerial.print((char)Serial.read());
  }
}


I changed the 'if' to 'while'.

If that still doesn't work, try it with the second while loop commented out.
User avatar
adafruit_support_rick
 
Posts: 2905
Joined: Tue Mar 15, 2011 10:42 am
Location: Buffalo, NY

Re: Ultimate GPS breakout: Problems with Arduino Fio

Postby Stephanie » Mon May 14, 2012 6:07 pm

I have a similar setup here, running the Ultimate GPS on a 32u4 at 8MHz. I'm using the interrupt routine and noticed that using only GGA and RMC sentences, I was losing characters. I remedied this with two fixes, while keeping the gps read inside the interrupt routine.

First, I modified the interrupt routine from reading a single byte to using a while-available loop, so it reads all available bytes.

Second, I edited the hardware_serial.cpp file in the Arduino cores and increased the serial buffer by about 50%. Since making those two changes, I have not seen any dropped characters.

Cheers!
User avatar
Stephanie
 
Posts: 286
Joined: Sat Dec 11, 2010 12:17 am
Location: Canada

Re: Ultimate GPS breakout: Problems with Arduino Fio

Postby Soul1986 » Wed May 16, 2012 11:28 am

Stephanie wrote:I have a similar setup here, running the Ultimate GPS on a 32u4 at 8MHz. I'm using the interrupt routine and noticed that using only GGA and RMC sentences, I was losing characters. I remedied this with two fixes, while keeping the gps read inside the interrupt routine.

First, I modified the interrupt routine from reading a single byte to using a while-available loop, so it reads all available bytes.

Second, I edited the hardware_serial.cpp file in the Arduino cores and increased the serial buffer by about 50%. Since making those two changes, I have not seen any dropped characters.

Cheers!


Hi, i have the same problem with arduino fio and GPS adafruit MTK3339, and it runs with this code:


Code: Select all
// Test code for Adafruit GPS modules using MTK3329/MTK3339 driver
//
// This code just echos whatever is coming from the GPS unit to the
// serial monitor, handy for debugging!
//
// Tested and works great with the Adafruit Ultimate GPS module
// using MTK33x9 chipset
//    ------> http://www.adafruit.com/products/746
// Pick one up today at the Adafruit electronics shop
// and help support open source hardware & software! -ada

#include <Adafruit_GPS.h>
#if ARDUINO >= 100
#include <SoftwareSerial.h>
#else
  // Older Arduino IDE requires NewSoftSerial, download from:
  // http://arduiniana.org/libraries/newsoftserial/
#include <NewSoftSerial.h>
// DO NOT install NewSoftSerial if using Arduino 1.0 or later!
#endif

// Connect the GPS Power pin to 5V
// Connect the GPS Ground pin to ground
// If using software serial (sketch example default):
//   Connect the GPS TX (transmit) pin to Digital 3
//   Connect the GPS RX (receive) pin to Digital 2
// If using hardware serial (e.g. Arduino Mega):
//   Connect the GPS TX (transmit) pin to Arduino RX1, RX2 or RX3
//   Connect the GPS RX (receive) pin to matching TX1, TX2 or TX3

// If using software serial, keep these lines enabled
// (you can change the pin numbers to match your wiring):
#if ARDUINO >= 100
  SoftwareSerial mySerial(3, 2);
#else
  NewSoftSerial mySerial(3, 2);
#endif
Adafruit_GPS GPS(&mySerial);
// If using hardware serial (e.g. Arduino Mega), comment
// out the above six lines and enable this line instead:
//Adafruit_GPS GPS(&Serial1);


// Set GPSECHO to 'false' to turn off echoing the GPS data to the Serial console
// Set to 'true' if you want to debug and listen to the raw GPS sentences
#define GPSECHO  true

// this keeps track of whether we're using the interrupt
// off by default!
boolean usingInterrupt = false;
void useInterrupt(boolean); // Func prototype keeps Arduino 0023 happy

void setup() 
{   
  // connect at 115200 so we can read the GPS fast enuf and
  // also spit it out
  Serial.begin(115200);
  Serial.println("Adafruit GPS library basic test!");

  // 9600 NMEA is the default baud rate for MTK - some use 4800
  GPS.begin(9600);
 
  // You can adjust which sentences to have the module emit, below
 
  // uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude
//  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  // uncomment this line to turn on only the "minimum recommended" data for high update rates!
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
  // uncomment this line to turn on all the available data - for 9600 baud you'll want 1 Hz rate
  //GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_ALLDATA);
 
  // Set the update rate
  // 1 Hz update rate
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
  // 5 Hz update rate- for 9600 baud you'll have to set the output to RMC or RMCGGA only (see above)
//  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_5HZ);
  // 10 Hz update rate - for 9600 baud you'll have to set the output to RMC only (see above)
  //GPS.sendCommand(PMTK_SET_NMEA_UPDATE_10HZ);

  // the nice thing about this code is you can have a timer0 interrupt go off
  // every 1 millisecond, and read data from the GPS for you. that makes the
  // loop code a heck of a lot easier!
  useInterrupt(false);
 
  delay(1000);
}

// Interrupt is called once a millisecond, looks for any new GPS data, and stores it
SIGNAL(TIMER0_COMPA_vect) {
  char c = GPS.read();
  // if you want to debug, this is a good time to do it!
  if (GPSECHO)
    if (c) UDR0 = c; 
    // writing direct to UDR0 is much much faster than Serial.print
    // but only one character can be written at a time.
}

void useInterrupt(boolean v) {
  if (v) {
    // Timer0 is already used for millis() - we'll just interrupt somewhere
    // in the middle and call the "Compare A" function above
    OCR0A = 0xAF;
    TIMSK0 |= _BV(OCIE0A);
    usingInterrupt = true;
  } else {
    // do not call the interrupt function COMPA anymore
    TIMSK0 &= ~_BV(OCIE0A);
    usingInterrupt = false;
  }
}


void loop()                     // run over and over again
{
   // do nothing! all reading and printing is done in the interrupt
    if (mySerial.available()) {
      Serial.print((char)mySerial.read());
  }
  if (Serial.available()) {
      mySerial.print((char)Serial.read());
  }

}


But its only 1hz and RMC only. Can you explain how modificate serial buffer speed and interrupt routine?

I would like use 5 hz without drop character. How can i do it? I used GPS em406a i had no problem with it, i dont know why with this gps have problems..

THanks
Soul1986
 
Posts: 4
Joined: Wed May 16, 2012 11:09 am

Re: Ultimate GPS breakout: Problems with Arduino Fio

Postby Stephanie » Wed May 16, 2012 7:47 pm

Hi Soul,

The change I made to the interrupt routine is very simple, but I don't know if it will work correctly with the Adafruit library. I'm not using that library. For space reasons (i've run out of flash in the 32u4) I'm using TinyGPS but have stripped it down to the barest minimum in order to pack in all the features I want.

Anyhow the change was just to wrap the read() inside a while(available()) function. Looking at your code, I am pretty sure this will work for you, but I haven't tested it:
Code: Select all
SIGNAL(TIMER0_COMPA_vect) {
  while(mySerial.available()) {
    char c = GPS.read();
    // if you want to debug, this is a good time to do it!
    if (GPSECHO)
      if (c) UDR0 = c; 
      // writing direct to UDR0 is much much faster than Serial.print
      // but only one character can be written at a time.
  }
}


What this change does is make it so that every time the interrupt is called, it will read all the available characters in the serial buffer. The original layout had it only reading a single character at a time. So if there were two or three characters in the buffer, it would take 2 or 3 milliseconds to read them, during which time more characters may have been received, until finally your buffer overflows and you lose characters.

The trade-off is that it will now take more time for the interrupt routine to finish its task, so that may cause other time-sensitive functions to be delayed and starved for cycles, if too much time is spent in the ISR.

So for the other half of this, in order to increase the serial buffer size, you need to modify a file in your Arduino core. I learned about this trick from one of Ladyada's tutorials (see here: http://www.ladyada.net/library/arduino/hacks.html ), but in that case she was showing how to free up memory by making the serial buffer smaller. You can do the opposite though, sacrifice some of your available RAM and make the serial buffer larger.

The file you want is called HardwareSerial.cpp but where it's located will vary depending on your installation. In my case it is in the Arduino folder, under hardware/arduino/cores/arduino/HardwareSerial.cpp

In that file, around line 40, you'll find this bit of code:
Code: Select all
#if (RAMEND < 1000)
  #define SERIAL_BUFFER_SIZE 24
#else
  #define SERIAL_BUFFER_SIZE 96
#endif


The actual numbers may be different in your case, because I've been tinkering with mine. The 32u4 has 2.5k of RAM so it's the second #define that comes into play, and in this case it's saying that 96 bytes will be allocated as serial buffer. You can make this number bigger or smaller. If you make it bigger, your sketch will have less ram for its own use, but your serial buffer will hold more characters before overflowing.

Between these two changes, I have not noticed any lost characters using the MTK3339 gps module with my 32u4.

Caveat: I am only using 1hz updates, but I am getting RMC and GGA sentences. If you're doing RMC only, then 5hz should be ok.

Cheers!
User avatar
Stephanie
 
Posts: 286
Joined: Sat Dec 11, 2010 12:17 am
Location: Canada

Re: Ultimate GPS breakout: Problems with Arduino Fio

Postby Stephanie » Wed May 16, 2012 8:32 pm

Oops I just realized I made a mistake re. the serial buffer. The instructions I gave were for tweaking the size of the hardware serial buffer.

If you're using arduino 1.0 you want to modify the SoftwareSerial.h file which is in the Arduino app folder, under Libraries/SoftwareSerial/SoftwareSerial.h

There is just one line to change, where it says:
#_SS_MAX_RX_BUFF 64

Just increase the 64 to something larger, like 96 or 128.

If you're using NewSoftSerial, then it will be in your NewSoftSerial library, but I don't have that library so I can't point you to the exact file/line.

Cheers!
User avatar
Stephanie
 
Posts: 286
Joined: Sat Dec 11, 2010 12:17 am
Location: Canada

Re: Ultimate GPS breakout: Problems with Arduino Fio

Postby adafruit_support_rick » Wed May 16, 2012 8:50 pm

Before you pick a value like 96 for _SS_MAX_RX_BUFF, make sure it's not expected to be a power of 2.

Serial drivers typically want the sizes of their circular buffers to have to be powers of 2. The next biggest one after 64 would be 128.
User avatar
adafruit_support_rick
 
Posts: 2905
Joined: Tue Mar 15, 2011 10:42 am
Location: Buffalo, NY

Re: Ultimate GPS breakout: Problems with Arduino Fio

Postby Stephanie » Wed May 16, 2012 9:08 pm

Oh I didn't know that - thanks for pointing that out, Driverblock.

I've had the hardware serial buffer set to 96 on my 32u4 without any trouble (yet). What sort of problem might it cause, if the buffer isn't an expected size?
User avatar
Stephanie
 
Posts: 286
Joined: Sat Dec 11, 2010 12:17 am
Location: Canada

Re: Ultimate GPS breakout: Problems with Arduino Fio

Postby adafruit_support_rick » Thu May 17, 2012 8:32 am

Stephanie - I just had a look at SoftwareSerial, and 96 is OK, although it will slow down the receiver interrupts a little bit. Here's a snippet of code from the ISR:
Code: Select all
    // if buffer full, set the overflow flag and return
    if ((_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF != _receive_buffer_head)
    {
      // save new data in buffer: tail points to where byte goes
      _receive_buffer[_receive_buffer_tail] = d; // save new byte
      _receive_buffer_tail = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF;
    }
_receive_buffer is a circular buffer, meaning that the ISR will write characters into it, one at a time, until it reaches the end of the buffer. At that point, it wraps around and starts writing to the beginning of the buffer again.
The driver maintains two index variables, a "head" and a "tail". Data is added at the tail offset as it is received, and removed at the head offset when your program does a read.

As you can see from the code above, new characters go into _receive_buffer[_receive_buffer_tail], and then _receive_buffer_tail is incremented by 1. When _receive_buffer_tail reaches _SS_MAX_RX_BUFF, it needs to be reset to 0 to wrap around to the start of the circular buffer.

Whoever wrote this driver was careful enough to use the modulo operator '%' to handle the wraparound (i.e., 96 % 96 = 0), but you will see other drivers that rely on the buffer length being a power of 2 so that they can handle the wraparound with a bitwise AND. For example:
Code: Select all
     _receive_buffer_tail = (_receive_buffer_tail + 1) & (_SS_MAX_RX_BUFF-1);

The modulo operation is going to be much slower than a simple AND, since it involves a divide and a subtract. However, assuming the compiler is smart enough to automatically substitute the AND when the divisor is a power of 2, using the modulo operator is a better approach, since it won't break if some other value is used for the buffer length.

As for what happens when it DOES break? Well, you essentially wind up with a short buffer. For instance, 96-1 = 95 = 1011111. So, the head and tail would wrap around at 32 instead of 96. If you chose an odd number, like 93, for some reason, then your effective buffer length would be one, because you'd be ANDing 93-1 = 92 = 1011100. Head and tail would wrap to zero after being incremented to 1.
User avatar
adafruit_support_rick
 
Posts: 2905
Joined: Tue Mar 15, 2011 10:42 am
Location: Buffalo, NY

Re: Ultimate GPS breakout: Problems with Arduino Fio

Postby Stephanie » Thu May 17, 2012 9:14 am

Driverblock, thank you for that detailed explanation. I read up a bit on ring buffers yesterday but didn't find any information on the dangers of setting the buffer size incorrectly.

I just had a look in the Arduino core files and it looks like HardwareSerial.cpp uses the same modulo process that you found in SoftSerial, so the '96' I was using should be safe (albeit slower) in both cases.

I'll remember though to use powers of 2 in the future when dealing with ring buffers.
User avatar
Stephanie
 
Posts: 286
Joined: Sat Dec 11, 2010 12:17 am
Location: Canada

Next

Return to Other Adafruit products

Who is online

Users browsing this forum: theserge and 4 guests

Stuff to buy from the Adafruit store and links to product documentation!


New Products [105]

Raspberry Pi[80]
 
FLORA[23]
 
Bunnie Studios[9]
 
FPGA[1]
 
mbed[11]
Arduino[60]
 
NETduino[14]
 
BeagleBone[24]
 
Android[6]
 
XBee[10]
More Dev Boards[30]


 
BoArduino[8]
 
SpokePOV[4]
 
TV-B-Gone[4]
 
MiniPOV[3]
 
SIM reader[3]
 
Microtouch[5]
 
Clocks & Watches[18]
 
Drawdio[4]
 
Brain Machine[1]
 
Game of Life[2]
 
MintyBoost[2]
More DIY Kits[16]


 
MaKey MaKey[3]
 
Tweet-a-Watt[5]
 
Young Engineers[33]
 
Discover Electronics[2]
 
Snap Circuits[4]
 
littleBits[3]
 
Project packs[8]


 
Breakout Boards[33]
LCDs & Displays[48]
Components & Parts[70]
Batteries & Power[49]
EL Wire/Tape/Panel[52]
LEDs[111]
 
Wireless[14]
Cables[61]
 
Lasers[6]
Sensors/Parts[145]
 
Enclosures/Cases[11]
 
Solar[11]
 
RFID / NFC[13]
Prototyping[70]
 
iDevices[13]
Tools[71]
 
Wearables[39]
 
CNC[37]
 
Robotics[29]
 
3D printing[1]
 
Materials[24]


 
Stickers[41]
 
Skill badges[55]
 
Books[25]
 
Circuit Playground[7]
 
Gift Certificates[4]