AVR Memory Challenges

I’ve never ran out of room on the Arduino’s ATMega328P before, but I knew that there would be some challenges when I started my most recent project. Here’s a breakdown of the memory for the sake of reference:

  • PROGMEM – read-only (32k)
  • RAM – read-write (2k)
  • EEPROM – read-write (1k)

First off, I wanted users to be able to change the devices preferences without plugging it back into a computer and manually changing the code and I knew this would be a great chance to learn about EEPROM (the only caveat being that it has a limited amount of writes). However, as I came near the end of my project, the two parallel sketches I’d been working on exceeded 32Kb when I merged them, so I knew it was time to gut the Strings out of my program in favor of character arrays. Finally, when I was done with that, I ran out of RAM which was perplexing for a few minutes since the Arduino IDE doesn’t throw any errors when this happens and you have to watch some confusing bytes stream by on the serial monitor. Inussopcali . Luckily, I found a nice blog post that gave me the information I needed to keep moving; particularly, storing the character arrays for user feedback into the program memory. Based on the post, I knew that implementing this would take a little bit of more PROGMEM overhead but would liberate some much precious RAM space.

Here’s an example I toyed with just to get the hang of it:

void setup(){

Serial.begin(57600);

Serial.println(“My program has a lot of strings”);

Serial.println(“and they are taking up all my RAM!”);

Serial.println(“So I have learned how to store them only in PROGMEM”);

}

void loop(){}

This is what I would normally do if I wasn’t preoccupied with running out of RAM. Here’s the output from running avr-size on the compiled program:

AVR Memory Usage

—————-

Device: atmega328p

Program: 2036 bytes (6.2% Full)

(.text + .data + .bootloader)

Data: 298 bytes (14.6% Full)

(.data + .bss + .noinit)

Notice how quick that RAM fills up?! Here’s another try that gives the same output but uses memory differently:

#include <avr/pgmspace.h>

prog_char string_0[] PROGMEM = “My program has a lot of strings”;

prog_char string_1[] PROGMEM = “and they are taking up all my RAM!”;

prog_char string_2[] PROGMEM = “So I have learned how to store them only in PROGMEM”;

PROGMEM const char *string_table[] = // change “string_table” name to suit

{

string_0,

string_1,

string_2,

};

char buffer[54]; // make sure this is large enough for the largest string it must hold

void setup()

{

Serial.begin(57600);

for (int i = 0; i < 4; i++)

{

strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i])));

Serial.println( buffer );

delay( 500 );

}

}

The code itself is longer and requires more operations, but here are the effects on memory use:

AVR Memory Usage

—————-

Device: atmega328p

Program: 2238 bytes (6.8% Full)

(.text + .data + .bootloader)

Data: 232 bytes (11.3% Full)

(.data + .bss + .noinit)

I only saved 68 bytes from RAM space but that space is much more limited than the PROGMEM and sometimes that tradeoff is worth it!

Comments are closed.