Skip to content

Commit 736bf20

Browse files
James FosterianfixesElizabeth Ventura
authored
Add support for EEPROM (#3)
* Introduce EEPROM support (#166) * Update CHANGELOG.md * Only include EEPROM if board supports it. * Add EEPROM_SIZE to mega boards. * Move `EEPROM_SIZE` macro to `misc/default.yml`. * Use E2END to calculate EEPROM_SIZE. * EEPROM is tested by uno and due so we don't need to add mega2560 (one less file changed). * Simplify reference to EEPROM library. * adding tests for EEPROM * test high memory and array read. * add setup to reset memory before each test * Add documentation of EEPROM (fix #190). Co-authored-by: Ian <[email protected]> Co-authored-by: Elizabeth Ventura <[email protected]>
1 parent d89f0ba commit 736bf20

File tree

5 files changed

+290
-0
lines changed

5 files changed

+290
-0
lines changed

Diff for: CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
88
## [Unreleased]
99
### Added
1010
- Add `__AVR__` to defines when compiling
11+
- Support for mock EEPROM (but only if board supports it)
1112

1213
### Changed
1314
- Move repository from https://github.com/ianfixes/arduino_ci to https://github.com/Arduino-CI/arduino_ci

Diff for: REFERENCE.md

+37
Original file line numberDiff line numberDiff line change
@@ -581,3 +581,40 @@ unittest(spi) {
581581
assertEqual("LMNOe", String(inBuf));
582582
}
583583
```
584+
585+
### EEPROM
586+
587+
`EEPROM` is a global with a simple API to read and write bytes to persistent memory (like a tiny hard disk) given an `int` location. Since the Arduino core already provides this as a global, and the core API is sufficient for basic testing (read/write), there is no direct tie to the `GODMODE` API. (If you need more, such as a log of intermediate values, enter a feature request.)
588+
589+
```C++
590+
unittest(eeprom)
591+
{
592+
uint8_t a;
593+
// size
594+
assertEqual(EEPROM_SIZE, EEPROM.length());
595+
// initial values
596+
a = EEPROM.read(0);
597+
assertEqual(255, a);
598+
// write and read
599+
EEPROM.write(0, 24);
600+
a = EEPROM.read(0);
601+
assertEqual(24, a);
602+
// update
603+
EEPROM.write(1, 14);
604+
EEPROM.update(1, 22);
605+
a = EEPROM.read(1);
606+
assertEqual(22, a);
607+
// put and get
608+
const float f1 = 0.025f;
609+
float f2 = 0.0f;
610+
EEPROM.put(5, f1);
611+
assertEqual(0.0f, f2);
612+
EEPROM.get(5, f2);
613+
assertEqual(0.025f, f2);
614+
// array access
615+
int val = 10;
616+
EEPROM[2] = val;
617+
a = EEPROM[2];
618+
assertEqual(10, a);
619+
}
620+
```

Diff for: SampleProjects/TestSomething/test/eeprom.cpp

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#include <ArduinoUnitTests.h>
2+
#include <Arduino.h>
3+
4+
// Only run EEPROM tests if there is hardware support!
5+
#if defined(EEPROM_SIZE) || (defined(E2END) && E2END)
6+
#include <EEPROM.h>
7+
8+
GodmodeState* state = GODMODE();
9+
unittest_setup()
10+
{
11+
state->reset();
12+
}
13+
14+
unittest(length)
15+
{
16+
assertEqual(EEPROM_SIZE, EEPROM.length());
17+
}
18+
19+
unittest(firstRead)
20+
{
21+
uint8_t a = EEPROM.read(0);
22+
assertEqual(255, a);
23+
}
24+
25+
unittest(writeRead)
26+
{
27+
EEPROM.write(0, 24);
28+
uint8_t a = EEPROM.read(0);
29+
assertEqual(24, a);
30+
31+
EEPROM.write(0, 128);
32+
a = EEPROM.read(0);
33+
assertEqual(128, a);
34+
35+
EEPROM.write(0, 256);
36+
a = EEPROM.read(0);
37+
assertEqual(0, a);
38+
39+
int addr = EEPROM_SIZE / 2;
40+
EEPROM.write(addr, 63);
41+
a = EEPROM.read(addr);
42+
assertEqual(63, a);
43+
44+
addr = EEPROM_SIZE - 1;
45+
EEPROM.write(addr, 188);
46+
a = EEPROM.read(addr);
47+
assertEqual(188, a);
48+
}
49+
50+
unittest(updateWrite)
51+
{
52+
EEPROM.write(1, 14);
53+
EEPROM.update(1, 22);
54+
uint8_t a = EEPROM.read(1);
55+
assertEqual(22, a);
56+
}
57+
58+
unittest(putGet)
59+
{
60+
const float f1 = 0.025f;
61+
float f2 = 0.0f;
62+
EEPROM.put(5, f1);
63+
assertEqual(0.0f, f2);
64+
EEPROM.get(5, f2);
65+
assertEqual(0.025f, f2);
66+
}
67+
68+
unittest(array)
69+
{
70+
int val = 10;
71+
EEPROM[2] = val;
72+
uint8_t a = EEPROM[2];
73+
assertEqual(10, a);
74+
}
75+
76+
#endif
77+
78+
unittest_main()

Diff for: cpp/arduino/EEPROM.h

+166
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
EEPROM.h - EEPROM library
3+
Original Copyright (c) 2006 David A. Mellis. All right reserved.
4+
New version by Christopher Andrews 2015.
5+
6+
Copy of https://github.com/arduino/ArduinoCore-megaavr/blob/c8a1dd996c783777ec46167cfd8ad3fd2e6df185/libraries/EEPROM/src/EEPROM.h
7+
modified by James Foster in 2020 to work with Arduino CI.
8+
9+
This library is free software; you can redistribute it and/or
10+
modify it under the terms of the GNU Lesser General Public
11+
License as published by the Free Software Foundation; either
12+
version 2.1 of the License, or (at your option) any later version.
13+
14+
This library is distributed in the hope that it will be useful,
15+
but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17+
Lesser General Public License for more details.
18+
19+
You should have received a copy of the GNU Lesser General Public
20+
License along with this library; if not, write to the Free Software
21+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22+
*/
23+
24+
#ifndef EEPROM_h
25+
#define EEPROM_h
26+
27+
#include <inttypes.h>
28+
#include <avr/io.h>
29+
30+
// different EEPROM implementations have different macros that leak out
31+
#if !defined(EEPROM_SIZE) && defined(E2END) && (E2END)
32+
#define EEPROM_SIZE (E2END + 1)
33+
#endif
34+
35+
// Does the current board have EEPROM?
36+
#ifndef EEPROM_SIZE
37+
// In lieu of an "EEPROM.h not found" error for unsupported boards
38+
#error "EEPROM library not available for your board"
39+
#endif
40+
41+
// On a real device this would be in hardware, but we have a mock board!
42+
static uint8_t eeprom[EEPROM_SIZE];
43+
inline uint8_t eeprom_read_byte( uint8_t* index ) { return eeprom[(unsigned long) index % EEPROM_SIZE]; }
44+
inline void eeprom_write_byte( uint8_t* index, uint8_t value ) { eeprom[(unsigned long) index % EEPROM_SIZE] = value; }
45+
46+
// Everything following is from the original (referenced above)
47+
48+
/***
49+
EERef class.
50+
51+
This object references an EEPROM cell.
52+
Its purpose is to mimic a typical byte of RAM, however its storage is the EEPROM.
53+
This class has an overhead of two bytes, similar to storing a pointer to an EEPROM cell.
54+
***/
55+
56+
struct EERef{
57+
58+
EERef( const int index )
59+
: index( index ) {}
60+
61+
//Access/read members.
62+
uint8_t operator*() const { return eeprom_read_byte( (uint8_t*) index ); }
63+
operator uint8_t() const { return **this; }
64+
65+
//Assignment/write members.
66+
EERef &operator=( const EERef &ref ) { return *this = *ref; }
67+
EERef &operator=( uint8_t in ) { return eeprom_write_byte( (uint8_t*) index, in ), *this; }
68+
EERef &operator +=( uint8_t in ) { return *this = **this + in; }
69+
EERef &operator -=( uint8_t in ) { return *this = **this - in; }
70+
EERef &operator *=( uint8_t in ) { return *this = **this * in; }
71+
EERef &operator /=( uint8_t in ) { return *this = **this / in; }
72+
EERef &operator ^=( uint8_t in ) { return *this = **this ^ in; }
73+
EERef &operator %=( uint8_t in ) { return *this = **this % in; }
74+
EERef &operator &=( uint8_t in ) { return *this = **this & in; }
75+
EERef &operator |=( uint8_t in ) { return *this = **this | in; }
76+
EERef &operator <<=( uint8_t in ) { return *this = **this << in; }
77+
EERef &operator >>=( uint8_t in ) { return *this = **this >> in; }
78+
79+
EERef &update( uint8_t in ) { return in != *this ? *this = in : *this; }
80+
81+
/** Prefix increment/decrement **/
82+
EERef& operator++() { return *this += 1; }
83+
EERef& operator--() { return *this -= 1; }
84+
85+
/** Postfix increment/decrement **/
86+
uint8_t operator++ (int){
87+
uint8_t ret = **this;
88+
return ++(*this), ret;
89+
}
90+
91+
uint8_t operator-- (int){
92+
uint8_t ret = **this;
93+
return --(*this), ret;
94+
}
95+
96+
int index; //Index of current EEPROM cell.
97+
};
98+
99+
/***
100+
EEPtr class.
101+
102+
This object is a bidirectional pointer to EEPROM cells represented by EERef objects.
103+
Just like a normal pointer type, this can be dereferenced and repositioned using
104+
increment/decrement operators.
105+
***/
106+
107+
struct EEPtr{
108+
109+
EEPtr( const int index )
110+
: index( index ) {}
111+
112+
operator int() const { return index; }
113+
EEPtr &operator=( int in ) { return index = in, *this; }
114+
115+
//Iterator functionality.
116+
bool operator!=( const EEPtr &ptr ) { return index != ptr.index; }
117+
EERef operator*() { return index; }
118+
119+
/** Prefix & Postfix increment/decrement **/
120+
EEPtr& operator++() { return ++index, *this; }
121+
EEPtr& operator--() { return --index, *this; }
122+
EEPtr operator++ (int) { return index++; }
123+
EEPtr operator-- (int) { return index--; }
124+
125+
int index; //Index of current EEPROM cell.
126+
};
127+
128+
/***
129+
EEPROMClass class.
130+
131+
This object represents the entire EEPROM space.
132+
It wraps the functionality of EEPtr and EERef into a basic interface.
133+
This class is also 100% backwards compatible with earlier Arduino core releases.
134+
***/
135+
136+
struct EEPROMClass{
137+
138+
//Basic user access methods.
139+
EERef operator[]( const int idx ) { return idx; }
140+
uint8_t read( int idx ) { return EERef( idx ); }
141+
void write( int idx, uint8_t val ) { (EERef( idx )) = val; }
142+
void update( int idx, uint8_t val ) { EERef( idx ).update( val ); }
143+
144+
//STL and C++11 iteration capability.
145+
EEPtr begin() { return 0x00; }
146+
EEPtr end() { return length(); } //Standards requires this to be the item after the last valid entry. The returned pointer is invalid.
147+
uint16_t length() { return EEPROM_SIZE; }
148+
149+
//Functionality to 'get' and 'put' objects to and from EEPROM.
150+
template< typename T > T &get( int idx, T &t ){
151+
EEPtr e = idx;
152+
uint8_t *ptr = (uint8_t*) &t;
153+
for( int count = sizeof(T) ; count ; --count, ++e ) *ptr++ = *e;
154+
return t;
155+
}
156+
157+
template< typename T > const T &put( int idx, const T &t ){
158+
EEPtr e = idx;
159+
const uint8_t *ptr = (const uint8_t*) &t;
160+
for( int count = sizeof(T) ; count ; --count, ++e ) (*e).update( *ptr++ );
161+
return t;
162+
}
163+
};
164+
165+
static EEPROMClass EEPROM;
166+
#endif

Diff for: cpp/arduino/Godmode.h

+8
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <avr/io.h>
44
#include "WString.h"
55
#include "PinHistory.h"
6+
#include "EEPROM.h"
67

78
// random
89
void randomSeed(unsigned long seed);
@@ -87,12 +88,19 @@ class GodmodeState {
8788
spi.readDelayMicros = 0;
8889
}
8990

91+
void resetEEPROM() {
92+
for(int i = 0; i < EEPROM.length(); ++i){
93+
EEPROM.update(i, 255);
94+
}
95+
}
96+
9097
void reset() {
9198
resetClock();
9299
resetPins();
93100
resetInterrupts();
94101
resetPorts();
95102
resetSPI();
103+
resetEEPROM();
96104
seed = 1;
97105
}
98106

0 commit comments

Comments
 (0)