0

Hey guys I am a noob when it comes to data structures and storing types of data, I have been recently working on a project where I needed to store long term data for later retrieval. I decided to buy a Adafruit 10$ 32kb i2c fram Which works, it can store a byte Of data per address which I can successfully do, I can also read those bytes on any address no problem.

One issue I first came across was storing floats into the chip which only took bytes, After googling I managed to spit a float using a union successfully and also storing those in a 4 byte array. Now I did this with 3 different float values which means every 4 bytes stored is basically one split float value.

The second issue is how do I retrieve this data in an organized way and also as a float. I found out you can use a union to do the opposite as well. But how do I tell my code to read every 4 bytes and convert back to float?

Is there a system that can allow me to store data in a structured way using the arduino? Like a time stamped data using an external rtc? Such that when I click retrieve it will print that data in an organized fashion.

  • It is unclear to me, where exactly the problem lies. Reading all 4 bytes, that you need for your float, means just reading 4 bytes sequentially. Depending on how your FRAM does communication, you could maybe do that in one single reading transmission. You can easily write the read data into a union and then read the float from it. That's just exactly the opposite way of splitting the float up. And surely, you could save a timestamp with each float, but why? The FRAM is just a piece of sequential data storage, just like any other memory. Do you want a filesystem here? – chrisl Jul 17 at 19:36
2

It'll be easier if you use a struct, not a union. Store all the data you want to preserve in a struct, then cast a pointer to it to be a byte pointer and just treat it as an array of bytes and read and write those bytes to the FRAM.

The union you were using explicitly did the same thing, but it's not easy to scale to multiple items.

Some caveats about what you can safely keep in the struct:

  • do not store pointers in it. A char array is fine because the entire array will take up space in the struct. A char * is not because all you'll save is the value of the pointer, not what it points at.

  • do not store objects (like String) in it. You don't know (and shouldn't know) how the object is composed internally. If need to use objects, they should have serialize and deserialize methods which would store or restore the contents of an object into an array of bytes which you could then store or restore with the FRAM.

Also remember that the C/C++ sizeof function (used below) tells you the size of thing at compile-time. So if you use it on a struct it will tell you the number of bytes it takes to store the struct. If you use it on a char *, it will tell you the number of bytes in a pointer to a char, not the number of bytes in the C string that the char * points at. If you use it on an object - like String str; sizeof(str); - it will tell you how many bytes it takes to store the String object, which will include the length of the string it stores.

Psuedo-code follows. There are more compact ways to write this; I'm aiming for clarity here.

#include <Arduino.h>

struct program_data {
  float first_thing;
  unsigned long second_thing;
  char third_thing[55];
  char fourth_thing;
  uint16_t fifth_thing;
} data;

void save_data(struct program_data *data_ptr) {
  byte *ptr = (byte *)data_ptr;

  for(size_t i = 0; i < sizeof(struct program_data); i++)
    store_byte_in_fram(ptr[i], i);
}

void restore_data(struct program_data *data_ptr) {
  byte *ptr = (byte *)data_ptr;

  for(size_t i = 0; i < sizeof(struct program_data); i++)
    retrieve_byte_from_fram(ptr[i], i);
}

// call when you want to save your data
  save_data(&data);

// call when you want to restore your data
  restore_data(&data);

| improve this answer | |
  • 1
    Dude you are incredible, first off thank you for replying. Second this was so easy to understand! Thank you dude I will try it out and tell you. – Steven Gangaram Jul 17 at 20:55
  • I have an external RTC that I want to add to it so that every 5 or 10 seconds it will save the struct of values and a time associated with it. Would this overwrite A specific sector or can it shift leaving the previous data? – Steven Gangaram Jul 17 at 20:58
  • Good question. RTCs usually use battery-backed static RAM where it wouldn't matter if it's overwriting the same addresses. It really depends on the system and the interface to it, though. If you're addressing memory directly then writing to the same address should be the same place in memory. – romkey Jul 17 at 21:00
  • Small concern. That approach might fail if it is not granted that the structure is packed – brtiberio Jul 18 at 7:28
  • @brtiberio why do you think that would be a problem? – romkey Jul 22 at 3:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.