From f3e70ff3cf1cf3908c46111873acb9648845227b Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Thu, 28 Mar 2024 10:35:30 +0100 Subject: [PATCH] implement verifyBlock (#67) - 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 --- .github/FUNDING.yml | 1 + .github/workflows/arduino-lint.yml | 3 +- .github/workflows/arduino_test_runner.yml | 4 +- .github/workflows/jsoncheck.yml | 5 +- CHANGELOG.md | 14 ++- I2C_eeprom.cpp | 87 ++++++++++++++-- I2C_eeprom.h | 9 +- README.md | 6 ++ examples/I2C_eeprom_test/I2C_eeprom_test.ino | 5 - .../I2C_eeprom_verify/performance_1.8.2.txt | 44 +++++++++ .../I2C_eeprom_verifyBlock.ino | 99 +++++++++++++++++++ keywords.txt | 3 + library.json | 2 +- library.properties | 2 +- 14 files changed, 258 insertions(+), 26 deletions(-) create mode 100644 examples/I2C_eeprom_verify/performance_1.8.2.txt create mode 100644 examples/I2C_eeprom_verifyBlock/I2C_eeprom_verifyBlock.ino diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 90d9ab4..6a2d613 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,4 +1,5 @@ # These are supported funding model platforms github: RobTillaart +custom: "https://www.paypal.me/robtillaart" diff --git a/.github/workflows/arduino-lint.yml b/.github/workflows/arduino-lint.yml index 8a26f14..70d8d1c 100644 --- a/.github/workflows/arduino-lint.yml +++ b/.github/workflows/arduino-lint.yml @@ -5,8 +5,9 @@ on: [push, pull_request] jobs: lint: runs-on: ubuntu-latest + timeout-minutes: 5 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: arduino/arduino-lint-action@v1 with: library-manager: update diff --git a/.github/workflows/arduino_test_runner.yml b/.github/workflows/arduino_test_runner.yml index fadfa90..393c225 100644 --- a/.github/workflows/arduino_test_runner.yml +++ b/.github/workflows/arduino_test_runner.yml @@ -6,12 +6,14 @@ on: [push, pull_request] jobs: runTest: runs-on: ubuntu-latest + timeout-minutes: 20 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 - run: | + sudo sysctl vm.mmap_rnd_bits=28 gem install arduino_ci arduino_ci.rb diff --git a/.github/workflows/jsoncheck.yml b/.github/workflows/jsoncheck.yml index 37a1129..fd05f5f 100644 --- a/.github/workflows/jsoncheck.yml +++ b/.github/workflows/jsoncheck.yml @@ -9,10 +9,11 @@ on: jobs: test: runs-on: ubuntu-latest + timeout-minutes: 5 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: json-syntax-check - uses: limitusus/json-syntax-check@v1 + uses: limitusus/json-syntax-check@v2 with: pattern: "\\.json$" diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f38ae1..79df37a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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/) 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 - minor edits @@ -14,7 +25,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - add example - minor edits - ## [1.8.0] - 2023-11-24 (breaking change) - simplify **begin()**, remove setting Wire pins from library. - add **getAddress()** diff --git a/I2C_eeprom.cpp b/I2C_eeprom.cpp index 4064e17..4214cdf 100644 --- a/I2C_eeprom.cpp +++ b/I2C_eeprom.cpp @@ -1,7 +1,7 @@ // // FILE: I2C_eeprom.cpp // AUTHOR: Rob Tillaart -// VERSION: 1.8.2 +// VERSION: 1.8.3 // PURPOSE: Arduino Library for external I2C EEPROM 24LC256 et al. // 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 @@ -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) { if (writeBlock(memoryAddress, buffer, length) != 0) return false; - uint8_t data[length]; - if (readBlock(memoryAddress, data, length) != length) return false; - return memcmp(data, buffer, length) == 0; + return verifyBlock(memoryAddress, buffer, length); } @@ -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) { 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; 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; } @@ -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) { if (updateBlock(memoryAddress, buffer, length) != length) return false; - uint8_t data[length]; - if (readBlock(memoryAddress, data, length) != length) return false; - return memcmp(data, buffer, length) == 0; + return verifyBlock(memoryAddress, buffer, length); } @@ -380,7 +403,7 @@ uint32_t I2C_eeprom::determineSizeNoWrite() //Read is perfomed just over size (size + BUFSIZE), this will only work for devices with mem > size; therefore return size * 2 _isAddressSizeTwoWords = addressSize; return size * 2; - } + } } _isAddressSizeTwoWords = addressSize; return 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() { // Wait until EEPROM gives ACK again. diff --git a/I2C_eeprom.h b/I2C_eeprom.h index 04b3493..69a6a46 100644 --- a/I2C_eeprom.h +++ b/I2C_eeprom.h @@ -2,7 +2,7 @@ // // FILE: I2C_eeprom.h // AUTHOR: Rob Tillaart -// VERSION: 1.8.2 +// VERSION: 1.8.3 // PURPOSE: Arduino Library for external I2C EEPROM 24LC256 et al. // URL: https://github.com/RobTillaart/I2C_EEPROM.git @@ -11,7 +11,7 @@ #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_24LC256 32768 @@ -92,7 +92,7 @@ public: // reads length bytes into buffer // returns bytes read. 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. // return 0 if data is same or written OK, error code otherwise. @@ -159,11 +159,14 @@ private: void _beginTransmission(const uint16_t memoryAddress); // 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); // returns I2C status, 0 = OK int _WriteBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint8_t length); // returns bytes read. 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 void _waitEEReady(); diff --git a/README.md b/README.md index 8a8762c..184f8ee 100644 --- a/README.md +++ b/README.md @@ -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 updateByteVerify(uint16_t memoryAddress, uint8_t value)** - **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 @@ -263,6 +266,8 @@ See examples - investigate smarter strategy for **updateBlock()** => find first and last changed position could possibly result in less writes. - can **setBlock()** use strategies from **updateBlock()** +- **pageBlock()**: incrBuffer is an implementation name, not a functional name. + #### Wont @@ -270,6 +275,7 @@ See examples - circular buffer? (see FRAM library) - dump function? + ## Support If you appreciate my libraries, you can support the development and maintenance. diff --git a/examples/I2C_eeprom_test/I2C_eeprom_test.ino b/examples/I2C_eeprom_test/I2C_eeprom_test.ino index 5bed50a..83ff564 100644 --- a/examples/I2C_eeprom_test/I2C_eeprom_test.ino +++ b/examples/I2C_eeprom_test/I2C_eeprom_test.ino @@ -39,11 +39,6 @@ void setup() SERIAL_OUT.println("ERROR: Can't find eeprom\nstopped..."); 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.println(ee.isConnected()); diff --git a/examples/I2C_eeprom_verify/performance_1.8.2.txt b/examples/I2C_eeprom_verify/performance_1.8.2.txt new file mode 100644 index 0000000..6b25a31 --- /dev/null +++ b/examples/I2C_eeprom_verify/performance_1.8.2.txt @@ -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... diff --git a/examples/I2C_eeprom_verifyBlock/I2C_eeprom_verifyBlock.ino b/examples/I2C_eeprom_verifyBlock/I2C_eeprom_verifyBlock.ino new file mode 100644 index 0000000..3cebabe --- /dev/null +++ b/examples/I2C_eeprom_verifyBlock/I2C_eeprom_verifyBlock.ino @@ -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 -- diff --git a/keywords.txt b/keywords.txt index fe6cfb1..c0a5347 100644 --- a/keywords.txt +++ b/keywords.txt @@ -19,6 +19,7 @@ setBlock KEYWORD2 readByte KEYWORD2 readBlock KEYWORD2 +verifyBlock KEYWORD2 updateByte KEYWORD2 updateBlock KEYWORD2 @@ -35,6 +36,8 @@ getDeviceSize KEYWORD2 getPageSize KEYWORD2 getLastWrite KEYWORD2 +setDeviceSize KEYWORD2 + setExtraWriteCycleTime KEYWORD2 getExtraWriteCycleTime KEYWORD2 diff --git a/library.json b/library.json index 87639da..49c46be 100644 --- a/library.json +++ b/library.json @@ -15,7 +15,7 @@ "type": "git", "url": "https://github.com/RobTillaart/I2C_EEPROM.git" }, - "version": "1.8.2", + "version": "1.8.3", "license": "MIT", "frameworks": "*", "platforms": "*", diff --git a/library.properties b/library.properties index 9954648..0ef948b 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=I2C_EEPROM -version=1.8.2 +version=1.8.3 author=Rob Tillaart maintainer=Rob Tillaart sentence=Library for I2C EEPROMS