Commit 962596fb authored by deroo's avatar deroo
Browse files

Initial commit

parent ad318736
#include <Nano33BLEflash.h>
A sketch to demo using Arduino Nano 33 BLE flash for non-volatile data storage
The Nano 33 BLE uses a nRF52840 microcontroller chip
The Flash on the nRF52840 has 256 pages of 1024 words, each word is 4 bytes.
Each page is individually erasable; each word is individually writable.
The first 16 pages (0-15) are used for the bootloader.
Do not corrupt the bootloader lest your Nano become useless!
The next 19 pages (16-35) are used by this sketch. Larger sketches may use more pages.
(it seems the smallest sketches, like blink, take 19 pages)
To check how many pages your sketch uses, watch the colored text as it uploads (hit the Arduino reset button to abort).
Or, compile and take the number of bytes in "Sketch uses NNNN bytes (X%) of program storage space..."
and divide by 4096, rounding up.
// change this from 1 to 0 the 2nd time uplaoding and running the code.
// Cut and restore power to demo volatile vs non-volatile memory
const int initialUpload = 1;
// basics of where in flash this sketch puts its array
// a random page, more than 16+19=35;
// less than or equal to 255, which is the last page.
const unsigned int flashPage = 253;
// the memory (byte) address of the above page, base of the flash array
const unsigned int flashAddr = flashPage * flashBytesPerPage;
// declaration of variables that use flash, not RAM:
// manually specify the memory location, thus must be via a pointer
// global scope, so they can be seen in both setup() and loop(),
// (as must be any variable that appears in both.)
// otherwise, they could be declared more locally
// and passed by reference like any array.
// the size of the array. keep it <1024 to keep it on one flash page
const unsigned int arraySize = 20;
// an array in flash: tell compiler where, but not how big
// (that's your job to keep track of)
int *ArrayInFlash = (int *)flashAddr;
// an array in RAM: tell compiler how big, but not where
// (that's the compiler's job to keep track of)
int ArrayInRAM[arraySize];
void setup() {
unsigned int index; // the array index
while (!Serial);
if (initialUpload == 1) {
// erase the page to initialize the flash array
Serial.println("About to erase");
flashMode(FLASH_ERASE); // enable erasing of pages in Flash
int result = flashErasePage(flashPage); // flash erase happens here.
flashMode(FLASH_READONLY); // protect flash from inadvertent writes
Serial.print("Page ");
if (result >= 0) {
} else {
Serial.print(" not");
Serial.println(" erased");
Serial.println("Erase complete");
// fill the arrays
for ( index = 0; index < arraySize; index++ ) {
int int2write = arbitraryFunction(index); // make up something to write
flashMode(FLASH_WRITE); // enable writing to flash
// write data to array in flash. Surround w/ calls to flashMode()
ArrayInFlash[index] = int2write;
flashMode(FLASH_READONLY); // protect flash from inadvertent writes
ArrayInRAM[index] = int2write; // write data to array in RAM.
// check the contents of the arrays
// reads an element of the integer arrays, compares to what it should be
for ( index = 0; index < arraySize; index++ ) {
Serial.print("] is ");
Serial.print(" while ArrayInRAM[");
Serial.print("] is ");
Serial.print(" ... both should be ");
if (initialUpload == 1) {
Serial.print("Now, to demonstrate how flash is non-volatile ");
Serial.println("while RAM is volatile, ");
Serial.println("change the line (near the top of the sketch) from ");
Serial.println("const int initialUpload = 1;");
Serial.println("to ");
Serial.println("const int initialUpload = 0;");
Serial.println("and upload again.");
} else {
Serial.print("Cut power to the Arduino, ");
Serial.println("plug it in again, and watch the output.");
void loop() {
// put your main code here, to run repeatedly:
int arbitraryFunction(int in) {
// a function to make different integer values
// as a function of the integer array index.
// just to make it clear we are not seeing something trivial
// in the Serial.prints
int out = in*2 + 10; // this is what's arbitrary. Make it whatever you want.
return out;
# keywords for Nano33BLEflash
# data types
_flashModeEnum KEYWORD1
# functions
flashMode KEYWORD2
flashErase KEYWORD2
_wait4flash2Bready KEYWORD2
# constants
flashPageSize LITERAL1
author=Roger De Roo
maintainer=Roger De Roo
sentence=Direct flash memory access
paragraph=This library enables Arduino Nano 33 BLE to use its onboard flash memory for storage of arrays. Thanks to Frank Holtz of arduino-NVM for inspiration.
category=Data Storage
architectures=mbed, (nRF52840 specifically)
* Even 'tho this file contains C and not C++, it must be a .cpp file
* for its dependencies
#include "Arduino.h"
#include "Nano33BLEflash.h"
#ifdef NRF52840_XXAA // this is defined iff Nano 33 BLE is selected
//void Nano33BLEflash::wait4flash2Bready(void)
void _wait4flash2Bready(void)
* private function to assist timing.
* Should not be directly called by a sketch,
* only by flashMode() and flashErasePage()
//void Nano33BLEflash::mode(Flash_mode mode)
void flashMode(_flashModeEnum mode)
* Set the flash mode using the _flashModeEnum enum values.
* Keep flash in READ_ONLY mode unless actively writing or erasing,
* so that on power fail and goofy things happen as the supply voltage drops,
* the flash (esp. the bootloader) remain locked from any inadvertent changes.
//int Nano33BLEflash::erase(byte page)
int flashErasePage(byte page)
* Function erases the page given by the input parameter page.
* Does range checking.
* Returns page number that was erased on success,
* or negative integer if not successful.
* hardwired to work only for nRF52840 (ie. an Arduino Nano 33 BLE)
if (Serial) {
Serial.println("Flash not in erase mode");
Serial.println("call flashMode(FLASH_ERASE); before flashErasePage()");
return -1;
if (page < 16) {
if (Serial) {
Serial.println("Attempt to erase bootloader page denied");
Serial.println("Advice: use pages b/t 50 and 255");
return -2;
if (page < 16+50) {
if (Serial) {
Serial.println("Attempt to erase sketch page denied");
Serial.println("Advice: use pages b/t 50 and 255");
return -3;
if (page >= NRF_FICR->CODESIZE) { // 256
if (Serial){
Serial.println("Attempt to erase non-existant page denied");
Serial.println("Advice: use pages b/t 50 and 255");
return -4;
uint32_t address=page*NRF_FICR->CODEPAGESIZE;
NRF_NVMC->ERASEPAGE = (size_t)(address);
return page;
#ifndef Nano33BLEflash_h
#define Nano33BLEflash_h
#include "Arduino.h"
#ifdef NRF52840_XXAA // this is defined iff Nano 33 BLE is selected
// Caution: these enums are the register settings for the given mode.
enum _flashModeEnum{
const int flashBytesPerPage = NRF_FICR->CODEPAGESIZE; // 4096 bytes
const int flashBytesPerWord = 4;
const int flashNumberOfPages = NRF_FICR->CODESIZE; // 256 pages
void flashMode(_flashModeEnum mode);
int flashErasePage(byte page);
void _wait4flash2Bready(void);
class Nano33BLEflash
const int bytesPerPage=NRF_FICR->CODEPAGESIZE; // 4096 bytes
void mode(Flash_mode mode);
int erase(byte page);
void wait4flash2Bready(void);
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment