From 0a4b70742e692997142ff3064a9569fb75167473 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Sun, 13 Oct 2019 21:27:40 -0600 Subject: [PATCH 1/8] Re-write of EEPROM functions This uses the more common EEPROM methods currently built into Arduino. The approach is a lot more complex but handles any size variable and struct more gracefully than previous approach. I originally hit this problem when trying to record a struct. This new approach works flawlessly. Tested against examples and various attempts to break it. --- .../Example1_GetPut/Example1_GetPut.ino | 2 +- .../Example2_AllFunctions.ino | 31 ++- libraries/EEPROM/src/EEPROM.cpp | 175 +-------------- libraries/EEPROM/src/EEPROM.h | 207 ++++++++++++------ 4 files changed, 172 insertions(+), 243 deletions(-) diff --git a/libraries/EEPROM/examples/Example1_GetPut/Example1_GetPut.ino b/libraries/EEPROM/examples/Example1_GetPut/Example1_GetPut.ino index ea86af35..b7b07be6 100644 --- a/libraries/EEPROM/examples/Example1_GetPut/Example1_GetPut.ino +++ b/libraries/EEPROM/examples/Example1_GetPut/Example1_GetPut.ino @@ -25,7 +25,7 @@ void setup() { - Serial.begin(9600); + Serial.begin(115200); Serial.println("EEPROM Examples"); byte myValue1 = 200; diff --git a/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino b/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino index ce9f1536..89d868fb 100644 --- a/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino +++ b/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino @@ -23,7 +23,7 @@ void setup() { - Serial.begin(9600); + Serial.begin(115200); Serial.println("EEPROM Examples"); randomSeed(analogRead(A0)); @@ -106,8 +106,8 @@ void setup() uint32_t myValue8 = 241544; randomLocation = random(0, AP3_FLASH_EEPROM_SIZE); - EEPROM.update(randomLocation, myValue7); - EEPROM.update(randomLocation + 4, myValue8); + EEPROM.put(randomLocation, myValue7); + EEPROM.put(randomLocation + 4, myValue8); int32_t response7; uint32_t response8; @@ -124,8 +124,8 @@ void setup() float myValue10 = 5.22; randomLocation = random(0, AP3_FLASH_EEPROM_SIZE); - EEPROM.update(randomLocation, myValue9); - EEPROM.update(randomLocation + 4, myValue10); + EEPROM.put(randomLocation, myValue9); + EEPROM.put(randomLocation + 4, myValue10); float response9; float response10; @@ -145,8 +145,8 @@ void setup() double myValue12 = 384.95734987; randomLocation = random(0, AP3_FLASH_EEPROM_SIZE); - EEPROM.update(randomLocation, myValue11); - EEPROM.update(randomLocation + 8, myValue12); + EEPROM.put(randomLocation, myValue11); + EEPROM.put(randomLocation + 8, myValue12); double response11; double response12; @@ -156,7 +156,22 @@ void setup() Serial.printf("Location %d should be %lf: %lf\n", randomLocation + 8, myValue12, response12); //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - Serial.println(); + Serial.println(""); + Serial.println("String test"); + + //String write test + //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + String myString = "How are you today?"; + randomLocation = random(0, AP3_FLASH_EEPROM_SIZE); + EEPROM.put(randomLocation, myString); + + String readMy; + EEPROM.get(randomLocation, readMy); + Serial.printf("Location %d string should read 'How are you today?': ", randomLocation); + Serial.println(readMy); + //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + Serial.println(""); Serial.print("Flash Contents:"); for (uint16_t x = 0; x < 8 * 4; x += 4) { diff --git a/libraries/EEPROM/src/EEPROM.cpp b/libraries/EEPROM/src/EEPROM.cpp index 863b2b89..863c8b31 100644 --- a/libraries/EEPROM/src/EEPROM.cpp +++ b/libraries/EEPROM/src/EEPROM.cpp @@ -40,190 +40,37 @@ #include "EEPROM.h" #include "Arduino.h" -//Constructor -ap3_EEPROM::ap3_EEPROM() -{ -} - //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //Write a byte to a given "EEPROM" location //Automatically masks user's byte into flash without //affecting other bytes in this flash word -void ap3_EEPROM::write(uint16_t eepromLocation, uint8_t dataToWrite) +void write(uint16_t eepromLocation, uint8_t dataToWrite) { uint32_t flashLocation = AP3_FLASH_EEPROM_START + eepromLocation; writeWordToFlash(flashLocation, (uint32_t)dataToWrite | 0xFFFFFF00); } //Read a byte from a given location in "EEPROM" -uint8_t ap3_EEPROM::read(uint16_t eepromLocation) +uint8_t read(uint16_t eepromLocation) { uint32_t flashLocation = AP3_FLASH_EEPROM_START + eepromLocation; return (*(uint8_t *)flashLocation); } -//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -//Get method is overloaded with the following variable types -//char, byte, int, unsigned int, long, unsigned long, float, double? - -void ap3_EEPROM::get(uint16_t eepromLocation, uint8_t &dataToGet) -{ - dataToGet = *(uint8_t *)(AP3_FLASH_EEPROM_START + eepromLocation); -} -void ap3_EEPROM::get(uint16_t eepromLocation, uint16_t &dataToGet) -{ - dataToGet = *(uint16_t *)(AP3_FLASH_EEPROM_START + eepromLocation); -} -void ap3_EEPROM::get(uint16_t eepromLocation, int16_t &dataToGet) -{ - dataToGet = *(int16_t *)(AP3_FLASH_EEPROM_START + eepromLocation); -} -void ap3_EEPROM::get(uint16_t eepromLocation, int &dataToGet) -{ - dataToGet = *(int *)(AP3_FLASH_EEPROM_START + eepromLocation); -} -void ap3_EEPROM::get(uint16_t eepromLocation, unsigned int &dataToGet) -{ - dataToGet = *(unsigned int *)(AP3_FLASH_EEPROM_START + eepromLocation); -} -void ap3_EEPROM::get(uint16_t eepromLocation, int32_t &dataToGet) -{ - dataToGet = *(int32_t *)(AP3_FLASH_EEPROM_START + eepromLocation); -} -void ap3_EEPROM::get(uint16_t eepromLocation, uint32_t &dataToGet) -{ - dataToGet = *(uint32_t *)(AP3_FLASH_EEPROM_START + eepromLocation); -} -void ap3_EEPROM::get(uint16_t eepromLocation, float &dataToGet) -{ - union { - float f; - uint32_t b; - } temp; - temp.b = *(uint32_t *)(AP3_FLASH_EEPROM_START + eepromLocation); - - dataToGet = temp.f; -} - -void ap3_EEPROM::get(uint16_t eepromLocation, double &dataToGet) -{ - union { - double lf; - uint32_t b[2]; - } temp; - temp.b[1] = *(uint32_t *)(AP3_FLASH_EEPROM_START + eepromLocation); //LSB; - temp.b[0] = *(uint32_t *)(AP3_FLASH_EEPROM_START + eepromLocation + 4); //MSB; - dataToGet = temp.lf; -} - -//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -//Put method is overloaded with the following variable types -//char, byte, int, unsigned int, long, unsigned long, float, double? - -void ap3_EEPROM::put(uint16_t eepromLocation, uint8_t dataToWrite) -{ - writeWordToFlash((AP3_FLASH_EEPROM_START + eepromLocation), (uint32_t)dataToWrite | 0xFFFFFF00); -} -void ap3_EEPROM::put(uint16_t eepromLocation, uint16_t dataToWrite) -{ - writeWordToFlash((AP3_FLASH_EEPROM_START + eepromLocation), (uint32_t)dataToWrite | 0xFFFF0000); -} -void ap3_EEPROM::put(uint16_t eepromLocation, int16_t dataToWrite) -{ - writeWordToFlash((AP3_FLASH_EEPROM_START + eepromLocation), (uint32_t)dataToWrite | 0xFFFF0000); -} -void ap3_EEPROM::put(uint16_t eepromLocation, int dataToWrite) //ints are 32 bit on M4F -{ - writeWordToFlash((AP3_FLASH_EEPROM_START + eepromLocation), (uint32_t)dataToWrite); -} -void ap3_EEPROM::put(uint16_t eepromLocation, unsigned int dataToWrite) //ints are 32 bit on M4F +//Write a new byte to a given location in "EEROM" only if new data is there +void update(uint16_t eepromLocation, uint8_t dataToWrite) { - writeWordToFlash((AP3_FLASH_EEPROM_START + eepromLocation), (uint32_t)dataToWrite); -} -void ap3_EEPROM::put(uint16_t eepromLocation, int32_t dataToWrite) -{ - writeWordToFlash((AP3_FLASH_EEPROM_START + eepromLocation), (int32_t)dataToWrite); -} -void ap3_EEPROM::put(uint16_t eepromLocation, uint32_t dataToWrite) -{ - writeWordToFlash((AP3_FLASH_EEPROM_START + eepromLocation), (uint32_t)dataToWrite); -} -void ap3_EEPROM::put(uint16_t eepromLocation, float dataToWrite) -{ - union { - float f; - uint32_t b; - } temp; - temp.f = dataToWrite; - - writeWordToFlash((AP3_FLASH_EEPROM_START + eepromLocation), (uint32_t)temp.b); -} - -void ap3_EEPROM::put(uint16_t eepromLocation, double dataToWrite) //64 bits -{ - union { - double lf; - uint32_t b[2]; - } temp; - temp.lf = dataToWrite; - - writeWordToFlash((AP3_FLASH_EEPROM_START + eepromLocation), (uint32_t)temp.b[1]); //LSB - writeWordToFlash((AP3_FLASH_EEPROM_START + eepromLocation + 4), (uint32_t)temp.b[0]); //MSB -} - -//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -//The update functions simply call the put functions -//Put automatically checks to see if a spot needs updating -void ap3_EEPROM::update(uint16_t eepromLocation, uint8_t dataToWrite) -{ - put(eepromLocation, dataToWrite); -} -void ap3_EEPROM::update(uint16_t eepromLocation, uint16_t dataToWrite) -{ - put(eepromLocation, dataToWrite); -} -void ap3_EEPROM::update(uint16_t eepromLocation, int16_t dataToWrite) -{ - put(eepromLocation, dataToWrite); -} -void ap3_EEPROM::update(uint16_t eepromLocation, int dataToWrite) //ints are 32 bit on M4F -{ - put(eepromLocation, dataToWrite); -} -void ap3_EEPROM::update(uint16_t eepromLocation, unsigned int dataToWrite) //ints are 32 bit on M4F -{ - put(eepromLocation, dataToWrite); -} -void ap3_EEPROM::update(uint16_t eepromLocation, int32_t dataToWrite) -{ - put(eepromLocation, dataToWrite); -} -void ap3_EEPROM::update(uint16_t eepromLocation, uint32_t dataToWrite) -{ - put(eepromLocation, dataToWrite); -} -void ap3_EEPROM::update(uint16_t eepromLocation, float dataToWrite) -{ - put(eepromLocation, dataToWrite); -} -void ap3_EEPROM::update(uint16_t eepromLocation, double dataToWrite) //64 bits -{ - put(eepromLocation, dataToWrite); + if (read(eepromLocation) != dataToWrite) + { + write(eepromLocation, dataToWrite); + } } //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -uint16_t ap3_EEPROM::length() -{ - return (AP3_FLASH_EEPROM_SIZE); -} - //Erase 8k page encapsulating the EEPROM section -void ap3_EEPROM::erase() +void EEPROMClass::erase() { am_hal_flash_page_erase(AM_HAL_FLASH_PROGRAM_KEY, AM_HAL_FLASH_ADDR2INST(AP3_FLASH_EEPROM_START), @@ -240,7 +87,7 @@ void ap3_EEPROM::erase() //4) Write SRAM back into flash //5) Write user's data onto the spot with recently created 0xFFs //Note - this code assumes EEPROM temp space is contained in one page -void ap3_EEPROM::writeWordToFlash(uint32_t flashLocation, uint32_t dataToWrite) +void writeWordToFlash(uint32_t flashLocation, uint32_t dataToWrite) { //Error check if (flashLocation >= AP3_FLASH_EEPROM_START + AP3_FLASH_EEPROM_SIZE) @@ -306,4 +153,4 @@ void ap3_EEPROM::writeWordToFlash(uint32_t flashLocation, uint32_t dataToWrite) AP3_FLASH_EEPROM_SIZE); } -ap3_EEPROM EEPROM; \ No newline at end of file +//ap3_EEPROM EEPROM; \ No newline at end of file diff --git a/libraries/EEPROM/src/EEPROM.h b/libraries/EEPROM/src/EEPROM.h index deb359d6..9eff1ffa 100644 --- a/libraries/EEPROM/src/EEPROM.h +++ b/libraries/EEPROM/src/EEPROM.h @@ -8,8 +8,6 @@ https://www.sparkfun.com/products/15411 https://www.sparkfun.com/products/15412 - Written by Nathan Seidle @ SparkFun Electronics, June 16th, 2019 - Pseudo-EEPROM on the Cortex-M4F https://github.com/sparkfun/SparkFun_Apollo3 @@ -30,13 +28,26 @@ Development environment specifics: Arduino IDE 1.8.x - This program is distributed in the hope that it will be useful, + Original Copyright (c) 2006 David A. Mellis. All right reserved. + New version by Christopher Andrews 2015. + This copy has minor modificatons for use with Teensy, by Paul Stoffregen + This copy has minor modificatons for use with Artemis, by Nathan Seidle + + This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + 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. - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ #ifndef _EEPROM_H @@ -58,81 +69,137 @@ Error : EEPROM start address must be divisble by 8192 //to 8096 if needed #define AP3_FLASH_EEPROM_SIZE 1024 - //class TwoWire : public Stream, public IOMaster{} + uint8_t + read(uint16_t eepromLocation); +void write(uint16_t eepromLocation, uint8_t dataToWrite); +void update(uint16_t eepromLocation, uint8_t dataToWrite); +void erase(); //Erase entire EEPROM +void writeWordToFlash(uint32_t flashLocation, uint32_t dataToWrite); - class ap3_EEPROM +struct EERef { -public: - ap3_EEPROM(); - - //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - - //8 bit - uint8_t read(uint16_t eepromLocation); - void write(uint16_t eepromLocation, uint8_t dataToWrite); - void get(uint16_t eepromLocation, uint8_t &dataToGet); - - //16 bit - void get(uint16_t eepromLocation, uint16_t &dataToGet); - void get(uint16_t eepromLocation, int16_t &dataToGet); - - //32 bit - void get(uint16_t eepromLocation, int &dataToGet); - void get(uint16_t eepromLocation, unsigned int &dataToGet); - void get(uint16_t eepromLocation, int32_t &dataToGet); - void get(uint16_t eepromLocation, uint32_t &dataToGet); - void get(uint16_t eepromLocation, float &dataToGet); - - //64 bit - void get(uint16_t eepromLocation, double &dataToGet); - - //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - - //8 bit - void put(uint16_t eepromLocation, uint8_t dataToWrite); + EERef(const int index) + : index(index) {} + + //Access/read members. + uint8_t operator*() const { return read(index); } + operator const uint8_t() const { return **this; } + + //Assignment/write members. + EERef &operator=(const EERef &ref) { return *this = *ref; } + EERef &operator=(uint8_t in) { return write(index, in), *this; } + EERef &operator+=(uint8_t in) { return *this = **this + in; } + EERef &operator-=(uint8_t in) { return *this = **this - in; } + EERef &operator*=(uint8_t in) { return *this = **this * in; } + EERef &operator/=(uint8_t in) { return *this = **this / in; } + EERef &operator^=(uint8_t in) { return *this = **this ^ in; } + EERef &operator%=(uint8_t in) { return *this = **this % in; } + EERef &operator&=(uint8_t in) { return *this = **this & in; } + EERef &operator|=(uint8_t in) { return *this = **this | in; } + EERef &operator<<=(uint8_t in) { return *this = **this << in; } + EERef &operator>>=(uint8_t in) { return *this = **this >> in; } + + EERef &update(uint8_t in) { return in != *this ? *this = in : *this; } + + /** Prefix increment/decrement **/ + EERef &operator++() { return *this += 1; } + EERef &operator--() { return *this -= 1; } + + /** Postfix increment/decrement **/ + uint8_t operator++(int) + { + uint8_t ret = **this; + return ++(*this), ret; + } + + uint8_t operator--(int) + { + uint8_t ret = **this; + return --(*this), ret; + } + + int index; //Index of current EEPROM cell. +}; - //16 bit - void put(uint16_t eepromLocation, uint16_t dataToWrite); - void put(uint16_t eepromLocation, int16_t dataToWrite); +/*** + EEPtr class. - // 32 bit - void put(uint16_t eepromLocation, int dataToWrite); - void put(uint16_t eepromLocation, unsigned int dataToWrite); - void put(uint16_t eepromLocation, int32_t dataToWrite); - void put(uint16_t eepromLocation, uint32_t dataToWrite); - void put(uint16_t eepromLocation, float dataToWrite); + This object is a bidirectional pointer to EEPROM cells represented by EERef objects. + Just like a normal pointer type, this can be dereferenced and repositioned using + increment/decrement operators. +***/ - //64 bit - void put(uint16_t eepromLocation, double dataToWrite); +struct EEPtr +{ - //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + EEPtr(const int index) + : index(index) {} - //8 bit - void update(uint16_t eepromLocation, uint8_t dataToWrite); + operator const int() const { return index; } + EEPtr &operator=(int in) { return index = in, *this; } - //16 bit - void update(uint16_t eepromLocation, uint16_t dataToWrite); - void update(uint16_t eepromLocation, int16_t dataToWrite); + //Iterator functionality. + bool operator!=(const EEPtr &ptr) { return index != ptr.index; } + EERef operator*() { return index; } - // 32 bit - void update(uint16_t eepromLocation, int dataToWrite); - void update(uint16_t eepromLocation, unsigned int dataToWrite); - void update(uint16_t eepromLocation, int32_t dataToWrite); - void update(uint16_t eepromLocation, uint32_t dataToWrite); - void update(uint16_t eepromLocation, float dataToWrite); + /** Prefix & Postfix increment/decrement **/ + EEPtr &operator++() { return ++index, *this; } + EEPtr &operator--() { return --index, *this; } + EEPtr operator++(int) { return index++; } + EEPtr operator--(int) { return index--; } - //64 bit - void update(uint16_t eepromLocation, double dataToWrite); + int index; //Index of current EEPROM cell. +}; - //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +/*** + EEPROMClass class. - uint16_t length(); - void erase(); //Erase entire EEPROM + This object represents the entire EEPROM space. + It wraps the functionality of EEPtr and EERef into a basic interface. + This class is also 100% backwards compatible with earlier Arduino core releases. +***/ -private: - void writeWordToFlash(uint32_t flashLocation, uint32_t dataToWrite); +struct EEPROMClass +{ + //Basic user access methods. + EERef operator[](const int idx) { return idx; } + uint8_t read(int idx) { return EERef(idx); } + void write(int idx, uint8_t val) { (EERef(idx)) = val; } + void update(int idx, uint8_t val) { EERef(idx).update(val); } + void erase(); + + //STL and C++11 iteration capability. + EEPtr begin() { return 0x00; } + EEPtr end() { return length(); } //Standards requires this to be the item after the last valid entry. The returned pointer is invalid. + uint16_t length() { return AP3_FLASH_EEPROM_SIZE + 1; } + + //Functionality to 'get' and 'put' objects to and from EEPROM. + template + T &get(int idx, T &t) + { + EEPtr e = idx; + uint8_t *ptr = (uint8_t *)&t; + for (int count = sizeof(T); count; --count, ++e) + *ptr++ = *e; + return t; + } + + template + const T &put(int idx, const T &t) + { + const uint8_t *ptr = (const uint8_t *)&t; + + //TODO - Write Artemis compatible function for block write + //#ifdef __arm__ + // eeprom_write_block(ptr, (void *)idx, sizeof(T)); + //#else + EEPtr e = idx; + for (int count = sizeof(T); count; --count, ++e) + (*e).update(*ptr++); + //#endif + return t; + } }; -extern ap3_EEPROM EEPROM; - -#endif +static EEPROMClass EEPROM __attribute__((unused)); +#endif //_EEPROM_H From faa963230d9fd2afeb6d2612eca2ff3dd659b631 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 15 Oct 2019 15:26:48 -0600 Subject: [PATCH 2/8] Block updates close to working. --- .../Example2_AllFunctions.ino | 11 ++- libraries/EEPROM/src/EEPROM.cpp | 70 ++++++++++++++++++- libraries/EEPROM/src/EEPROM.h | 25 ++++--- 3 files changed, 90 insertions(+), 16 deletions(-) diff --git a/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino b/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino index 89d868fb..3327b8e8 100644 --- a/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino +++ b/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino @@ -53,6 +53,12 @@ void setup() Serial.printf("Write byte time: %dms\n", endTime - startTime); + startTime = millis(); + EEPROM.write(randomLocation, myValue1); //(location, data) + endTime = millis(); + + Serial.printf("Write identical byte to same location (should be 0): %dms\n", endTime - startTime); + byte response1 = EEPROM.read(randomLocation); byte response2 = EEPROM.read(randomLocation + 1); Serial.printf("Location %d should be %d: %d\n\r", randomLocation, myValue1, response1); @@ -160,8 +166,9 @@ void setup() Serial.println("String test"); //String write test - //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - String myString = "How are you today?"; + dont do string.Do char *array with phone # + //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + String myString = "How are you today?"; randomLocation = random(0, AP3_FLASH_EEPROM_SIZE); EEPROM.put(randomLocation, myString); diff --git a/libraries/EEPROM/src/EEPROM.cpp b/libraries/EEPROM/src/EEPROM.cpp index 863c8b31..d85cca8d 100644 --- a/libraries/EEPROM/src/EEPROM.cpp +++ b/libraries/EEPROM/src/EEPROM.cpp @@ -153,4 +153,72 @@ void writeWordToFlash(uint32_t flashLocation, uint32_t dataToWrite) AP3_FLASH_EEPROM_SIZE); } -//ap3_EEPROM EEPROM; \ No newline at end of file +void EEPROMClass::writeBlockToEEPROM(uint16_t eepromLocation, const uint8_t *dataToWrite, uint16_t blockSize) +{ + //Error check + if (eepromLocation + blockSize >= AP3_FLASH_EEPROM_SIZE) + { + blockSize = AP3_FLASH_EEPROM_SIZE - eepromLocation; + } + + //First we have to read the contents of current "EEPROM" to SRAM, one byte at a time + uint8_t eepromContents[AP3_FLASH_EEPROM_SIZE]; + for (uint16_t x = 0; x < AP3_FLASH_EEPROM_SIZE; x++) + { + eepromContents[x] = *(uint8_t *)(AP3_FLASH_EEPROM_START + x); + } + + //Write the caller's new data into the byte array + for (int x = 0; x < blockSize; x++) + { + eepromContents[eepromLocation + x] = dataToWrite[x]; + } + + //Only update flash with new data. + //Run a check here to see if the new data is the same as what's in flash. If it's the same, don't erase flash. + bool theSame = true; + for (uint16_t x = 0; x < AP3_FLASH_EEPROM_SIZE; x++) + { + if (eepromContents[x] != *(uint8_t *)(AP3_FLASH_EEPROM_START + x)) + { + theSame = false; + break; + } + } + if (theSame == true) + return; + + //Then we erase an 8K page + am_hal_flash_page_erase(AM_HAL_FLASH_PROGRAM_KEY, + AM_HAL_FLASH_ADDR2INST(AP3_FLASH_EEPROM_START + eepromLocation), + AM_HAL_FLASH_ADDR2PAGE(AP3_FLASH_EEPROM_START + eepromLocation)); + + //Flash is written in 32bit words so we split the byte array into 4 byte chunks + uint32_t flashContent[AP3_FLASH_EEPROM_SIZE / 4]; + uint16_t spot = 0; + for (uint16_t x = 0; x < AP3_FLASH_EEPROM_SIZE; x += 4) + { + flashContent[spot] = (uint32_t)eepromContents[x + 3] << (8 * 3); + flashContent[spot] |= (uint32_t)eepromContents[x + 2] << (8 * 2); + flashContent[spot] |= (uint32_t)eepromContents[x + 1] << (8 * 1); + flashContent[spot] |= (uint32_t)eepromContents[x + 0] << (8 * 0); + + spot++; + } + + // Serial.println(""); + // Serial.print("EEPROM Contents:"); + // for (uint16_t x = 0; x < 32; x++) + // { + // if (x % 8 == 0) + // Serial.println(); + // Serial.printf("0x%08X ", eepromContentWords[x]); + // } + // Serial.println(); + + // //Then we write the contents of the array back + am_hal_flash_program_main(AM_HAL_FLASH_PROGRAM_KEY, + flashContent, + (uint32_t *)AP3_FLASH_EEPROM_START, + AP3_FLASH_EEPROM_SIZE / 4); +} diff --git a/libraries/EEPROM/src/EEPROM.h b/libraries/EEPROM/src/EEPROM.h index 9eff1ffa..6087012b 100644 --- a/libraries/EEPROM/src/EEPROM.h +++ b/libraries/EEPROM/src/EEPROM.h @@ -64,10 +64,10 @@ Error : EEPROM start address must be divisble by 8192 #endif -//By limiting EEPROM size to 1024, we reduce the amount of SRAM required and +//By limiting EEPROM size to 1024 bytes, we reduce the amount of SRAM required and //time needed to mask in individual bytes and words into flash. It can be increased //to 8096 if needed -#define AP3_FLASH_EEPROM_SIZE 1024 +#define AP3_FLASH_EEPROM_SIZE 1024 //In bytes uint8_t read(uint16_t eepromLocation); @@ -167,11 +167,16 @@ struct EEPROMClass void write(int idx, uint8_t val) { (EERef(idx)) = val; } void update(int idx, uint8_t val) { EERef(idx).update(val); } void erase(); + void writeBlockToEEPROM(uint16_t eepromLocation, const uint8_t *dataToWrite, uint16_t blockSize); //STL and C++11 iteration capability. - EEPtr begin() { return 0x00; } + EEPtr + begin() + { + return 0x00; + } EEPtr end() { return length(); } //Standards requires this to be the item after the last valid entry. The returned pointer is invalid. - uint16_t length() { return AP3_FLASH_EEPROM_SIZE + 1; } + uint16_t length() { return AP3_FLASH_EEPROM_SIZE; } //Functionality to 'get' and 'put' objects to and from EEPROM. template @@ -185,18 +190,12 @@ struct EEPROMClass } template - const T &put(int idx, const T &t) + const T &put(int idx, const T &t) //Address, data { const uint8_t *ptr = (const uint8_t *)&t; - //TODO - Write Artemis compatible function for block write - //#ifdef __arm__ - // eeprom_write_block(ptr, (void *)idx, sizeof(T)); - //#else - EEPtr e = idx; - for (int count = sizeof(T); count; --count, ++e) - (*e).update(*ptr++); - //#endif + writeBlockToEEPROM(idx, ptr, sizeof(T)); //Address, data, sizeOfData + return t; } }; From d1753ea5ec1c07776c380b07cc4803359a175562 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 15 Oct 2019 15:38:05 -0600 Subject: [PATCH 3/8] Byte write() now uses block write. --- .../Example2_AllFunctions.ino | 2 +- libraries/EEPROM/src/EEPROM.cpp | 15 ++------------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino b/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino index 3327b8e8..f52f4f79 100644 --- a/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino +++ b/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino @@ -57,7 +57,7 @@ void setup() EEPROM.write(randomLocation, myValue1); //(location, data) endTime = millis(); - Serial.printf("Write identical byte to same location (should be 0): %dms\n", endTime - startTime); + Serial.printf("Write identical byte to same location (should be ~1): %dms\n", endTime - startTime); byte response1 = EEPROM.read(randomLocation); byte response2 = EEPROM.read(randomLocation + 1); diff --git a/libraries/EEPROM/src/EEPROM.cpp b/libraries/EEPROM/src/EEPROM.cpp index d85cca8d..df2e5794 100644 --- a/libraries/EEPROM/src/EEPROM.cpp +++ b/libraries/EEPROM/src/EEPROM.cpp @@ -47,8 +47,7 @@ //affecting other bytes in this flash word void write(uint16_t eepromLocation, uint8_t dataToWrite) { - uint32_t flashLocation = AP3_FLASH_EEPROM_START + eepromLocation; - writeWordToFlash(flashLocation, (uint32_t)dataToWrite | 0xFFFFFF00); + EEPROM.writeBlockToEEPROM(eepromLocation, &dataToWrite, 1); } //Read a byte from a given location in "EEPROM" @@ -206,17 +205,7 @@ void EEPROMClass::writeBlockToEEPROM(uint16_t eepromLocation, const uint8_t *dat spot++; } - // Serial.println(""); - // Serial.print("EEPROM Contents:"); - // for (uint16_t x = 0; x < 32; x++) - // { - // if (x % 8 == 0) - // Serial.println(); - // Serial.printf("0x%08X ", eepromContentWords[x]); - // } - // Serial.println(); - - // //Then we write the contents of the array back + //Then we write the contents of the array back am_hal_flash_program_main(AM_HAL_FLASH_PROGRAM_KEY, flashContent, (uint32_t *)AP3_FLASH_EEPROM_START, From af4e1370493e576b8bc6a3a3b2cb8a7a82664fc5 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 15 Oct 2019 16:59:32 -0600 Subject: [PATCH 4/8] Block write works. Updated examples. Write speed decreased from 30ms to 19ms due to block writing instead of multi-byte writes. Works with arbitrary length variables such as char arrays. --- .../Example2_AllFunctions.ino | 16 ++- libraries/EEPROM/src/EEPROM.cpp | 97 +------------------ libraries/EEPROM/src/EEPROM.h | 3 - 3 files changed, 17 insertions(+), 99 deletions(-) diff --git a/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino b/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino index f52f4f79..7f049321 100644 --- a/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino +++ b/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino @@ -149,30 +149,38 @@ void setup() Serial.printf("Size of double: %d\n", sizeof(double)); double myValue11 = -290.3485723409857; double myValue12 = 384.95734987; + double myValue13 = 917.14159; randomLocation = random(0, AP3_FLASH_EEPROM_SIZE); + startTime = millis(); EEPROM.put(randomLocation, myValue11); + endTime = millis(); + Serial.printf("Time to record 64-bits: %dms\n", endTime - startTime); + EEPROM.put(randomLocation + 8, myValue12); + EEPROM.put(EEPROM.length() - sizeof(myValue13), myValue13); //Test end of EEPROM space double response11; double response12; + double response13; EEPROM.get(randomLocation, response11); EEPROM.get(randomLocation + 8, response12); + EEPROM.get(EEPROM.length() - sizeof(myValue13), response13); Serial.printf("Location %d should be %lf: %lf\n", randomLocation, myValue11, response11); Serial.printf("Location %d should be %lf: %lf\n", randomLocation + 8, myValue12, response12); + Serial.printf("Edge of EEPROM %d should be %lf: %lf\n", EEPROM.length() - sizeof(myValue13), myValue13, response13); //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Serial.println(""); Serial.println("String test"); //String write test - dont do string.Do char *array with phone # - //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - String myString = "How are you today?"; + //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + char myString[19] = "How are you today?"; randomLocation = random(0, AP3_FLASH_EEPROM_SIZE); EEPROM.put(randomLocation, myString); - String readMy; + char readMy[19]; EEPROM.get(randomLocation, readMy); Serial.printf("Location %d string should read 'How are you today?': ", randomLocation); Serial.println(readMy); diff --git a/libraries/EEPROM/src/EEPROM.cpp b/libraries/EEPROM/src/EEPROM.cpp index df2e5794..b922a772 100644 --- a/libraries/EEPROM/src/EEPROM.cpp +++ b/libraries/EEPROM/src/EEPROM.cpp @@ -21,8 +21,8 @@ Flash is 0x00 to 0xFF000. EEPROM writes will start at 0xFF000 - 8192 = 0xF2000. Page erase takes 15ms - Writing a byte takes 30ms - Writing a float across two words takes 30ms + Writing a byte takes 19ms + Writing a float across two words takes 19ms Update (no write) takes 1ms Development environment specifics: @@ -40,11 +40,7 @@ #include "EEPROM.h" #include "Arduino.h" -//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - //Write a byte to a given "EEPROM" location -//Automatically masks user's byte into flash without -//affecting other bytes in this flash word void write(uint16_t eepromLocation, uint8_t dataToWrite) { EEPROM.writeBlockToEEPROM(eepromLocation, &dataToWrite, 1); @@ -57,17 +53,6 @@ uint8_t read(uint16_t eepromLocation) return (*(uint8_t *)flashLocation); } -//Write a new byte to a given location in "EEROM" only if new data is there -void update(uint16_t eepromLocation, uint8_t dataToWrite) -{ - if (read(eepromLocation) != dataToWrite) - { - write(eepromLocation, dataToWrite); - } -} - -//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - //Erase 8k page encapsulating the EEPROM section void EEPROMClass::erase() { @@ -76,82 +61,10 @@ void EEPROMClass::erase() AM_HAL_FLASH_ADDR2PAGE(AP3_FLASH_EEPROM_START)); } -//This is the main helper function -//Reprogram a given location with 32-bits -//Flash is written to in words at locations that are %4=0 -//Span words if necessary //1) Make copy of current flash contents into SRAM -//2) Turn user's requested spot into 0xFFs +//2) Record user data into SRAM. Check if new data is different from flash. //3) Erase flash page (8k) //4) Write SRAM back into flash -//5) Write user's data onto the spot with recently created 0xFFs -//Note - this code assumes EEPROM temp space is contained in one page -void writeWordToFlash(uint32_t flashLocation, uint32_t dataToWrite) -{ - //Error check - if (flashLocation >= AP3_FLASH_EEPROM_START + AP3_FLASH_EEPROM_SIZE) - { - return; - } - if (flashLocation < AP3_FLASH_EEPROM_START) - { - return; - } - - //Check to see if location needs updating - if (*(uint32_t *)(flashLocation) == dataToWrite) - { - return; - } - - //First we have to read the contents of current "EEPROM" to SRAM - uint32_t tempContents[AP3_FLASH_EEPROM_SIZE / 4]; - uint16_t spot = 0; - for (uint16_t x = 0; x < AP3_FLASH_EEPROM_SIZE; x += 4) - { - tempContents[spot++] = *(uint32_t *)(AP3_FLASH_EEPROM_START + x); - } - - //Then we erase an 8K page - am_hal_flash_page_erase(AM_HAL_FLASH_PROGRAM_KEY, - AM_HAL_FLASH_ADDR2INST(flashLocation), - AM_HAL_FLASH_ADDR2PAGE(flashLocation)); - - //Zero out this word(s) - uint8_t byteOffset = (flashLocation % 4); - uint16_t wordLocation = (flashLocation - AP3_FLASH_EEPROM_START) / 4; - - //Mask in the new data into the array - if (byteOffset == 0) - { - //Easy - update this word with new word - tempContents[wordLocation] = dataToWrite; - } - else - { - //Clear the upper bytes of the first word to 0s - tempContents[wordLocation] &= ~(0xFFFFFFFF << (byteOffset * 8)); - - //Clear the lower bytes of the second word to 0s - tempContents[wordLocation + 1] &= ~(0xFFFFFFFF >> ((4 - byteOffset) * 8)); - - //OR in upper bytes of this word with new data - uint32_t dataToWriteFirstWord = dataToWrite << (byteOffset * 8); - - //OR in the lower bytes of the following word with new data - uint32_t dataToWriteSecondWord = dataToWrite >> ((4 - byteOffset) * 8); - - tempContents[wordLocation] |= dataToWriteFirstWord; - tempContents[wordLocation + 1] |= dataToWriteSecondWord; - } - - //Then we write the contents of the array back - am_hal_flash_program_main(AM_HAL_FLASH_PROGRAM_KEY, - tempContents, - (uint32_t *)AP3_FLASH_EEPROM_START, - AP3_FLASH_EEPROM_SIZE); -} - void EEPROMClass::writeBlockToEEPROM(uint16_t eepromLocation, const uint8_t *dataToWrite, uint16_t blockSize) { //Error check @@ -168,7 +81,7 @@ void EEPROMClass::writeBlockToEEPROM(uint16_t eepromLocation, const uint8_t *dat } //Write the caller's new data into the byte array - for (int x = 0; x < blockSize; x++) + for (uint16_t x = 0; x < blockSize; x++) { eepromContents[eepromLocation + x] = dataToWrite[x]; } @@ -192,7 +105,7 @@ void EEPROMClass::writeBlockToEEPROM(uint16_t eepromLocation, const uint8_t *dat AM_HAL_FLASH_ADDR2INST(AP3_FLASH_EEPROM_START + eepromLocation), AM_HAL_FLASH_ADDR2PAGE(AP3_FLASH_EEPROM_START + eepromLocation)); - //Flash is written in 32bit words so we split the byte array into 4 byte chunks + //Flash is written in 32-bit words so we split the byte array into 4 byte chunks uint32_t flashContent[AP3_FLASH_EEPROM_SIZE / 4]; uint16_t spot = 0; for (uint16_t x = 0; x < AP3_FLASH_EEPROM_SIZE; x += 4) diff --git a/libraries/EEPROM/src/EEPROM.h b/libraries/EEPROM/src/EEPROM.h index 6087012b..702cca5b 100644 --- a/libraries/EEPROM/src/EEPROM.h +++ b/libraries/EEPROM/src/EEPROM.h @@ -72,9 +72,6 @@ Error : EEPROM start address must be divisble by 8192 uint8_t read(uint16_t eepromLocation); void write(uint16_t eepromLocation, uint8_t dataToWrite); -void update(uint16_t eepromLocation, uint8_t dataToWrite); -void erase(); //Erase entire EEPROM -void writeWordToFlash(uint32_t flashLocation, uint32_t dataToWrite); struct EERef { From 669bb4f147a87d380ef9640e150a1d22f8ba080e Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 15 Oct 2019 17:11:00 -0600 Subject: [PATCH 5/8] Move writeBlock function outside of class. --- .../Example2_AllFunctions/Example2_AllFunctions.ino | 2 +- libraries/EEPROM/src/EEPROM.cpp | 4 ++-- libraries/EEPROM/src/EEPROM.h | 13 ++++++------- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino b/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino index 7f049321..438fbb69 100644 --- a/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino +++ b/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino @@ -30,7 +30,7 @@ void setup() long startTime; long endTime; - uint16_t randomLocation; + int randomLocation; //Test erase time startTime = millis(); diff --git a/libraries/EEPROM/src/EEPROM.cpp b/libraries/EEPROM/src/EEPROM.cpp index b922a772..6472b25b 100644 --- a/libraries/EEPROM/src/EEPROM.cpp +++ b/libraries/EEPROM/src/EEPROM.cpp @@ -43,7 +43,7 @@ //Write a byte to a given "EEPROM" location void write(uint16_t eepromLocation, uint8_t dataToWrite) { - EEPROM.writeBlockToEEPROM(eepromLocation, &dataToWrite, 1); + writeBlockToEEPROM(eepromLocation, &dataToWrite, 1); } //Read a byte from a given location in "EEPROM" @@ -65,7 +65,7 @@ void EEPROMClass::erase() //2) Record user data into SRAM. Check if new data is different from flash. //3) Erase flash page (8k) //4) Write SRAM back into flash -void EEPROMClass::writeBlockToEEPROM(uint16_t eepromLocation, const uint8_t *dataToWrite, uint16_t blockSize) +void writeBlockToEEPROM(uint16_t eepromLocation, const uint8_t *dataToWrite, uint16_t blockSize) { //Error check if (eepromLocation + blockSize >= AP3_FLASH_EEPROM_SIZE) diff --git a/libraries/EEPROM/src/EEPROM.h b/libraries/EEPROM/src/EEPROM.h index 702cca5b..b4c43fc8 100644 --- a/libraries/EEPROM/src/EEPROM.h +++ b/libraries/EEPROM/src/EEPROM.h @@ -64,14 +64,14 @@ Error : EEPROM start address must be divisble by 8192 #endif -//By limiting EEPROM size to 1024 bytes, we reduce the amount of SRAM required and -//time needed to mask in individual bytes and words into flash. It can be increased -//to 8096 if needed -#define AP3_FLASH_EEPROM_SIZE 1024 //In bytes + //By limiting EEPROM size to 1024 bytes, we reduce the amount of SRAM required and + //time needed to read/write words into flash. It can be increased + //to 8096 if needed + const int AP3_FLASH_EEPROM_SIZE = 1024 * 2; //In bytes - uint8_t - read(uint16_t eepromLocation); +uint8_t read(uint16_t eepromLocation); void write(uint16_t eepromLocation, uint8_t dataToWrite); +void writeBlockToEEPROM(uint16_t eepromLocation, const uint8_t *dataToWrite, uint16_t blockSize); struct EERef { @@ -164,7 +164,6 @@ struct EEPROMClass void write(int idx, uint8_t val) { (EERef(idx)) = val; } void update(int idx, uint8_t val) { EERef(idx).update(val); } void erase(); - void writeBlockToEEPROM(uint16_t eepromLocation, const uint8_t *dataToWrite, uint16_t blockSize); //STL and C++11 iteration capability. EEPtr From 2433f67140531fe2872be4faaa897de1aff36b68 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Tue, 15 Oct 2019 20:46:03 -0600 Subject: [PATCH 6/8] Reduce EEPROM area back to original 1024 bytes --- libraries/EEPROM/src/EEPROM.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/EEPROM/src/EEPROM.h b/libraries/EEPROM/src/EEPROM.h index b4c43fc8..9b3307dc 100644 --- a/libraries/EEPROM/src/EEPROM.h +++ b/libraries/EEPROM/src/EEPROM.h @@ -67,7 +67,7 @@ Error : EEPROM start address must be divisble by 8192 //By limiting EEPROM size to 1024 bytes, we reduce the amount of SRAM required and //time needed to read/write words into flash. It can be increased //to 8096 if needed - const int AP3_FLASH_EEPROM_SIZE = 1024 * 2; //In bytes + const int AP3_FLASH_EEPROM_SIZE = 1024; //In bytes uint8_t read(uint16_t eepromLocation); void write(uint16_t eepromLocation, uint8_t dataToWrite); From 3829af2b3dc20818cd38871962dcd93797465c13 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Wed, 16 Oct 2019 09:39:19 -0600 Subject: [PATCH 7/8] Add re-write test to example 2. This helps verify the EEPROM lib is erasing flash. --- .../Example2_AllFunctions/Example2_AllFunctions.ino | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino b/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino index 438fbb69..98569180 100644 --- a/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino +++ b/libraries/EEPROM/examples/Example2_AllFunctions/Example2_AllFunctions.ino @@ -150,6 +150,7 @@ void setup() double myValue11 = -290.3485723409857; double myValue12 = 384.95734987; double myValue13 = 917.14159; + double myValue14 = 254.8877; randomLocation = random(0, AP3_FLASH_EEPROM_SIZE); startTime = millis(); @@ -169,6 +170,11 @@ void setup() Serial.printf("Location %d should be %lf: %lf\n", randomLocation, myValue11, response11); Serial.printf("Location %d should be %lf: %lf\n", randomLocation + 8, myValue12, response12); Serial.printf("Edge of EEPROM %d should be %lf: %lf\n", EEPROM.length() - sizeof(myValue13), myValue13, response13); + + double response14; + EEPROM.put(EEPROM.length() - sizeof(myValue14), myValue14); //Test the re-write of a spot + EEPROM.get(EEPROM.length() - sizeof(myValue14), response14); + Serial.printf("Rewrite of %d should be %lf: %lf\n", EEPROM.length() - sizeof(myValue14), myValue14, response14); //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Serial.println(""); From 196d6857f9d16c3aa559e950ede2728989131cfe Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Wed, 16 Oct 2019 09:40:06 -0600 Subject: [PATCH 8/8] Rewrite EEPROM block write to use one array instead of two (less SRAM!). Update comments. Now works up to 2096 bytes of flash based EEPROM. --- libraries/EEPROM/src/EEPROM.cpp | 36 ++++++++++++++------------------- libraries/EEPROM/src/EEPROM.h | 10 +++++---- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/libraries/EEPROM/src/EEPROM.cpp b/libraries/EEPROM/src/EEPROM.cpp index 6472b25b..f8b9b802 100644 --- a/libraries/EEPROM/src/EEPROM.cpp +++ b/libraries/EEPROM/src/EEPROM.cpp @@ -23,7 +23,7 @@ Page erase takes 15ms Writing a byte takes 19ms Writing a float across two words takes 19ms - Update (no write) takes 1ms + Update (no write) takes ~1ms Development environment specifics: Arduino IDE 1.8.x @@ -62,9 +62,10 @@ void EEPROMClass::erase() } //1) Make copy of current flash contents into SRAM -//2) Record user data into SRAM. Check if new data is different from flash. -//3) Erase flash page (8k) -//4) Write SRAM back into flash +//2) Record user data into SRAM. +//3) Check if new data is different from flash. +//4) Erase flash page (8k) +//5) Write SRAM back into flash void writeBlockToEEPROM(uint16_t eepromLocation, const uint8_t *dataToWrite, uint16_t blockSize) { //Error check @@ -73,8 +74,14 @@ void writeBlockToEEPROM(uint16_t eepromLocation, const uint8_t *dataToWrite, uin blockSize = AP3_FLASH_EEPROM_SIZE - eepromLocation; } - //First we have to read the contents of current "EEPROM" to SRAM, one byte at a time - uint8_t eepromContents[AP3_FLASH_EEPROM_SIZE]; + //Read the contents of current "EEPROM" to SRAM + //Flash is written in 32-bit words but user passes in array of bytes + //Create an array of 32-bit words but reference it a byte at a time + uint32_t flashContent[AP3_FLASH_EEPROM_SIZE / 4]; + + //We can't read 32bits at a time because the way flash is oriented (little endian) + //So we read a byte at a time + uint8_t *eepromContents = (uint8_t *)flashContent; for (uint16_t x = 0; x < AP3_FLASH_EEPROM_SIZE; x++) { eepromContents[x] = *(uint8_t *)(AP3_FLASH_EEPROM_START + x); @@ -86,8 +93,8 @@ void writeBlockToEEPROM(uint16_t eepromLocation, const uint8_t *dataToWrite, uin eepromContents[eepromLocation + x] = dataToWrite[x]; } - //Only update flash with new data. - //Run a check here to see if the new data is the same as what's in flash. If it's the same, don't erase flash. + //Run a check here to see if the new data is the same as what's in flash. If it's the same, + //just return, don't erase flash. bool theSame = true; for (uint16_t x = 0; x < AP3_FLASH_EEPROM_SIZE; x++) { @@ -105,19 +112,6 @@ void writeBlockToEEPROM(uint16_t eepromLocation, const uint8_t *dataToWrite, uin AM_HAL_FLASH_ADDR2INST(AP3_FLASH_EEPROM_START + eepromLocation), AM_HAL_FLASH_ADDR2PAGE(AP3_FLASH_EEPROM_START + eepromLocation)); - //Flash is written in 32-bit words so we split the byte array into 4 byte chunks - uint32_t flashContent[AP3_FLASH_EEPROM_SIZE / 4]; - uint16_t spot = 0; - for (uint16_t x = 0; x < AP3_FLASH_EEPROM_SIZE; x += 4) - { - flashContent[spot] = (uint32_t)eepromContents[x + 3] << (8 * 3); - flashContent[spot] |= (uint32_t)eepromContents[x + 2] << (8 * 2); - flashContent[spot] |= (uint32_t)eepromContents[x + 1] << (8 * 1); - flashContent[spot] |= (uint32_t)eepromContents[x + 0] << (8 * 0); - - spot++; - } - //Then we write the contents of the array back am_hal_flash_program_main(AM_HAL_FLASH_PROGRAM_KEY, flashContent, diff --git a/libraries/EEPROM/src/EEPROM.h b/libraries/EEPROM/src/EEPROM.h index 9b3307dc..56890856 100644 --- a/libraries/EEPROM/src/EEPROM.h +++ b/libraries/EEPROM/src/EEPROM.h @@ -21,9 +21,9 @@ at 0xFE000; Page erase takes 15ms - Writing a byte takes 30ms - Writing a float across two words takes 30ms - Update (no write) takes 1ms + Writing a byte takes 19ms + Writing a float across two words takes 19ms + Update (no write) takes ~1ms Development environment specifics: Arduino IDE 1.8.x @@ -66,7 +66,9 @@ Error : EEPROM start address must be divisble by 8192 //By limiting EEPROM size to 1024 bytes, we reduce the amount of SRAM required and //time needed to read/write words into flash. It can be increased - //to 8096 if needed + //to 2048 if needed + //1024 = 19ms update time + //2048 = 23ms update time const int AP3_FLASH_EEPROM_SIZE = 1024; //In bytes uint8_t read(uint16_t eepromLocation);