I've been looking into how to store data in between restarts. With an Arduino UNO, there are plenty of EEPROM libraries, but I'm not finding something 'off the rack' for the Arduino Nano 33 BLE.

I did manage to find a well documented example by Pete Warden, who recently put on github (https://github.com/petewarden/arduino_nano_ble_write_flash), and it can be compiled and downloaded, but I'm unclear as to how one would expand on it, to write a simple function that can store and read multiple values (integer, float, string, arrays).

The code is below, I'm a bit rusty on things, but I am thinking that the key is in the part:

  // Treat the first four bytes of the copy of our flash array as a 32-bit
  // integer.
  int32_t* counter_address = reinterpret_cast<int32_t*>(ram_buffer);

How would one add additional variables (and of different lengths) to this code, so you could write and read more than one variable? Somehow, it would seem a command like:

int32_t* another_variable = [modified version of:] reinterpret_cast<int32_t*>(ram_buffer);

... would do the trick, but I'm not quite sure about how this is done.

   * Copyright 2021 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
See the License for the specific language governing permissions and
limitations under the License.

// This sketch demonstrates how to initialize, read, and update flash memory
// on an Arduino Nano BLE Sense 33. It contains a counter that starts at zero
// when the sketch is first uploaded, and is incremented by one every time that
// the board is reset without a re-flash. You can test this by uploading the
// sketch, opening the serial monitor, and seeing "Counter=0" output initially.
// If you then press the reset button, you should see "Counter=1", and so on as
// the board is restarted.

// This Mbed API lets us access flash memory, so we include the header. See
// https://os.mbed.com/docs/mbed-os/v6.9/apis/flashiapblockdevice.html
#include "FlashIAPBlockDevice.h"

// One of the challenges I had with the existing examples I found of using flash
// was that they didn't demonstrate how to set an initial value for the memory
// when the sketch was first uploaded. This was essential for most use cases,
// for example we want the counter to start at zero so the initial contents need
// to be set when the program is flashed. I would typically try to use linker
// scripts to set aside an area of memory and mark it so it's initialized during
// flashing, but that's not very easy with the Arduino IDE. Instead I use a bit of
// a hack, by:
//  - Declaring an array of bytes as const, so I know it will end up in
//    flash.
//  - Forcing it to align with the block size of the flash, so it can be
//    accessed by the API that works with whole pages of flash.
//  - Adding an empty initializer list ({}) tells the compiler to zero out the
//    contents in the binary that's flashed to the device.
// The last point is a bit subtle, because you might think that doing it in a
// constructor or setup() would work, but that would be called every time the
// program is reset. What I needed was a way to create a binary with that area
// already initialized before upload, which this approach offers.
// Some other examples use hard-coded addresses for the flash, usually towards
// the top of the address space so that they won't clash with the loaded program,
// but this approach does have the advantage that your writable area is dealt with
// in the same way as other variables, so you shouldn't have to worry about
// overwriting anything.

// From experimentation I know that the "page size" or "block size" of the flash
// on the board is 4KB, and should match the reported get_erase_size() from the
// block device object. In theory we should be able to use the
// MBED_CONF_FLASHIAP_BLOCK_DEVICE_SIZE macro, but this seems to be set to zero.  
    #include "FlashIAPBlockDevice.h"
    constexpr int kFlashBlockSize = 4096;
        // Your flash area needs to be a multiple of the block size. In this case I want
        // 64KB (even though I'm only using the first four bytes). You should make this
        // the smallest multiple of the block size that will hold your data.
        #define ROUND_UP(val, block_size) ((((val) + ((block_size) - 1)) / (block_size)) * (block_size))
        constexpr int kFlashBufferSize = ROUND_UP(64 * 1024, kFlashBlockSize);
        // As mentioned above, alignas ensures we get a valid block-aligned address,
        // const should make sure it's in flash, and the empty brackets mean the array
        // is filled with zeroes when the program is first uploaded.
        alignas(kFlashBlockSize) const uint8_t flash_buffer[kFlashBufferSize] = {};
        void setup() {
              // Beware! If you copy and paste this code into your own example, and try
              // running it without the serial monitor attached, this line will hang forever.
              // You'll need to remove this in production (and yes I have been caught by this
              // myself far too often).
              while (!Serial);
              // The address of the array will be determined by the compiler, and we need to
              // grab it as a 32-bit integer to use with the Mbed API.
              const uint32_t flash_buffer_address = reinterpret_cast<uint32_t>(flash_buffer);
              Serial.println(String("flash_buffer_address=0x") + String(flash_buffer_address, 16));
              // Create the flash object we'll be using to access the flash memory.
              static FlashIAPBlockDevice bd(flash_buffer_address, kFlashBufferSize);
              // We'll need to copy the area of flash to RAM to modify it, so allocate an
              // array of the right size.  
              uint8_t* ram_buffer = (uint8_t*)(malloc(kFlashBufferSize));
              // Copy the existing flash contents into our ram buffer.  
              bd.read(ram_buffer, 0, kFlashBufferSize);
              // We need to erase the flash area before we can write into it again.
              bd.erase(0, kFlashBufferSize);
              // Treat the first four bytes of the copy of our flash array as a 32-bit
              // integer.
              int32_t* counter_address = reinterpret_cast<int32_t*>(ram_buffer);
              // Print out the value before any changes.
              Serial.println(String("Counter=") + String(*counter_address, 16));
              // Update our RAM copy of the counter integer.
              *counter_address += 1;
              // Write the whole copy of our RAM buffer back into flash. 
              bd.program(ram_buffer, 0, kFlashBufferSize);
              // Shut down our flash access object.
  • put them in the buffer, read them from buffer
    – Juraj
    May 4, 2021 at 5:49
  • OK... but how does one exactly put them in the buffer? The syntax is what is not understood. It is understood that if you have a buffer, you can put at certain locations in the buffer - but how is that done?
    – asylumax
    May 4, 2021 at 10:44
  • The flash will be erased everytime you upload a new sketch. Is that what you want?
    – Fahad
    May 5, 2021 at 6:08
  • 1
    No; the request is that you be able to add N variables. In doing this with EEPROM, it involved offsets from a memory location. What I'm curious about is how you can do this with a bunch of variables of different types.
    – asylumax
    May 5, 2021 at 20:31

3 Answers 3


I can't really help with the source code you found, but here is a simpler solution for your original problem: I wrote a library called NanoBLEFlashPrefs. It allows you to store parameters and preferences persistently between program restarts and even reprogramming.

The Arduino boards mentioned above use a nRF52840 microcontroller from Nordic Semiconductor. This chip features a very simple file system for flash storage. This is used in the library to store and retrieve an arbitrary struct of data of your program.

Please take a look at the GitHub repository of NanoBLEFlashPrefs.

  • In the new Arduino board setup, I get the message "WARNING: library NanoBLEFlashPrefs claims to run on mbed_nano architecture(s) and may be incompatible with your current board which runs on mbed architecture(s). "
    – asylumax
    Feb 8, 2022 at 2:17
  • @asylumax You can safely ignore this if you really use an Arduino Nano 33 BLE. I have seen this as well, but now it is gone. Which version of the IDE and which version of the board support "Arduino Mbed OS Nano Boards" do you use? With version 2.6.1 of that board support and version 1.8.15 of the IDE I don't see this warning any more.
    – Dirk
    Feb 8, 2022 at 6:43

You can also try my FS_Nano33BLE Library with simple-to-use LittleFS / FATFS.

The filesystem access uses normal POSIX APIs or mbed FileSystem APIs

  • Great library; there doesn't seem to be a 'directory' function to figure out what files exist. Right now, I'm writing a few wrappers so you can use strings, which some folks might use.
    – asylumax
    Feb 9, 2022 at 1:29
  • I was able to build the 'directory' command, based on the link you provided, (os.mbed.com/docs/mbed-os/v6.10/apis/file-system-apis.html). Thanks.
    – asylumax
    Feb 10, 2022 at 1:59

I guess a simple solution would be to stick with the original pattern and use only one variable... but have this variable be a container for all the stuff you need:

struct StoredData {
    int32_t some_integer_variable;
    float some_float;
    // etc...

Then you can use the same pattern as the original code:

StoredData* my_data = reinterpret_cast<StoredData*>(ram_buffer);

and access the individual variables as my_data->some_integer_variable, my_data->some_float, etc.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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