I'm trying to use Adafruits libaries for GPS and LCD screen. I can get them to each do exactly what I want in separate programs but once I put them in the same program, shit hits the fan. Does anyone know how or if it is possible to figure out what in them is giving me the issue? Thanks
#include <Adafruit_GPS.h> GPS LIBRARY
#include <Adafruit_SSD1306.h> LCD LIBRARY
Just look in those header files and see what pins they use. They are defined their.
Well, it might be helpful to go into more detail of exactly is going wrong? Please quote the entire message that the compiler gives you if it is a compiler message, or what doesn't happen if it fails at runtime.
Given you want to use both GPS and the LCD, do these two devices use any pins that are in common? For example, do they both want to use pin 10 for completely separate things? Then you have to figure out whether you can change pins (possibly not, several of the pins in Arduino are specialized, and if you have shields, the pins tend to be fixed), or you can move one of the devices to something like I2C (such as the LCD).
Another possibility is whether you have enough power for your Arduino, GPS, and LCD. This tends to happen more with motors or lots of LEDs, where you just don't have enough power, and you need to use external power supplies.
magruder13:
I'm trying to use Adafruits libaries for GPS and LCD screen. I can get them to each do exactly what I want in separate programs but once I put them in the same program,...
Maybe copy and paste the error messages?
Complete shot in the dark without having any idea what your error message said, but...
I've noticed that it can be rather picky at times about the order in which the libraries are included. (The list of "#include" at top of sketch.)
Sorry for being so brief. The two devices do not use the same pins, the LCD uses 9-13 with SPI and the GPS uses 2 and 3 with TTL. What I did to create my program was write two programs, one talking to the GPS and saving variables, the other writing to the LCD to print made up variables to the text in the correct location, ect. Then I tried combining the two programs into one final one. With the GPS saving the data and LCD printing it.
Turns out, it all goes to hell, the LCD screen just displays random pixels, the GPS spits out strange data, even when I comment out all print line statements.
I cant figure out what would be the issue that would cause both to mess up at the same time? Here is my code, but please be nice, my coding isn't the best, but I do try to comment everything.
Please note, I combined the two programs, where they are in the same program, but the two codes don't interact with each other. The GPS still gets data and prints to serial monitor, and the LCD still prints dummy values. (well they are supposed to)
#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>
//<SCREEN>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
//DEFINE LCD PINS and CONST
#define OLED_DC 11
#define OLED_CS 12
#define OLED_CLK 10
#define OLED_MOSI 9
#define OLED_RESET 13
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
// Connect the GPS TX (transmit) pin to Digital 3
// Connect the GPS RX (receive) pin to Digital 2
SoftwareSerial mySerial(3, 2);
Adafruit_GPS GPS(&mySerial);
// Set GPSECHO to 'false' to turn off echoing the GPS data to the Serial console
#define GPSECHO false
int tempF = 0;
int speed = 0;
int NESW = 1;
int hour = 5;
int minute = 15;
void setup()
{
// connect at 115200 so we can read the GPS fast enough and echo without dropping chars
Serial.begin(115200);
// 9600 NMEA is the default baud rate for Adafruit MTK GPS's- some use 4800
GPS.begin(9600);
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
// Set the update rate
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); // 1 Hz update rate
//<SCREEN>
// by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
display.begin(SSD1306_SWITCHCAPVCC);
// init done
display.clearDisplay(); // clears the screen and buffer
display.setTextColor(WHITE, BLACK);
delay(1000);
}
uint32_t timer = millis();
void loop() // run over and over again
{
// read data from the GPS in the 'main loop'
char c = GPS.read();
// if you want to debug, this is a good time to do it!
if (GPSECHO)
if (c) Serial.print(c);
// if a sentence is received, we can check the checksum, parse it...
if (GPS.newNMEAreceived()) {
// a tricky thing here is if we print the NMEA sentence, or data
// we end up not listening and catching other sentences!
// so be very wary if using OUTPUT_ALLDATA and trytng to print out data
//Serial.println(GPS.lastNMEA()); // this also sets the newNMEAreceived() flag to false
if (!GPS.parse(GPS.lastNMEA())) // this also sets the newNMEAreceived() flag to false
return; // we can fail to parse a sentence in which case we should just wait for another
}
// if millis() or timer wraps around, we'll just reset it
if (timer > millis()) timer = millis();
// approximately every 2 seconds or so, print out the current stats
if (millis() - timer > 2000) {
timer = millis(); // reset the timer
Serial.print("\nTime: ");
Serial.print(GPS.hour, DEC); Serial.print(':');
Serial.print(GPS.minute, DEC); Serial.print(':');
Serial.println(GPS.seconds, DEC);
Serial.print("Fix: "); Serial.print((int)GPS.fix);
Serial.print(" quality: "); Serial.println((int)GPS.fixquality);
if (GPS.fix) {
UpdateTime(hour, minute);
UpdateSpeed(speed);
// print the display
display.display();
Serial.print("Location: ");
Serial.print(GPS.latitude, 4); Serial.print(GPS.lat);
Serial.print(", ");
Serial.print(GPS.longitude, 4); Serial.println(GPS.lon);
Serial.print("Speed (knots): "); Serial.println(GPS.speed);
Serial.print("Angle: "); Serial.println(GPS.angle);
Serial.print("Altitude: "); Serial.println(GPS.altitude);
Serial.print("Satellites: "); Serial.println((int)GPS.satellites);
}
}
}
void UpdateTime(int hour, int minute){
// display the time
display.setTextSize(2);
if (hour < 10)
display.setCursor(80,0);
else
display.setCursor(68,0);
display.print(hour,DEC);
display.print(":");
if(minute < 10)
display.print("0");
display.print(minute,DEC);
}
void UpdateSpeed(int Speed){
// display speed
if(speed > 99)
display.setCursor(28,17);
else if(speed > 9){
display.setCursor(42,17);
display.fillRect(28, 17, 14, 28,BLACK);
}
else{
display.setCursor(54,17);
display.fillRect(28, 17, 26, 28,BLACK);
}
display.setTextSize(4);
display.print(speed);display.print(" ");
// write MPH below the speed
display.setCursor(55,47);
display.setTextSize(1);
display.print("MPH");
}
Then I suspect your problem is either you are running out of memory and things are being overwritten. Or possibly each is trying to use one of the hardware resources (like the timers), and not working together. For the later, you will need to do a deep dive to see what resources are being used.
So, it compiles and runs but strange things happen?
If both libraries are adafruit then you'd think they probably don't clash with any public variables etc.
Memory is another area to look, as stated.
You can try running a freeram sketch to see what SRAM usage is like.
You have quite a few serial.print statements with string literals so the first thing to do is wrap them up in the F() macro to move them into PROGMEM. Every character is using a byte and you only have 2kB. Your NMEA sentences are all strings, being buffered over serial, so I'd suspect SRAM in the first instance.
Get those string literals into PROGMEM then report back.
It does sound like either memory, timing...or both. How many pixels is your display?
I was using the same Adafruit GPS module & library with a small Nokia GLCD display. After a while the display would just stop updating on me. I switched to an I2C character LCD & it's much more reliable now. Though, the screen still flickers a bit when new NMEA sentences come in.
Have you tried using hardware serial ports?
Also....I don't see you you ever clearing the display in loop(). Typically, that will cause the display just keep writing the new data (pixels, letters, etc...) over the old. Which, eventually just looks like 'random pixels' changing.
tack:
You can try running a freeram sketch to see what SRAM usage is like.You have quite a few serial.print statements with string literals so the first thing to do is wrap them up in the F() macro to move them into PROGMEM. Every character is using a byte and you only have 2kB. Your NMEA sentences are all strings, being buffered over serial, so I'd suspect SRAM in the first instance.
Get those string literals into PROGMEM then report back.
I'm a hardware guy, so programming is not my strong suit. Could you please explain what freeram is?
Also, what is F() macro? I've used macros in assembly programming, but never in arduino.
And again, what is PROGMEM?
1ChicagoDave:
It does sound like either memory, timing...or both. How many pixels is your display?I was using the same Adafruit GPS module & library with a small Nokia GLCD display. After a while the display would just stop updating on me. I switched to an I2C character LCD & it's much more reliable now. Though, the screen still flickers a bit when new NMEA sentences come in.
Have you tried using hardware serial ports?
Also....I don't see you you ever clearing the display in loop(). Typically, that will cause the display just keep writing the new data (pixels, letters, etc...) over the old. Which, eventually just looks like 'random pixels' changing.
Screen is 128x64. I have no tried using hardware serial. I don't clear the display because I have the text background color set as black, so if I write a number over another number it will black out what was there. I know exactly what you're talking about though, I have that issue with another LCD I've used.
magruder13:
I'm a hardware guy, so programming is not my strong suit. Could you please explain what freeram is?
...
And again, what is PROGMEM?
http://arduino.cc/en/Tutorial/Memory
Also, what is F() macro? I've used macros in assembly programming, but never in arduino.
Change:
Serial.print(" quality: ");
to:
Serial.print(F(" quality: "));
That keeps the literal in PROGMEM (of which you have quite a bit) and stops it being copied into RAM.
And again, what is PROGMEM?
I don't clear the display because I have the text background color set as black, so if I write a number over another number it will black out what was there.
Ah.
I haven't played with OLEDs too much. Could you post a photo of what it looks like while in-use?
Also, this hints that if too much else is going on, the Arduino might not fully 'capture' all the GPS output.
// connect at 115200 so we can read the GPS fast enough and echo without dropping chars
When using serial monitor (with your posted version of code), does it still display all the updated GPS information?
1ChicagoDave:
Ah.I haven't played with OLEDs too much. Could you post a photo of what it looks like while in-use?
Also, this hints that if too much else is going on, the Arduino might not fully 'capture' all the GPS output.
// connect at 115200 so we can read the GPS fast enough and echo without dropping charsWhen using serial monitor (with your posted version of code), does it still display all the updated GPS information?
I don't have one of it showing actual variables, but it looks the exact same with numbers.
It displays some GPS information, but its all broken up into unintelligible data.
I'm trying to mod the code now to put my text into PROGMEM now, will update in a few.
I've made some progress, but I still think I'm running out of RAM. I stopped getting jumbled up BS and now I'm getting SOME real data back, but not everything. What else can I do to save RAM? If I go into the GPS library, and only pull out the parts that I NEED (Speed, time, direction) and cut out all the shit I dont need (a lot) will that cut down on my ram usage? I only use the library for 10% of it's use.
Here is my most up to date code:
#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>
//<SCREEN>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
//DEFINE LCD PINS and CONST
#define OLED_DC 11
#define OLED_CS 12
#define OLED_CLK 10
#define OLED_MOSI 9
#define OLED_RESET 13
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
// Connect the GPS TX (transmit) pin to Digital 3
// Connect the GPS RX (receive) pin to Digital 2
SoftwareSerial mySerial(3, 2);
Adafruit_GPS GPS(&mySerial);
// Set GPSECHO to 'false' to turn off echoing the GPS data to the Serial console
#define GPSECHO false
byte tempF = 0;
byte speed = 0;
byte NESW = 1;
byte hour = 5;
byte minute = 15;
void setup()
{
// connect at 115200 so we can read the GPS fast enough and echo without dropping chars
Serial.begin(115200);
// 9600 NMEA is the default baud rate for Adafruit MTK GPS's- some use 4800
GPS.begin(9600);
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
// Set the update rate
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); // 1 Hz update rate
//<SCREEN>
// by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
display.begin(SSD1306_SWITCHCAPVCC);
// init done
display.clearDisplay(); // clears the screen and buffer
display.setTextColor(WHITE, BLACK);
delay(1000);
}
uint32_t timer = millis();
void loop() // run over and over again
{
// read data from the GPS in the 'main loop'
char c = GPS.read();
// if you want to debug, this is a good time to do it!
if (GPSECHO)
if (c) Serial.print(c);
// if a sentence is received, we can check the checksum, parse it...
if (GPS.newNMEAreceived()) {
// a tricky thing here is if we print the NMEA sentence, or data
// we end up not listening and catching other sentences!
// so be very wary if using OUTPUT_ALLDATA and trytng to print out data
//Serial.println(GPS.lastNMEA()); // this also sets the newNMEAreceived() flag to false
if (!GPS.parse(GPS.lastNMEA())) // this also sets the newNMEAreceived() flag to false
return; // we can fail to parse a sentence in which case we should just wait for another
}
// if millis() or timer wraps around, we'll just reset it
if (timer > millis()) timer = millis();
// approximately every 2 seconds or so, print out the current stats
if (millis() - timer > 2000) {
timer = millis(); // reset the timer
Serial.print(F("\nTime: "));
Serial.print(GPS.hour, DEC); Serial.print(F(":"));
Serial.print(GPS.minute, DEC); Serial.print(F(":"));
Serial.print(F("Fix: ")); Serial.print((boolean)GPS.fix);
Serial.print(F("Quality: ")); Serial.println((byte)GPS.fixquality);
if (GPS.fix) {
/*
UpdateTime(hour, minute);
UpdateTemp(tempF);
UpdateSpeed(speed);
UpdateDirection(NESW);
// print the display
display.display();
*/
Serial.print(F("Location: "));
Serial.print(GPS.latitude, 4); Serial.print(GPS.lat);
Serial.print(F(", "));
Serial.print(GPS.longitude, 4); Serial.println(GPS.lon);
Serial.print(F("Speed (knots): ")); Serial.println(GPS.speed);
Serial.print(F("Angle: ")); Serial.println(GPS.angle);
Serial.print(F("Altitude: ")); Serial.println(GPS.altitude);
Serial.print(F("Satellites: ")); Serial.println((int)GPS.satellites);
}
}
}
void UpdateTime(byte hour, byte minute){
// display the time
display.setTextSize(2);
if (hour < 10)
display.setCursor(80,0);
else
display.setCursor(68,0);
display.print(hour,DEC);
display.print(F(":"));
if(minute < 10)
display.print(F("0"));
display.print(minute,DEC);
}
void UpdateTemp(byte Temp){
// display the temperature
display.setCursor(0,0);
display.setTextSize(2);
display.print(Temp);display.print(F("F "));
}
void UpdateSpeed(byte Speed){
// display speed
if(speed > 99)
display.setCursor(28,17);
else if(speed > 9){
display.setCursor(42,17);
display.fillRect(28, 17, 14, 28,BLACK);
}
else{
display.setCursor(54,17);
display.fillRect(28, 17, 26, 28,BLACK);
}
display.setTextSize(4);
display.print(speed);display.print(" ");
// write MPH below the speed
display.setCursor(55,47);
display.setTextSize(1);
display.print(F("MPH"));
}
void UpdateDirection(byte NESW){
// write direction (NESW)
display.setCursor(0,50);
display.setTextSize(2);
switch (NESW) {
case 1:
display.print(F("N"));
break;
case 2:
display.print(F("E"));
break;
case 3:
display.print(F("S"));
break;
case 4:
display.print(F("W"));
break;
}
}
I can see two ways to tackle this. Firstly, use the freeMemory() function from the playground to see how close you are to running out of RAM. If necessary, simplify your sketch until it runs reliably to ensure that freeMemory() is giving you a valid answer before you trust it. (If you have run out of memory then freeMemory() itself, or the mechanisms used to show you the result, might not work correctly.) This will tell you whether you actually have a memory problem.
Secondly, disable everything that writes to the Serial port and only echo the characters received from the GPS port. Unless/until you get sensible data from that, nothing else will work. If you're getting garbage, try simplifying the sketch until you produce something that does produce sensible output. Then reinstate the remaining functionality piece by piece. If it stops working, you can assume it's due to the last thing you changed. By monitoring the amount of free memory at the same time, you can get a clue whether this is simple memory exhaustion, or a logic fault or memory corruption in your code or a library you're using.
As a general rule the linker will omit functions that aren't ever used. Your sketch looks short enough that it shouldn't really be running out of RAM. I would do what PeterH suggests and see if you are indeed near the limit.
PeterH, I followed exactly what you suggested, it worked great, I got a really good handle on how much each instruction uses memory. I now know have a better idea what is wrong.
I went back and started over. I started with the GPS parse code I had, cutting out EVERYTHING I had that would use memory and I didn't need. I got down to having 1175kb of free memory. Then I started putting in my LCD code. The libraries alone, cut me down to only 984kb of free memory. Then I included this line and everything went haywire. My output became erratic, and I'm back to my original problem.
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
So it turns out that the libraries are indeed arguing with each other. Here is the code I have that works, but once you remove the comment marks (//) before the line I have shown above, it stops working.
Output before putting that line in:
20:44
Fix: 1
Qual: 0
Speed: 1.57
Angle: 4.07
Alt: 0.00
Sats: 0
$PGTOP,11,96E
$GPRMC,204422.000,A,4125.6232,N,08805.2409,W,0.98,50.08,151013,,,D4D
$PGTOP,11,6E
$GPRMC,204423.000,A,4125.6228,N,08805.2406,W,0.91,81.52,151013,,,D42freeMemory()=984
Output After putting that line in:
freeµem
$PGTOP,11,26E
$GPRMC,204537.000,A,4125.6133,N,08805.2468,W,0.25,51.896151013,,,D43
$PGTOP,11,26E
$GPRMC,204538.000,A,4125.6134,N,08805.2468,W,0.33,51.89,15101,,,D4C
My code:
#include <Wire.h>
#include <Adafruit_GPS.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <SoftwareSerial.h>
#include <MemoryFree.h>
// Connect the GPS TX (transmit) pin to Digital 3
// Connect the GPS RX (receive) pin to Digital 2
SoftwareSerial mySerial(3, 2);
Adafruit_GPS GPS(&mySerial);
#define GPSECHO true
//DEFINE LCD PINS and CONST
#define OLED_DC 11
#define OLED_CS 12
#define OLED_CLK 10
#define OLED_MOSI 9
#define OLED_RESET 13
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
// 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 enough and echo without dropping chars
// also spit it out
Serial.begin(115200);
Serial.println("Adafruit GPS library basic test!");
// 9600 NMEA is the default baud rate for Adafruit MTK GPS's- some use 4800
GPS.begin(9600);
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); // 1 Hz update rate
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!
#ifdef UDR0
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.
#endif
}
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;
}
}
uint32_t timer = millis();
void loop() // run over and over again
{
// if a sentence is received, we can check the checksum, parse it...
if (GPS.newNMEAreceived()) {
// a tricky thing here is if we print the NMEA sentence, or data
// we end up not listening and catching other sentences!
// so be very wary if using OUTPUT_ALLDATA and trytng to print out data
//Serial.println(GPS.lastNMEA()); // this also sets the newNMEAreceived() flag to false
if (!GPS.parse(GPS.lastNMEA())) // this also sets the newNMEAreceived() flag to false
return; // we can fail to parse a sentence in which case we should just wait for another
}
// if millis() or timer wraps around, we'll just reset it
if (timer > millis()) timer = millis();
// approximately every 2 seconds or so, print out the current stats
if (millis() - timer > 2000) {
timer = millis(); // reset the timer
Serial.print(F("\nfreeMemory()="));
Serial.println(freeMemory());
Serial.println(("\n"));
Serial.print(GPS.hour, DEC); Serial.print(F(":"));Serial.println(GPS.minute, DEC);
Serial.print(F("Fix: ")); Serial.println((int)GPS.fix);
Serial.print(F("Qual: ")); Serial.println((int)GPS.fixquality);
if (GPS.fix) {
Serial.print(F("Speed: ")); Serial.println(GPS.speed);
Serial.print(F("Angle: ")); Serial.println(GPS.angle);
Serial.print(F("Alt: ")); Serial.println(GPS.altitude);
Serial.print(F("Sats: ")); Serial.println((int)GPS.satellites);
}
}
}
Another option I had thought of, was to go into the library, and take out only the code I need, and put it into my program. Wont this eliminate any interference?
// 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!
#ifdef UDR0
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.
#endif
}
Why are you doing this? That means you are calling GPS.read with interrupts off, which is probably not a good thing.
I thought the same thing when I first saw the code. If you look at the end of the setup, it turns interrupts on. That code is directly from the example code that came with the library. I assume its so the interrupt doesn't try to launch before the setup is complete.
