Go Down

Topic: Well this is cute: an easy way of saving RAM (Read 811 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;
Please post technical questions on the forum, not by personal message. Thanks!

More info:
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.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
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...


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.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
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