28

According to the Arduino documentation, the ATmega328 has 32KB of Flash memory for the bootloader + uploaded sketch, and only 2KB SRAM for runtime data. The ATmega2560 has quite a bit more, totalling 256KB and 8KB respectively.

In either case, those limits seem rather small, especially when compared to similarly sized consumer devices, such as smartphones.

What can you do if you run out? E.g. if your sketch is too big, or you need to process a lot of data (such as strings) at runtime? Is there any way to expand the Flash or SRAM?

  • Try using some variable optimization. Some different variable are discussed here – TheDoctor Feb 15 '14 at 1:49
  • 1
    Use proper scopes for your variables if not already doing so, the compiler will optimize RAM usage for you when variables are unused. – jippie Feb 15 '14 at 7:44
  • 1
    You might actually use a Teensy 3.2 (with Teensyduino Software), which would be comparable to an Arduino. Given that you're running out of RAM/PROGMEM it would mean that you're also likely that what you're trying to do is pushing your Arduino. A Teensy 3.2 is not that much more expensive. but has: 32bit, 72MHz (wtf!?) 256KB FLASH and 64KB RAM and 3x UART. Not more program memory as the ATmega2560, but the RAM and speed increase should suffice. – Paul Feb 26 '16 at 15:24
30

Optimisation
Low-level programming for embedded systems is quite different from programming for general purpose devices, such as computers and cell phones. Efficiency (in terms of speed and space) is far more important because resources are at a premium. That means the very first thing to do if you run out of space is to look at what parts of your code you can optimise.

In terms of reducing program space (Flash) usage, the code size can be quite difficult to optimise if you're inexperienced, or if you're more used to programming for desktop computers which don't tend to need that skill. Unfortunately, there's no 'magic bullet' approach which will work for all situations, although it helps if you consider seriously what your sketch really needs to have. If a feature isn't needed, take it out.

Sometimes it's also helpful to identify where multiple parts of your code are the same (or very similar). You may be able to condense them into reusable functions which can be called from multiple places. However, be aware that sometimes trying to make code too reusable actually ends up making it more verbose. It's a tricky balance to strike that tends to come with practice. Spending some time looking at how code changes affect the compiler output can help.

Runtime data (SRAM) optimisation tends to be a bit easier when you're used to it. A very common pitfall for beginner programmers is using too much global data. Anything declared at global scope will exist for the entire lifetime of the sketch, and that isn't always necessary. If a variable is only used inside one function, and it doesn't need to persist between calls, then make it a local variable. If a value needs to be shared between functions, consider if you can pass it as a parameter instead of making it global. That way you'll only use SRAM for those variables when you actually need it.

Another killer for SRAM usage is text processing (e.g. using the String class). Generally speaking, you should avoid doing String operations if possible. They are massive memory hogs. For example, if you're outputting lots of text to serial, use multiple calls to Serial.print() instead of using string concatenation. Also try to reduce the number of string literals in your code if possible.

Avoid recursion if possible as well. Each time a recursive call is made, it takes the stack a level deeper. Refactor your recursive functions to be iterative instead.

Use EEPROM
EEPROM is used for long-term storage of things that only change occasionally. If you need to use large lists or look-up tables of fixed data, then consider storing it in EEPROM in advance, and only pulling out what you need when necessary.

Obviously EEPROM is quite limited in size and speed though, and has a limited number of write cycles. It's not a great solution to data limitations, but it might be enough to ease the burden on Flash or SRAM. It's also quite possible to interface with similar external storage, such as an SD card.

Expansion
If you've exhausted all other options, then expansion may be a possibility. Unfortunately, expanding Flash memory to increase program space isn't possible. However, it is possible to expand SRAM. This means you may be able to refactor your sketch to reduce code size at the expense of increasing data size.

Getting more SRAM is actually fairly straightforward. One option is to use one or more 23K256 chips. They are accessed via SPI, and there is the SpiRAM library to help you use them. Just beware that they operate at 3.3V not 5V!

If you're using the Mega, you could alternatively get SRAM expansion shields from Lagrangian Point or Rugged Circuits.

  • 1
    You can also store constant data in program memory, rather then SRAM, if you have SRAM space issues and free program memory. See here or here – Connor Wolf Feb 15 '14 at 2:09
  • 1
    Another great alternative to EEPROM is an SD card. It does take up a few IO ports but if you do need a large chunk of space for, say map data or similar, it can be easy to swap out and edit with a custom program on a PC. – Anonymous Penguin Feb 17 '14 at 14:05
  • 1
    People should not be encouraged to use SPI SRAMs or RAM expansions, if they are running low on memory. That's just a waste of money. Choosing a bigger MCU would be cheaper. Beside, the performance could be very poor. One should first make a ballpark estimation: if the estimated RAM usage is too close to the limit, then you're choosing the wrong board/microcontroller/development platform. Sure, good usage (storing strings in flash) and optimization (avoiding using some libraries) can be true game changers. However at this point I see no benefits of using the Arduino Software platform. – next-hack Sep 2 '17 at 17:36
24

When you upload your code to your Arduino, say an Uno for example, it'll tell you how many bytes it uses up out of the 32K available. That's how much flash memory you have (think computer hard disk). While your program is running, it's using whats called SRAM, and there is much less of that available.

Sometimes you'll notice your program behaving oddly at a point that you haven't even touched in a while. It could be that your most recent changes cause it to run out of memory (SRAM). Here are a few tips on how to free up some SRAM.

Storing strings in Flash instead of SRAM.

One of the most common things I've seen is the chip running out of memory because there are too many long strings.

Use the F() function when using strings so they are stored in Flash instead of SRAM, since you have much more of that available.

Serial.println(F("This string will be stored in flash memory"));

Use the right data types

You can save a byte by switching from an int (2 bytes) to a byte (1 byte). An unsigned byte will give you 0-255 so if you have numbers that don't go higher than 255, save a byte!

How do I know I'm running out of memory?

Usually you'll observe your program behaving strangely and wonder what went wrong... You didn't change anything in the code near the point where it's messing up, so what gives? It's running out of memory.

There are a couple of functions to tell you how much available memory you have.

Available Memory

  • Do you know if the F() thing is an Arduino specific function or is it in the AVR libraries? You could consider to mention PROGMEM const ... too. – jippie Feb 15 '14 at 7:52
  • Also you can use bit structures to further reduce space used by your variables 5eg if you deal with lots of boolean). – jfpoilpret Feb 15 '14 at 10:22
17

In addition to what others have said (on which I fully agree), I would advise to read this adafruit article about memory; it's well written, explains a lot of things about memory and provide hints on how to optimize it.

At the end of the read, I think you would get a quite complete answer to your question.

To sum it up, you have 2 possible optimization targets (depending on where you memory problems are located):

  • Flash (ie Program Memory); for this, you can:
    • remove dead code (e.g. any code that is included but not used) and unused variables (that one also helps with SRAM)
    • factor out duplicated code
    • remove the bootloader altogether (you can gain between 0.5K for a UNO and 2 or 4K for other Arduino models); this has some downsides though
  • SRAM (ie stack, heap and static data); for this you can:
    • remove unused variables
    • optimize the size of each variable (eg don't use long -4 bytes- if you need only int -2 bytes)
    • use the right scope for your variables (and prefer stack to static data when possible)
    • reduce buffers size to the strict minimum
    • move constant data to PROGMEM (ie your static data will stay in Flash memory and won't get copied to SRAM at program start); that also applies to constant strings for which you can use F() macro)
    • avoid dynamic allocation if it is not absolutely necessary; you will avoid a fragmented heap that may not shrink even after freeing memory

An additional approach to reduce SRAM usage is also described (but seldom used, because it is a bit heavy when coding and not very efficient), it consists in using EEPROM to store data built by your program, but not used until later when some conditions occur, when data can be loaded back from EEPROM.

  • 1
    Removing dead code-- the compiler is really good about handling this for you- it won't make any difference if you have lots of code that's not ever called. If you accidentally call code that you don't need, then that's different, of course. – dethSwatch Jun 16 '15 at 18:17
9

There are two things to do if you run out of storage:

  • Somehow "optimize" your code so it needs less storage; or at least uses less of the particular kind of storage that you ran out of (and uses more of the kind of storage that you still have plenty of). Or,
  • Add more storage.

There are lots of tips online on how to do the first (and for the vast majority of things people do with the Arduino, the build-in storage is more than enough after "optimizing"). So I'll focus on the second:

There are 3 things that use up flash or SRAM; each one needs a slightly different approach to adding storage:

  • variable storage: it is possible to expand SRAM, as sachleen has already pointed out. SRAM, FRAM, and NVSRAM are all appropriate for rapidly-changing variables. (While in principle you could use flash to store variables, then you have to worry about flash wear-out). SPI (a serial protocol) is the easiest to connect to the Arduino. The SpiRAM library works with the Microchip 23K256 serial SRAM chip. The Ramtron FM25W256 serial FRAM chip (now owned by Cypress) also uses SPI. The Cypress CY14B101 NVSRAM also uses SPI. Etc.

  • constant data that needs to still be there the next time the power comes on: this is almost as simple as expanding SRAM. There are many external EEPROM, FRAM, NVSRAM, and FLASH storage devices available. Currently the lowest cost per MB are SD flash cards (which can accessed via SPI). The Ramtron FM25W256 (see above), the Cypress CY14B101 (see above), etc. can also store constant data. Many expansion shields include a SD card slot, and several libraries and tutorials support reading and writing to (flash) SD cards. (We can't use SRAM for this, because SRAM forgets everything when the power goes out).

  • executable code: Unfortunately, expanding an Arduino's Flash memory to increase program space isn't possible. However, a programmer can always refactor a sketch to reduce code size at the expense of increasing data size and making it run slightly slower. (In theory, you could go so far as translate your entire sketch into some interpreted language, store that version of your sketch on a SD card, and then write a interpreter for that language that runs on the Arduino to fetch and execute instructions from the SD card -- Forth on Arduino, a BASIC interpreter, a Tom Napier Picaro interpreter, some application-specific language, etc.).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.