|
| 1 | +# FlashStorage_SAMD library for Arduino |
| 2 | + |
| 3 | + |
| 4 | +### Initial Version v1.0.0 |
| 5 | +1. Add support to SAMD51 family such as Itsy-Bitsy M4, etc. |
| 6 | + |
| 7 | +Library is based on and modified from: |
| 8 | +1. [Cristian Maglie's FlashStorage](https://github.com/cmaglie/FlashStorage) |
| 9 | + |
| 10 | +The FlashStorage library aims to provide a convenient way to store and retrieve |
| 11 | +user's data using the non-volatile flash memory of microcontrollers. |
| 12 | + |
| 13 | +The flash memory, due to his properties, is generally used to store the firmware |
| 14 | +code, but it can also be used to store user data. |
| 15 | + |
| 16 | +## Supported hardware |
| 17 | + |
| 18 | +Currently, ***ATSAMD21 and ATSAMD51*** are supported (and consequently every board based on |
| 19 | +this cpu like the ***Arduino Zero, Aduino MKR1000, Nano-33 IoT, Itsy-Bitsy M4, etc***). |
| 20 | + |
| 21 | +## Limited number of writes |
| 22 | + |
| 23 | +The flash memory has a limited amount of write cycles. Typical flash |
| 24 | +memories can perform about 10000 writes cycles to the same flash block |
| 25 | +before starting to "wear out" and begin to lose the ability to retain data. |
| 26 | + |
| 27 | +So **BEWARE: IMPROPER USE OF THIS LIBRARY CAN QUICKLY AND PERMANENTLY |
| 28 | +DESTROY THE FLASH MEMORY OF YOUR MICRO**, in particular you should avoid to |
| 29 | +call the `write()` function too often and make sure that in the entire life |
| 30 | +of the micro the number of calls to `write` stay well below the above limit |
| 31 | +of 10000 (it's a good rule-of-thumb to keep that number in mind even if the |
| 32 | +manufacturer of the micro guarantees a bigger number of cycles). |
| 33 | + |
| 34 | +The same caution must be taken if you're using the EEPROM API emulation (see |
| 35 | +below) with the `EEPROM.commit()` function. |
| 36 | + |
| 37 | +## Installation |
| 38 | + |
| 39 | +### Use Arduino Library Manager |
| 40 | +The best and easiest way is to use `Arduino Library Manager`. Search for `FlashStorage_SAMD`, then select / install the latest version. |
| 41 | +You can also use this link [](https://www.ardu-badge.com/FlashStorage_SAMD) for more detailed instructions. |
| 42 | + |
| 43 | +### Manual Install |
| 44 | + |
| 45 | +1. Navigate to [FlashStorage_SAMD](https://github.com/khoih-prog/FlashStorage_SAMD) page. |
| 46 | +2. Download the latest release `FlashStorage_SAMD-master.zip`. |
| 47 | +3. Extract the zip file to `FlashStorage_SAMD-master` directory |
| 48 | +4. Copy whole |
| 49 | + - `FlashStorage_SAMD-master` folder to Arduino libraries' directory such as `~/Arduino/libraries/`. |
| 50 | + |
| 51 | +## Usage |
| 52 | + |
| 53 | +First of all you must declare a global `FlashStorage` object for each piece of |
| 54 | +data you intend to store in the flash memory. |
| 55 | +For example if you want to store the age of a person you must declare an |
| 56 | +`age_storage` like this: |
| 57 | + |
| 58 | +```c++ |
| 59 | +FlashStorage(age_storage, int); |
| 60 | +``` |
| 61 | +
|
| 62 | +this instruction means "create a `FlashStorage` to store an `int` variable and call |
| 63 | +it `age_storage`". Now you can use `age_storage` as a place to safely store an integer: |
| 64 | +
|
| 65 | +```c++ |
| 66 | +void readAndStoreUserAge() { |
| 67 | + Serial.println("Please enter your age:"); |
| 68 | + String age = Serial.readStringUntil('\n'); |
| 69 | +
|
| 70 | + age_storage.write(age.toInt()); // <-- save the age |
| 71 | +} |
| 72 | +``` |
| 73 | + |
| 74 | +after a reset of the microcontroller to retrieve the stored age you can use: |
| 75 | + |
| 76 | +```c++ |
| 77 | +int user_age = age_storage.read(); |
| 78 | +``` |
| 79 | + |
| 80 | +### Using the alternative EEPROM-like API |
| 81 | + |
| 82 | +If you include `FlashAsEEPROM.h` you'll get an EEPROM emulation with the internal flash memory. |
| 83 | +See [EmulateEEPROM](examples/EmulateEEPROM) sketch for an example. |
| 84 | + |
| 85 | +The API is very similar to the well known Arduino EEPROM.h API but with two additional functions: |
| 86 | + |
| 87 | +* `EEPROM.isValid()` returns `true` if data in the EEPROM is valid or, in other words, if the data has been written at least once, otherwise EEPROM data is "undefined" and the function returns `false`. |
| 88 | +* `EEPROM.commit()` store the EEPROM data in flash. Use this with care: Every call writes the complete EEPROM data to flash. This will reduce the remainig flash-write-cycles. Don't call this method in a loop or [you will kill your flash soon](https://github.com/khoih-prog/FlashStorage_SAMD#limited-number-of-writes). |
| 89 | + |
| 90 | +### Examples |
| 91 | + |
| 92 | + 1. [EmulateEEPROM](examples/EmulateEEPROM) |
| 93 | + 2. [FlashStoreAndRetrieve](examples/FlashStoreAndRetrieve) |
| 94 | + 3. [StoreNameAndSurname](examples/StoreNameAndSurname) |
| 95 | + |
| 96 | +This is the code of [StoreNameAndSurname](examples/StoreNameAndSurname) |
| 97 | + |
| 98 | +```cpp |
| 99 | +#include <FlashStorage_SAMD.h> |
| 100 | + |
| 101 | +// Create a structure that is big enough to contain a name |
| 102 | +// and a surname. The "valid" variable is set to "true" once |
| 103 | +// the structure is filled with actual data for the first time. |
| 104 | +typedef struct |
| 105 | +{ |
| 106 | + boolean valid; |
| 107 | + char name[100]; |
| 108 | + char surname[100]; |
| 109 | +} Person; |
| 110 | + |
| 111 | +// Reserve a portion of flash memory to store a "Person" and |
| 112 | +// call it "my_flash_store". |
| 113 | +FlashStorage(my_flash_store, Person); |
| 114 | + |
| 115 | +// Note: the area of flash memory reserved lost every time |
| 116 | +// the sketch is uploaded on the board. |
| 117 | + |
| 118 | +void setup() |
| 119 | +{ |
| 120 | + SERIAL_PORT_MONITOR.begin(9600); |
| 121 | + while (!SERIAL_PORT_MONITOR); |
| 122 | + |
| 123 | + // Create a "Person" variable and call it "owner" |
| 124 | + Person owner; |
| 125 | + |
| 126 | + // Read the content of "my_flash_store" into the "owner" variable |
| 127 | + owner = my_flash_store.read(); |
| 128 | + |
| 129 | + // If this is the first run the "valid" value should be "false"... |
| 130 | + if (owner.valid == false) |
| 131 | + { |
| 132 | + // ...in this case we ask for user data. |
| 133 | + SERIAL_PORT_MONITOR.setTimeout(30000); |
| 134 | + SERIAL_PORT_MONITOR.println("Insert your name:"); |
| 135 | + String name = SERIAL_PORT_MONITOR.readStringUntil('\n'); |
| 136 | + SERIAL_PORT_MONITOR.println("Insert your surname:"); |
| 137 | + String surname = SERIAL_PORT_MONITOR.readStringUntil('\n'); |
| 138 | + |
| 139 | + // Fill the "owner" structure with the data entered by the user... |
| 140 | + name.toCharArray(owner.name, 100); |
| 141 | + surname.toCharArray(owner.surname, 100); |
| 142 | + // set "valid" to true, so the next time we know that we |
| 143 | + // have valid data inside |
| 144 | + owner.valid = true; |
| 145 | + |
| 146 | + // ...and finally save everything into "my_flash_store" |
| 147 | + my_flash_store.write(owner); |
| 148 | + |
| 149 | + // Print a confirmation of the data inserted. |
| 150 | + SERIAL_PORT_MONITOR.println(); |
| 151 | + SERIAL_PORT_MONITOR.print("Your name: "); |
| 152 | + SERIAL_PORT_MONITOR.println(owner.name); |
| 153 | + SERIAL_PORT_MONITOR.print("and your surname: "); |
| 154 | + SERIAL_PORT_MONITOR.println(owner.surname); |
| 155 | + SERIAL_PORT_MONITOR.println("have been saved. Thank you!"); |
| 156 | + |
| 157 | + } |
| 158 | + else |
| 159 | + { |
| 160 | + // Say hello to the returning user! |
| 161 | + SERIAL_PORT_MONITOR.println(); |
| 162 | + SERIAL_PORT_MONITOR.print("Hi "); |
| 163 | + SERIAL_PORT_MONITOR.print(owner.name); |
| 164 | + SERIAL_PORT_MONITOR.print(" "); |
| 165 | + SERIAL_PORT_MONITOR.print(owner.surname); |
| 166 | + SERIAL_PORT_MONITOR.println(", nice to see you again :-)"); |
| 167 | + } |
| 168 | +} |
| 169 | + |
| 170 | +void loop() |
| 171 | +{ |
| 172 | + // Do nothing... |
| 173 | +} |
| 174 | +``` |
| 175 | +
|
| 176 | +## License |
| 177 | +
|
| 178 | +This library is released under MIT license. |
| 179 | +
|
| 180 | +## FAQ |
| 181 | +
|
| 182 | +### Can I use a single FlashStorage object to store more stuff? |
| 183 | +
|
| 184 | +Yes, you can declare a `struct` with more fields and create a `FlashStorage` object to |
| 185 | +store the entire structure. See the [StoreNameAndSurname](examples/StoreNameAndSurname) |
| 186 | +sketch for an example on how to do it. |
| 187 | +
|
| 188 | +### The content of the FlashStorage is erased each time a new sketch is uploaded? |
| 189 | +
|
| 190 | +Yes, every time you upload a new sketch, the previous content of the FlashStorage is erased. |
| 191 | +
|
| 192 | +### Do you recommend to use FLASH instead of EEPROM? |
| 193 | +
|
| 194 | +No. If your micro provides an EEPROM it's almost always better to use that because |
| 195 | +it's a kind of memory designed with the specific purpose to store user data (it has a |
| 196 | +longer lifetime, number of write cycles, etc...). |
| 197 | +
|
| 198 | +In the absence of an EEPROM you can use this library to use a piece of the flash memory |
| 199 | +as an alternative to EEPROM but you must always keep in mind his limits. |
| 200 | +
|
| 201 | +### Contributions and thanks |
| 202 | +1. Forked and modified from [Cristian Maglie's FlashStorage](https://github.com/cmaglie/FlashStorage). All the credits go to [Cristian Maglie](https://github.com/cmaglie) |
| 203 | +
|
| 204 | +## Contributing |
| 205 | +
|
| 206 | +If you want to contribute to this project: |
| 207 | +- Report bugs and errors |
| 208 | +- Ask for enhancements |
| 209 | +- Create issues and pull requests |
| 210 | +- Tell other people about this library |
| 211 | +
|
0 commit comments