Go Down

Topic: PROGMEM confusion (Read 765 times) previous topic - next topic

Fjornir

I was just running a wee little test on PROGMEM and I'm a little bit surprised at the results.

Code: [Select]

#include <avr/pgmspace.h>

void loop()
{
}

void setup()
{
  Serial.begin(9600);
  //prog_char PROGMEM myStr[] = {"This is how much memory I have left: "};
  //Serial.print(myStr);
  Serial.print( "This is how much memory I have left: " );
  Serial.println( availableMemory() );
}

int availableMemory() {
int size = 1024;
byte *buf;
while ((buf = (byte *) malloc(--size)) == NULL);
free(buf);
return size;
}



The code above reports 875 bytes free. However if I comment out the Serial.print() call which has the literal string and uncomment the PROGMEM string and corresponding Serial.print() call I am seeing 837 bytes free.

Does anyone have any insight into this?

halley

Read through this:  http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1231801806

Short answer:  calling malloc() is not a robust way of measuring available heap space.  There is an overhead to a heap allocator that is not accounted for in this sketch, and the overhead is hard to quantify in bigger sketches.

mikalhart

#2
Jan 26, 2009, 08:21 pm Last Edit: Jan 26, 2009, 08:22 pm by mikalhart Reason: 1
fjornir--

I have been working a lot with PROGMEM recently, and your problem stems from the fact that your syntax is not quite correct.  If your string were really stored in flash memory, you couldn't use Serial.print() to print it.  The fact that Serial.print() works for your example is a clue that the declaration of myStr is not actually placing the string in flash.  Adding "static const" fixes the problem.  Try this example:

Code: [Select]
void printStr(const prog_char *p)
{
 while (1)
 {
   char c = pgm_read_byte(p++);
   if (!c) break;
   Serial.print(c);
 }
}

void setup()
{
  Serial.begin(9600);
  static const char PROGMEM myStr[] = "This is how much memory I have left: ";
  printStr(myStr);
  //Serial.print( "This is how much memory I have left: " );
  Serial.println( availableMemory() );
}


Mikal

macegr

Part of the fix (half of the memory recovery) in mikalhart's code is that he's reading the data out of flash one byte at a time. If you store data in flash and then eventually put the entire string into a print command, then that much memory has to be reserved. If you have a lot of strings to store in flash, then that's still a significant memory savings...if you only have one string, then mikalhart's bytewise method saves the most RAM.
Unique RGB LED Modules and Arduino shields: http://www.macetech.com/store

mikalhart

@macegr--

Can you help me understand your comment a little better?  It sounds like you are saying the bytewise reading trick is effective for one flash string, but not so much for lots?

Mikal

Fjornir

mikalhart - Got it. Thanks!

macegr

mikalhart: I'm saying that if you have a lot of strings, not bothering to deal with things bytewise is still a significant RAM savings.
Unique RGB LED Modules and Arduino shields: http://www.macetech.com/store

Go Up