Go Down

Topic: Well this is cute: an easy way of saving RAM (Read 784 times) previous topic - next topic

Nick Gammon

Version 1.0 of the IDE does have the nice feature of allowing you to directly access strings from program memory. In particular, compare this:

Code: [Select]
#include <Streaming.h>

void setup ()
{
  Serial.begin (115200);
  Serial << "test: " << ("The slythy toves did gyre and gimble in the wabe.") << endl;
}

void loop() {}


... to:

Code: [Select]
#include <Streaming.h>

void setup ()
{
  Serial.begin (115200);
  Serial << "test: " << F("The slythy toves did gyre and gimble in the wabe.") << endl;
}

void loop() {}


The addition of the letter F around the string has saved 50 bytes of RAM! And it is hardly much work to do. :P

Plus, it works with the Streaming library, which is handy for other reasons, like imbedding variables and printing floating-point numbers. For example:

Code: [Select]
  Serial << F("The slythy toves did gyre and gimble in the wabe. ") << 42.42 << endl;
http://www.gammon.com.au/electronics

Graynomad

That looks simple. I actually like the streaming library, much neater than a stack of prints and easier to understand than sprintf, I guess it's not used much because it's too resource hungry but that should change with the Due.

I assume that the F will not be required though on an ARM machine.

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

Nick Gammon

Resource hungry?

Code: [Select]
#include <Streaming.h>

void setup ()
{
  Serial.begin (115200);
  Serial << "test: " << F("The slythy toves did gyre and gimble in the wabe.") << endl;
}

void loop() {}


Code: [Select]
Binary sketch size: 2092 bytes (of a 32256 byte maximum)




Code: [Select]
void setup ()
{
  Serial.begin (115200);
  Serial.print ("test: ");
  Serial.println (F("The slythy toves did gyre and gimble in the wabe."));
}

void loop() {}


Code: [Select]
Binary sketch size: 2126 bytes (of a 32256 byte maximum)




The "old fashioned" way took more program memory, not less.
http://www.gammon.com.au/electronics

Graynomad

Well cut off me legs and call me shorty.

I never checked, just assumed :)

I can see a lot more streaming in my future.

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

westfw

Quote
Resource hungry?

The first version of my "fusebytes" sketch (which does little other than print strings) grew about 40% going from a homebrew flash_print function to streaming:

Code: [Select]
#ifdef USEFLASHLIB
#include "Flash.h"
#define fp(string) Serial << F(string)
#else
#include <avr/pgmspace.h>
#define fp(string) flashprint(PSTR(string))
void flashprint (const char p[])
{
   byte c;
   while (0 != (c = pgm_read_byte(p++))) {
Serial.write(c);
   }
}
#endif

IIRC, each use of the streaming operator adds "a few" instructions to do the indirection, more than doubling the size of the function linkage.  A couple of uses are fine, but it adds up...

maniacbug


Quote
Resource hungry?

The first version of my "fusebytes" sketch (which does little other than print strings) grew about 40% going from a homebrew flash_print function to streaming


I think the real test is comparing against code that uses a lot of printf_P and sprintf_P's do to formatted output.

Nick Gammon

A quick test seems to bear out that the streaming library has an overhead of around 3 bytes per string. Test sketch:

Code: [Select]
//#define USEFLASHLIB

#ifdef USEFLASHLIB
 #include <Streaming.h>
 #define fp(string) Serial << F(string)
#else
 #define fp(string) flashprint(PSTR(string))
 
  void flashprint (const char p[])
   {
     byte c;
     while (0 != (c = pgm_read_byte(p++))) {
  Serial.write(c);
     }
   }
#endif

void setup ()
{
 Serial.begin (115200);
 
 fp ("Lorem");
 fp ("ipsum");
 fp ("dolor");
 fp ("sit");
 fp ("amet");
 fp ("consectetur");
 fp ("adipisicing");
 fp ("elit");
 fp ("sed");
 fp ("do");
 fp ("eiusmod");
 fp ("tempor");
 fp ("incididunt");
 fp ("ut");
 fp ("labore");
 fp ("et");
 fp ("dolore");
 fp ("magna");
 fp ("aliqua");
 fp ("Ut");
 fp ("enim");
 fp ("ad");
 fp ("minim");
 fp ("veniam");
 fp ("quis");
 fp ("nostrud");
 fp ("exercitation");
 fp ("ullamco");
 fp ("laboris");
 fp ("nisi");
 fp ("ut");
 fp ("aliquip");
 fp ("ex");
 fp ("ea");
 fp ("commodo");
 fp ("consequat");
 fp ("Duis");
 fp ("aute");
 fp ("irure");
 fp ("dolor");
 fp ("in");
 fp ("reprehenderit");
 fp ("in");
 fp ("voluptate");
 fp ("velit");
 fp ("esse");
 fp ("cillum");
 fp ("dolore");
 fp ("eu");
 fp ("fugiat");
 fp ("nulla");
 fp ("pariatur");
 fp ("Excepteur");
 fp ("sint");
 fp ("occaecat");
 fp ("cupidatat");
 fp ("non");
 fp ("proident");
 fp ("sunt");
 fp ("in");
 fp ("culpa");
 fp ("qui");
 fp ("officia");
 fp ("deserunt");
 fp ("mollit");
 fp ("anim");
 fp ("id");
 fp ("est");
 fp ("laborum");
 
}

void loop () {}



Using streaming, sketch size is 3028 bytes. Without it is 2842. Difference: 186 bytes. Number of prints: 69. So about 2.7 bytes each (strangely).

I make that about 6.5% larger, not 40%.

No doubt your overall sketch was more complex, but for something like this, the overheads, whilst they are there, aren't too bad.
http://www.gammon.com.au/electronics

westfw

Ah.  The current version of Streaming.h seems to be much better than the one I downloaded before.
fusebytes.h is now also only slightly bigger in the stream-using version.

Go Up