Have you ever hit āUpload,ā and watched your Arduino mysteriously freeze, restart, or print pure gibberish?
If your code is fine but the board is acting possessed, youāve hit the invisible wall: You ran out of SRAM. The Uno only has 2KB of RAM, which is laughably small. Today, we learn how to use PROGMEM to force your code into flash memory and save your projects from crashing.
Your Arduino Uno (specifically the ATmega328P chip) has three different pools of memory. Understanding them is the key to writing stable code.
The Problem: 2 KB (2,048 bytes) of SRAM is incredibly tiny. If you use a lot of Serial.print("Some long text here"); statements, arrays, or global variables, that 2KB fills up instantly. When it overflows, your program crashes.
F() MacroThe biggest hidden SRAM killers are text strings. Look at this line of code:
Serial.println("System starting up, checking sensors...");
By default, the Arduino compiler takes this text string, stores it in Flash memory, and then copies it into SRAM when the board boots up. If you have dozens of Serial.print() menus or debug messages, your SRAM is gone before loop() even starts!
The solution is the F() macro. It tells the compiler to keep the string in Flash memory and read it directly from there, completely skipping the SRAM.
void setup() {
Serial.begin(9600);
Serial.println("Initializing the primary sensor array...");
Serial.println("Connection to Wi-Fi module successful.");
Serial.println("Error 404: Actuator not found on I2C bus.");
}
void setup() {
Serial.begin(9600);
Serial.println(F("Initializing the primary sensor array..."));
Serial.println(F("Connection to Wi-Fi module successful."));
Serial.println(F("Error 404: Actuator not found on I2C bus."));
}
Just wrap your double-quoted strings in F()! This simple trick can easily free up hundreds of bytes of SRAM.
PROGMEMThe F() macro is fantastic for simple strings, but what if you have a massive array of data? For example, custom graphics for an OLED screen, wavetables for a synthesizer, or a giant lookup table?
You canāt use F() for arrays. Instead, you use the PROGMEM keyword.
PROGMEM tells the compiler: āStore this variable in Flash memory, and do NOT copy it to SRAM.ā
To use PROGMEM, you first need to include the AVR program memory library at the very top of your sketch:
#include <avr/pgmspace.h>
Letās say we have an array of integers representing a sine wave. We add const (because data in Flash canāt be changed while running) and PROGMEM.
// Store this large array directly in Flash memory
const int sineWave[10] PROGMEM = {0, 50, 100, 150, 200, 250, 200, 150, 100, 50};
Because the data isnāt in normal SRAM, you canāt just read it like a normal variable (e.g., int x = sineWave[2]; will fail). You have to use special functions to fetch the data out of Flash memory.
For an integer array, we use pgm_read_word_near():
void setup() {
Serial.begin(9600);
// Read the 3rd value (index 2) from PROGMEM
int myValue = pgm_read_word_near(&sineWave[2]);
Serial.print(F("The value is: "));
Serial.println(myValue);
}
Note: For byte arrays, use pgm_read_byte_near(). For floats, use pgm_read_float_near().
When your Arduino starts crashing mysteriously, check your SRAM usage! The IDE prints memory usage at the bottom of the screen every time you compile. If your āGlobal variablesā use more than 75% of dynamic memory, you are in the danger zone.
F() macro for static text inside Serial.print() and lcd.print().PROGMEM to lock large, unchanging arrays (like fonts, bitmaps, and lookup tables) inside the much larger Flash memory.By mastering memory management, you can cram massive, complex programs into the tiny brain of the Arduino Uno without breaking a sweat!