Flash

A Library to Ease Accessing Flash-based (PROGMEM) Data

Note: Flash 4.0 now supports Arduino 1.0!

Storing static program data in flash/PROGMEM is a tricky part of Arduino programming. To save precious RAM, a novice user already at odds with unfamiliar C++ syntax must digest such daunting concepts as prog_char, PSTR(), PROGMEM, pgm_read_word(), etc. Even seasoned users get tripped up by the indirection and typecasting that are required to retrieve valid PROGMEM data. Add to that a couple of apparent bugs in the implementation, and it’s clear that PROGMEM is a complicated mess.

I have written a new library, Flash, which abstracts away most of this complexity. It provides new String, Array, Table, and String Array types that make ROM-based data collections as easy to use as “normal” types. Each overrides the C++ [] operator, so to extract individual elements one uses familiar array access syntax:

// float array example
float t = temperatures[950];

// (2D) font table example
digitalWrite(pin[i], font_table['a'][i]);
// string example
for (int i=0; i<str.length(); ++i)
  if (str[i] == ';') break;

Creating named Flash objects

To create a Flash object, you use a library-provided macro. Each of the four basic types provides its own creation macro:

Strings: FLASH_STRING(name, value)
Arrays: FLASH_ARRAY(type, name, list of values…)
Tables: FLASH_TABLE(type, name, columns, values…)
String Arrays: FLASH_STRING_ARRAY(name, values…)

Examples:

FLASH_STRING(big_string, "Moreover, as you might appreciate, "
    "their implications were such as to provoke a certain "
    "degree of sorrow within me. Indeed - why should I not "
    "admit it? - at that moment, my heart was breaking.");
FLASH_ARRAY(float, temperatures, 23.1, 23.1, 23.2, 23.2, 23.4,
    23.7, 25.0, 26.0, 26.8, 28.8, 30.2, 31.9, 33.1, 33.1, 33.2,
    33.2, 33.4, 33.7, 35.0, 36.0, 36.8, 38.8, 40.2, 41.9);
FLASH_TABLE(boolean, font_table, 7, {0,0,0,0,0,0,0},
    {0,0,0,1,0,1,1}, {1,0,1,1,1,0,1}, {1,1,0,0,0,0,0},
    {0,1,0,1,0,1,0}, {1,0,1,1,1,0,1}, {1,0,0,1,0,0,1},
    {0,0,1,1,0,1,1}, {1,0,1,1,1,1,1});
FLASH_STRING_ARRAY(digits, PSTR("Zero"), PSTR("One"),
    PSTR("Two"), PSTR("Three"), PSTR("Four"), PSTR("Five"),
    PSTR("Six"), PSTR("Seven"), PSTR("Eight"), PSTR("Nine"));

[Note that you can make Arrays and Tables out of any native type.]

[Note also that the String Array is a slightly special case. For technical reasons, as you can see in the example, each member of the array initializer must be wrapped with the PSTR() operator. For this reason, String Arrays cannot be declared at global scope, but must be non-statically defined within in the body of a function. Note also that while the individual strings in a String Array are contained in PROGMEM space, the array itself (again, for technical reasons) is RAM-based, consuming 2 bytes per array element. This limitation does not apply to the other Flash types.]

Using named Flash objects

Array-like access. Each Flash type provides an [] operator to get access to the underlying data, for example:

    // extract an element from an Array
    float t = temperatures[5];
    // examine characters in a String
    for (int i=0; i<big_string.length(); ++i)
      if (big_string[i] == 'O') ++big_O_counter;
    // Use a font table to configure a 7-segment display
    for (int i=0; i<font_table[1].count(); ++i)
      digitalWrite(pins[i], font_table[1][i]);
    // Examine the sizes of strings in a String Arra
    for (int i=0; i<digits.count(); ++i)
      Serial.println(digits[i].length());

Since Tables are really just two-dimensional arrays, the Table object’s implementation of [] returns a one-dimensional Array object.

Size. Each Flash type provides a mechanism for determining its size:

String and String Array: size_t length();
Array: size_t count();
Table: size_t rows(); size_t cols();

Access. If you need it, each Flash object provides an access() method that returns the underlying PROGMEM pointer

Print compatibility. Each Flash object has a print() method that can be used to serialize the object to any stream derived from core class Print (HardwareSerial, NewSoftSerial, LiquidCrystal, Ethernet, PString, etc.) See “Printing Flash objects” below.

String copy. Flash String objects may be copied in whole or part to RAM using the String object’s copy method:

    // copies the first 10 characters of the big_string
    char temp[11];
    big_string.copy(temp, 10);

Printing Flash objects

Each Flash object can “print” itself, using either its print method directly:

    temperatures.print(Serial);
    big_string.print(lcd);
    font_table.print(newsoftserial);

or, equivalently, by using the << streaming operator:

    Serial << temperatures;
    lcd << big_string;
    newsoftserial << font_table;

Flash objects can also be “printed” using the familiar Serial.print[ln] syntax, but this requires a small patch to the core Print.h file. See “Patching Print.h” below

Library Version

You can retrieve the version of the Flash library by inspecting FLASH_LIBRARY_VERSION.

int ver = FLASH_LIBRARY_VERSION;

Download

The latest version of Flash is available here: Flash4.zip

Change Log

  1. initial version
  2. moved some code to a new .cpp file to avoid inlining every member function
  3. fixed a bug in the copy() method

Acknowledgements

Thanks to forum user Bill W. (“westfw”) for testing Flash and observing that Strings take up a surprising amount of extra PROGMEM space (20 bytes per string). I used his data to modify the library so that some of the commonly used functions, notably the _FLASH_STRING constructor are not inlined. This change reduces the footprint of the example programs noticeably. Thanks, Bill!

I appreciate any suggestions or input.

Mikal Hart

Page last updated on January 28, 2012 at 12:16 am
163 Responses → “Flash”

  1. Mikal

    3 months ago

    Hmmm. Thanks, p0g0. I need to check on that!


  2. Frank Mertens

    3 months ago

    Hi Mikal,

    I’m new to Arduino… learning every day…
    I’m doing an aquarium automation project with an lcd.
    Recently I fell into the “String concatenation” pitfall, which I managed to solve by using your PString library in a function that takes care of this.
    Thanks for that…
    Now I wanted to move my fixed String arrays to flash so I don’t get in trouble again when adding languages later.
    When I declare the String array as:
    void Stringdeclaration() {
    FLASH_STRING_ARRAY (Day, PSTR(“Monday”), PSTR(“Tuesday”), PSTR(“Wednesday”), PSTR(“Thursday”), PSTR(“Friday”), PSTR(“Saturday”), PSTR(“Sunday”));
    }
    void setup() {
    Stringdeclaration();
    ….
    }
    I assumed I did it as described in your notes (inside a function with PSTR).
    However, I got a compiler error: ‘Day’ was not declared in this scope.
    The only way I got it working was declaring it ‘normally’ without the function and removing the PSTR operator. But I think this way everything stays in RAM, I’m not sure.
    All other combinations I have tried failed…
    Can you give me some more info so I can get this working, and hopefully even understand why…
    Thanks


  3. Mikal

    3 months ago

    @Frank Mertens,

    The declaration has to be in the same function that you use it in. In other words, delete the Stringdeclaration() function and move the declaration of “Day” directly into setup():

    void setup() {
    FLASH_STRING_ARRAY (Day, PSTR(“Monday”), PSTR(“Tuesday”), PSTR(“Wednesday”), PSTR(“Thursday”), PSTR(“Friday”), PSTR(“Saturday”), PSTR(“Sunday”));
    ...
    }

  4. Sparks

    3 months ago

    Mikal, I have added the Flash library to my sketch. I am using the FLASH_STRING_ARRAY. I declare it inside the function where I use it:

    void example(PString &m_data) {
    FLASH_STRING_ARRAY(test_header,
    PSTR(“string 0\n”),
    PSTR(“string 1\n”),
    PSTR(“string 2\n”),
    PSTR(“string 3″));
    etc.
    }
    I nevertheless see warnings in the compilers verbose reporting output: “warning: only initialized variables can be placed into program memory area”.
    What have I missed ? Thanks for your advice !


  5. Mikal

    2 months ago

    Hi Sparks,

    I believe we determined that that warning is a gcc compiler error. Anyway, we just ignore it, as unpleasant as that is.


  6. Sparks

    2 months ago

    OK, thanks for your advice.


  7. Stuart Galloway

    2 months ago

    This program gives weird errors.
    I get the right answer if I print to serial.
    I keep getting the zeroth array member if if dont print to serial!

    #include

    #define ODD 1
    #define EVEN 0
    #define DRY 1
    #define WET 0
    #define RAIN 1
    #define FINE 0
    #define V1 1
    #define V2 2
    #define V3 8
    #define V4 16

    FLASH_TABLE(int, sprinkler, 6 /* width of table */,
    {20,30,V1,ODD,DRY,RAIN},
    {20,32,V2,ODD,FINE,WET},
    {20,36,V3,EVEN,DRY,RAIN},
    {20,39,V4,ODD,WET,RAIN}
    );

    void setup() {
    int tm,t1,t2;
    Serial.begin(115200);
    for (int i = 0; i<4; i++){
    Serial.println(i);
    Serial.println("Error");
    t1 =sprinkler[i][0];
    //Serial.print(t1);
    t2 = sprinkler[i][1];
    //Serial.println(t2);
    tm =t1*60 + t2;
    Serial.println(tm);

    Serial.println("OK");

    t1 =sprinkler[i][0];
    Serial.print(t1);
    t2 = sprinkler[i][1];
    Serial.println(t2);
    tm =t1*60 + t2;
    Serial.println(tm);

    }
    }

    void loop(){
    }


  8. Jose M

    4 weeks ago

    Congratulations. Your library has been really useful for me. It allowed me to free precious ram space in a complex sketch.

5 Trackbacks For This Post
  1. New Flash library « Arduiniana

    [...] Interested to learn more? Read all about it here! [...]

  2. vkick Blog Site » Blog Archive » How to do Timer and Save Settings?

    [...] http://arduiniana.org/libraries/Flash/ Categories: Arduino Posted By: Mon Last Edit: 18 Jun 2009 @ 04 01 PM Email • Permalink Previous  Responses to this post » (None)  Post a Comment Click here to cancel reply. [...]

  3. Arduino net connected clock tells weather not time

    [...] third party libraries were used; PString to handle parsing the incoming website, Flash for memory management, and Streaming for easier coding. [...]

  4. Blog What I Made » YAHMS: Base Station

    [...] interface, see the links below for that too. You’ll also need NewSoftSerial of course and the Flash library which I’ve used to decrease memory usage. Follow the instructions in [...]

  5. Arduino – Steuern per Internet | bastianmueller - blog

    [...] Steckdose (An/Aus) hängt sich der Ardu komplett auf. Ihr benötigt zusätzlich die Bibliothek Flash (für das Speichern im Flash statt SRAM) und FreeMemory (für die Anzeige des freien [...]

Leave a Reply