Flash, SRAM, and EEPROM are the three different types of memory that Arduino boards use. Each type has its own job. To write stable, efficient, and scalable sketches, you need to know how these types of memory work and how Arduino uses them. This is especially true as projects get more complicated.
Many problems with Arduino, like random crashes, corrupted variables, or unexpected resets, are not logic errors but memory problems, especially when SRAM runs out.
This guide goes into great detail about each type of memory, shows how Arduino allocates memory, and gives a lot of examples of how to code in real life.
Arduino Memory Types at a Glance
| Memory Type | Purpose | Volatile | Typical Size (Uno) |
|---|---|---|---|
| Flash | Program storage | No | 32 KB |
| SRAM | Runtime variables | Yes | 2 KB |
| EEPROM | Persistent data | No | 1 KB |
Flash Memory (Program Memory)
What Flash Memory Does
Flash memory stores:
- Your compiled sketch
- Constant data (if explicitly stored there)
- Bootloader
Flash memory is non-volatile, meaning it retains data when power is removed.
On most Arduino boards:
- Flash is much larger than SRAM
- Ideal for constants, strings, and lookup tables
Flash Memory Example: Basic Program Storage
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println("Hello from Flash");
delay(1000);
}
Even though the string literal appears small, by default it is copied into SRAM at runtime, which can be wasteful.
Storing Data in Flash with PROGMEM
#include <avr/pgmspace.h>
const char message[] PROGMEM = "Stored in Flash";
void setup() {
Serial.begin(9600);
char buffer[20];
strcpy_P(buffer, message);
Serial.println(buffer);
}
void loop() {}
Why this matters: The string stays in Flash and is only copied into SRAM when needed.
Flash Lookup Table Example
#include <avr/pgmspace.h>
const int sineTable[10] PROGMEM = {
0, 173, 342, 500, 642, 766, 866, 939, 984, 1000
};
void setup() {
Serial.begin(9600);
for (int i = 0; i < 10; i++) {
int value = pgm_read_word(&sineTable[i]);
Serial.println(value);
}
}
void loop() {}
Best use cases for Flash:
- Text strings
- Lookup tables
- Fixed configuration data
- Fonts and graphics
SRAM (Static Random-Access Memory)
What SRAM Does
SRAM stores:
- Global variables
- Local variables
- Function call stack
- Heap (dynamic memory)
SRAM is volatile and extremely limited. On an Arduino Uno, you have only 2048 bytes.
SRAM Allocation Breakdown
|-------------------|
| Global variables |
|-------------------|
| Heap (malloc/new)|
|-------------------|
| Free SRAM |
|-------------------|
| Stack |
|-------------------|
If the heap and stack collide, your program becomes unstable.
Example: Global vs Local Variables
int globalCounter = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
int localCounter = 0;
globalCounter++;
localCounter++;
Serial.println(globalCounter);
}
Global variables permanently consume SRAM, while local variables are created and destroyed on the stack.
Dangerous SRAM Usage: Strings
String name = "Arduino";
String greeting;
void setup() {
greeting = "Hello " + name;
Serial.println(greeting);
}
This causes:
- Heap fragmentation
- Unpredictable crashes in long-running programs
Safer Alternative: Character Arrays
char name[] = "Arduino";
char greeting[20];
void setup() {
strcpy(greeting, "Hello ");
strcat(greeting, name);
Serial.println(greeting);
}
This uses fixed memory, avoiding fragmentation.
Measuring Free SRAM
extern int __heap_start, *__brkval;
int freeMemory() {
int v;
return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval);
}
void setup() {
Serial.begin(9600);
Serial.print("Free SRAM: ");
Serial.println(freeMemory());
}
void loop() {}
This helps diagnose memory leaks and overuse.
EEPROM (Electrically Erasable Programmable ROM)
What EEPROM Does
EEPROM stores:
- Calibration values
- User settings
- Persistent counters
EEPROM:
- Retains data after power loss
- Has limited write cycles (typically ~100,000)
Writing to EEPROM
#include <EEPROM.h>
void setup() {
EEPROM.write(0, 123);
}
void loop() {}
This writes a single byte to address 0.
Reading from EEPROM
#include <EEPROM.h>
void setup() {
Serial.begin(9600);
int value = EEPROM.read(0);
Serial.println(value);
}
void loop() {}
EEPROM Put and Get (Preferred)
#include <EEPROM.h>
struct Settings {
int threshold;
float calibration;
};
Settings config = { 100, 1.23 };
void setup() {
EEPROM.put(0, config);
Settings loaded;
EEPROM.get(0, loaded);
Serial.begin(9600);
Serial.println(loaded.threshold);
Serial.println(loaded.calibration);
}
void loop() {}
put() only writes if the data changes, reducing wear.
EEPROM Wear Management Example
int address = 0;
void saveValue(int value) {
EEPROM.update(address, value);
}
update() avoids unnecessary writes.
Common Memory Mistakes
Mistake 1: Too Many Global Variables
int bigArray[500]; // Consumes 1000 bytes of SRAM
This alone uses nearly half of Uno SRAM.
Mistake 2: Uncontrolled Dynamic Allocation
char* buffer = (char*)malloc(100);
Repeated allocations cause fragmentation.
Mistake 3: Forgetting PROGMEM for Strings
Serial.println("Long debug message...");
Repeated string literals silently consume SRAM.
Best Practices for Arduino Memory Management
- Store constants in Flash using
PROGMEM - Avoid
Stringclass in long-running sketches - Use EEPROM sparingly and intentionally
- Monitor free SRAM during development
- Prefer fixed-size buffers
- Keep global variables minimal
Memory Comparison Summary
| Feature | Flash | SRAM | EEPROM |
|---|---|---|---|
| Volatile | No | Yes | No |
| Size | Large | Very small | Small |
| Speed | Fast | Fastest | Slow |
| Best Use | Code, constants | Variables | Persistent data |
Final Thoughts
The difference between beginner sketches and reliable embedded systems is knowing how to use Arduino memory.
You can greatly improve stability, performance, and scalability by carefully choosing where data lives, like in Flash, SRAM, or EEPROM.
Most of the time, Arduino problems in the real world are caused by memory.
With the methods shown here, you can avoid those problems and write code that is as good as what professionals do.

