Sketch too big. Trying to use GPS, Barometer, OLED, RTC & SD logging

Hi Arduino.cc forum! First time posting, hope I do it right for you all :slight_smile:

I am running out of program storage space on my Arduino Uno project, have done heaps of Googling with no luck and would like your assistance.

There are 9 libraries included in the sketch for all the components. I am guessing the compiler will only include code that is actually used. i.e. not including unused functions etc? maybe not though.

Is this project simply surpassing the limitations of the Arduino Uno?
OR this project is possible and my coding needs to be optimized (if so, please assist)?
OR something else entirely I haven’t considered!

Any help, ideas, thoughts, comments, suggestions would be greatly appreciated!!

Thanks :smiley:

Project Components:

  • Arduino Uno
  • Adafruit Ultimate GPS Breakout - 66 channel w/10 Hz updates - Version 3
  • Barometric Pressure Sensor MS5637-02BA03 - (prod page link)
  • 128x128 OLED Module - (prod page link)
  • Duinotech DataLogger Shield - 16gb SD Card - onboard RTC

Error:

Sketch uses 34,656 bytes (107%) of program storage space. Maximum is 32,256 bytes.
Global variables use 1,824 bytes (89%) of dynamic memory, leaving 224 bytes for local variables. Maximum is 2,048 bytes.
processing.app.debug.RunnerException: Sketch too big; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing it.
	at cc.arduino.Compiler.size(Compiler.java:336)
	at cc.arduino.Compiler.build(Compiler.java:159)
	at processing.app.SketchController.build(SketchController.java:643)
	at processing.app.SketchController.exportApplet(SketchController.java:668)
	at processing.app.Editor$DefaultExportHandler.run(Editor.java:2189)
	at java.lang.Thread.run(Thread.java:745)
Sketch too big; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing it.

Sketch:

#include <SPI.h> //for OLED and SD
#include <Wire.h> //for Baro and RTC


// for SD card . (needs to be declared first or else OLED lib creates new 'File' class = issues!
#include <SD.h>
const int sdChipSelect = 10;
File logfile;
String logfileName = "log_12.csv";
Sd2Card card;


//for OLED
#include <FTOLED.h>
#include <fonts/SystemFont5x7.h>
const byte pin_cs = 7;
const byte pin_dc = 8;
const byte pin_reset = 9;
OLED oled(pin_cs, pin_dc, pin_reset);
OLED_TextBox box(oled);



//for GPS
#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>
SoftwareSerial myGpsSerial(3, 2);
Adafruit_GPS GPS(&myGpsSerial);
boolean usingInterrupt = false;
void useInterrupt(boolean); // Func prototype keeps Arduino 0023 happy

//for Barometer
#include <BaroSensor.h>
float baroGroundPressure = 0.00;

//for Real Time Clock (RTC) on SD card board
#include "RTClib.h"
RTC_DS1307 rtc;


void setup() {
  //for OLED
  oled.begin();
  oled.selectFont(SystemFont5x7);
  box.setForegroundColour(BLUE);
  box.println(F(" ===SYSTEM START==="));
  box.setForegroundColour(LIMEGREEN);
  box.println(F("OLED Setup"));

  //for GPS
  GPS.begin(9600);
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
  GPS.sendCommand(PGCMD_ANTENNA);
  useInterrupt(true);
  box.println(F("GPS Setup"));

      
  //for Baro
  BaroSensor.begin();
  box.println(F("Barometer Setup"));


  //for SD
  if (!card.init(SPI_HALF_SPEED, sdChipSelect)) {
    box.println(F("SD Card init failed"));
  } else {
    box.println(F("SD Card init success"));
  }  
  
  //for logfile on SD
  SD.begin(sdChipSelect);
  logfile = SD.open(logfileName, FILE_WRITE); 

  if (logfile) {
    logfile.println(F("millis,time,lat,lon,gAlt,sats,angle,speed,pressure,alti,temp"));  
    logfile.close();
    box.print(F("Logging to:"));
    box.print(logfile);
    tone(4,2500,1000);
  } else {
    tone(4,200,1000);
    box.println(F("X - Couldnt create log"));
  }
  
//
  //for RTC
  if (! rtc.begin()) {
    box.setForegroundColour(RED);
    box.println("RTC Fail: Couldnt Find");
    while (1);
  }else if (! rtc.isrunning()) {
    box.setForegroundColour(RED);
    box.println("RTC Fail: Couldnt Init");
  }else{
    box.setForegroundColour(GREEN);
    box.println("RTC Init Success");
    DateTime rtcNow = rtc.now();
    box.print(":" + rtcNow.minute() );
    if (rtcNow.hour()>=12) {box.println("pm");} else {box.println("am");};
  }

  //test speaker
  box.println(F("Speaker Test"));
  tone(4, 2000, 500);
    
  //loading countdown...
  box.print(F("Loading"));
  for (int i=3;i>0;i--) {
    box.print(F("."));
    delay(500);
  }
  delay(1000);
  oled.clearScreen();
  
}



// GPS Interrupt is called once a millisecond, looks for any new GPS data, and stores it
SIGNAL(TIMER0_COMPA_vect) {
  char c = GPS.read();
}
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() {
  
  // put your main code here, to run repeatedly:
    // if a GPS sentence is received, we can check the checksum, parse it...
    if (GPS.newNMEAreceived()) {  
      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();

    if (millis() - timer > 1000) { 
      timer = millis(); // reset the timer
      box.reset();
      box.setForegroundColour(BLUE);
      box.println(F("=== SENSOR VALS ==="));
      oled.drawString(90,0,String(millis()),GREEN,BLACK);
      
      
      if (GPS.fix) {
        box.setForegroundColour(DEEPPINK);
        box.print(F("Loc:"));
        box.print(GPS.latitudeDegrees, 5);
        box.print(F(",")); 
        box.println(GPS.longitudeDegrees, 5);
        box.print(F("Sats: "));
        box.println(GPS.satellites);
        box.print(F("Speed: "));
        box.print(GPS.speed * 1.852);
        box.println(F("km/h"));
        box.print(F("Angle: "));
        box.println(GPS.angle);
        box.print(F("Alt: "));
        box.print(GPS.altitude); box.println(F("m"));
      }else{
        box.setForegroundColour(RED);
        box.print(F("No GPS FIX  "));
        box.println(millis());
      }
      
  
      float temp;
      float pressure;
      if(!BaroSensor.getTempAndPressure(&temp, &pressure)) {
        box.setForegroundColour(RED);
        box.println(F("Baro Error :"));
        box.println(BaroSensor.getError());
      } else {
        //Serial.println("Ground Pressure: " + String(baroGroundPressure));
        if (baroGroundPressure==0.00) {
          baroGroundPressure = pressure;
          box.setForegroundColour(RED);
          box.println(F("Ground Press Reset"));
          delay(1000);
          oled.clearScreen();
        }
        
        box.setForegroundColour(WHITE);
        box.print(F("Temp: "));
        box.print(temp); 
        box.print(F("C\nPress: "));
        box.println(pressure);
        box.print(F("Alt: "));
        //box.print(getAlt(pressure, int(temp*100))); box.println(F("m"));
        box.print(((pow((baroGroundPressure / pressure), 1/5.257) - 1.0) * (temp + 273.15)) / 0.0065);
        
      }


      
      logfile = SD.open(logfileName, FILE_WRITE); 
      logfile.print(millis());
      logfile.print(",");
      logfile.print("");//time
      logfile.print(GPS.year); 
      logfile.print("-");
      logfile.print(GPS.month); 
      logfile.print("-");
      logfile.print(GPS.day); 
      logfile.print(" ");
      logfile.print(GPS.hour); 
      logfile.print(":");
      logfile.print(GPS.minute); 
      logfile.print(":");
      logfile.print(GPS.seconds); 
      logfile.print(",");
      logfile.print(GPS.latitudeDegrees, 5);
      logfile.print(",");
      logfile.print(GPS.longitudeDegrees, 5);
      logfile.print(",");
      logfile.print(GPS.altitude);
      logfile.print(",");
      logfile.print(GPS.satellites);
      logfile.print(",");
      logfile.print(GPS.angle);
      logfile.print(",");
      logfile.println(GPS.speed);
      logfile.close();
      tone(4,2500,30);
  }

  
    
}

Rather than write one big mega program with everything in it, write it in stages so you can see where the memory goes.

Think of it as a test program, testing the harware in stages.

First the bare UNO, flash the LED.

Add the OLED display, write a simple message to screen.

Etc .......

Hey Srnet,

Thanks for your reply. Individually the code for each component works flawlessly. I can even add it all except the SD logging or all except the OLED successfully.

The problem is when i try to add it all that i run out of program storage space.

Any more ideas?

brentxi:
Any more ideas?

Use a Mega.

There are some of the libraries that could be replaced for smaller more efficient ones, but your still going to be close to the limit.

You might possibly get it all working and maybe even reliable, but when you come to 'enhance' the software next week you will be back on here saying how do I cut the space some more.

Code optimizing is the solution. Your sketch doesn’t seems to big and complicated.
For an example, you can save some space with removing duplicity strings like: “RTC Fail: Couldnt Find” and “RTC Fail: Couldnt Init”, and to use flash memory of course. Consider if it wouldn’t be better to print it per parts.
Another one, the comma at different places:

 box.print(F(","));
 logfile.print(",");
 logfile.print(",");

and other similar characters too.

If the code will grow, you could go to bigger Arduino like Meaga or like mine is (128kB flash and 16kB SRAM): http://forum.arduino.cc/index.php?topic=277260.0

ok so there is definitely a LOT of future development planned. this was the basic "test all components" sketch that didn't even start the full development.

at this stage i'll most likely move to a much higher capacity board. maybe the Arduino 101 or... would love some ideas?

would love some ideas?

Would you?

Get rid of crap like this! There is NOTHING that the String class can do that c-style strings can not.

String logfileName = "log_12.csv";
      oled.drawString(90,0,String(millis()),GREEN,BLACK);

ltoa() can convert a long to a string, with FAR less overhead that String.

at this stage i’ll most likely move to a much higher capacity board. maybe the Arduino 101 or… would love some ideas?

You certainly could, but you really don’t have to… all you need to do is:

* Use F macros for “double-quoted” strings,
* Don’t use the String class
* Don’t use the RTC lib (the GPS has an internal RTC),
* Connect the GPS to Serial (pins 0 & 1, you’re not using it),
* Remove scrolling text from FTOLED library (there must be a better library :P), and
* Use a tightly-configured NeoGPS

That’s all! :smiley:

Your original sketch takes 36802 bytes of program space and 1926 bytes of RAM.
The modified sketch takes 32326 bytes of program space and 1273 bytes of RAM. It fits!

BTW, the modified sketch below has the correct loop structure, where the display is updated after a new GPS fix is received. Running off the GPS 1Hz updates is much more accurate than the millis() timer, and does the time-consuming work just when the GPS quits sending characters for a while.

Cheers,
/dev


#include <SPI.h> //for OLED and SD
#include <Wire.h> //for Baro and RTC


// for SD card . (needs to be declared first or else OLED lib creates new 'File' class = issues!

#include <SD.h>
const int sdChipSelect = 10;
File logfile;
const char logfileName[] = "log_12.csv";
Sd2Card card;

//for OLED
#include <FTOLED.h>
#include <fonts/SystemFont5x7.h>
const byte pin_cs = 7;
const byte pin_dc = 8;
const byte pin_reset = 9;
OLED oled(pin_cs, pin_dc, pin_reset);
OLED_TextBox box(oled);


//for GPS
#include <NMEAGPS.h>
NMEAGPS gps;
HardwareSerial & gps_port = Serial; // just an alias

//for Barometer
#include <BaroSensor.h>
float baroGroundPressure = 0.00;

void setup() {
  //for OLED
  oled.begin();
  oled.selectFont(SystemFont5x7);
  box.setForegroundColour(BLUE);
  box.println(F(" ===SYSTEM START==="));
  box.setForegroundColour(LIMEGREEN);
  box.println(F("OLED Setup"));

  //for GPS
  gps_port.begin(9600);
  gps_port.print( F("$PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28\r\n"
                    "$PMTK220,1000*1F\r\n") ); // RMC+GGA and 1Hz
  box.println(F("GPS Setup"));


  //for Baro
  BaroSensor.begin();
  box.println(F("Barometer Setup"));

  //for SD
  if (!card.init(SPI_HALF_SPEED, sdChipSelect)) {
    box.println(F("SD Card init failed"));
  } else {
    box.println(F("SD Card init success"));
  }

  //for logfile on SD
  SD.begin(sdChipSelect);
  logfile = SD.open(logfileName, FILE_WRITE);

  if (logfile) {
    logfile.println(F("millis,time,lat,lon,gAlt,sats,angle,speed,pressure,alti,temp"));
    box.print(F("Logging to:"));
    box.println(logfileName);
    tone(4,2500,1000);
  } else {
    tone(4,200,1000);
    box.println(F("X - Couldnt create log"));
  }

  //test speaker
  box.println(F("Speaker Test"));
  tone(4, 2000, 500);

  //loading countdown...
  box.print(F("Loading"));
  for (int i=3;i>0;i--) {
    box.print(F("."));
    delay(500);
  }
  box.println();
  delay(1000);
  oled.clearScreen();

}



void loop() {

    while (gps.available( gps_port )) {
      gps_fix fix = gps.read();

      box.reset();
      box.setForegroundColour(BLUE);
      box.println(F("=== SENSOR VALS ==="));
      char currentMS[12];
      ltoa( millis(), currentMS, 10 );
      oled.drawString(90,0,currentMS,GREEN,BLACK);

      if (fix.valid.location) {
        box.setForegroundColour(DEEPPINK);
        box.print(F("Loc:"));
        box.print( fix.latitude(), 5 );
        box.print(F(","));
        box.println( fix.longitude(), 5 );
        #ifdef GPS_FIX_SATELLITES
          box.print(F("Sats: "));
          box.println( fix.satellites );
        #endif
        box.print(F("Speed: "));
        box.print( fix.speed_kph() );
        box.println(F("km/h"));
        box.print(F("Angle: "));
        box.println( fix.heading() );
        box.print(F("Alt: "));
        box.print( fix.altitude() );
        box.println(F("m"));
      }else{
        box.setForegroundColour(RED);
        box.print(F("No GPS FIX  "));
        box.println(millis());
      }


      float temp;
      float pressure;
      if(!BaroSensor.getTempAndPressure(&temp, &pressure)) {
        box.setForegroundColour(RED);
        box.print(F("Baro Error :"));
        box.println(BaroSensor.getError());
      } else {
        //box.print(F("Ground Pressure: "));
        //box.println(baroGroundPressure);
        if (baroGroundPressure==0.00) {
          baroGroundPressure = pressure;
          box.setForegroundColour(RED);
          box.println(F("Ground Press Reset"));
          delay(1000);
          oled.clearScreen();
        }

        box.setForegroundColour(WHITE);
        box.print(F("Temp: "));
        box.print(temp);
        box.print(F("C\nPress: "));
        box.println(pressure);
        box.print(F("Alt: "));
        //box.print(getAlt(pressure, int(temp*100)));
        //box.println(F("m"));
        box.print(((pow((baroGroundPressure / pressure), 1/5.257) - 1.0) * (temp + 273.15)) / 0.0065);

      }



      logfile.print(millis());
      logfile.print(',');
      //time
      logfile.print( fix.dateTime.year);
      logfile.print('-');
      logfile.print(fix.dateTime.month);
      logfile.print('-');
      logfile.print(fix.dateTime.day);
      logfile.print(' ');
      logfile.print(fix.dateTime.hours);
      logfile.print(':');
      logfile.print(fix.dateTime.minutes);
      logfile.print(':');
      logfile.print(fix.dateTime.seconds);
      logfile.print(',');
      logfile.print(fix.latitude(), 5);
      logfile.print(',');
      logfile.print(fix.longitude(), 5);
      logfile.print(',');
      logfile.print(fix.altitude());
      logfile.print(',');
      #ifdef GPS_FIX_SATELLITES
        logfile.print(fix.satellites);
        logfile.print(',');
      #endif
      logfile.print(fix.heading());
      logfile.print(',');
      logfile.println(fix.speed_kph());

      // Flush the logfile once every 8 seconds
      //     (avoids data loss at power-down)
      if ((fix.dateTime.seconds % 8) == 0)
        logfile.flush();

      tone(4,2500,30);
  }



}

Thank you /dev!

The Sketch is working perfectly now and i am able to successfully test all components together. You have saved me a huge amount of hassle, thank you :smiley:

You don't have big arrays, you are using F() where you can, and this isn't a runtime problem, so runtime fixes won't help. It's just a lot of code.

At the end of the day, you can't shovel 10 pounds of whatever into a 5-pound bag. You may simply need to get an arduino with more memory.

brentxi:
You have saved me a huge amount of hassle, thank you :smiley:

That may be true, but only just, and only for the moment. In view of your intentions, what he has really done is to simply put off the inevitable. While you are right in that the IDE picks what it needs out of libraries, libraries are still libraries, and you have a lot of them. A Uno is not up to the job, and you have already had the best advice you will ever get - Mega.

brentxi:
ok so there is definitely a LOT of future development planned.. would love some ideas?

Thanks for the advice everyone :slight_smile: