Skip to content

Commit 08dbd3d

Browse files
authored
Merge pull request #38 from merlinz01/add-put-changed-method
Implement putChanged method
2 parents c64d7df + 067e138 commit 08dbd3d

File tree

2 files changed

+225
-0
lines changed

2 files changed

+225
-0
lines changed
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
/*
2+
Read and write data to an external I2C EEPROM
3+
By: Nathan Seidle, Merlin Z
4+
SparkFun Electronics
5+
Date: July 11, 2024
6+
License: This code is public domain but you buy me a coffee if you use this
7+
and we meet someday (Beerware license).
8+
Feel like supporting our work? Buy a board from SparkFun!
9+
https://www.sparkfun.com/products/18355
10+
11+
This example demonstrates how to record various user settings easily to EEPROM,
12+
only writing settings that changed in order to preserve the life of the memory.
13+
Use the ExternalEEPROM::putChanged() method instead of External_EEPROM::put() to do this.
14+
15+
The I2C EEPROM should have all its ADR pins set to GND (0). This is default
16+
on the Qwiic board.
17+
18+
Hardware Connections:
19+
Plug the SparkFun Qwiic EEPROM to an Uno, Artemis, or other Qwiic equipped board
20+
Load this sketch
21+
Open output window at 115200bps
22+
*/
23+
24+
#include <Wire.h>
25+
26+
#include "SparkFun_External_EEPROM.h" // Click here to get the library: http://librarymanager/All#SparkFun_External_EEPROM
27+
ExternalEEPROM myMem;
28+
29+
#define LOCATION_SETTINGS 0 //Position in EEPROM to store the user setting structure
30+
31+
//This is the struct that contains all the user settings. Add as many vars as you want.
32+
struct struct_userSettings {
33+
unsigned long baudRate;
34+
bool logDate;
35+
bool enableIMU;
36+
float calValue;
37+
};
38+
39+
//These are the default settings for each variable. They will be written if the EEPROM is blank.
40+
struct_userSettings settings = {
41+
.baudRate = 115200,
42+
.logDate = false,
43+
.enableIMU = true,
44+
.calValue = -5.17,
45+
};
46+
47+
void setup()
48+
{
49+
Serial.begin(115200);
50+
//delay(250); //Often needed for ESP based platforms
51+
Serial.println(F("Qwiic EEPROM example"));
52+
53+
Wire.begin();
54+
55+
// Default to the Qwiic 24xx512 EEPROM: https://www.sparkfun.com/products/18355
56+
myMem.setMemoryType(512); // Valid types: 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1025, 2048
57+
58+
if (myMem.begin() == false)
59+
{
60+
Serial.println(F("No memory detected. Freezing."));
61+
while (true);
62+
}
63+
Serial.println(F("Memory detected!"));
64+
65+
Serial.print("Size of user settings (bytes): ");
66+
Serial.println(sizeof(settings));
67+
68+
loadUserSettings();
69+
70+
Serial.print("Baud rate: ");
71+
Serial.println(settings.baudRate);
72+
73+
Serial.print("logDate: ");
74+
if (settings.logDate == true) Serial.println("True");
75+
else Serial.println("False");
76+
77+
Serial.print("calValue: ");
78+
Serial.println(settings.calValue, 2);
79+
80+
//Now we can change something
81+
settings.baudRate = 57600;
82+
83+
//Now we can save it
84+
recordUserSettings();
85+
86+
//And we never have to worry about byte alignment or EEPROM locations!
87+
88+
Serial.println("Press any key to get menu");
89+
}
90+
91+
void loop()
92+
{
93+
if (Serial.available()) mainMenu(); //Present user menu
94+
}
95+
96+
void mainMenu()
97+
{
98+
while (1)
99+
{
100+
Serial.println();
101+
Serial.println("Menu: Main Menu");
102+
103+
Serial.println("1) Set Baud Rate");
104+
Serial.println("x) Exit");
105+
106+
byte incoming = getByteChoice(); //Timeout after 10 seconds
107+
108+
if (incoming == '1')
109+
{
110+
Serial.print("Enter baud rate (1200 to 115200): ");
111+
int newBaud = getNumber();
112+
if (newBaud < 1200 || newBaud > 115200)
113+
{
114+
Serial.println("Error: baud rate out of range");
115+
}
116+
else
117+
{
118+
settings.baudRate = newBaud;
119+
recordUserSettings();
120+
}
121+
}
122+
else if (incoming == 'x')
123+
break;
124+
else
125+
{
126+
Serial.print("Unknown choice: ");
127+
Serial.write(incoming);
128+
Serial.println();
129+
}
130+
}
131+
}
132+
133+
//Blocking wait for user input
134+
void waitForInput()
135+
{
136+
delay(10); //Wait for any incoming chars to hit buffer
137+
while (Serial.available() > 0) Serial.read(); //Clear buffer
138+
while (Serial.available() == 0);
139+
}
140+
141+
//Get single byte from user
142+
//Waits for and returns the character that the user provides
143+
byte getByteChoice()
144+
{
145+
waitForInput(); //Wait for user to send a value
146+
return (Serial.read());
147+
}
148+
149+
//Get a string/value from user, remove all non-numeric values
150+
int getNumber()
151+
{
152+
waitForInput(); //Wait for user to send a value
153+
154+
//Get input from user
155+
char cleansed[20];
156+
157+
int spot = 0;
158+
while (spot < 20 - 1) //Leave room for terminating \0
159+
{
160+
while (Serial.available() == 0) ; //Wait for user input
161+
162+
byte incoming = Serial.read();
163+
if (incoming == '\n' || incoming == '\r')
164+
{
165+
Serial.println();
166+
break;
167+
}
168+
169+
if (isDigit(incoming) == true)
170+
{
171+
Serial.write(incoming); //Echo user's typing
172+
cleansed[spot++] = (char)incoming;
173+
}
174+
}
175+
176+
cleansed[spot] = '\0';
177+
178+
String tempValue = cleansed;
179+
return (tempValue.toInt());
180+
}
181+
182+
183+
//Load the current settings from EEPROM into the settings struct
184+
void loadUserSettings()
185+
{
186+
//Uncomment these lines to forcibly erase the EEPROM and see how the defaults are set
187+
//Serial.println("Erasing EEPROM");
188+
//myMem.erase();
189+
190+
//Check to see if EEPROM is blank. If the first four spots are zeros then we can assume the EEPROM is blank.
191+
uint32_t testRead = 0;
192+
if (myMem.get(LOCATION_SETTINGS, testRead) == 0) //EEPROM address to read, thing to read into
193+
{
194+
//At power on, settings are set to defaults within the struct.
195+
//So go record the struct as it currently exists so that defaults are set.
196+
recordUserSettings();
197+
198+
Serial.println("Default settings applied");
199+
}
200+
else
201+
{
202+
//Read current settings
203+
myMem.get(LOCATION_SETTINGS, settings);
204+
}
205+
}
206+
207+
//Record the current settings into EEPROM
208+
void recordUserSettings()
209+
{
210+
// The putChanged() method does the same as put() except it only writes data that changed.
211+
myMem.putChanged(LOCATION_SETTINGS, settings); // That's it!
212+
}

src/SparkFun_External_EEPROM.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,19 @@ class ExternalEEPROM
174174
return t;
175175
}
176176

177+
template <typename T> const T &putChanged(uint32_t idx, const T &t) // Address, data
178+
{
179+
const uint8_t *newData = (const uint8_t *)&t;
180+
uint8_t oldData[sizeof(T)];
181+
read(idx, oldData, sizeof(T)); // Address, data, sizeOfData
182+
for (uint16_t i = 0; i < sizeof(T); i++) {
183+
if (oldData[i] != newData[i]) {
184+
write(idx + i, newData[i]);
185+
}
186+
}
187+
return t;
188+
}
189+
177190
uint32_t putString(uint32_t eepromLocation, String &strToWrite);
178191
void getString(uint32_t eepromLocation, String &strToRead);
179192

0 commit comments

Comments
 (0)