Commit 64c83d0f authored by deroo's avatar deroo
Browse files

separate declare type/scope from where/how much

parent eabadb5c
......@@ -3,7 +3,7 @@
Functions and constants for declaring arrays in the flash memory
of an Arduino Nano 33 BLE and Arduino Nano 33 BLE Sense.
The Nano 33 BLE uses a nRF52840 microcontroller chip.
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.
......@@ -21,16 +21,16 @@ flashBytesPerWord
flashNumberOfPages
with the values of 4096, 4 and 256, respectively.
Finally, it declares 2 macros:<br>
NANO33BLE_FLASH( \<datatype\>, \<arrayName\>, \<numberOfArrayElements\> )<br>
NANO33BLE_FLASH_LOWEST_PAGE<br>
Finally, it declares 2 macros:
NANO33BLE_PUT_ARRAY_IN_FLASH( \<datatype\>, \<arrayName\>, \<numberOfArrayElements\> )
NANO33BLE_FLASH_LOWEST_PAGE
which are described below.
This code is most useful for implementing non-volatile arrays,
particularly when the datatype is of the size of a flash word or larger
(eg. int, long, float, double).
(eg. int, long, float, double).
Arrays of datatypes smaller than a flash word (eg. char, byte, short)
are awkward to implement, but doable.
are awkward to implement, but doable.
The issue is that the nature of flash memory is such that each word
is writable essentially once after each erase.
......@@ -48,24 +48,40 @@ value = arrayInFlash[index];
or
Serial.print(arrayInFlash[index]);
Declare arrays in flash using a macro:<br>
NANO33BLE_FLASH( \<datatype\>, \<arrayName\>, \<numberOfArrayElements\> )<br>
such as<br>
NANO33BLE_FLASH( int, arrayInFlash, 200 )<br>
to create an array named "arrayInFlash" of 200 ints.
The order of the three arguments is meant to match the order of arguments for declaring an array in RAM, which is:<br>
\<datatype\> \<arrayName\> [ \<numberOfArrayElements\> ];<br>
like<br>
int arrayInRAM[200];<br>
to make a same-sized array of ints in RAM.
The macro sequentially packs the arrays in from the top of the available flash memory, reaching down as far as it needs to go.
The lowest flash page that is partially or fully occupied with your arrays is given by the macro NANO33BLE_FLASH_LOWEST_PAGE.
Declare arrays in flash is a two-step process.
The first step is to declare the array data type, and specify its scope.
This is done with a statement with a format of
\<datatype\> *\<arrayName\>;
such as
double *arrayInFlash;
to declare an array of doubles named "arrayInFlash".
The asterisk ( * ) before the array name is important.
The scope of the array is determined by where the declaration is made.
If outside of any function, the scope is global (all functions can see the array), while if it is inside a function, it will be seen only within that function , and others to which it is passed in the function argument list.
The second step is to specify where and how big the array is.
This is done using a macro:
NANO33BLE_PUT_ARRAY_IN_FLASH( \<datatype\>, \<arrayName\>, \<numberOfArrayElements\> )
such as
NANO33BLE_PUT_ARRAY_IN_FLASH( double, arrayInFlash, 200 )
to put the array named "arrayInFlash", previously defined to be an array of doubles, into flash memory such that it can hold up to 200 elements.
The order of the three arguments is meant to match the order of arguments for declaring an array in RAM, which is:
\<datatype\> \<arrayName\> [ \<numberOfArrayElements\> ];
like
double arrayInRAM[200];
to make a same-sized array of doubles in RAM.
The array macro NANO33BLE_PUT_ARRAY_IN_FLASH must be inside a function, because it makes calculations as to where the array will fit in flash. It should be called only once for each array, and prior to using that array. It makes the most sense to put it into the function setup(). The declaration must preceed the macro call, but can be in the same function (for a local array) or before all the functions (for a global array).
The array macro NANO33BLE_PUT_ARRAY_IN_FLASH does not initialize or otherwise modify the contents of the array. It just makes the sketch look in the correct place in flash memory when it encounters future references to the array.
The macro sequentially packs the arrays in from the top of the available flash memory, reaching down as far as it needs to go.
The lowest flash page that is partially or fully occupied with your arrays is given by the macro NANO33BLE_FLASH_LOWEST_PAGE.
Thus, if you need to erase all the pages your sketch is using in order to initialize them, loop with a for loop from NANO33BLE_FLASH_LOWEST_PAGE to flashNumberOfPages, erasing each page as you go.
Valid datatypes include structs and typedefs, in addition to the predefined C datatypes. Structs appear to default to multiples of flash words, so the programmer's attention to alignment issues does not appear to be neccessary.
Valid datatypes for arrays in flash using this library include structs and typedefs, in addition to the predefined C datatypes. Structs appear to default to multiples of flash words, so the programmer's attention to alignment issues does not appear to be neccessary.
Some limitations: the sizeof operator on any array declared in flash will always return 4 (=flashBytesPerWord). Also, C string functions like strcpy and strlen do not always work as one would expect to manipulate the arrays in flash, 'tho memcpy and strcpy do work to copy the contents out of flash, and memcpy does work to copy into flash, but the number of bytes should be a multple of flashBytesPerWord. I recommend using macros (ie. #define) or variables to declare the number of array elements as the sketch cannot easily figure out by itself how big a flash array has been declared after the declaration.
Some limitations: the sizeof operator on any array in flash will always return 4 (=flashBytesPerWord). Also, C string functions like strcpy and strlen do not always work as one would expect to manipulate the arrays in flash, 'tho memcpy and strcpy do work to copy the contents out of flash, and memcpy does work to copy into flash if the number of bytes is a multple of flashBytesPerWord. I recommend using macros (ie. #define) or variables to declare the number of array elements as the sketch cannot easily figure out by itself how big a flash array has been declared after the declaration.
If you want more control over the details of the declarations in flash,
declare arrays in flash using pointers:<br>
......
name=Nano33BLE-flash
version=0.3
version=0.4
author=Roger De Roo
maintainer=Roger De Roo
sentence=Direct flash memory access
......
......@@ -26,19 +26,30 @@ _flashAddr &= 0xFFFFC;
// public macro: declare array in flash at highest flash addresses available
// first push _arrayAddr down by size of array in bytes,
// then use array - pointer equivalence to declare a pointer to that address
// as it contains executable statements, cannot be used to make a global array
#define NANO33BLE_FLASH( _datatype, _arrayName, _numberOfArrayElements ) \
_NANO33BLE_FLASH_DECR_ADDR((sizeof(_datatype)) * (_numberOfArrayElements)) \
_datatype *_arrayName = (_datatype *)_flashAddr;
// public macro to be used after all the flash array declarations
// sets the type and scope of the array in Flash, depending on where done.
#define NANO33BLE_DECLARE( _datatype, _arrayName) \
_datatype *_arrayName;
// move existing pointer _arrayName to next available spot in Flash
// macro includdes executable code, so call this in setup()
#define NANO33BLE_PUT_ARRAY_IN_FLASH( _datatype, _arrayName, _numberOfArrayElements ) \
_NANO33BLE_FLASH_DECR_ADDR((sizeof(_datatype)) * (_numberOfArrayElements)) \
_arrayName = (_datatype *)_flashAddr;
// public macro to be used after all the flash array movement
// useful for looping over flash pages to initialize/erase them.
#define NANO33BLE_FLASH_LOWEST_PAGE \
((_flashAddr - _NANO33BLE_FLASH_BASE) / NRF_FICR->CODEPAGESIZE)
/*
// test. result: don't do sizeof(#_datatype)
#define NANO33BLE_FLASH_SIZEOF(_datatype) \
(sizeof(_datatype))
/*
// these two defines below do work...
#define NANO33BLE_FLASH_INT(_arrayName) \
int *_arrayName = (int *)0x100000;
......@@ -47,6 +58,8 @@ _datatype *_arrayName = (_datatype *)_flashAddr;
TYPE *_arrayName = (TYPE *)0x100000;
*/
//#undef _flashAddr
static unsigned int _flashAddr = (_NANO33BLE_FLASH_BASE + NRF_FICR->CODESIZE * NRF_FICR->CODEPAGESIZE);
// Caution: these enums are the register settings for the given mode.
......
Markdown is supported
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