Skip to content

Commit

Permalink
EEPROM: add wrapper class based on DATA FLASH
Browse files Browse the repository at this point in the history
  • Loading branch information
maidnl authored and facchinm committed Jan 4, 2023
1 parent 8f85017 commit 60e600f
Show file tree
Hide file tree
Showing 18 changed files with 1,383 additions and 2 deletions.
4 changes: 2 additions & 2 deletions cores/arduino/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ static inline uint16_t getPinCfg(const uint16_t *cfg, PinCfgReq_t req) {
#define ADC_1 (1 << ADD_CONFIG_POS)
#define IS_ADC1(x) ((x & ADD_CONFIG_MASK) == ADC_1)



#define LP_FLASH 1
#define HP_FLASH 2

#endif
139 changes: 139 additions & 0 deletions libraries/EEPROM/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
## **EEPROM Library V2.0** - Arduino RA

**Written by:** _Christopher Andrews_.

### **What is the EEPROM library.**

Th EEPROM library provides an easy to use interface to interact with the internal non-volatile storage found in AVR based Arduino boards. This library will work on many AVR devices like ATtiny and ATmega chips.

### **How to use it**
The EEPROM library is included in your IDE download. To add its functionality to your sketch you'll need to reference the library header file. You do this by adding an include directive to the top of your sketch.

```Arduino
#include <EEPROM.h>
void setup(){
}
void loop(){
}
```

The library provides a global variable named `EEPROM`, you use this variable to access the library functions. The methods provided in the EEPROM class are listed below.

You can view all the examples [here](examples/).

### **Library functions**

#### **`EEPROM.read( address )`** [[_example_]](examples/eeprom_read/eeprom_read.ino)

This function allows you to read a single byte of data from the eeprom.
Its only parameter is an `int` which should be set to the address you wish to read.

The function returns an `unsigned char` containing the value read.

#### **`EEPROM.write( address, value )`** [[_example_]](examples/eeprom_write/eeprom_write.ino)

The `write()` method allows you to write a single byte of data to the EEPROM.
Two parameters are needed. The first is an `int` containing the address that is to be written, and the second is a the data to be written (`unsigned char`).

This function does not return any value.

#### **`EEPROM.update( address, value )`** [[_example_]](examples/eeprom_update/eeprom_update.ino)

This function is similar to `EEPROM.write()` however this method will only write data if the cell contents pointed to by `address` is different to `value`. This method can help prevent unnecessary wear on the EEPROM cells.

This function does not return any value.

#### **`EEPROM.get( address, object )`** [[_example_]](examples/eeprom_get/eeprom_get.ino)

This function will retrieve any object from the EEPROM.
Two parameters are needed to call this function. The first is an `int` containing the address that is to be written, and the second is the object you would like to read.

This function returns a reference to the `object` passed in. It does not need to be used and is only returned for convenience.

#### **`EEPROM.put( address, object )`** [[_example_]](examples/eeprom_put/eeprom_put.ino)

This function will write any object to the EEPROM.
Two parameters are needed to call this function. The first is an `int` containing the address that is to be written, and the second is the object you would like to write.

This function uses the _update_ method to write its data, and therefore only rewrites changed cells.

This function returns a reference to the `object` passed in. It does not need to be used and is only returned for convenience.

#### **Subscript operator: `EEPROM[address]`** [[_example_]](examples/eeprom_crc/eeprom_crc.ino)

This operator allows using the identifier `EEPROM` like an array.
EEPROM cells can be read _and_ **_written_** directly using this method.

This operator returns a reference to the EEPROM cell.

```c++
unsigned char val;

//Read first EEPROM cell.
val = EEPROM[ 0 ];

//Write first EEPROM cell.
EEPROM[ 0 ] = val;

//Compare contents
if( val == EEPROM[ 0 ] ){
//Do something...
}
```

#### **`EEPROM.length()`**

This function returns an `unsigned int` containing the number of cells in the EEPROM.

---

### **Advanced features**

This library uses a component based approach to provide its functionality. This means you can also use these components to design a customized approach. Two background classes are available for use: `EERef` & `EEPtr`.

#### **`EERef` class**

This object references an EEPROM cell.
Its purpose is to mimic a typical byte of RAM, however its storage is the EEPROM.
This class has an overhead of two bytes, similar to storing a pointer to an EEPROM cell.

```C++
EERef ref = EEPROM[ 10 ]; //Create a reference to 11th cell.

ref = 4; //write to EEPROM cell.

unsigned char val = ref; //Read referenced cell.
```

#### **`EEPtr` class**

This object is a bidirectional pointer to EEPROM cells represented by `EERef` objects.
Just like a normal pointer type, this type can be dereferenced and repositioned using
increment/decrement operators.

```C++
EEPtr ptr = 10; //Create a pointer to 11th cell.

*ptr = 4; //dereference and write to EEPROM cell.

unsigned char val = *ptr; //dereference and read.

ptr++; //Move to next EEPROM cell.
```

#### **`EEPROM.begin()`**

This function returns an `EEPtr` pointing to the first cell in the EEPROM.
This is useful for STL objects, custom iteration and C++11 style ranged for loops.

#### **`EEPROM.end()`**

This function returns an `EEPtr` pointing at the location after the last EEPROM cell.
Used with `begin()` to provide custom iteration.

**Note:** The `EEPtr` returned is invalid as it is out of range. In fact the hardware causes wrapping of the address (overflow) and `EEPROM.end()` actually references the first EEPROM cell.
60 changes: 60 additions & 0 deletions libraries/EEPROM/example/eeprom_write/eeprom_write.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* EEPROM Write
*
* Stores values read from analog input 0 into the EEPROM.
* These values will stay in the EEPROM when the board is
* turned off and may be retrieved later by another sketch.
*/

#include <EEPROM.h>

/** the current address in the EEPROM (i.e. which byte we're going to write to next) **/
int addr = 0;

void setup() {
/** Empty setup. **/
}

void loop() {
/***
Need to divide by 4 because analog inputs range from
0 to 1023 and each byte of the EEPROM can only hold a
value from 0 to 255.
***/

int val = analogRead(0) / 4;

/***
Write the value to the appropriate byte of the EEPROM.
these values will remain there when the board is
turned off.
***/

EEPROM.write(addr, val);

/***
Advance to the next address, when at the end restart at the beginning.
Larger AVR processors have larger EEPROM sizes, E.g:
- Arduino Duemilanove: 512 B EEPROM storage.
- Arduino Uno: 1 kB EEPROM storage.
- Arduino Mega: 4 kB EEPROM storage.
Rather than hard-coding the length, you should use the pre-provided length function.
This will make your code portable to all AVR processors.
***/
addr = addr + 1;
if (addr == EEPROM.length()) {
addr = 0;
}

/***
As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an
EEPROM address is also doable by a bitwise and of the length - 1.
++addr &= EEPROM.length() - 1;
***/


delay(100);
}
39 changes: 39 additions & 0 deletions libraries/EEPROM/examples/eeprom_clear/eeprom_clear.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* EEPROM Clear
*
* Sets all of the bytes of the EEPROM to 0.
* Please see eeprom_iteration for a more in depth
* look at how to traverse the EEPROM.
*
* This example code is in the public domain.
*/

#include <EEPROM.h>

void setup() {
// initialize the LED pin as an output.
pinMode(13, OUTPUT);

/***
Iterate through each byte of the EEPROM storage.
Larger AVR processors have larger EEPROM sizes, E.g:
- Arduino Duemilanove: 512 B EEPROM storage.
- Arduino Uno: 1 kB EEPROM storage.
- Arduino Mega: 4 kB EEPROM storage.
Rather than hard-coding the length, you should use the pre-provided length function.
This will make your code portable to all AVR processors.
***/

for (int i = 0 ; i < EEPROM.length() ; i++) {
EEPROM.write(i, 0);
}

// turn the LED on when we're done
digitalWrite(13, HIGH);
}

void loop() {
/** Empty loop. **/
}
52 changes: 52 additions & 0 deletions libraries/EEPROM/examples/eeprom_crc/eeprom_crc.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/***
Written by Christopher Andrews.
CRC algorithm generated by pycrc, MIT licence ( https://github.com/tpircher/pycrc ).
A CRC is a simple way of checking whether data has changed or become corrupted.
This example calculates a CRC value directly on the EEPROM values.
The purpose of this example is to highlight how the EEPROM object can be used just like an array.
***/

#include <Arduino.h>
#include <EEPROM.h>

void setup() {

//Start serial
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}

//Print length of data to run CRC on.
Serial.print("EEPROM length: ");
Serial.println(EEPROM.length());

//Print the result of calling eeprom_crc()
Serial.print("CRC32 of EEPROM data: 0x");
Serial.println(eeprom_crc(), HEX);
Serial.print("\n\nDone!");
}

void loop() {
/* Empty loop */
}

unsigned long eeprom_crc(void) {

const unsigned long crc_table[16] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};

unsigned long crc = ~0L;

for (int index = 0 ; index < EEPROM.length() ; ++index) {
crc = crc_table[(crc ^ EEPROM[index]) & 0x0f] ^ (crc >> 4);
crc = crc_table[(crc ^ (EEPROM[index] >> 4)) & 0x0f] ^ (crc >> 4);
crc = ~crc;
}
return crc;
}
68 changes: 68 additions & 0 deletions libraries/EEPROM/examples/eeprom_get/eeprom_get.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/***
eeprom_get example.
This shows how to use the EEPROM.get() method.
To pre-set the EEPROM data, run the example sketch eeprom_put.
This sketch will run without it, however, the values shown
will be shown from what ever is already on the EEPROM.
This may cause the serial object to print out a large string
of garbage if there is no null character inside one of the strings
loaded.
Written by Christopher Andrews 2015
Released under MIT licence.
***/

#include <EEPROM.h>

void setup() {

float f = 0.00f; //Variable to store data read from EEPROM.
int eeAddress = 0; //EEPROM address to start reading from

Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.print("Read float from EEPROM: ");

//Get the float data from the EEPROM at position 'eeAddress'
EEPROM.get(eeAddress, f);
Serial.println(f, 3); //This may print 'ovf, nan' if the data inside the EEPROM is not a valid float.

/***
As get also returns a reference to 'f', you can use it inline.
E.g: Serial.print( EEPROM.get( eeAddress, f ) );
***/

/***
Get can be used with custom structures too.
I have separated this into an extra function.
***/

secondTest(); //Run the next test.
}

struct MyObject {
float field1;
byte field2;
char name[10];
};

void secondTest() {
int eeAddress = sizeof(float); //Move address to the next byte after float 'f'.

MyObject customVar; //Variable to store custom object read from EEPROM.
EEPROM.get(eeAddress, customVar);

Serial.println("Read custom object from EEPROM: ");
Serial.println(customVar.field1);
Serial.println(customVar.field2);
Serial.println(customVar.name);
}

void loop() {
/* Empty loop */
}
Loading

0 comments on commit 60e600f

Please sign in to comment.