- Buy a bigger chip. Are you trying to compile a large project for an ATMega328? Go with a Pi Pico ($4) and save yourself the headache. If you need the program to “just work” go overkill with a Teensy 4.1 that comes with 8Mb of flash and plenty of extra pins. Teensy has just about every library and works in the Arduino IDE so it’s a very little change to the development process.
- Strings use a TON of memory. Try removing any
Serial.printlns to see how much memory you save. Likewise, every character takes up a byte, so the simple act of shortening your messages is preferable to long sentences.
- Free 2KB if you remove the bootloader. Use an in-circuit programmer like the USBASP ($10) to overwrite the bootloader. (How to program using a USBASP in the Arduino IDE)
- Use appropriate data types. (compiler may not always optimize for compile size) It’s common to use unsigned data types for variables you know will never be negative:
- uint8_t (unsigned 8 bit integer) will store between 0 and 255
- uint16_t (unsigned 16 bit integer) will store between 0 and 65536
- uint32_t (unsigned 32 bit integer) will store between 0 and 4294967296
- uint64_t (unsigned 64 bit integer) will store between 0 and 18446744073709551616
- Do you need longs doubles, floats? Can you use an unsigned integer based data type? Just be careful about the order of operation. i.e. (number / 255) * 128 = (number * 128) / 255
- Don’t repeat code. The compiler can only do so much. Use for loops for redundant operations. If that seems too hard, store/write results to an array.
- Exception: don’t pull out inline functions that speed up something. Or go for it, I don’t care. You decide.
- Learn what a pointer is and pass by reference when appropriate.
- Are you implementing something dumb? Imagine if you proposed your approach on the forums. Would some old guy rip you a new one? Are you trying to implement some sort of virtual buffer for a screen or some gigantic matrix operation? Delete it, refactor it, or just take the slightly slower operation time.
- Upload initialized arrays/small data to EEPROM and then remove from your code.
- Store large data in an SD card. If your project uses audio, bitmaps, etc. just store it in an SD and stream it in instead. Or the opposite, if your image is small enough to convert to an array of bits (for black/white) or uint16_t colors and you can exclude the SD library. (It’s a big boy, like 2KB flash compiled for basic features)
- Don’t use the SD library. 2KB goes a long way. If you MUST use an SD reader, go with the Fat16 library instead. It limits the file structure options on the SD card, but makes compile size smaller.
- Use bitshift operators. Some cool things you can do with bitshift operators include: testing individual bits of any data type, inverting a number with a single operation, storing several numbers inside a bigger number, etc. Learn how to use unions too, they’re pretty handy!
- Ask on the Forums! Post your code and ask for help. Sure you’ll get destroyed by people who know more than you, but hey your code will work better and you’ll probably learn something.
“Pain in the ***” Fixes:
- Remove floating point code. Before you start bitching, I know. I had arctangent functions, sin/cos, resistance calculation with floats, hue saturation value -> rgb565 stuff, etc. Doing any unit circle stuff? Store pre-calculated values for a quadrant of the circle in EEPROM (sin, angles, data, distance)
- Profile your code. If you’re still trying to cram a ridiculous amount of code into that poor chip and have no idea what’s causing the compile size bloat, it’s time to upgrade your build process and profile your code.
- Move your code over to use PlatformIO, either building from CLion, the Atom editor, via command line, etc.
- Once you’ve done that, PlatformIO has an Inspection option that will build your code and then show you visually what your biggest functions and symbols are. Focus optimization efforts on the biggest contributors and you’ll get to where you need to be.
- Optimize a library‘s size by going through and removing what you don’t need. (Not really recommended because it makes working on the project later a big pain, especially if something breaks due to your changes). Only do this if it’s a single library taking up the majority of space (found via profiling).
- Put fonts in EEPROM This requires editing whatever Arduino library you’re using like Adafruit_GFX, so it’s big pain, but worth the amount of flash you regain.