Introduction: Make an Arduino Sketch Smaller

If you've every hit that 32,256 byte maximum on an Arduino Uno and wondered if you could make your sketch smaller instead of upgrading to a Mega, this is for you!

The advice given at the url the compiler gives is good advice, but how exactly does one "make your program shorter"?  There are several ways, and I'll cover using "#if" defines to switch between debugging and production code, and an intro on how to trim down generic libraries. 

Step 1: Conditional Compilation

Conditional compilation is one method you can use to save program space without removing code.  It allows you to turn features on and off as needed.

An example can be found in one of the DHT22 sensor libraries to disable the code that returns float values.  At line 35, 57, and 65 you can see "#if !defined(DHT22_NO_FLOAT)".   By default DHT22_NO_FLOAT is not defined so the code is included.   You can define it in your code, before including the library, to disable these functions if you do not need them and reduce the compiled size slightly like:

 #define DHT22_NO_FLOAT
 #include <DHT22.h>

You can also use #defines in your code to switch out debugging and production code, such as:

//uncomment this for dev mode
//#define DEVMODE 1

void setup(){
#if defined(DEVMODE)
    Serial.begin(115200);
    Serial.print("Devmode ON");
#else
  // Setup the LCD
    myGLCD.InitLCD();
#endif

  i2cbuffer = "";
  i2cOutput = "";
  Wire.begin(I2C_SLAVE);
  Wire.onRequest(sendI2Cdata);
  Wire.onReceive(recvI2Cdata);

#if defined(DEVMODE)
  Serial.println("started");
#endif
}

In this case, I don't initialize the LCD, and later in the code I also don't use LCD drawing functions.  This allows me to test the i2c methods while watching the serial port, but sacrifices the LCD display.

Step 2: Trim Down the Libraries

A more extreme and brute force method of reducing the program size is to make a copy of any large complex libraries and remove any code you aren't going to use.  One of the libraries I'm using is the UTFT lcd library.  It supports several LCDs and has a lot of drawing functions.  Doing this requires a lot of code reading and tracing to determine what you really do have to keep, and some trial and error to get it all to compile and work.  Even after using UTFT's memorysaver.h I was able to save over 5K of additional space by removing all the code to support multiple LCDs and by removing class members that I'm not going to use.  I'll try explain how I went about this so that you can apply it to any library.

First off, I went into the arduino/library folder and made a copy of the UTFT folder and named it "myUTFT", then renamed UTFT.h and UTFT.cpp to myUTFT.h and myUTFT.cpp.
Next, I opened myUTFT.h and myUTFT.cpp in a text editor and replaced all UTFTs with myUTFT.  This gets me a totally new library and class that won't ever cause a conflict in the Arduino environment.

Now the hard part, removing code!  I started with myUTFT.h and started at the top, reading the code.  First I saw there's a list of defines for all the different LCDs and chips supported.  I removed everything except the ones I'm using.  Next there are some "#if defined"' lines for the different micro-controllers supported.  I could have left these as-is, but decided to brute-force everything and removed all but the AVR ones for the Arduino.  Finally, there's a list of class methods, and I removed the ones I'm not using.  UTFT has a note about some undocumented methods, and these appear to be used internally, so I left them.

Now for myUTFT.cpp.  I gave this the same treatment as the .h file, renaming UTFT to myUTFT and removing unneeded defines and functions.  I also removed some overloaded functions.  I only plan on setting colors by the "word" named constants and not by RGB bytes, so I removed "setColor(byte r, byte g, byte b)" and "setBackColor(byte r, byte g, byte b)" functions.  I then read each function and looked for code I don't need, for instance the LCD I'm using has an include files that sets "display_transfer_mode = 8", so I don't need any code that uses any other display_transfer_mode values, so I removed those blocks of code.  I also removed methods for features my lcd does not support, just as the on/off and contrast methods.

Next, I opened every file included under the myUTFT folder and gave them all the same treatment.

Now in your sketch, change the include and class names to match your new library and do a Verify.  My first try I got a lot of compile errors because I removed too much code, or removed a variable definition and missed the code where that variable was used.  The errors will tell you what files and lines to look at, follow them and fix anything it complains about.  This is the advantage of making a copy of the library, I can refer to the original to see what I need to add back.  Once it Verifies, upload the new image and see if it still works.

Step 3: Conclusion

There are other little things you can do to make your code tighter, and many of them will also make the code less readable and self-documenting.  Using fewer variables, more fancy one-liners, fewer libraries and instead just doing the raw code in your own local methods.

Hopeful trimming libraries and using conditional compilation will save you enough space to squeeze in that final feature you want.  Good luck and happy coding!

Arduino Contest

Participated in the
Arduino Contest