In the previous blog in this series, using Flash for non-volatile program data was covered. One aspect of this was the F( ) macro that enables Serial.print/println strings to be accessed from Flash where the program is stored. That is, they do not consume RAM space allowing for more volatile programming space. This blog compares using and not using the F( ) macro. In the Telemetry sketch this allows for nearly double the number of name-value pairs.


Previous: Ardjson-Part 10- Reducing RAM Usage – Permanent Storage


Version 1.6 of the Telemetry app, that uses the F( ) macros:                       1.6

Version 1.5 of the same Telemetry app, that doesn't use the F( ) macros:   1.5

Version 1.4 of the same as 1.5 but doesn't do array bounds checking     :   1.5

All on the Downloads tab at 

Earlier versions of the Telemetry app crashed because lack of RAM. This was exasperated by the parser algorithm unnecessarily storing all of the HTTP GET Response before processing it. A stream parser was then developed to address but the earlier versions displayed each name-value pair as it was deciphered without storing for later processing. When the name-value pairs were stored the lack of RAM resurfaced. The earlier versions just displayed name


One approach used to address this latter issue was to use 2 byte integer id field rather than 36 byte GUID strings. The previous blog (Part 10) discussed using Flash for fixed data and EEPROM for semi-permanent data. One of the Flash techniques was to use the F( ) in Serial.print/println statements.

That is replace all such statement that contain a constant string with a string in Flash. For example replace:

    Serial.print("Expected: ");


    Serial.print(F("Expected: "));

An additional approach is to where possible, move global declarations to inside functions. That is, if a data entity is only required by, say start_up, they declare it within that function rather globally.That way such data only occupies RAM when that function runs. An example of this is the IP declarations:

// Ethernet shield MAC address (sticker in the back)
// Note: Will use DHCP
byte mac = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 0, 177);
IPAddress dbitmask(255, 255, 255, 0);
IPAddress dgateway(192, 168, 0, 1);
IPAddress ddns(192, 168, 0, 1);


Version 1.6 of the Telemetry sketch is a simple rework of 1.5 to

Use the F( ) macros within Serial.print/ln statements

Move global data to within functions where possible


Version 1.5 could handle 14 name-value pairs before any issues arose.

Version 1.6 could handle 25 name-value pairs



Using the F( ) in Serial.print statements can significantly free up RAM. Also only have global declarations for entities that are used by multiple functions.