It wasn't until I needed to use a GSM modem together with a microSD until I realized the RAM limitations on atmega328p micro. It made me learn some interesting things about RAM saving techniques on Arduino and how to deal with SD cards.
The project was about sending some data stored in a microSD card to a internet site using GSM Shield, but concepts learned can be applied to any RAM limited project, or any project dealing with SD cards, beacuse as I have seen in forums, these RAM problems happen to many people at the time of including a SD to a project.
atmega328p RAM
You probably have read this in the atmega328p datasheet:
I had, but didn't take much care about it because my sketches (+ 512 bytes of the optiboot bootloader) were less than that 32KBytes (32768 bytes).
From the atmega datasheet, the RAM memory map is this:
so we have 2048 bytes for the executing program.
- 4/8/16/32K Bytes of In-System Self-Programmable Flash progam memory (ATmega48PA/88PA/168PA/328P)
- 256/512/512/1K Bytes EEPROM (ATmega48PA/88PA/168PA/328P)
- 512/1K/1K/2K Bytes Internal SRAM (ATmega48PA/88PA/168PA/328P)
I had, but didn't take much care about it because my sketches (+ 512 bytes of the optiboot bootloader) were less than that 32KBytes (32768 bytes).
From the atmega datasheet, the RAM memory map is this:
atmega329p RAM memory map |
so we have 2048 bytes for the executing program.
How to detect RAM problems
In my case: in the Serial.print debugging messages began to appear strange things, and I could recognize part of texts from others lines in the code merged with the expected ones plus some strange characters. It seemed like the program was accessing an incorrect part of the RAM or that those bytes in the RAM were overwritten. In general when you run out of RFAM you can expect any abnormal behaviour from your program, even it need not to be at the startup. The program will upload without problem, you can run out of RAM at any
If you have doubts, use this popular function to get the current available free RAM:
__heap_start is a avr-libc variable that the linker automatically set to the heap start section, and that malloc uses to know where to start to use memory (char *__malloc_heap_start = &__heap_start;), __brkval is a variable that stores the highest point used in the heap.
int freeRam () {
extern int __heap_start, *__brkval;
int v;return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);}
RAM saving techniques
There is a lot of information and advices about techniques for saving RAM, but the principal findings for me were:
- Strings in C are copied to RAM, to store them in Flash use the F() macro inside functions and/or PROGMEM attribute. Quite interesting how F() manages to access Flash data address space (remember it is Harvard arquitecture, data and program memory are separated)
- If there is a communication buffer in your library be aware of its size, specially for SD libraries as they need exactly 512bytes (data block). Other libraries like HardwareSerial automatically fit the buffer size depending on free RAM:
#if (RAMEND < 1000)
#define SERIAL_BUFFER_SIZE 16
#else #define SERIAL_BUFFER_SIZE 64
#endif
- If you really need String class.., use reserve() function, it is much better to reserve the exact size from the beginning (detailed explanation here)
microSD libraries
It was when I included the Arduino Sd library (#include <SD.h>) when my problems began, it was too much for atmega running GSM library and SD, beside lots of then unconscious Serial.print("blablabla")...
After some investigation you realize that there are several SD library implementations out there, and Arduino IDE default one is not the best for optimizig RAM. The best I found was SDFat library. It comes with lot of examples, includes benchmarking sketches to compare to standard SD library performance, and also contains a MiniSerial class to substitute Serial, after changing to SDFat and massive use of F() macro all my RAM problems became solved. Hope this helps!
I leave here my code, it sends a complete file using GPRS to a web site using POST.
It can also help thie reading on optimizing c code for avr:
Tips and Tricks to Optimize Your C Code for 8-bit AVR Microcontrollers
It can also help thie reading on optimizing c code for avr:
Tips and Tricks to Optimize Your C Code for 8-bit AVR Microcontrollers