Flash

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

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;

Download and Installation

To install this library, download here, unzip the archive into the Arduino “libraries” folder, and restart Arduino. You should rename the folder “Flash”, because the IDE doesn’t like dashes in the name.
Download

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      if (big_string[i] == 'O') ++big_O_counter;
    // Use a font table to configure a 7-segment display
    for (int i=0; i      digitalWrite(pins[i], font_table[1][i]);
    // Examine the sizes of strings in a String Array
    for (int i=0; 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(softserial);

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

    Serial << temperatures;
    lcd << big_string;
    softserial << font_table;

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: Flash5.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 30, 2014 at 9:41 pm
252 Responses → “Flash”

  1. Xavier

    14 years ago

    Hi,

    your library is very useful. I wrote a sketch with many string, and there was problems… I suspected a problem with RAM…

    Few minutes to add your library in my sketch and everything work well : thanks !!

    XH


  2. John Raines

    14 years ago

    You say:
    “Then add a couple of inline print methods — alongside all the others — to the body of class Print:

    void println(const _Printable &obj)
    { obj.print(*this); println(); }
    void print(const _Printable &obj)
    { obj.print(*this); }

    Should these be ‘inline’?


  3. Mikal

    14 years ago

    John, I think the fact that they are embedded in the body of the class declaration make them inline by default, but yes, it would probably be more expressive to add the “inline” keyword.

    M


  4. brad

    14 years ago

    Why does this not work? and what would be a good way to implement something like returning a string stored in ROM based on the case?

    String identifydata(int x){ //accepts a binary number and returns a corresponding number that matches into state[“blah”] to match to a human string
    //Serial.print(x); // see what binary number were trying to match
    FLASH_STRING(yo,”YOO”)
    switch(x){
    case 0 : // see if binary number matches zero
    return (yo);
    break;
    case 1010101010:
    return(1);
    break;
    case 1110000111:
    return(2);
    }


  5. Mikal

    14 years ago

    Hi Brad,

    I think it would be possible to create several _FLASH_STRING objects and then switch on an index to return one of them. You example fails because in the one case (0) you return a FLASH_STRING, but in others you return integers.

    Mikal


  6. Sam

    14 years ago

    Is there a way to write to an individual element of a flash_table.

    First I initiated and a table:

    FLASH_TABLE(boolean,relay,10,
    {0,0,0,0,0,0,0,0,0,0},
    {0,1,0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0,0,0});

    I can read a specific element with the phrase:

    Serial.println(relay[i][0],BIN); //[row][col]

    I would like to write to an element in the same way although the following doesn’t work:

    boolean relay[i][1]=1;


  7. Mikal

    14 years ago

    Sorry, Sam. From the Arduino sketch’s point of view, all flash-based data is strictly read-only.

    Mikal


  8. Meredith Turner

    14 years ago

    Jumping into building a reverse geocache box and would like to use the libraries that you have generously made available.

    What compiler would you recommend?

    Thanks.
    Meredith


  9. Peter

    14 years ago

    Is there any way to store variables into flash memory?

    i.e:

    int i = 2;
    int j = 9;
    int k = 3;
    FLASH_ARRAY(int, font_table2, i,j,k);

    Thanks!


  10. Mikal

    14 years ago

    @Peter,

    Generally the answer is no. You can only store values in the flash that are known at compile-time. However, if you adjust your code like this to make your “variables” compile-time constants, it will work:


    static const int i = 2;
    static const int j = 9;
    static const int k = 3;
    FLASH_ARRAY(int, font_table2, i,j,k);


  11. Shane

    13 years ago

    Hi. Im new to coding and Arduino.

    I have a project that uses a thermistor to return a temp value and print it to an LCD.

    I would like to use a lookup table, that would look up a temp against the ADC value from the thermistor..

    i just cant find out how to create such a table in the code, and be able to call on it to return me a temp that i can then print to the LCD.

    i can easily get the ADC vs temp table such as

    ADC Temp
    100 23C
    200 24C
    300 25C
    etc etc.

    But i dont know how to do that in code.

    Can you tell me how to do it? or point me in the right direction?

    Ive searched the arduino site, and google and cant find anything that gives me a breakdown on how to create the table that i want and how to compare an ADC value and get a result.


  12. Jan

    13 years ago

    Hi!
    Thank you for a nice lib. I’m just quite new to C and to arduino and I would need to explain one thing. Can I create a function to accept what’s generated by your FLASH_STRING_ARRAY, FLASH_TABLE or FLASH_STRING macros as a parameter? Could you give me some hint how to do that? Thanks a lot!


  13. Mikal

    13 years ago

    Jan, the FLASH_STRING macro creates and object of type _FLASH_STRING.

    FLASH_ARRAY creates an object of type _FLASH_ARRAY.

    FLASH_TABLE creates an object of type _FLASH_TABLE.

    Mikal


  14. Patrick

    13 years ago

    How would I store a 2 dimension array with Flash.h??

    char * menu[][2] = {
    {“Item 1″,”apples, coke” },
    {“Item 2″,”OJ, Cranberry” },
    {“Item 3″,”Peach, Bamboo” },
    {“Item 4″,”cheese, carrots” },
    {“Item 5″,”big fluffy chicken cat” }
    };

    Do I have to build two different String Arrays? Can you store char arrays inside of a Table Array??


  15. Mikal

    13 years ago

    Patrick, I’m afraid there’s no convenient way to make a 2D array of strings.


  16. Synthy

    13 years ago

    Hi Mikal,

    I have made a lookup string, but when i try to use it as in your example, the string is too long. There are 9 characters printed instead of 8. Here is the code:
    FLASH_STRING(xgvoice, “GrandPnoGrndPnoKMelloGrPPianoStr”);

    myGLCD.setBackColor(0,0,0);
    char temp_str[8] = {0};
    xgvoice.copy(temp_str, 8, vc*8);
    myGLCD.print(temp_str,x,y);

    Do you know what i did wrong?

    Thanks, Pim.


  17. Mikal

    13 years ago

    Pim,

    This is a documentation problem that I need to fix. When you do xgvoice.copy(temp_str, 8, vc*8), eight characters are moved to temp_str, but because the underlying code call strncpy_P, the string is not 0-terminated. (Also temp_str should be 9 characters long to hold the 8 characters plus the 0 terminator.) So change

    char temp_str[8] = {0};

    to

    char temp_str[9] = {0};

    I think this will solve your problem.


  18. Travis

    13 years ago

    Hi Mikal,

    I am trying to use your Flash library to write two data tables, which are then used for interpolation (using Kerinin’s Spline library); however, when I try to compile, the spline function errors out saying invalid conversion from _FLASH_ARRAY to float. Any ideas on how to fix this with your library. (I am trying to pass the two arrays to the function)

    Here is the line of code:
    Spline linearSpline(alt_a.access(),rho_a.access(),51,1);

    Thanks!


  19. Mikal

    13 years ago

    Travis, I won’t be able to guess at the problem without a definition of the Spline class. Are alt_a and rho_a FLASH_ARRAYs? I’m guessing that whoever wrote Spline expects memory-based arrays, so Flash Arrays will fail. ?

    M


  20. John

    13 years ago

    Thanks for a great library. I’ve got one newbie C++ question though …

    I’ve created a class which uses a flash array which is quite large (it holds graphics information). I want to split this flash array out into its own library file “Graphics.cpp” and have the class library include the Graphics library. I’ve tried a number of ways to do this but I’m not getting anywhere – Can this be done?

    Thanks – J.


  21. Mikal

    13 years ago

    @John,

    If a secondary .cpp file or library file #includes a certain header, then it is a quirky requirement of Arduino that the main sketch file must also #include that same header. Could that be your problem?

    M


  22. anthrolume

    13 years ago

    Mikal,

    This thing is great! My project will be using a 4×40 LCD, so I’ll be using a lot of strings. Even now my I have a test program that I use to test the electronics and unit test my classes and that thing was failing to run on an Uno because of quoted strings. I switched to Flash and I’m in great shape again. Thanks so much for this great contribution.

    -Bryan
    aka anthrolume


  23. Mikal

    13 years ago

    @anthrolume,

    Thanks!


  24. anthrolume

    13 years ago

    Hi Mikal,

    I am using your library with great success now. I have found it convenient to make one small change, and I suggest that perhaps you roll that change into the next official version.

    I have found it useful to subclass _FLASH_STRING. To facilitate that, I’ve changed the “private” on _arr to “protected”. In my experience, if I can even vaguely imagine someone ever wanting to subclass a class I write, I use protected for the data members – it’s saved my ass many times. :-)

    Thanks again for this great library. I’m abusing flash strings to store a compact representation of arrays of LED addresses for pattern animations in my project. It’s working great.

    -Bryan
    aka anthrolume


  25. Bryan

    13 years ago

    I have an array of motivational slogans.

    void show() // Function shows a slogan.
    {FLASH_STRING_ARRAY(slogans, // Program memory slogans.
    PSTR(“Go all-out!”), // Slogan 0, top line.
    PSTR(“”), // Slogan 0, bottom line.

    But the count of slogans is so far manual.

    int slogan = 2 * random(93); // Randomly select a slogan.
    lcd << slogans[slogan]; // Display slogan top line.
    lcd.setCursor(0, 1); // Put the cursor bottom left.
    lcd << slogans[slogan + 1]; // Show slogan bottom line.

    I have been unable to get an automatic count to work.

    Size. Each Flash type provides a mechanism for determining its size:
    String and String Array: size_t length();
    Array: size_t count();

    I have found this cryptic, and would appreciate examples!


  26. Mikal

    13 years ago

    @Bryan,

    If I understand your question correctly, you can simply make a FLASH_STRING_ARRAY and then choose a random number from 0 to 2 * (array.length() – 1) to select a random pair of strings.

    Hope that helps…

    Mikal


  27. Luigi

    13 years ago

    Hi, I want to store and to access to a bidimensional array 103×103 of integer numbers, that’s a look up table of a fuzzy controller. Is this library the right way to implement my l.u.t? in case the answer is yes wich is the code that better fit that?
    thank you in advance


  28. Mikal

    13 years ago

    Luigi, I think FLASH_ARRAY is the perfect fit for your application.

    Mikal


  29. idealabs

    13 years ago

    Hi, I would like using the flash memory of my Arduino UNO, in order to store values in a bidimensional vector and modify it while the program is running. Add new values and delete others. Is it possible? How can I do this? I’m trying to modify a FLASH_STRING but I don’t have success.


  30. Mikal

    13 years ago

    Sorry idealabs,

    From the point-of-view of the software, FLASH_STRING objects (and the flash in general) are immutable at run-time.


  31. ben

    13 years ago

    Hi i’m new to arduino and programming, but ive found this library very useful in an arduino project om working on. Ive got the FLASH_ARRAY to work for integer arrays but not for floating point number arrays. is something like this acceptable?

    FLASH_ARRAY(float, points,
    2.082E+001 ,3.272E+001,
    2.071E+001 ,3.295E+001,
    2.039E+001 ,3.295E+001
    );

    im have trouble reading each number from the array, it works if i use it as a normal array but for my project i need large arrays of hundreds of floating point numbers.

    anyway thanks for this amazing library its helped me out a lot! :)


  32. Mikal

    13 years ago

    @Ben, I tried your example. What problem are you having precisely?

    Mikal


  33. josx

    13 years ago

    I am using FLASH_STRING_ARRAY but i cant understand why must be declared inside the body of a function.

    Why cant use it as global?
    I need global a FLASH_STRING_ARRAY


  34. Mikal

    13 years ago

    josx,

    The reason is that these variable declarations use a fancy C++ extension that gcc doesn’t allow to be used at global scope.

    I’d love to find a solution, but meanwhile what I do is declare my FLASH_STRING_ARRAY in setup, then set a global pointer to it. (Its type is _FLASH_STRING_ARRAY *.)

    Mikal


  35. Craig Hollabaugh

    13 years ago

    Mikal,
    I’m doing some curve fitting and want to store an array of structs instead of native type. compiling print yields errors because

    no matching function for call to ‘Print::print(mypoint_t)
    which is expected.

    I have two options here
    1. hack on print to print my struct
    2. individually store mypoint_t as separate arrays

    I’m leaning towards option 2. Have any advice?

    Thanks,
    Craig

    Dr. Craig Hollabaugh
    Senior Engineer at Brightleaf Technologies


  36. ben

    13 years ago

    Hi Mikal
    sorry It works now It was a problem in my programming
    thanks


  37. Mikal

    13 years ago

    Hi Craig–

    This is worth an email response. Check yours. :)

    Mikal


  38. GTech

    13 years ago

    So this doesn’t seem to work with the Streaming library. As soon as I changed my int array to FLASH_ARRAY it said the name was not declared so I moved the #includes around and then it complained about my _DEC(foo) modifier in streaming so I took that out and then just got a barrage of errors. I thought maybe the patch would fix it but I don’t think I put the second part in the right place. I can’t seem to find where to put it. Any help would be appreciated. I’m using 6 libraries and am at 800 lines so it’s getting very confusing AND my SRAM is overflowing all over the place!


  39. GTech

    13 years ago

    Mikal, (<cool spelling btw)

    I was able to get it working and your library saved my butt. I had 2 80 int arrays which froze everything up. I however, did still remove anything to do with streaming which ended up not being a big deal. Thanks for your great library. You can remove my previous comment and this one.


  40. rod

    13 years ago

    Hi Mikal,
    A couple of things I’ve noticed…

    Flash.h has to be included after Streaming.h , otherwise the defines collide and, for instance, endl becomes a missing symbol.

    Flash.h doesn’t have #include guards, if you need to include it from different files it’ll complain.

    Great job, btw!


  41. Andreas

    13 years ago

    hi,

    I’m experiencing some strange behaviors while using this library. I’m not sure if this is my fault or a bug in your lib. My problem the following:

    I have a table with values:

    FLASH_TABLE( unsigned int, FScene_1, 3,
    {4000, 2000, 333},
    {2550, 300, 2555},
    {100, 2002, 400}
    );

    now I try to access the individual values:

    unsigned int t0 = FScene_1[0][0];
    unsigned int t1 = FScene_1[0][1];
    unsigned int t2 = FScene_1[0][2];

    now if I print these:

    Serial.println(t0); // will output 4000 -> correct
    Serial.println(t1); // will output 4000 -> wrong, should be 2000
    Serial.println(t2); // will output 4000 -> wrong, should be 333

    the strange thing is, if I print them directly:

    Serial.println(FScene_1[0][0]); // will output 4000 -> correct
    Serial.println(FScene_1[0][1]); // will output 2000 -> correct
    Serial.println(FScene_1[0][2]); // will output 333 -> correct

    … now, everything seems to work fine?!?!?!

    I really don’t get it if I’m doing something fundamentally wrong or if there is a mysterious bug somewhere!

    thanks
    Andreas


  42. Mikal

    13 years ago

    @rod,

    Yeah, that’s a good point. I’ll fix that.

    Mikal


  43. Mikal

    13 years ago

    @Andreas, I’ve heard reports of this kind of behavior in the past, and I have never been able to understand it. Can anyone shed some light? When I get a moment I’ll try to understand this. I don’t think there’s anything wrong with your code.

    M


  44. Hakan

    13 years ago

    If I got 366 lines looking like this:

    1 1 08:44
    1 2 08:45
    1 3 08:46
    10 1 08:55
    10 2 08:56
    11 12 09:30
    11 13 09:32

    Then I need to search for ex. “10 2” and then recive “08:56”

    How to do that ?


  45. marf

    13 years ago

    I’m having trouble passing _FLASH_TABLE type to a function. The table structure is:

    // Decimal 1-wire unique ids in Decimal format
    FLASH_TABLE(int, ds18b20address, 8,
    {40, 120, 70, 86, 03, 00, 00, 103},
    {40, 97, 67, 86, 03, 00, 00, 120},
    {40, 59, 64, 86, 03, 00, 00, 215},
    );

    I make the call as:

    payload.dpFzHpnt_temp = readout1wire(ds18b20address[DOWN_PANTRY_FRZR_HPNT]);

    The function is called as:

    static int readout1wire (_FLASH_TABLE addr[]) {

    The error message is:

    Reefers:34: error: missing template arguments before ‘addr’
    Reefers:146: error: redefinition of ‘int readout1wire’

    where 34 is the #include and 146 is the function line.

    Maybe a better question would be: Is it possible to pass the 1st or 2nd dimension of 8 elements, or would I need to copy to a local array?

    Great work, by the way. I’ve used everything else in the lib with great success.


  46. David

    13 years ago

    Hi Mikal,

    I am trying to use your libary to store a large array, 256×256 chars, running on an Arduino Mega 2560.
    I keep on getting an “size of array too large” error but I thought that 1 byte x 256 x 256 should fit in the 256kB flash of the arduino (the rest of the code is under 1kB)

    Am I using your libary incorrectly?
    My code is (leaving out the lut, but I can send this if it’s any help,
    #include
    FLASH_TABLE(byte, lut, 256,
    {x,x,x,x,…},{…},etc,{}
    );

    Thanks!

    David


  47. Rick

    13 years ago

    Mikal,
    If I had two arrays that I wanted to reference to each other how would I correlate the position of one array to the other similar to a look up table function?

    To use your example above:

    FLASH_ARRAY(float, temperatures, 23.1, 23.1, 23.2, 23.2, 23.4);

    FLASH_ARRAY(float, tempvoltage, 1.5, 2.0, 2.5, 3.0, 3.5);

    How would I write the code to return 23.1 if tempvoltage=1.5?

    Or am I completely wrong on the opertion here?

    Thanks for any assistance!


  48. dulises

    13 years ago

    Hi Mikal, thank you for your work. I´m just starting with Arduino and i appreciate it.

    Just one thing, I´ve downloaded your Flash library and in Flash.h I had to change the line with WProgram.h with this to work properly with the new environment Arduino 1.0

    Maybe you want to change it so it works for everybody.

    As I said before, thank you.


  49. Erik

    13 years ago

    Hi,

    Can someone explain why the sketch below does not seem to assign the correct value (9) to the variable x2?

    I get the following output:
    ————————
    5 , 9
    5 , 5
    ————————

    Of course I expect the 2nd line to be identical to the 1st, but it’s not… (using arduino 0022 with arduino nano 328)

    thanks,
    Erik

    CODE:
    ——————————

    #include
    FLASH_ARRAY(int, arrayData, 5, 9);

    void setup() {
    Serial.begin(57600);
    int x1=arrayData[0];
    int x2=arrayData[1];
    Serial.println(“————————“);
    Serial.print(arrayData[0]);Serial.print(” , “);Serial.println(arrayData[1]);
    Serial.print(x1);Serial.print(” , “);Serial.println(x2);
    Serial.println(“————————“);
    }

    void loop() {
    }

1 Trackbacks For This Post
  1. 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 […]

Leave a Reply