1.8.3 I2C_EEPROM

This commit is contained in:
Rob Tillaart 2024-03-28 10:50:48 +01:00
parent 6f2cc904c9
commit 7c3a797cfb
14 changed files with 260 additions and 28 deletions

View File

@ -1,4 +1,5 @@
# These are supported funding model platforms # These are supported funding model platforms
github: RobTillaart github: RobTillaart
custom: "https://www.paypal.me/robtillaart"

View File

@ -5,8 +5,9 @@ on: [push, pull_request]
jobs: jobs:
lint: lint:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 5
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: arduino/arduino-lint-action@v1 - uses: arduino/arduino-lint-action@v1
with: with:
library-manager: update library-manager: update

View File

@ -6,12 +6,14 @@ on: [push, pull_request]
jobs: jobs:
runTest: runTest:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 20
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1 - uses: ruby/setup-ruby@v1
with: with:
ruby-version: 2.6 ruby-version: 2.6
- run: | - run: |
sudo sysctl vm.mmap_rnd_bits=28
gem install arduino_ci gem install arduino_ci
arduino_ci.rb arduino_ci.rb

View File

@ -9,10 +9,11 @@ on:
jobs: jobs:
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 5
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: json-syntax-check - name: json-syntax-check
uses: limitusus/json-syntax-check@v1 uses: limitusus/json-syntax-check@v2
with: with:
pattern: "\\.json$" pattern: "\\.json$"

View File

@ -5,7 +5,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/) The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/). and this project adheres to [Semantic Versioning](http://semver.org/).
## [1.8.2] - 2023-01-02
## [1.8.3] - 2024-03-28
- Fix #64, compiler warning.
- add **verifyBlock(memoryAddress, buffer, length)**
- add example **I2C_eeprom_verifyBlock.ino**
- update GitHub actions
- update keywords.txt
- update examples
- update readme.md
## [1.8.2] - 2024-01-02
- updated **uint32_t determineSizeNoWrite()**, kudos to roelandkluit - updated **uint32_t determineSizeNoWrite()**, kudos to roelandkluit
- minor edits - minor edits
@ -14,7 +25,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- add example - add example
- minor edits - minor edits
## [1.8.0] - 2023-11-24 (breaking change) ## [1.8.0] - 2023-11-24 (breaking change)
- simplify **begin()**, remove setting Wire pins from library. - simplify **begin()**, remove setting Wire pins from library.
- add **getAddress()** - add **getAddress()**

View File

@ -1,7 +1,7 @@
// //
// FILE: I2C_eeprom.cpp // FILE: I2C_eeprom.cpp
// AUTHOR: Rob Tillaart // AUTHOR: Rob Tillaart
// VERSION: 1.8.2 // VERSION: 1.8.3
// PURPOSE: Arduino Library for external I2C EEPROM 24LC256 et al. // PURPOSE: Arduino Library for external I2C EEPROM 24LC256 et al.
// URL: https://github.com/RobTillaart/I2C_EEPROM.git // URL: https://github.com/RobTillaart/I2C_EEPROM.git
@ -147,6 +147,27 @@ uint16_t I2C_eeprom::readBlock(const uint16_t memoryAddress, uint8_t * buffer, c
} }
// returns true or false.
bool I2C_eeprom::verifyBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length)
{
uint16_t addr = memoryAddress;
uint16_t len = length;
while (len > 0)
{
uint8_t cnt = I2C_BUFFERSIZE;
if (cnt > len) cnt = len;
if (_verifyBlock(addr, buffer, cnt) == false)
{
return false;
}
addr += cnt;
buffer += cnt;
len -= cnt;
}
return true;
}
///////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////
// //
// UPDATE SECTION // UPDATE SECTION
@ -203,9 +224,7 @@ bool I2C_eeprom::writeByteVerify(const uint16_t memoryAddress, const uint8_t val
bool I2C_eeprom::writeBlockVerify(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length) bool I2C_eeprom::writeBlockVerify(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length)
{ {
if (writeBlock(memoryAddress, buffer, length) != 0) return false; if (writeBlock(memoryAddress, buffer, length) != 0) return false;
uint8_t data[length]; return verifyBlock(memoryAddress, buffer, length);
if (readBlock(memoryAddress, data, length) != length) return false;
return memcmp(data, buffer, length) == 0;
} }
@ -213,12 +232,18 @@ bool I2C_eeprom::writeBlockVerify(const uint16_t memoryAddress, const uint8_t *
bool I2C_eeprom::setBlockVerify(const uint16_t memoryAddress, const uint8_t value, const uint16_t length) bool I2C_eeprom::setBlockVerify(const uint16_t memoryAddress, const uint8_t value, const uint16_t length)
{ {
if (setBlock(memoryAddress, value, length) != 0) return false; if (setBlock(memoryAddress, value, length) != 0) return false;
uint8_t data[length]; uint8_t * data = (uint8_t *) malloc(length);
if (data == NULL) return false;
if (readBlock(memoryAddress, data, length) != length) return false; if (readBlock(memoryAddress, data, length) != length) return false;
for (uint16_t i = 0; i < length; i++) for (uint16_t i = 0; i < length; i++)
{ {
if (data[i] != value) return false; if (data[i] != value)
{
free(data);
return false;
} }
}
free(data);
return true; return true;
} }
@ -236,9 +261,7 @@ bool I2C_eeprom::updateByteVerify(const uint16_t memoryAddress, const uint8_t va
bool I2C_eeprom::updateBlockVerify(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length) bool I2C_eeprom::updateBlockVerify(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length)
{ {
if (updateBlock(memoryAddress, buffer, length) != length) return false; if (updateBlock(memoryAddress, buffer, length) != length) return false;
uint8_t data[length]; return verifyBlock(memoryAddress, buffer, length);
if (readBlock(memoryAddress, data, length) != length) return false;
return memcmp(data, buffer, length) == 0;
} }
@ -640,6 +663,50 @@ uint8_t I2C_eeprom::_ReadBlock(const uint16_t memoryAddress, uint8_t * buffer, c
} }
// compares content of EEPROM with buffer.
// returns true if equal.
bool I2C_eeprom::_verifyBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint8_t length)
{
_waitEEReady();
this->_beginTransmission(memoryAddress);
int rv = _wire->endTransmission();
if (rv != 0)
{
// if (_debug)
// {
// SPRN("mem addr r: ");
// SPRNH(memoryAddress, HEX);
// SPRN("\t");
// SPRNL(rv);
// }
return false; // error
}
// readBytes will always be equal or smaller to length
uint8_t readBytes = 0;
if (this->_isAddressSizeTwoWords)
{
readBytes = _wire->requestFrom(_deviceAddress, length);
}
else
{
uint8_t addr = _deviceAddress | ((memoryAddress >> 8) & 0x07);
readBytes = _wire->requestFrom(addr, length);
}
yield(); // For OS scheduling
uint8_t cnt = 0;
while (cnt < readBytes)
{
if (buffer[cnt++] != _wire->read())
{
return false;
}
}
return true;
}
void I2C_eeprom::_waitEEReady() void I2C_eeprom::_waitEEReady()
{ {
// Wait until EEPROM gives ACK again. // Wait until EEPROM gives ACK again.

View File

@ -2,7 +2,7 @@
// //
// FILE: I2C_eeprom.h // FILE: I2C_eeprom.h
// AUTHOR: Rob Tillaart // AUTHOR: Rob Tillaart
// VERSION: 1.8.2 // VERSION: 1.8.3
// PURPOSE: Arduino Library for external I2C EEPROM 24LC256 et al. // PURPOSE: Arduino Library for external I2C EEPROM 24LC256 et al.
// URL: https://github.com/RobTillaart/I2C_EEPROM.git // URL: https://github.com/RobTillaart/I2C_EEPROM.git
@ -11,7 +11,7 @@
#include "Wire.h" #include "Wire.h"
#define I2C_EEPROM_VERSION (F("1.8.2")) #define I2C_EEPROM_VERSION (F("1.8.3"))
#define I2C_DEVICESIZE_24LC512 65536 #define I2C_DEVICESIZE_24LC512 65536
#define I2C_DEVICESIZE_24LC256 32768 #define I2C_DEVICESIZE_24LC256 32768
@ -92,7 +92,7 @@ public:
// reads length bytes into buffer // reads length bytes into buffer
// returns bytes read. // returns bytes read.
uint16_t readBlock(const uint16_t memoryAddress, uint8_t * buffer, const uint16_t length); uint16_t readBlock(const uint16_t memoryAddress, uint8_t * buffer, const uint16_t length);
bool verifyBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length);
// updates a byte at memoryAddress, writes only if there is a new value. // updates a byte at memoryAddress, writes only if there is a new value.
// return 0 if data is same or written OK, error code otherwise. // return 0 if data is same or written OK, error code otherwise.
@ -159,11 +159,14 @@ private:
void _beginTransmission(const uint16_t memoryAddress); void _beginTransmission(const uint16_t memoryAddress);
// returns I2C status, 0 = OK // returns I2C status, 0 = OK
// TODO incrBuffer is an implementation name, not a functional name.
int _pageBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length, const bool incrBuffer); int _pageBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length, const bool incrBuffer);
// returns I2C status, 0 = OK // returns I2C status, 0 = OK
int _WriteBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint8_t length); int _WriteBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint8_t length);
// returns bytes read. // returns bytes read.
uint8_t _ReadBlock(const uint16_t memoryAddress, uint8_t * buffer, const uint8_t length); uint8_t _ReadBlock(const uint16_t memoryAddress, uint8_t * buffer, const uint8_t length);
// compare bytes in EEPROM.
bool _verifyBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint8_t length);
// to optimize the write latency of the EEPROM // to optimize the write latency of the EEPROM
void _waitEEReady(); void _waitEEReady();

View File

@ -39,11 +39,6 @@ void setup()
SERIAL_OUT.println("ERROR: Can't find eeprom\nstopped..."); SERIAL_OUT.println("ERROR: Can't find eeprom\nstopped...");
while (1); while (1);
} }
SERIAL_OUT.print("I2C eeprom library: ");
SERIAL_OUT.print(I2C_EEPROM_VERSION);
SERIAL_OUT.println("\n");
SERIAL_OUT.print("isConnected:\t"); SERIAL_OUT.print("isConnected:\t");
SERIAL_OUT.println(ee.isConnected()); SERIAL_OUT.println(ee.isConnected());

View File

@ -0,0 +1,44 @@
I2C_EEPROM_VERSION: 1.8.2
Testruns NN: 100
TEST: NN x writeByte()
DUR1: 466516
TEST: NN x writeByteVerify()
DUR1: 542336
TEST: NN x updateByte() same data
DUR2: 58616
TEST: NN x updateByteVerify() same data
DUR2: 116896
TEST: NN x updateByteVerify() not same data
DUR2: 596672
TEST: NN x writeBlock()
DUR1: 1414432
TEST: NN x writeBlockVerify()
DUR1: 2010844
TEST: NN x updateBlock() same data
DUR2: 594796
TEST: NN x updateBlockVerify() same data
DUR2: 1186644
TEST: NN x updateBlockVerify() not same data
DUR2: 1204960
TEST: NN x setBlock() same data
DUR2: 1415932
TEST: NN x setBlockVerify() same data
DUR2: 2014048
TEST: NN x setBlockVerify() not same data
DUR2: 2009780
done...

View File

@ -0,0 +1,99 @@
//
// FILE: I2C_eeprom_verifyBlock.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo I2C_EEPROM library
//
// uses a 24LC256 (32KB) EEPROM
#include "Wire.h"
#include "I2C_eeprom.h"
I2C_eeprom ee(0x50, I2C_DEVICESIZE_24LC256);
uint32_t start, dur1;
char buffer[] = "12345678901234567890123456789012345678901234567890"; // 50 bytes
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for Serial port to connect. Needed for Leonardo only
Serial.println(__FILE__);
Serial.print("I2C_EEPROM_VERSION: ");
Serial.println(I2C_EEPROM_VERSION);
Wire.begin();
ee.begin();
if (! ee.isConnected())
{
Serial.println("ERROR: Can't find eeprom\nstopped...");
while (1);
}
delay(10);
//////////////////////////////////////////////////////////////////////
Serial.println("\nTEST: writeBlock()");
delay(10);
start = micros();
ee.writeBlock(0, (uint8_t *) buffer, 50);
dur1 = micros() - start;
Serial.print("DUR1: ");
Serial.println(dur1);
delay(10);
Serial.println("\nTEST: verifyBlock() no change");
delay(10);
start = micros();
if (ee.verifyBlock(0, (uint8_t *) buffer, 50) == false)
{
Serial.print("X");
}
dur1 = micros() - start;
Serial.print("DUR1: ");
Serial.println(dur1);
delay(10);
for (uint8_t loc = 0; loc < 50; loc += 5)
{
disrupt(loc);
}
Serial.println("done...");
}
void loop()
{
}
void disrupt(uint8_t location)
{
bool flag = true;
// disrupt memory
Serial.print("\nTEST: verifyBlock() after change @ ");
Serial.println(location);
delay(10);
ee.writeBlock(0, (uint8_t *) buffer, 50);
ee.writeByte(location, 255);
start = micros();
if (ee.verifyBlock(0, (uint8_t *) buffer, 50) == false)
{
flag = false;
}
dur1 = micros() - start;
Serial.print("DUR1: ");
Serial.println(dur1);
Serial.println(flag);
delay(10);
}
// -- END OF FILE --

View File

@ -19,6 +19,7 @@ setBlock KEYWORD2
readByte KEYWORD2 readByte KEYWORD2
readBlock KEYWORD2 readBlock KEYWORD2
verifyBlock KEYWORD2
updateByte KEYWORD2 updateByte KEYWORD2
updateBlock KEYWORD2 updateBlock KEYWORD2
@ -35,6 +36,8 @@ getDeviceSize KEYWORD2
getPageSize KEYWORD2 getPageSize KEYWORD2
getLastWrite KEYWORD2 getLastWrite KEYWORD2
setDeviceSize KEYWORD2
setExtraWriteCycleTime KEYWORD2 setExtraWriteCycleTime KEYWORD2
getExtraWriteCycleTime KEYWORD2 getExtraWriteCycleTime KEYWORD2

View File

@ -15,7 +15,7 @@
"type": "git", "type": "git",
"url": "https://github.com/RobTillaart/I2C_EEPROM.git" "url": "https://github.com/RobTillaart/I2C_EEPROM.git"
}, },
"version": "1.8.2", "version": "1.8.3",
"license": "MIT", "license": "MIT",
"frameworks": "*", "frameworks": "*",
"platforms": "*", "platforms": "*",

View File

@ -1,5 +1,5 @@
name=I2C_EEPROM name=I2C_EEPROM
version=1.8.2 version=1.8.3
author=Rob Tillaart <rob.tillaart@gmail.com> author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com> maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Library for I2C EEPROMS sentence=Library for I2C EEPROMS

View File

@ -52,13 +52,13 @@ before calling **I2C_eeprom.begin()**.
```cpp ```cpp
+---U---+ +---U---+
A0 | 1 8 | VCC = +5V A0 | 1 8 | VCC = 1.7V to 5.5V
A1 | 2 7 | WP = write protect pin A1 | 2 7 | WP = write protect pin
A2 | 3 6 | SCL = I2C clock A2 | 3 6 | SCL = I2C clock
GND | 4 5 | SDA = I2C data GND | 4 5 | SDA = I2C data
+-------+ +-------+
default address = 0x50 .. 0x57 depending on three address lines Default address = 0x50 .. 0x57 depending on three address lines (A0, A1, A2).
``` ```
@ -131,6 +131,9 @@ Same as write and update functions above. Returns true if successful, false indi
- **bool setBlockVerify(uint16_t memoryAddress, uint8_t value, uint16_t length)** - **bool setBlockVerify(uint16_t memoryAddress, uint8_t value, uint16_t length)**
- **bool updateByteVerify(uint16_t memoryAddress, uint8_t value)** - **bool updateByteVerify(uint16_t memoryAddress, uint8_t value)**
- **bool updateBlockVerify(uint16_t memoryAddress, uint8_t \* buffer, uint16_t length)** - **bool updateBlockVerify(uint16_t memoryAddress, uint8_t \* buffer, uint16_t length)**
- **bool verifyBlock(uint16_t memoryAddress, uint8_t \* buffer, uint16_t length)**
Returns true is buffer equals memoryAddres for length bytes.
### Other ### Other
@ -263,6 +266,8 @@ See examples
- investigate smarter strategy for **updateBlock()** - investigate smarter strategy for **updateBlock()**
=> find first and last changed position could possibly result in less writes. => find first and last changed position could possibly result in less writes.
- can **setBlock()** use strategies from **updateBlock()** - can **setBlock()** use strategies from **updateBlock()**
- **pageBlock()**: incrBuffer is an implementation name, not a functional name.
#### Wont #### Wont
@ -270,6 +275,7 @@ See examples
- circular buffer? (see FRAM library) - circular buffer? (see FRAM library)
- dump function? - dump function?
## Support ## Support
If you appreciate my libraries, you can support the development and maintenance. If you appreciate my libraries, you can support the development and maintenance.