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. Coofer Cat

    15 years ago

    This library rocks! I’ve just moved all the long strings from my application to flash (saving around 100-200 bytes of RAM) in about 5 minutes! I wonder what else I can save…?

    I’m now looking at putting many more strings into my application, which I’d have had to live without before. One easy library just made my application many times more usable – thank you!


  2. Mikal

    15 years ago

    Hey– thanks for the nice feedback, Coofer!

    Mikal


  3. Christian

    15 years ago

    Mikal,
    This is a great library. How would you write back to one of the array elements? To clarify, let’s use your simple temparature array declration above. After I declare the array, if later in my sketch I wanted to change the value temperature[5], how would I do that? Could you please provide some sample code? I did not see any further documentation on the Access() function which it appears may be what I am looking for.

    Thanks in advance,
    Christian


  4. Mikal

    15 years ago

    Christian —

    Unfortunately, because of the nature of the architecture of flash memory, there is no way for a program to rewrite the flash values. They must be considered read-only by the software. If you want to store values in non-volatile memory, use the EEPROM library.

    Mikal


  5. Matt E

    14 years ago

    Awesome library!

    So far converting all my Serial.print(“”); commands to Serial << F(“”); has saved me 2/3 of my previous used RAM, though it seems the expected amount of saved RAM versus used Flash is not consistent. The first batch of commands I converted yielded an average 3.5:1 of used Flash to saved RAM. The second batch yielded an average of 7.9:1. I would have expected the second batch to have a better average as the flash library’s overhead would already be accounted for but that wasn’t the case.

    What would be the best method of comparing FLASH_STRING(string1,”Data here”); with char string2[]=”Data here”; in terms of RAM usage? I was using strcmp when comparing two whole strings and a nested for-loop when looking for a partial match.

    Cheers


  6. Mikal

    14 years ago

    Thank you, Matt.

    Yeah it would be nice if there were a built-in “compare” function to compare to strings. Without it, I guess the best thing is to write a for loop:

    for (int i=0; i<string1.size(); ++i)
    {
      if (string1[i] != string2[i])
        return false;
    }
    return true;

    Mikal


  7. topper

    14 years ago

    Thank you Mikal,
    I can now finish my Christmas lights easily thanks to your excellent work.

    Happy Christmas


  8. Mikal

    14 years ago

    Hey, thanks for sharing, topper! Happy Christmas to you as well!
    Best wishes,

    Mikal


  9. Johann

    14 years ago

    @Matt E: You can add the following to Flash.h:

    // compare to another string
      bool operator==(const char *str) 
      { return compare(str)==0; }
    
      // compare to anoter string: less, equal, greater
      inline byte compare(const char *str) 
      { return -strcmp_P(str, _arr); }

    it allows comparisons:
    (myFlashStr == “abc”)

    Thanks for a great library!

    -kellerza


  10. Mikal

    14 years ago

    Johann,

    Excellent contribution. I’ll add that into the next version. Thanks!

    Mikal


  11. Cort

    14 years ago

    Please excuse my lack of programming experience. I’ve been using this library with good luck so far, but have found one strange issue and a question.

    When I do two reads back to back, I have problems without doing something to delay in between them”

    ratemin = row_wave[0][0];
    delayMicroseconds(50);
    ratemax = row_wave[0][1];
    rate = random(ratemin, ratemax);

    If I take out the delayMicroseconds (just to give it something to do) the data reads don’t return the correct data. This is totally confusing to me.

    The question is, I’m trying to create pointers to FLASH_TABLE items I’d like to randomly select a table from a list, then pass it to a function. I can do this with a “normal” table without problem, but it doesn’t seem to work with FLASH_TABLE and I fear my skill level isn’t sufficient to determine if this is simply a limitation of the library, or I simply don’t know the syntax.

    Thanks, and again, Mikal, I very much appreciate the effort to hide PROGMEM from me!


  12. Mikal

    14 years ago

    Cort,

    I can’t understand why you might be experiencing differing behaviors when you add or remove the delay. Could you perhaps post the entire relevant code body? I don’t see this behavior.

    As far as the question about selecting a random table, suffice it to know that when you use the FLASH_TABLE macro, under the covers a template class of type _FLASH_TABLE<type> is created. So for example, here’s some code that randomly selects one of two tables and passes a reference to that table to a function, which then dumps some of it:

    #include <Flash.h>
    FLASH_TABLE(int, row_wave1, 4, 
      {1,2,3,4}, {5,6,7,8}, {9,10,11,12}, {13,14,15,16});
    FLASH_TABLE(int, row_wave2, 4, 
      {4,3,2,1}, {8,7,6,5}, {12,11,10,9}, {16,15,14,13});
    
    typedef _FLASH_TABLE<int> TABLETYPE;
    TABLETYPE *tables[] = {&row_wave1, &row_wave2};
    
    void myfunction(TABLETYPE &table)
    {
      Serial.print(table[0][0]);
      Serial.print(table[1][1]);
      Serial.print(table[2][2]);
      Serial.print(table[3][3]);
    }
    
    void setup()
    {
      Serial.begin(9600);  
      int which = rand() % 2;
      myfunction(*tables[which]);
    }
    
    void loop()
    {}

  13. Bruce

    14 years ago

    When I use the variables from the Flash to call another function, funny things happen. For instance, this variant on the code you provide above, does not output correctly:
    #include <Flash.h>
    FLASH_TABLE(int, row_wave1, 4,
    {1,2,3,4}, {5,6,7,8}, {9,10,11,12}, {13,14,15,16});
    FLASH_TABLE(int, row_wave2, 4,
    {4,3,2,1}, {8,7,6,5}, {12,11,10,9}, {16,15,14,13});

    typedef _FLASH_TABLE TABLETYPE;
    TABLETYPE *tables[] = {&row_wave1, &row_wave2};

    void myfunction(TABLETYPE &table)
    {
    Serial.print(table[0][0]);
    Serial.print(table[1][1]);
    Serial.print(table[2][2]);
    Serial.print(table[3][3]);
    tablePrinter(table[0][0],table[1][1],table[2][2],table[3][3]);
    }

    void tablePrinter(int a, int b, int c, int d) {
    Serial.print(a);
    Serial.print(b);
    Serial.print(c);
    Serial.print(d);

    }
    void setup()
    {
    Serial.begin(115200);
    int which = rand() % 2;
    myfunction(*tables[which]);
    }

    void loop()
    {}

    the result is 4710134444
    Where the second sequence, ‘4444’ indicates that the same variable is being passed to ‘tablePrinter’ four times.

    I created this test code because I was finding the same effect in a larger project.


  14. Mikal

    14 years ago

    Most curious, Bruce. I get the same behavior when I test on my local box. I can’t explain it. In the _FLASH_ARRAY operator [], I was able to “correct” the behavior by adding the keyword “volatile” in a single line:

    return *reinterpret_cast<volatile T *>(&val);

    I’m not satisfied with this fix because I don’t understand why it works, but I don’t have time to delve into the assembly to find out right now. Thanks for the most interesting update.

    Mikal


  15. Matt E

    14 years ago

    Can Johann or Mikal elaborate a bit on this:

    @Matt E: You can add the following to Flash.h:

    // compare to another string
    bool operator==(const char *str)
    { return compare(str)==0; }

    // compare to anoter string: less, equal, greater
    inline byte compare(const char *str)
    { return -strcmp_P(str, _arr); }

    it allows comparisons:
    (myFlashStr == “abc”)

    I just downloaded Flash3. Where is the best place to add this to flash.h? I get the following errors when trying to compile my sketch.

    d:\Matt\Documents\Arduino\libraries\Flash\/Flash.h:43: error: ‘bool operator==(const char*)’ must have an argument of class or enumerated type

    d:\Matt\Documents\Arduino\libraries\Flash\/Flash.h: In function ‘byte compare(const char*)’:

    d:\Matt\Documents\Arduino\libraries\Flash\/Flash.h:48: error: ‘_arr’ was not declared in this scope


  16. jl

    14 years ago

    Hi!

    Thanx for this useful library. I’m just wondering, is it possible to create a flash array by “copying” a table. As earlier mentioned the values in a flash table can’t be edited afterwards so I thought about first putting the values in a normal array and then calling the FLASH_ARRAY from a function:

    int test[];

    … fill test[] with numbers…

    FLASH_ARRAY(int, flashArray, test);

    Doesn’t work. :(
    And this doesn’t seem to work either:

    int variable1=5;
    int variable2=10;

    FLASH_ARRAY(int, flashArray, variable1, variable2 etc.);

    It says: undefined reference to `__cxa_guard_acquire’

    Is it ONLY possible to create a flash array in this way:

    FLASH ARRAY(int, flashArray, 1,2,3,4,5, etc. the numbers one by one ); ?

    In my project I’m gonna have values coming in from a Processing sketch that I want to store in the Flash memory; there are a lot of values so the space in the EEPROM (512 bytes) won’t suffice. Do I have to start reading on the scary looking PROGMEM-stuff, or is it impossible even with PROGMEM?


  17. Mikal

    14 years ago

    jl– The good news for you is that you won’t have to learn all that scary-looking PROGMEM stuff. The bad news is, well, you guessed it: there is no way to take *run time* data and stuff it into flash memory. That’s only for constant data that is programmed at the time you upload your sketch.

    What you’re probably going to want is to interface with an external SD storage device. Here’s some discussion: http://www.arduino.cc/playground/Learning/SDMMC.

    Mikal

    Mikal


  18. jl

    14 years ago

    Thx for your answer.


  19. Jon Isaiah

    14 years ago

    Does the library support nested boolean/int/float arrays ?


  20. Hutch

    14 years ago

    Mikal

    I concur with others… this library rocks (as does NewSoftSerial)! Thank you for sharing with an appreciative world.

    Question One:

    When printing an unnamed flash string like this:

    Serial << F(“Starting setup function”);

    is there a way to append a linefeed? Of course I could follow it with:

    Serial.println(“”);

    but that’s kinda’ clunky. I’ll be distributing the code, so I don’t want to require every user to apply the Print.h patch.

    Question Two:

    I’ve saved a lot of ram by putting data into flash. I’ve used your example for creating pointers to flash arrays like this:

    // 6 channel, 1 lamp chase
    FLASH_ARRAY(byte, chase0, 6, 6, B000001, B000010, B000100, B001000, B010000, B100000);
    // 6 channel, 2 lamp chase
    FLASH_ARRAY(byte, chase1, 6, 5, B000011, B000110, B001100, B011000, B110000, B100001);
    // 6 channel, 3 lamp chase
    FLASH_ARRAY(byte, chase2, 6, 4, B000111, B001110, B011100, B111000, B110001, B100011);
    // 6 channel, simple spell
    FLASH_ARRAY(byte, chase3, 7, 7, B000000, B000001, B000011, B000111, B001111, B011111, B111111);

    typedef _FLASH_ARRAY ARRAYTYPE;
    // create an array of pointers to the arrays above
    ARRAYTYPE *builtInChase[] = {
    &chase0, &chase1, &chase2, &chase3};

    ARRAYTYPE &currentChasePointer = *builtInChase[1];
    byte currentChaseSteps = currentChasePointer[0];

    I have a lot of those pointer arrays in ram. Could those be put in flash? How? Would there be any trick to dereference them?

    Thanks!

    Hutch


  21. Mikal

    14 years ago

    @Jon,

    As long as each array is two-dimensional you can use FLASH_TABLE, but beyond that, I’m afraid not.

    Mikal


  22. Mikal

    14 years ago

    @Hutch, the first question is easy. You can simply do this to add a newline:

    Serial << F("Hello, world!") << endl;

    The second question is a little trickier. I understand the utility of such a facility; in fact I have wished for it myself. It may be that the current library can do this somehow, or could be easily modified to do so, but I don’t currently know the answer to the question. Let me think about it a bit.

    Mikal


  23. osgeld

    14 years ago

    Love it!


  24. Hutch

    14 years ago

    When I do this:

    Serial << F(“Hello, world!”) << endl;

    I get this:

    In function ‘void setup()’:
    error: ‘endl’ was not declared in this scope

    Hutch


  25. Tadeu

    14 years ago

    Hi for all, I´m just dropping a letter to say that I´m glad to find this website. It is the most usefull and colaborative that I ever found. You all guys are awesome. And special thanks to Mikal, congratulations for the efforts!!!
    I hope i can contribute sooner here as well, because the most important is pull the knowledge ahead, instead of keep.

    Tadeu


  26. JKW

    14 years ago

    Hi,
    i’d like to store a 2d array of strings for a menu structure.
    I defined multiple FLASH_STRING_ARRAY, but i don’t know how to copy the value back to a char array.

    basic idea:
    FLASH_STRING_ARRAY(one,
    PSTR(” 1.blabla”),
    PSTR(” 2.blabla”));

    FLASH_STRING_ARRAY(two,
    PSTR(” 10.blabla”),
    PSTR(” 20.blabla”));

    _FLASH_STRING_ARRAY Menu[]={one,two};

    “somehow”
    char buffer[30];
    strcopy_P(buffer,Menu[1,1]);

    is that possible and can you explain me how?
    Thank you really much.


  27. Mikal

    14 years ago

    You’re not too far off, JKW…

    Try this:

    #include 
    void setup()
    {
      FLASH_STRING_ARRAY(one, 
                      PSTR(" 1.blabla"),
                      PSTR(" 2.blabla"));
    
      FLASH_STRING_ARRAY(two, 
                      PSTR(" 10.blabla"),
                      PSTR(" 20.blabla"));
    
      _FLASH_STRING_ARRAY Menu[]={one,two};
    
      char buffer[30];
      Menu[1][1].copy(buffer, 30);
      
      Serial.begin(115200);
      Serial.println(buffer);
    }
    
    void loop(){}

  28. pelrun

    14 years ago

    Nice library, and a godsend to me!

    I have found a couple of problems though:

    First, the header isn’t wrapped with the usual #ifndef guards to ignore multiple inclusions.

    Second, this includes a conflicting definition of the Streaming header, so you have to include *before* if you want things like endl. I cheated and just put a FLASH_STRING(endl,”\n”) in my code instead….


  29. Chris Williamson

    14 years ago

    Great Library, though I’m trying to figure out some things. I am storing a very large array right now in ram, the array is a 2d array:

    const int DemoDisplay[][25] = {
    {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, 6173, 6173, 0, 0, 0, 0, 0, 0, 0, 0, 6173, 6173, 0, 0, 0, 0, 0, 0, 0, 0, 6173},
    {0, 0, 0, 6173, 0, 0, 6173, 0, 0, 0, 0, 0, 0, 6173, 6173, 0, 6173, 0, 0, 0, 0, 0, 0, 6173, 0},
    {0, 6173, 0, 0, 0, 0, 0, 0, 6173, 0, 0, 6173, 6173, 6173, 6173, 0, 0, 0, 6173, 0, 0, 6173, 0, 0, 0},
    {6173, 0, 0, 0, 6173, 6173, 0, 0, 0, 6173, 6173, 6173, 6173, 6173, 6173, 6173, 0, 0, 0, 6173, 6173, 0, 0, 0, 6173},
    {0, 0, 0, 6173, 0, 0, 6173, 0, 0, 0, 6173, 6173, 6173, 6173, 0, 0, 6173, 0, 0, 0, 0, 0, 0, 6173, 0},

    ETC

    When I need a row, I need it all at one time, but all of this data is constant. Its a pre-programmed RGB display for a 5×5 Matrix.

    Anyway to store this as a 2d array using your library easily?

    Thanks!


  30. Mikal

    14 years ago

    Thanks, pelrun. Yes, I hope to tidy up both those little problems with the next release of flash.

    Mikal


  31. Mikal

    14 years ago

    Hi Chris–

    The FLASH_TABLE type is what you need here. (A table in this context is simply a 2D array.) I designed FLASH_TABLE with exactly this type of application in mind. You’d do something like

    FLASH_TABLE(int, DemoDisplay, 25,
    {0,0,0,0,0…},
    {0,0,0,0,0…},
    {0,0,0,6173,6173…}

    );

    That help?

    Thanks for the note.

    Mikal


  32. Brian Tucker

    14 years ago

    Hi Mikal,
    This is my third day programming my arduino (programming 101 with java is my education) and your lib has enabled me to move pretty quickly towards my goals. I have used this to import data for a 4096 byte array of char data (8×8 chars). Works perfectly in my implementation.

    As noted above, memory usage is quite large, my 4k char set adds 12k in size. I use FLASH_TABLE function like this:

    FLASH_TABLE(int, charData, 8,
    { 60, 102, 110, 110, 96, 98, 60, 0,},
    { 24, 60, 102, 126, 102, 102, 102, 0,},
    { 124, 102, 102, 124, 102, 102, 124, 0,},
    …….
    { 15, 15, 15, 15, 255, 255, 255, 255,},
    { 15, 15, 15, 15, 240, 240, 240, 240,}
    );

    which is processed by the main loop:

    void loop() {
    Serial.println(availableMemory());
    for(int x = 0; x < charData.rows(); x++){
    for(int y = 0; y < 8; y++){
    pixelBuffer[y] = charData[x][y]; //pixelBuffer[8] doubble buffer
    }
    delay(175);
    // Serial.println(x);
    }

    }

    I didn't have to change a thing in the code, just the declarations for the table and the includes, very nice! I can't tell you how nice it was to have it compiled and running with all the chars displaying in less than two or three minutes.

    Is there something you think I could possibly do to reduce the over all size of the data? I'm using a mega328 so I still have plenty of room but of course would like to get 6-8k of that back if possible.


  33. Brian Tucker

    14 years ago

    so changing the data type of the table from ‘int’ to ‘byte’ shaves off 4096 bytes when compiled. I should have noticed that ‘int’ would be 16 bit words. It made a substantial difference switching to 8 bit bytes. So the data is now weighing in at about 2x it’s actual size, not bad.


  34. Mikal

    14 years ago

    Hey, Brian, that’s pretty decent work for day 3! :)

    I don’t think that the data structure is occupying 2x its actual size in flash. These data structures do have some overhead, but not that much. I suspect that most of what you’re seeing is program code and other data. Shall we do an experiment? Temporarily add fours more line to your FLASH_TABLE. I’m thinking that should increase the image size by exactly 32 bytes — and not 64 or some other such big number.

    Mikal


  35. Brian Tucker

    14 years ago

    Your absolutely right Mikal, I compiled the code with the flash data commented out to find size sans char data, it weighs in @ 3880 bytes, and with 4k of char data it’s: 8498 bytes. I would say that in this case 522 bytes or ~13% overhead is actually excellent. :)

    So, now I just have to hack up the bit shift routine for the scrolling and I’m on to the next step.

    Thanks so much for the routine and great support, now I can cope with c++ labels/pointers and addressing modes in my own time. ;)
    I’ll post a link when I finish the project.


  36. Terry

    14 years ago

    Hi Mikal,
    I’m using your Flash library with great success, but am curious to the overheads for storing strings. I’m wondering what lengths of strings warrant the use of Flash.h – ie; is storing a 2 byte string in progmem likely to be more of an expense than saving?


  37. Mark

    14 years ago

    Hi Mikal,

    First off, I think this library is fantastic. I’ve used it for several other projects with much success. I am having an issue with my current project though. I’m using your flash library to hold a table of floats that I use to interpolate barometric altitude from a pressure reading. When I look up the row in the table i get the correct values returned. But, when I do the math on the values, my result doesn’t make sense. If i do the math with the numbers hard coded, it works. I have attached the code below. Any idea as to what is going on? Thanks,

    Mark

    #include // stores non-volitile data in the flash program memory
    // *******************************************************
    // Altitude Interpolation Table
    // generated on 08/12/2010 12:56 AM
    // *******************************************************
    FLASH_TABLE(float, altitudeTable, 3,
    {0.1515, 42913.09,-12845.65000},
    {1.1615, 29939.32,-3946.02800},
    {2.1714, 25953.93,-2408.68100},
    {3.1814, 23521.23,-1738.74600},
    {4.1914, 21765.14,-1361.50500},
    {5.2014, 20390.05,-1119.12700},
    {6.2113, 19259.76,-950.14230},
    {7.2213, 18300.14,-825.55910},
    {8.2313, 17466.35,-729.89150},
    {9.2413, 16729.18,-654.11130},
    {10.2512, 16068.54,-592.59750},
    {11.2612, 15470.04,-541.66550},
    {12.2712, 14922.97,-498.79960},
    {13.2812, 14419.19,-462.22350},
    {14.2911, 13952.36,-430.64630},
    {15.3011, 13517.42,-403.11000},
    {16.3111, 13110.29,-378.88420},
    {17.3211, 12727.62,-357.40570},
    {18.3310, 12366.65,-338.23270},
    {19.3410, 12025.05,-321.01190},
    {20.3510, 11700.83,-305.46060},
    {21.3610, 11392.33,-291.34590},
    {22.3709, 11098.07,-281.51720},
    {23.3809, 10813.75,-268.62520},
    {24.3909, 10542.44,-259.76390},
    {25.4009, 10280.09,-251.53020},
    {26.4108, 10026.05,-243.85860},
    {27.4208, 9779.76,-236.68990},
    {28.4308, 9540.71,-229.97700},
    {29.4408, 9308.44,-223.67520},
    {30.4507, 9082.53,-217.74600},
    {31.4607, 8862.61,-212.15730},
    {32.4707, 8648.34,-206.87980},
    {33.4806, 8439.40,-201.88610},
    {34.4906, 8235.50,-197.15510},
    {35.5006, 8036.38,-192.66360},
    {36.5106, 7841.79,-188.39610},
    {37.5205, 7651.52,-184.33290},
    {38.5305, 7465.34,-180.46110},
    {39.5405, 7283.08,-176.76630},
    {40.5505, 7104.55,-173.23670},
    {41.5604, 6929.59,-169.86020},
    {42.5704, 6758.04,-166.62820},
    {43.5804, 6589.75,-163.52980},
    {44.5904, 6424.58,-160.55800},
    {45.6003, 6262.43,-157.70350},
    {46.6103, 6103.15,-154.96000},
    {47.6203, 5946.64,-152.32170},
    {48.6303, 5792.80,-149.78120},
    {49.6402, 5641.53,-147.33340},
    {50.6502, 5492.72,-144.97310},
    {51.6602, 5346.30,-142.69660},
    {52.6702, 5202.19,-140.49730},
    {53.6801, 5060.29,-138.37300},
    {54.6901, 4920.53,-136.31920},
    {55.7001, 4782.85,-134.33220},
    {56.7101, 4647.18,-132.40850},
    {57.7200, 4513.45,-130.54580},
    {58.7300, 4381.61,-128.74000},
    {59.7400, 4251.58,-126.98990},
    {60.7500, 4123.32,-125.29150},
    {61.7599, 3996.78,-123.64320},
    {62.7699, 3871.91,-122.04290},
    {63.7799, 3748.65,-120.48760},
    {64.7898, 3626.96,-118.97640},
    {65.7998, 3506.79,-117.50660},
    {66.8098, 3388.12,-116.07710},
    {67.8198, 3270.88,-114.68540},
    {68.8297, 3155.05,-113.33090},
    {69.8397, 3040.59,-112.01140},
    {70.8497, 2927.46,-110.72590},
    {71.8597, 2815.63,-109.47290},
    {72.8696, 2705.07,-108.25110},
    {73.8796, 2595.74,-107.05910},
    {74.8896, 2487.61,-105.89660},
    {75.8996, 2380.66,-104.76160},
    {76.9095, 2274.85,-103.65340},
    {77.9195, 2170.16,-102.57090},
    {78.9295, 2066.57,-101.51390},
    {79.9395, 1964.04,-100.48060},
    {80.9494, 1862.56,-99.47040},
    {81.9594, 1762.10,-98.48285},
    {82.9694, 1662.63,-97.51674},
    {83.9794, 1564.14,-96.57182},
    {84.9893, 1466.61,-95.64687},
    {85.9993, 1370.01,-94.74169},
    {87.0093, 1274.32,-93.85515},
    {88.0193, 1179.53,-92.98734},
    {89.0292, 1085.61,-92.13687},
    {90.0392, 992.56,-91.30389},
    {91.0492, 900.34,-90.48738},
    {92.0592, 808.95,-89.68705},
    {93.0691, 718.37,-88.90243},
    {94.0791, 628.58,-88.13288},
    {95.0891, 539.57,-87.37816},
    {96.0990, 451.32,-86.63770},
    {97.1090, 363.82,-85.91109},
    {98.1190, 277.05,-85.19798},
    {99.1290, 191.00,-84.49798},
    {100.1389, 105.66,-83.81069},
    {101.1489, 21.01,-83.13577},
    {102.1589, -62.95,-82.47288},
    {103.1689, -146.25,-81.82170},
    {104.1788, -228.88,-81.82170});

    float AltitudeFromPressure( float Pascals )
    {

    int index = altitudeTable.rows() – 1;

    float slope = 0;
    float delta = 0;
    float pressure = 0;
    // find the pressure element to start from
    while ( altitudeTable[ index ][0] > Pascals )
    index–;

    float base = altitudeTable[ index ][1];
    // get the values
    pressure = altitudeTable[ index ][0];
    //base = altitudeTable[ index ][1];
    slope = altitudeTable[ index ][2];
    delta = Pascals – pressure;

    // return the altitude
    Serial.print(“Pressure : ” );
    Serial.println(Pascals, 4);
    Serial.print(“Table Pressure : ” );
    Serial.println(altitudeTable[ index ][0], 4);
    Serial.print(“Base Altitude : ” );
    Serial.println(altitudeTable[ index ][1], 4);
    Serial.print(“Slope : ” );
    Serial.println(altitudeTable[ index ][2], 4);
    Serial.print(“Static Math : ” );
    Serial.println( ((float) -83.8107 * ((float) 100.8096 – (float) 100.1389)) + (float) 105.66);
    Serial.print(“Calc : ” );
    return (slope * delta ) + base;
    //return ( altitudeTable[ index + 1 ] + (( Pascals – altitudeTable[ index ]) * altitudeTable[ index + 2 ]));

    }

    void setup()
    {

    Serial.begin(115200);

    Serial.println( AltitudeFromPressure( 100.8096 ));
    }

    void loop()
    {}


  38. Mikal

    14 years ago

    Terry, I agree with your suggestion that short strings are not worth storing in flash. In my own projects I usually keep strings of 2 or fewer characters as “normal” strings. A “_FLASH_STRING” object only takes up 2 bytes of RAM, but then there is the overhead of loading the string from flash every time you use it.

    Thanks,

    Mikal


  39. Mikal

    14 years ago

    Mark, sorry I can’t see anything wrong here. What happens when you print the values of slope, delta, and base?

    Mikal


  40. Mark

    14 years ago

    Mikal,

    Here is the output I get when i run it:

    Pressure : 100.8096
    Table Pressure : 100.1389
    Base Altitude : 105.6600
    Slope : -83.8107
    Var Pressure : 100.1389
    Var Altitude : 100.1389
    Var Slope : 100.1389
    Static Math (This is the correct value) : 49.45
    Calc (This is the bad value) : 167.30

    It looks like the values read from the table are returned correctly (Table Pressure, Base Altitude and slope) but the variables all contain the same value (Var Pressure, Var Altitude and Var Slope.)

    Thanks,

    Mark


  41. Mark

    14 years ago

    Mikal,

    I forgot to include the code I changed to get the results above.

    float AltitudeFromPressure( float Pascals )
    {

    int index = altitudeTable.rows() – 1;

    float slope = 0;
    float delta = 0;
    float pressure = 0;
    float base = 0;

    // find the pressure element to start from
    while ( altitudeTable[ index ][0] > Pascals )
    index–;

    altitudeTable[ index ][1];
    // get the values
    pressure = altitudeTable[ index ][0];
    base = altitudeTable[ index ][1];
    slope = altitudeTable[ index ][2];
    delta = Pascals – pressure;

    // return the altitude
    Serial.print(“Pressure : ” );
    Serial.println(Pascals, 4);
    Serial.print(“Table Pressure : ” );
    Serial.println(altitudeTable[ index ][0], 4);
    Serial.print(“Base Altitude : ” );
    Serial.println(altitudeTable[ index ][1], 4);
    Serial.print(“Slope : ” );
    Serial.println(altitudeTable[ index ][2], 4);
    Serial.print(“Var Pressure : ” );
    Serial.println(pressure, 4);
    Serial.print(“Var Altitude : ” );
    Serial.println(base, 4);
    Serial.print(“Var Slope : ” );
    Serial.println(slope, 4);
    Serial.print(“Static Math (This is the correct value) : ” );
    Serial.println( ((float) -83.8107 * ((float) 100.8096 – (float) 100.1389)) + (float) 105.66);
    Serial.print(“Calc (This is the bad value) : ” );
    return (slope * delta ) + base;
    //return ( altitudeTable[ index + 1 ] + (( Pascals – altitudeTable[ index ]) * altitudeTable[ index + 2 ]));

    }
    Thanks,

    Mark


  42. Mikal

    14 years ago

    Mark, I ran this code in Arduino 0018, and it generated the correct results. Or, to be perfectly accurate, I cleaned up one puzzling bit of your code:

    // find the pressure element to start from
    while ( altitudeTable[ index ][0] > Pascals )
    index–;
    
    altitudeTable[ index ][1];
    
    

    I’m frankly surprised (and puzzled) that that compiles. [Note: I checked in 0018 and it doesn’t]. I changed it to:

    // find the pressure element to start from
    while ( altitudeTable[ index ][0] > Pascals )
       index–-;
    

    I don’t see how that change fixed the problem though. What version of the Arduino software are you using anyway?

    Mikal


  43. Mark

    14 years ago

    Mikal,

    I am using Arduino 18 on a Duemilanove (ATMEGA328P).

    I found the same thing you did after I posted the last code segment. Funny, I still don’t get the right results. Can you send me (email) the output you got? I really appreciate the time you’ve given this. Thanks,

    Mark


  44. Mircha Emanuel D'Angelo

    14 years ago

    AWESOME!!! You saved me! :)

    Just a note: if I use the library Streaming.h and I declare Flash.h before Streaming.h there is an exception in compile time due to some conflicts. The conflicts are resolved if I declare Streaming.h before Flash.h.

    THANKS for your work!!!
    Mircha


  45. Antonio

    14 years ago

    Dear Mikal,
    First of all: I subscribe to the list of the ones grateful for your libraries and for sharing them with us.

    I used all of them with success in all my project.
    Now, however, I would like to use them in a slight different scope: I would like to replace all my constant strings defined in the header file of my library, with strings stored in the flash memory of my Arduino (IDE ver. 18 + Arduino 2009 328, FYI).
    I know I cannot include something like:

    FLASH_STRING(CMD_ACTIVE_ON,”HH P1 S1\r”);

    in the header file of my library, or I would get a multiple definition error from compiler (since I must include the header file both in the .pde sketch and in the .cpp of my library).
    I could use the FLASH functions in the .pde sketch. But in this case I have the problem that the flash strings would not be accessible by the .cpp of my library (not in scope).
    If I’m correct I think I should declare my flash strings in the header of my library and define them (calling the FLASH_STRING function) in the .cpp file of my library.
    But I couldn’t find a correct way to solve this despite all my attempts.
    Supposing that I could properly explain my problem, do you have any suggestion to solve it?
    Thanks in advance for your attention.

    Antonio


  46. Mikal

    14 years ago

    This is a superb question, Antonio, and one that I am interested to find the answer to as well. The question basically is “how can I include a library header from another library?”.

    If you modify the flash.h header so that it is safe for multiple inclusions, does that make it work? Something like:

    #ifndef __FLASH_H_INCLUDED__
    #define __FLASH_H_INCLUDED__
    [original flash.h text here]

    #endif

    Mikal


  47. Antonio

    14 years ago

    Hi Mikal,
    thanks for your reply.
    Indeed wrapping the Flash library’s header into the preprocessor ‘#ifndef’ was one of my first moves but not the solution.
    I think I’ve found a workaround for the _FLASH_STRING. This is what I did:

    ////////////// MyLibrary.h:

    #ifndef _MyLibrary_H_
    #define _MyLibrary_H_

    #include “Wprogram.h”
    #include “Flash.h”

    //–Flash strings declaration
    extern _FLASH_STRING CMD1;
    extern _FLASH_STRING CMD2;
    ….
    ….
    #endif

    ////////////// MyLibrary.cpp

    #include “WProgram.h”
    #include “Flash.h”
    #include “MyLibrary.h”

    //–Flash strings definition
    FLASH_STRING(CMD1,”Command1_string\r”);
    FLASH_STRING(CMD2,”Command1_string\r”);

    ///////////////////////////////

    So I realized that
    -the compiler is accepting _FLASH_STRING as a type.
    -the Flash strings are only declared in the .h and then defined in the .cpp (the compiler is now happier)
    -the Flash strings are both visible in the scope of MyLibrary.cpp and in my sketch, after including MyLibrary.h.

    I still have the feeling this is not the best solution….but, for the time being, is working.

    The problems started again when I try to use _FLASH_STRING_ARRAY or _FLASH_ARRAY as types: no way I could get them work.
    For the _FLASH_STRING_ARRAY I’m now trying to use the PROGMEM type ‘extern const prog_char** myStrArray’ in MyLibrary.h and then define it in MyLibrary.cpp with: FLASH_STRING_ARRAY(myStrArray, PSTR(“subStr1”), PSTR(“subStr2”),…);

    I still don’t know if it’s properly working, but at least the compiler does not complain.

    Looking forward to your comments and/or suggestions.

    Thanks in advance.

    Antonio

3 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. […]

Leave a Reply