Friday, December 31, 2010

Simple way how to use PROGMEM

If you write large Arduino program with a lot of strings, RAM can be huge issue.

When reading something about Arduino Memory organization you might notice that all strings are being put in to RAM. And Arduino has "only" 2kB of the RAM. So if you have a program with lots of these:

Serial.prinln("Some very long string...");
Serial.prinln("Some another very long string...");

RAM runs out very quickly. In my case it was quite talkative telnet server that sometimes unexpectedly crashed because of this issue.

Note: Free RAM could be determined by function ATS_GetFreeMemory() form ArduinoTestSuite.

The solution is to put strings into program memory (Arduino has 32kB of program memory). However that is not as simple as it sounds. Details can be found in PROGMEM section in Arduino reference. You will probably end with something like this:

#include <avr/pgmspace.h>

const char message[] PROGMEM = "Some very long string...";
char buffer[30];

strcpy_P(buffer, message);
Serial.println(buffer);

And this is a lot of code for one println, isn't it. Ideal would be something like

Serial.prinln(P("Some very long string..."));

And surprise, it's possible. Solution is to declare a macro.

#include <avr/pgmspace.h>
 
char p_buffer[80];
#define P(str) (strcpy_P(p_buffer, PSTR(str)), p_buffer)

That’s all!

Principle is simple. String is stored in the program memory and processor copies it to the buffer and returns this buffer instead of the string. Key is macro PSTR from pgmspace.h. PSTR allows you to declare string inline into the program memory without PROGMEM keyword and variables.

In my telnet server, I've saved more then 1kB (more then 50%!). And it only requires to surround all strings with P("...").

5 comments:

  1. You are a SAINT!! Thanks very much for this!

    ReplyDelete
  2. what if your progmem string is greatet than 80 chars?

    ReplyDelete
  3. If it exceeds then you step into other variables or not. You can not know if the next memory block is reserved from an other variable. So your code might work but when you use the next variable which will be now corrupted.

    It is chaos. You can not tell. For this you must be very careful. You could make a library that handles those errors by counting the lenght of the characters.

    ReplyDelete
  4. great! clarified my self with this simple explanation. Thanks a lot.

    ReplyDelete