Skip to content

Commit

Permalink
- Fix long reads bug, #3
Browse files Browse the repository at this point in the history
 - Implement paged reads and writes (32 bytes pages, as 64 bits doesn't fit on Wire library's buffer) to mitigate EEPROM wearing.
 - Added html documentation
 - Splitted docs and extras to another repository
  • Loading branch information
Naguissa committed Apr 21, 2020
1 parent 4d14963 commit 973bfd6
Show file tree
Hide file tree
Showing 7 changed files with 275 additions and 70 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,15 @@ For manual installation:



## Example ##
## Documentation and extras ##

You can find all documentation and extras in this repository: https://github.com/Naguissa/uEEPROMLib_doc_and_extras

Due GitHub limitations HTML documentation is not avaliable online, you need to download the zip.



## Examples ##

Included on example folder, available on Arduino IDE.

Expand Down
1 change: 1 addition & 0 deletions contributors.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
Naguissa - https://github.com/Naguissa
hyperion11 - https://github.com/hyperion11 - Multibyte EEPROM read/write
linusnielsen - https://github.com/linusnielsen - Remove stray Serial.print
Alex Wong - https://github.com/alw1746 - Find long reads bug, #3
73 changes: 73 additions & 0 deletions examples/uEEPROMLib_pages/uEEPROMLib_pages.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
* I2C EEPROM library example. Split from uRTCLib https://github.com/Naguissa/uRTCLib
*
* This library controls any I2C EEPROM, independent ones or incorporated on DS1307 or DS3231 RTCs.
*
* @copyright Naguissa
* @author Naguissa
* @email [email protected]
* @url https://www.foroelectro.net/librerias-arduino-ide-f29/ueepromlib-arduino-libreria-simple-y-eficaz-para-e-t225.html
* @url https://github.com/Naguissa/uEEPROMLib
* @version 1.0.0
* @created 2018-07-27
*/
#include "Arduino.h"
#include "Wire.h"
#include "uEEPROMLib.h"


// uEEPROMLib eeprom;
uEEPROMLib eeprom(0x57);

// 305 bytes
char longMessage[310] = "I2C EEPROM library example. Split from uRTCLib\n\nThis library controls any I2C EEPROM, independent ones or incorporated on DS1307 or DS3231 RTCs.\n\nhttps://github.com/Naguissa/uEEPROMLib\nhttps://www.foroelectro.net/librerias-arduino-ide-f29/ueepromlib-arduino-libreria-simple-y-eficaz-para-e-t225.html\0";

void setup() {
delay (2000);
Serial.begin(9600);
Serial.println("Serial OK");

delay(2500);
Serial.println("Delay OK");

#ifdef ARDUINO_ARCH_ESP8266
Wire.begin(0, 2); // D3 and D4 on ESP8266
#else
Wire.begin();
#endif

// Alligned
if (!eeprom.eeprom_write(0, (byte *) &longMessage[0], 305)) {
Serial.println("Failed to store aligned STRING");
} else {
Serial.println("Aligned STRING correctly stored");
}

if (!eeprom.eeprom_write(311, (byte *) &longMessage[0], 305)) {
Serial.println("Failed to store unaligned STRING");
} else {
Serial.println("Unaligned STRING correctly stored");
}

}

void loop() {
char *readMessageA;
char *readMessageB;
readMessageA = (char * ) malloc(210);
readMessageB = (char * ) malloc(210);
Serial.println("-------------------------------------");
Serial.println();

Serial.println("Algined string:");
eeprom.eeprom_read(0, (byte *) readMessageA, 305);
Serial.println(readMessageA);

Serial.println();

Serial.println("Unalgined string:");
eeprom.eeprom_read(0, (byte *) readMessageB, 305);
Serial.println(longMessage);

Serial.println();
}
Binary file removed extras/AT24C32.pdf
Binary file not shown.
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=uEEPROMLib
version=1.0.1
version=1.1.0
author=Naguissa <[email protected]>
maintainer=Naguissa <[email protected]>
sentence=I2C EEPROM library. Split from uRTCLib https://github.com/Naguissa/uRTCLib - This library controls any I2C EEPROM, independent ones or incorporated on DS1307 or DS3231 RTCs.
Expand Down
176 changes: 128 additions & 48 deletions src/uEEPROMLib.cpp
Original file line number Diff line number Diff line change
@@ -1,31 +1,29 @@
/**
* I2C EEPROM library. Split from uRTCLib https://github.com/Naguissa/uRTCLib
* \class uEEPROMLib
* \brief I2C EEPROM library. Split from uRTCLib.
*
* This library controls any I2C EEPROM, independent ones or incorporated on DS1307 or DS3231 RTCs.
*
* @copyright Naguissa
* @author Naguissa
* @email [email protected]
* @url https://www.foroelectro.net/librerias-arduino-ide-f29/ueepromlib-arduino-libreria-simple-y-eficaz-para-e-t225.html
* @url https://github.com/Naguissa/uEEPROMLib
* @version 1.0.1
* @created 2018-07-27
* @see <a href="https://github.com/Naguissa/uEEPROMLib">https://github.com/Naguissa/uEEPROMLib</a>
* @see <a href="https://www.foroelectro.net/librerias-arduino-ide-f29/ueepromlib-arduino-libreria-simple-y-eficaz-para-e-t225.html">https://www.foroelectro.net/librerias-arduino-ide-f29/ueepromlib-arduino-libreria-simple-y-eficaz-para-e-t225.html</a>
* @see <a href="mailto:[email protected]">[email protected]</a>
* @see <a href="https://github.com/Naguissa/uRTCLib">https://github.com/Naguissa/uRTCLib</a>
* @version 1.1.0
*/

#include <Arduino.h>
#include <Wire.h>
#include "uEEPROMLib.h"

/**
* Constructor
* \brief Constructor
*/
uEEPROMLib::uEEPROMLib() { }


/**
* Constructor
* \brief Constructor
*
* @param bool skipInit Set true to skip Wire.init (needed for STM32, SAM and Arduino, at least)
* @param skipInit Set true to skip Wire.init (needed for STM32, SAM and Arduino, at least)
*/
uEEPROMLib::uEEPROMLib(bool skipInit) {
init = skipInit;
Expand All @@ -35,42 +33,43 @@ uEEPROMLib::uEEPROMLib(bool skipInit) {


/**
* Constructor
* \brief Constructor
*
* @param int ee_address I2C address of EEPROM
* @param addr I2C address of EEPROM
*/
uEEPROMLib::uEEPROMLib(const int ee_address) {
_ee_address = ee_address;
uEEPROMLib::uEEPROMLib(const int addr) {
_ee_address = addr;
}


/**
* Constructor
* \brief Constructor
*
* @param bool skipInit Set true to skip Wire.init (needed for STM32, SAM and Arduino, at least)
* @param int ee_address I2C address of EEPROM
* @param skipInit Set true to skip Wire.init (needed for STM32, SAM and Arduino, at least)
* @param addr I2C address of EEPROM
*/
uEEPROMLib::uEEPROMLib(bool skipInit, const int ee_address) {
uEEPROMLib::uEEPROMLib(bool skipInit, const int addr) {
init = skipInit;
_ee_address = ee_address;
_ee_address = addr;
}


/**
* Sets EEPROM i2c addres
* \brief Sets EEPROM i2c addres
*
* @param int addr EEPROM i2C address
* @param skipInit Set true to skip Wire.init (needed for STM32, SAM and Arduino, at least)
* @param addr I2C address of EEPROM
*/
void uEEPROMLib::set_address(const uint8_t addr) {
_ee_address = addr;
}


/**
* Read one byte
* \brief Read one byte
*
* @param unsigned int address Address inside EEPROM to read from
* @return char read byte
* @param address Address inside EEPROM to read from
* @return read byte
*/
byte uEEPROMLib::_eeprom_read(const unsigned int address) {
uEEPROMLIB_STM32_INIT_FIX()
Expand All @@ -79,28 +78,61 @@ byte uEEPROMLib::_eeprom_read(const unsigned int address) {
Wire.beginTransmission(_ee_address);
Wire.write((int)(address >> 8)); // MSB
Wire.write((int)(address & 0xFF)); // LSB
delay(uEEPROMLIB_WIRE_DELAY); // Little delay to assure EEPROM is able to process data; if missing and inside for look meses some values
delay(uEEPROMLIB_WIRE_DELAY); // Little delay to assure EEPROM is able to process data; if missing and inside a for loop meses some values
if (Wire.endTransmission() == 0) {
Wire.requestFrom(_ee_address, 1);
delay(uEEPROMLIB_WIRE_DELAY); // Little delay to assure EEPROM is able to process data; if missing and inside for look meses some values
delay(uEEPROMLIB_WIRE_DELAY); // Little delay to assure EEPROM is able to process data; if missing and inside a for loop meses some values
if(Wire.available()) {
rdata = (byte) Wire.read();
delay(uEEPROMLIB_WIRE_DELAY); // Little delay to assure EEPROM is able to process data; if missing and inside for look meses some values
delay(uEEPROMLIB_WIRE_SHORT_DELAY); // Little delay to assure EEPROM is able to process data; if missing and inside a for loop meses some values
}
}
uEEPROMLIB_YIELD
return rdata;
}

/**
* Read sequence of n bytes. Optionally from offset
* \brief Read sequence of n bytes.
*
* Public function, can read any arbitrary data length
*
* @param address Address inside EEPROM to read from
* @param data Pointer to where read data to
* @param number of bytes to read
* @return true if bytes read are the same as requested
*/
bool uEEPROMLib::eeprom_read(const unsigned int address, byte *data, const uint16_t n) {
unsigned int _address = address;
byte * _data = data;
uint16_t remaining = n;
bool ret = true;
while (remaining > 0 && ret) {
if (remaining < 32) {
ret = _eeprom_read_sub(_address, (data + n - remaining), (uint8_t) remaining);
remaining = 0;
} else {
ret = _eeprom_read_sub(_address, (data + n - remaining), 32);
remaining -= 32;
_address += 32;
_data += 32;
}
}
return ret;
}



/**
* \brief Read sequence of n bytes.
*
* Private function to read chunks of 32 bytes maximum
*
* @param unsigned int address Address inside EEPROM to read from
* @param byte* data Pointer to where read data to
* @param uint8_t n number of bytes to read
* @return Bool true if bytes read are the same as requested
* @param address Address inside EEPROM to read from
* @param data Pointer to where read data to
* @param number of bytes to read
* @return true if bytes read are the same as requested
*/
bool uEEPROMLib::eeprom_read(const unsigned int address, byte *data, const uint8_t n) {
bool uEEPROMLib::_eeprom_read_sub(const unsigned int address, byte *data, const uint8_t n) {
bool ret = false;
uEEPROMLIB_STM32_INIT_FIX()
uEEPROMLIB_YIELD
Expand All @@ -115,11 +147,11 @@ bool uEEPROMLib::eeprom_read(const unsigned int address, byte *data, const uint8
byte i = 0, j;
for (; i < n && Wire.available(); i++) {
*(data + i) = (byte) Wire.read();
delay(uEEPROMLIB_WIRE_DELAY); // Little delay to assure EEPROM is able to process data; if missing and inside for look meses some values
delay(uEEPROMLIB_WIRE_SHORT_DELAY); // Little delay to assure EEPROM is able to process data; if missing and inside for look meses some values
uEEPROMLIB_YIELD
// Added to wait if needed but cut after a failure (timeout)
for (j = 0; j < 255 && !Wire.available(); j++) {
delay(uEEPROMLIB_WIRE_DELAY); // Little delay to assure EEPROM is able to process data; if missing and inside for look meses some values
delay(uEEPROMLIB_WIRE_SHORT_DELAY); // Little delay to assure EEPROM is able to process data; if missing and inside for look meses some values
uEEPROMLIB_YIELD
}
}
Expand All @@ -132,21 +164,21 @@ bool uEEPROMLib::eeprom_read(const unsigned int address, byte *data, const uint8


/**
* Read a byte from EEPROM address
* \brief Read a byte from EEPROM address
*
* @param unsigned int address Address inside EEPROM to read from
* @return byte read data
* @param address Address inside EEPROM to read from
* @return Read data
*/
byte uEEPROMLib::eeprom_read(const unsigned int address) {
return _eeprom_read(address);
}

/**
* Write one byte to EEPROM
* \brief Write one byte to EEPROM
*
* @param unsigned int address Address inside EEPROM to write to
* @param byte data byte to write
* @return bool true if successful
* @param address Address inside EEPROM to write to
* @param data byte to write
* @return true if successful
*/
bool uEEPROMLib::_eeprom_write(const unsigned int address, const byte data) {
uEEPROMLIB_YIELD
Expand All @@ -159,6 +191,29 @@ bool uEEPROMLib::_eeprom_write(const unsigned int address, const byte data) {
return Wire.endTransmission() == 0;
}

/**
* \brief Write one block to EEPROM
*
* Internal INSECURE function to write up to 16 byte blocks (arduino has a 32 byte buffer but it includes 2-byte address
*
* @param address Address inside EEPROM to write to
* @param data byte to write
* @return true if successful
*/
bool uEEPROMLib::_eeprom_write_sub(const unsigned int address, byte *data, const uint8_t n) {
uint8_t idx = 0;
uEEPROMLIB_YIELD
Wire.beginTransmission(_ee_address);
Wire.write((int)(address >> 8)); // MSB
Wire.write((int)(address & 0xFF)); // LSB
for (; idx < n; idx++) {
Wire.write(*(data + idx));
uEEPROMLIB_YIELD
}
delay(uEEPROMLIB_WIRE_DELAY); // Little delay to assure EEPROM is able to process data; if missing and inside for look meses some values
return Wire.endTransmission() == 0;
}


/**
* Write sequence of n bytes
Expand All @@ -168,11 +223,36 @@ bool uEEPROMLib::_eeprom_write(const unsigned int address, const byte data) {
* @param n uint8_t number of bytes to write
* @return bool true if successful
*/
bool uEEPROMLib::eeprom_write(const unsigned int address, void *data, const uint8_t n) {
bool uEEPROMLib::eeprom_write(const unsigned int address, void *data, const uint16_t n) {
bool r = true;
uint8_t i;
for (i = 0; i < n; i++) {
r &= _eeprom_write(address + i, (byte) *(((byte *) data) + i));
byte *dataptr;

uint8_t sublen;
uint16_t act;
uint16_t i = 0;


if (n == 0) {
r = false;
} else if (n == 1) {
_eeprom_write(address, (byte) *((byte *) data));
} else {
dataptr = (byte *) data;
// head part:
if (address % 16 != 0) {
r = _eeprom_write_sub(address, dataptr, (uint8_t) (address % 16));
i = address % 16;
dataptr += address % 16;
}
// 16 byte middle parts
for (; r && i + 16 <= n; i += 16, dataptr += 16) {
r &= _eeprom_write_sub(address + i, dataptr, 16);
}
// tail, if any
if (r && i < n) {
r &= _eeprom_write_sub(address, dataptr, (uint8_t) (n - i));
}

}
return r;
}
Expand Down
Loading

0 comments on commit 973bfd6

Please sign in to comment.