Compare commits

...
37 Commits
Author SHA1 Message Date
Rob TillaartandGitHub 86a5017fa9 fix #83, update readme.md (#85)
- fix #83, update readme.md (thanks to TonyRiddiough)
- add calculatePageSize(deviceSize) to replace getPageSize(deviceSize) prep.
- update GitHub actions
- minor update examples
- minor edits
2025-09-01 10:05:59 +02:00
Rob TillaartandGitHub 86228c599f update readme.md (#84)
- update readme.md
2025-08-01 11:43:10 +02:00
Rob TillaartandGitHub e57418ba44 update version to 1.9.2 (#81) 2024-11-25 08:54:43 +01:00
ekinohitoandGitHub bb84b19faf Fix RobTillaart/I2C_EEPROM#79 (#80) 2024-11-25 08:36:16 +01:00
Rob TillaartandGitHub 43f4886a91 fix #77, updateBlock() returns bytes written (#78)
- fix #77, updateBlock() returns bytes actually written.
- minor edits
2024-10-26 20:10:46 +02:00
Rob TillaartandGitHub 8cb180d081 Fix #74, memory leak in verifyBlock() (#75)
- Fix #74, memory leak in setBlockVerify()
2024-10-09 09:38:39 +02:00
Rob TillaartandGitHub 0de303ff95 Fix #72, parameter type requestFrom() (#73)
- Fix #72, force requestFrom parameters to use int type
2024-04-22 18:38:03 +02:00
Rob TillaartandGitHub 6c3cb3081c Fix #70, increase internal lengths allowed (#71)
- Fix #70, increase length internal buffer.
- add compile time flag **EN_AUTO_WRITE_PROTECT** (thanks to microfoundry)
- improve readability: cnt => count  addr => address
- add URL to examples
- minor edits.
2024-04-21 10:57:04 +02:00
Rob Tillaart d5ad5ce16d update GitHub actions 2024-04-13 11:04:46 +02:00
Rob TillaartandGitHub f3e70ff3cf 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
2024-03-28 10:35:30 +01:00
Thijs TriemstraandGitHub af9448c770 doc: update vcc schematic (#65) 2024-03-27 20:52:07 +01:00
ee4d38aac7 Improved determineNoWrite, removed static references to Serial (#63)
* Improved  determineNoWrite, now works with larger EEPROMS. tested with AT24C02, AT24C23 and AT24C256
* Added loop exit, updated license and changelog

---------

Co-authored-by: Roeland Kluit <roeland@kluit.net>
2024-01-02 16:07:19 +01:00
Rob TillaartandGitHub 42cdf1a95e add determineSizeNoWrite() (#62)
- add **uint32_t determineSizeNoWrite()**, kudos to roelandkluit
- add example
- minor edits
2023-12-14 11:56:20 +01:00
0248508109 Added read only function to determine device size. (#61)
Co-authored-by: Roeland Kluit <roeland@kluit.net>
2023-12-14 11:26:14 +01:00
Rob TillaartandGitHub ff21bd6cdc simplify begin() (#60)
- simplify **begin()**, remove setting Wire pins from library.
- add **getAddress()**
- update readme.md
- update examples
2023-11-25 13:19:42 +01:00
Emmett BrownandGitHub 54cf6bee85 Prevent eternal loop in_eeprom::setPageSize with size 128 (#59) 2023-11-20 19:30:09 +01:00
Rob TillaartandGitHub e7c5075c36 add WP writeProtect support (#58)
- solve #57 add support for WriteProtectPin
- add writeProtectPin as optional parameter in **begin()**
- add **bool hasWriteProtectPin()**
- add **void allowWrite()**
- add **void preventWrite()**
- add **void setAutoWriteProtect(bool b)**
- add **bool getAutoWriteProtect()**
- optimized **waitEEReady()**
- update keywords.txt
- update readme.md
2023-09-08 11:31:51 +02:00
Rob TillaartandGitHub a13ec203ef fix #55, redo #53 (#56)
- fix #55 ==> redo fix #53
  - add test to detect **MBED** and **RP2040**
- adjust **I2C_BUFFERSIZE** for RP2040 to 128.
- update readme.md
2023-05-11 12:26:57 +02:00
Rob TillaartandGitHub c4400ea101 fix #53 PICO_RP2040 support (#54)
- fix #53 support RP2040 (kudos to jotamachuca)
- move code from .h to .cpp
- make I2C_WRITEDELAY overridable
- minor edits
2023-05-02 13:02:17 +02:00
Rob TillaartandGitHub d26182c753 add setDeviceSize() setPageSize() (#51)
- add setDeviceSize() 
- add setPageSize()
- use setDeviceSize() in constructor to force power of 2.
- update unit test
- update GitHub actions
- update license
- update readme.md
- minor edits
2023-01-12 17:49:13 +01:00
rob tillaart b61c5f9c0a update GitHub actions 2023-01-03 19:33:38 +01:00
rob tillaart 8caac3eb91 update license to 2023 2023-01-03 19:23:25 +01:00
Rob TillaartandGitHub 8f530b6d8f fix #48 constructor (#49)
* fix #48
2022-12-03 12:37:49 +01:00
Rob TillaartandGitHub 4db0ca9815 add changelog.md + optimize yield() calls (#47)
* add changelog.md
* optimize yield() calls
* update readme.md
2022-10-31 16:51:06 +01:00
Rob TillaartandGitHub 9001ab38c7 fix build (#45) 2022-08-04 13:08:29 +02:00
rob tillaart 803147a945 add GitHub sponsor button 2022-08-03 21:13:26 +02:00
Rob TillaartandGitHub a39c7a1bc2 update documentation + minor edits (#43)
* update documentation + minor edits
* add verify performance test sketch
2022-06-12 12:42:42 +02:00
Rob TillaartandGitHub f80f4eea31 add write with verify functions (#41)
* add write with verify functions
2022-06-03 12:52:34 +02:00
Rob TillaartandGitHub 1a6461a7dd update library.json, license, minor edits (#37) 2021-12-19 20:01:34 +01:00
Ivan KravetsandGitHub 7eae2b7ba2 Declare header files for PlatformIO (#36) 2021-11-19 12:19:55 +01:00
Rob TillaartandGitHub 5adbe66a14 Develop (#35)
* build-CI + badges
* add setExtraWriteCycleTIme() to adjust some timing.
2021-11-04 16:52:26 +01:00
rob tillaart 710e1d1fb1 fix bug in example 2021-07-29 18:00:41 +02:00
Rob TillaartandGitHub 1cd0bdaf07 1.5.0 fix memory address for 24LC04/08/16 (#29)
* 1.5.0 #28 fix addressing 24LC04/08/16
2021-07-01 10:05:27 +02:00
Rob TillaartandGitHub 23c86332ee fix #6 add unit tests (#27) 2021-06-13 16:59:58 +02:00
rob tillaart acb263880a add license to library.json 2021-05-28 14:12:36 +02:00
rob tillaart a0826324f9 add arduino-lint check 2021-05-27 23:11:24 +02:00
rob tillaart 8454c12512 add arduino-lint check 2021-05-27 18:40:46 +02:00
33 changed files with 2289 additions and 542 deletions
+24 -3
View File
@@ -1,7 +1,28 @@
platforms:
rpipico:
board: rp2040:rp2040:rpipico
package: rp2040:rp2040
gcc:
features:
defines:
- ARDUINO_ARCH_RP2040
warnings:
flags:
packages:
rp2040:rp2040:
url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
- uno
- leonardo
- due
- zero
# - due
# - zero
# - leonardo
- m4
- esp32
- esp8266
# - mega2560
- rpipico
+4
View File
@@ -0,0 +1,4 @@
# These are supported funding model platforms
github: RobTillaart
custom: "https://www.paypal.me/robtillaart"
+13
View File
@@ -0,0 +1,13 @@
name: Arduino-lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v5
- uses: arduino/arduino-lint-action@v2
with:
library-manager: update
compliance: strict
+9 -5
View File
@@ -1,13 +1,17 @@
---
name: Arduino CI
on: [push, pull_request]
jobs:
arduino_ci:
runTest:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v2
- uses: Arduino-CI/action@master
# Arduino-CI/action@v0.1.1
- uses: actions/checkout@v5
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6
- run: |
gem install arduino_ci
arduino_ci.rb
+6 -4
View File
@@ -5,14 +5,16 @@ on:
paths:
- '**.json'
pull_request:
paths:
- '**.json'
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v5
- name: json-syntax-check
uses: limitusus/json-syntax-check@v1
uses: limitusus/json-syntax-check@v2
with:
pattern: "\\.json$"
pattern: "\\.json$"
+234
View File
@@ -0,0 +1,234 @@
# Change Log I2C_EEPROM
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.9.4] - 2025-08-27
- fix #83, update readme.md (thanks to TonyRiddiough)
- add calculatePageSize(deviceSize) to replace getPageSize(deviceSize) prep.
- update GitHub actions
- minor update examples
- minor edits
## [1.9.3] - 2025-08-01
- update readme.md
## [1.9.2] - 2024-11-25
- fix #79, wrong default in constructor - kudos to ekinohito
## [1.9.1] - 2024-10-26
- fix #77, updateBlock() returns bytes actually written.
- minor edits
## [1.9.0] - 2024-10-09
- Fix #74, memory leak in setBlockVerify() - kudos to cmichailidis
----
## [1.8.5] - 2024-04-22
- Fix #72, force requestFrom parameters to use int type
## [1.8.4] - 2024-04-20
- Fix #70, increase length internal buffer.
- add compile time flag **EN_AUTO_WRITE_PROTECT** (thanks to microfoundry)
- improve readability: cnt => count addr => address
- add URL to examples
- minor edits.
## [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
## [1.8.1] - 2023-12-14
- add **uint32_t determineSizeNoWrite()**, kudos to roelandkluit
- add example
- minor edits
## [1.8.0] - 2023-11-24 (breaking change)
- simplify **begin()**, remove setting Wire pins from library.
- add **getAddress()**
- update readme.md
- update examples
----
## [1.7.4] - 2023-09-06
- solve #57 add support for WriteProtectPin
- add writeProtectPin as optional parameter in **begin()**
- add **bool hasWriteProtectPin()**
- add **void allowWrite()**
- add **void preventWrite()**
- add **void setAutoWriteProtect(bool b)**
- add **bool getAutoWriteProtect()**
- optimized **waitEEReady()**
- update keywords.txt
- update readme.md
## [1.7.3] - 2023-05-10
- fix #55 ==> redo fix #53
- add test to detect **MBED** and **RP2040**
- adjust **I2C_BUFFERSIZE** for RP2040 to 128.
- update readme.md
## [1.7.2] - 2023-05-02
- fix #53 support RP2040 (kudos to jotamachuca)
- move code from .h to .cpp
- make I2C_WRITEDELAY overridable
- minor edits
## [1.7.1] - 2023-01-12
- add setDeviceSize()
- add setPageSize()
- use setDeviceSize() in constructor to force power of 2.
- update unit test
- update GitHub actions
- update license
- update readme.md
- minor edits
## [1.7.0] - 2022-12-02
- fix #48 rewrote constructor.
----
## [1.6.2] - 2022-10-30
- Add RP2040 support to build-CI.
- Add CHANGELOG.md
- remove **yield()** calls in writeBlock(), readBlock() and updateBlock()
as these are already handled on a lower level. See #46
- better explain **begin()** in readme.md
## [1.6.1] - 2022-06-11
- update documentation
- minor edits
- minor improvements / bug fixes
## [1.6.0] - 2022-06-02
- add verify functions.
----
## [1.5.2] - 2021-12-19
- update library.json
- update license
- minor edits
## [1.5.1] - 2021-10-14
- function to add extra for write cycle (experimental)
## [1.5.0] - 2021-06-30
- #28 fix addressing 24LC04/08/16
----
## [1.4.3] - 2021-05-05
- adjust buffer size AVR / ESP
- rename ?
## [1.4.2] - 2021-01-31
- add updateBlock()
## [1.4.1] - 2021-01-28
- fix addressing bug 24LC04/08/16 equivalents from ST e.g. m24c08w
- add Wire1..WireN;
## [1.4.0] - 2021-01-27
- rewrite addressing scheme
- fix determineSize() - See determineSize for all tested.
----
## [1.3.2] - 2021-01-18
- add cyclic store functionality (Thanks to Tomas Hübner)
## [1.3.1] - 2020-12-22
- add Arduino-CI + unit tests
- add updateByte()
## [1.3.0] - 2020-06-19
- refactor
- remove pre 1.0 support
- add ESP32 support.
----
## [1.2.7] - 2019-09-03
- fix issue #113 and #128
## [1.2.6] - 2019-02-01
- fix issue #121
## [1.2.5] - 2017-04-20
- refactor the removed timeout (Thanks to Koepel)
## [1.2.4] - 2017-04-19
- remove timeout - issue #63
## [1.2.03] - 2015-05-15
- fix in \_pageBlock & example (thanks ifreislich )
## [1.2.02] - 2015-03-06
- stricter interface
## [1.2.01] - 2014-05-21
- Refactoring
## [1.2.00] - 2014-05-21
- Add support for Arduino DUE ( thanks to Tyler F.)
----
## [1.1.00] - 2013-11-13
- added begin() function (Note breaking interface)
- use faster block Wire.write()
- int casting removed
----
## [1.0.05] - 2013-11-06
- improved waitEEReady(),
- add determineSize()
## [1.0.04] - 2013-11-03
- fix bug in readBlock
- moved waitEEReady() -> more efficient.
## [1.0.03] - 2013-11-03
- refactor 5 millis() write-latency
## [1.0.02] - 2013-11-03
- optimize internal buffers
- refactor
## [1.0.01] - 2013-11-01
- fixed writeBlock bug
- refactor
## [1.0.00] - 2013-06-09
- support for Arduino 1.0.x
----
## [0.2.01] - 2011-08-13
- \_readBlock made more robust + return value
## [0.2.00] - 2011-02-11
- fix 64 bit boundary bug
----
## [0.1.01] - 2011-02-07
- add setBlock function
## [0.1.00] - 2011-01-21
- initial version
+530 -158
View File
@@ -1,48 +1,15 @@
//
// FILE: I2C_eeprom.cpp
// AUTHOR: Rob Tillaart
// VERSION: 1.4.3
// VERSION: 1.9.3
// PURPOSE: Arduino Library for external I2C EEPROM 24LC256 et al.
// URL: https://github.com/RobTillaart/I2C_EEPROM.git
//
// HISTORY:
// 0.1.00 2011-01-21 initial version
// 0.1.01 2011-02-07 added setBlock function
// 0.2.00 2011-02-11 fixed 64 bit boundary bug
// 0.2.01 2011-08-13 _readBlock made more robust + return value
// 1.0.00 2013-06-09 support for Arduino 1.0.x
// 1.0.01 2013-11-01 fixed writeBlock bug, refactor
// 1.0.02 2013-11-03 optimize internal buffers, refactor
// 1.0.03 2013-11-03 refactor 5 millis() write-latency
// 1.0.04 2013-11-03 fix bug in readBlock, moved waitEEReady()
// -> more efficient.
// 1.0.05 2013-11-06 improved waitEEReady(),
// added determineSize()
// 1.1.00 2013-11-13 added begin() function (Note breaking interface)
// use faster block Wire.write()
// int casting removed
// 1.2.00 2014-05-21 Added support for Arduino DUE ( thanks to Tyler F.)
// 1.2.01 2014-05-21 Refactoring
// 1.2.02 2015-03-06 stricter interface
// 1.2.03 2015-05-15 bugfix in _pageBlock & example (thanks ifreislich )
// 1.2.4 2017-04-19 remove timeout - issue #63
// 1.2.5 2017-04-20 refactor the removed timeout (Thanks to Koepel)
// 1.2.6 2019-02-01 fix issue #121
// 1.2.7 2019-09-03 fix issue #113 and #128
// 1.3.0 2020-06-19 refactor; removed pre 1.0 support; added ESP32 support.
// 1.3.1 2020-12-22 arduino-ci + unit tests + updateByte()
// 1.3.2 2021-01-18 cyclic store functionality (Thanks to Tomas Hübner)
// 1.4.0 2021-01-27 rewritten addressing scheme + determineSize
// See determineSize for all tested.
// 1.4.1 2021-01-28 fixed addressing bug 24LC04/08/16 equivalents from ST e.g. m24c08w
// add Wire1..WireN;
// 1.4.2 2021-01-31 add updateBlock()
// 1.4.3 2021-05-05 adjust buffer size AVR / ESP +rename
// URL: https://github.com/RobTillaart/I2C_EEPROM
#include <I2C_eeprom.h>
#include "I2C_eeprom.h"
// Not used directly
// Not used directly
#define I2C_PAGESIZE_24LC512 128
#define I2C_PAGESIZE_24LC256 64
#define I2C_PAGESIZE_24LC128 64
@@ -55,54 +22,48 @@
#define I2C_PAGESIZE_24LC01 8
// TWI buffer needs max 2 bytes for eeprom address
// 1 byte for eeprom register address is available in txbuffer
#if defined(ESP32) || defined(ESP8266)
// I2C buffer needs max 2 bytes for EEPROM address
// 1 byte for EEPROM register address is available in transmit buffer
#if defined(ESP32) || defined(ESP8266) || defined(PICO_RP2040)
#define I2C_BUFFERSIZE 128
#else
#define I2C_BUFFERSIZE 30 // AVR, STM
#define I2C_BUFFERSIZE 30 // AVR, STM
#endif
I2C_eeprom::I2C_eeprom(const uint8_t deviceAddress, TwoWire *wire)
////////////////////////////////////////////////////////////////////
//
// PUBLIC FUNCTIONS
//
I2C_eeprom::I2C_eeprom(const uint8_t deviceAddress, TwoWire * wire) :
I2C_eeprom(deviceAddress, I2C_DEVICESIZE_24LC256, wire)
{
I2C_eeprom(deviceAddress, I2C_PAGESIZE_24LC256, wire);
}
I2C_eeprom::I2C_eeprom(const uint8_t deviceAddress, const uint32_t deviceSize, TwoWire *wire)
I2C_eeprom::I2C_eeprom(const uint8_t deviceAddress, const uint32_t deviceSize, TwoWire * wire)
{
_deviceAddress = deviceAddress;
_deviceSize = deviceSize;
_pageSize = getPageSize(_deviceSize);
_wire = wire;
_deviceAddress = deviceAddress;
_deviceSize = setDeviceSize(deviceSize);
_pageSize = calculatePageSize(_deviceSize);
_wire = wire;
// Chips 16Kbit (2048 Bytes) or smaller only have one-word addresses.
this->_isAddressSizeTwoWords = (deviceSize <= I2C_DEVICESIZE_24LC16) ? false : true;
// Chips 16 Kbit (2048 Bytes) or smaller only have one-word addresses.
this->_isAddressSizeTwoWords = deviceSize > I2C_DEVICESIZE_24LC16;
}
#if defined (ESP8266) || defined(ESP32)
bool I2C_eeprom::begin(uint8_t sda, uint8_t scl)
bool I2C_eeprom::begin(int8_t writeProtectPin)
{
if ((sda < 255) && (scl < 255))
{
_wire->begin(sda, scl);
}
else
{
_wire->begin();
}
_lastWrite = 0;
return isConnected();
}
#endif
bool I2C_eeprom::begin()
{
_wire->begin();
// if (_wire == 0) SPRNL("zero"); // test #48
_lastWrite = 0;
_writeProtectPin = writeProtectPin;
if (_writeProtectPin >= 0)
{
_autoWriteProtect = EN_AUTO_WRITE_PROTECT;
pinMode(_writeProtectPin, OUTPUT);
preventWrite();
}
return isConnected();
}
@@ -114,6 +75,18 @@ bool I2C_eeprom::isConnected()
}
uint8_t I2C_eeprom::getAddress()
{
return _deviceAddress;
}
/////////////////////////////////////////////////////////////
//
// WRITE SECTION
//
// returns I2C status, 0 = OK
int I2C_eeprom::writeByte(const uint16_t memoryAddress, const uint8_t data)
{
int rv = _WriteBlock(memoryAddress, &data, 1);
@@ -121,6 +94,7 @@ int I2C_eeprom::writeByte(const uint16_t memoryAddress, const uint8_t data)
}
// returns I2C status, 0 = OK
int I2C_eeprom::setBlock(const uint16_t memoryAddress, const uint8_t data, const uint16_t length)
{
uint8_t buffer[I2C_BUFFERSIZE];
@@ -133,13 +107,20 @@ int I2C_eeprom::setBlock(const uint16_t memoryAddress, const uint8_t data, const
}
int I2C_eeprom::writeBlock(const uint16_t memoryAddress, const uint8_t* buffer, const uint16_t length)
// returns I2C status, 0 = OK
int I2C_eeprom::writeBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length)
{
int rv = _pageBlock(memoryAddress, buffer, length, true);
return rv;
}
/////////////////////////////////////////////////////////////
//
// READ SECTION
//
// returns the value stored in memoryAddress
uint8_t I2C_eeprom::readByte(const uint16_t memoryAddress)
{
uint8_t rdata;
@@ -148,58 +129,156 @@ uint8_t I2C_eeprom::readByte(const uint16_t memoryAddress)
}
uint16_t I2C_eeprom::readBlock(const uint16_t memoryAddress, uint8_t* buffer, const uint16_t length)
// returns bytes read.
uint16_t I2C_eeprom::readBlock(const uint16_t memoryAddress, uint8_t * buffer, const uint16_t length)
{
uint16_t addr = memoryAddress;
uint16_t address = memoryAddress;
uint16_t len = length;
uint16_t rv = 0;
uint16_t bytes = 0;
while (len > 0)
{
uint8_t cnt = I2C_BUFFERSIZE;
if (cnt > len) cnt = len;
rv += _ReadBlock(addr, buffer, cnt);
addr += cnt;
buffer += cnt;
len -= cnt;
yield(); // For OS scheduling etc
uint8_t count = I2C_BUFFERSIZE;
if (count > len) count = len;
bytes += _ReadBlock(address, buffer, count);
address += count;
buffer += count;
len -= count;
}
return rv;
return bytes;
}
// returns true or false.
bool I2C_eeprom::verifyBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length)
{
uint16_t address = memoryAddress;
uint16_t len = length;
while (len > 0)
{
uint8_t count = I2C_BUFFERSIZE;
if (count > len) count = len;
if (_verifyBlock(address, buffer, count) == false)
{
return false;
}
address += count;
buffer += count;
len -= count;
}
return true;
}
/////////////////////////////////////////////////////////////
//
// UPDATE SECTION
//
// returns 0 == OK
int I2C_eeprom::updateByte(const uint16_t memoryAddress, const uint8_t data)
{
if (data == readByte(memoryAddress)) return 0;
return writeByte(memoryAddress, data);
}
int I2C_eeprom::updateBlock(const uint16_t memoryAddress, const uint8_t* buffer, const uint16_t length)
// returns bytes actually written <= length
uint16_t I2C_eeprom::updateBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length)
{
uint16_t addr = memoryAddress;
uint16_t address = memoryAddress;
uint16_t len = length;
uint16_t rv = 0;
uint16_t bytes = 0;
while (len > 0)
{
uint8_t buf[I2C_BUFFERSIZE];
uint8_t cnt = I2C_BUFFERSIZE;
if (cnt > len) cnt = len;
rv += _ReadBlock(addr, buf, cnt);
if (memcmp(buffer, buf, cnt) != 0)
uint8_t count = I2C_BUFFERSIZE;
if (count > len) count = len;
_ReadBlock(address, buf, count);
if (memcmp(buffer, buf, count) != 0)
{
_pageBlock(addr, buffer, cnt, true);
_pageBlock(address, buffer, count, true);
bytes += count;
}
addr += cnt;
buffer += cnt;
len -= cnt;
yield(); // For OS scheduling etc
address += count;
buffer += count;
len -= count;
}
return rv;
return bytes;
}
// returns size in bytes
// returns 0 if not connected
/////////////////////////////////////////////////////////////
//
// VERIFY SECTION
//
// return false if write or verify failed.
bool I2C_eeprom::writeByteVerify(const uint16_t memoryAddress, const uint8_t value)
{
if (writeByte(memoryAddress, value) != 0 ) return false;
uint8_t data = readByte(memoryAddress);
return (data == value);
}
// return false if write or verify failed.
bool I2C_eeprom::writeBlockVerify(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length)
{
if (writeBlock(memoryAddress, buffer, length) != 0) return false;
return verifyBlock(memoryAddress, buffer, length);
}
// return false if write or verify failed.
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 = (uint8_t *) malloc(length);
if (data == NULL) return false;
if (readBlock(memoryAddress, data, length) != length)
{
free(data);
return false;
}
for (uint16_t i = 0; i < length; i++)
{
if (data[i] != value)
{
free(data);
return false;
}
}
free(data);
return true;
}
// return false if write or verify failed.
bool I2C_eeprom::updateByteVerify(const uint16_t memoryAddress, const uint8_t value)
{
if (updateByte(memoryAddress, value) != 0 ) return false;
uint8_t data = readByte(memoryAddress);
return (data == value);
}
// return false if write or verify failed.
bool I2C_eeprom::updateBlockVerify(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length)
{
// zero bytes written means nothing needs to be verified
if (0 == updateBlock(memoryAddress, buffer, length)) return true;
return verifyBlock(memoryAddress, buffer, length);
}
/////////////////////////////////////////////////////////////
//
// METADATA SECTION
//
// returns size in bytes
// returns 0 if not connected
//
// tested for
// 2 byte address
@@ -217,7 +296,7 @@ int I2C_eeprom::updateBlock(const uint16_t memoryAddress, const uint8_t* buffer,
// 24LC01 128 B YES
uint32_t I2C_eeprom::determineSize(const bool debug)
{
// try to read a byte to see if connected
// try to read a byte to see if connected
if (! isConnected()) return 0;
uint8_t patAA = 0xAA;
@@ -227,26 +306,26 @@ uint32_t I2C_eeprom::determineSize(const bool debug)
{
bool folded = false;
// store old values
// store old values
bool addressSize = _isAddressSizeTwoWords;
_isAddressSizeTwoWords = (size <= 2048) ? false : true;
_isAddressSizeTwoWords = size > I2C_DEVICESIZE_24LC16; // 2048
uint8_t buf = readByte(size);
// test folding
uint8_t cnt = 0;
// test folding
uint8_t count = 0;
writeByte(size, pat55);
if (readByte(0) == pat55) cnt++;
if (readByte(0) == pat55) count++;
writeByte(size, patAA);
if (readByte(0) == patAA) cnt++;
folded = (cnt == 2);
if (readByte(0) == patAA) count++;
folded = (count == 2);
if (debug)
{
Serial.print(size, HEX);
Serial.print('\t');
Serial.println(readByte(size), HEX);
SPRNH(size, HEX);
SPRN('\t');
SPRNLH(readByte(size), HEX);
}
// restore old values
// restore old values
writeByte(size, buf);
_isAddressSizeTwoWords = addressSize;
@@ -256,121 +335,414 @@ uint32_t I2C_eeprom::determineSize(const bool debug)
}
uint8_t I2C_eeprom::getPageSize(uint32_t deviceSize)
// new 1.8.1 #61
// updated 1.8.2 #63
//
// Returns:
// 0 if device size cannot be determined or device is not online
// 1 if device has default bytes in first dataFirstBytes bytes [0-BUFSIZE]
// Write some dataFirstBytes to the first bytes and retry or use the determineSize method
// 2 if device has all the same bytes in first dataFirstBytes bytes [0-BUFSIZE]
// Write some random dataFirstBytes to the first bytes and retry or use the determineSize method
// >= 128 Device size in bytes
uint32_t I2C_eeprom::determineSizeNoWrite()
{
// determine page size from device size - based on Microchip 24LCXX datasheets.
#define BUFSIZE (32)
// try to read a byte to see if connected
if (!isConnected()) return 0;
bool addressSize = _isAddressSizeTwoWords;
_isAddressSizeTwoWords = true; // Otherwise reading large EEPROMS fails
bool isModifiedFirstSector = false;
bool dataIsDifferent = false;
byte dataFirstBytes[BUFSIZE];
byte dataMatch[BUFSIZE];
readBlock(0, dataFirstBytes, BUFSIZE);
for (uint8_t pos = 0; pos < BUFSIZE; pos++)
{
if (dataIsDifferent || pos == 0)
{
// ignore further comparison if dataFirstBytes is not the same in buffer
// Ignore first byte
}
else if (dataFirstBytes[pos - 1] != dataFirstBytes[pos])
{
dataIsDifferent = true;
}
if (dataFirstBytes[pos] != 0xFF && dataFirstBytes[pos] != 0x00)
{
// Default dataFirstBytes value is 0xFF or 0x00
isModifiedFirstSector = true;
}
if (dataIsDifferent && isModifiedFirstSector)
break;
}
if (!isModifiedFirstSector)
{
// Cannot determine diff, at least one of the first bytes within 0 - len [BUFSIZE] needs to be changed
// to something other than 0x00 and 0xFF
_isAddressSizeTwoWords = addressSize;
return 1;
}
if (!dataIsDifferent)
{
// Data in first bytes within 0 - len [BUFSIZE] are all the same.
_isAddressSizeTwoWords = addressSize;
return 2;
}
// Read from largest to smallest size
for (uint32_t size = 32768; size >= 64; size /= 2)
{
_isAddressSizeTwoWords = (size >= I2C_DEVICESIZE_24LC16); // == 2048
// Try to read last byte of the block, should return length of 0 when fails for single byte devices
// Will return the same dataFirstBytes as initially read on other devices
// as the data pointer could not be moved to the requested position
delay(2);
uint16_t bSize = readBlock(size, dataMatch, BUFSIZE);
if (bSize == BUFSIZE && memcmp(dataFirstBytes, dataMatch, BUFSIZE) != 0)
{
// Read is performed 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;
}
uint32_t I2C_eeprom::getDeviceSize()
{
return _deviceSize;
}
uint8_t I2C_eeprom::getPageSize()
{
return _pageSize;
}
uint8_t I2C_eeprom::calculatePageSize(uint32_t deviceSize)
{
// determine page size from device size
// based on Microchip 24LCXX data sheets.
if (deviceSize <= I2C_DEVICESIZE_24LC02) return 8;
if (deviceSize <= I2C_DEVICESIZE_24LC16) return 16;
if (deviceSize <= I2C_DEVICESIZE_24LC64) return 32;
if (deviceSize <= I2C_DEVICESIZE_24LC256) return 64;
// I2C_DEVICESIZE_24LC512
return 128;
if (deviceSize <= I2C_DEVICESIZE_24LC512) return 128;
// Error.
return 0;
}
uint8_t I2C_eeprom::getPageSize(uint32_t deviceSize)
{
return calculatePageSize(deviceSize);
}
uint32_t I2C_eeprom::getLastWrite()
{
return _lastWrite;
}
uint32_t I2C_eeprom::setDeviceSize(uint32_t deviceSize)
{
uint32_t size = 128;
// force power of 2.
while ((size <= 65536) && ( size <= deviceSize))
{
_deviceSize = size;
size *= 2;
}
// Chips 16 Kbit (2048 Bytes) or smaller only have one-word addresses.
this->_isAddressSizeTwoWords = _deviceSize > I2C_DEVICESIZE_24LC16;
return _deviceSize;
}
uint8_t I2C_eeprom::setPageSize(uint8_t pageSize)
{
// force power of 2.
if (pageSize >= 128) {
_pageSize = 128;
}
else if (pageSize >= 64) {
_pageSize = 64;
}
else if (pageSize >= 32) {
_pageSize = 32;
}
else if (pageSize >= 16) {
_pageSize = 16;
}
else {
_pageSize = 8;
}
return _pageSize;
}
void I2C_eeprom::setExtraWriteCycleTime(uint8_t ms)
{
_extraTWR = ms;
}
uint8_t I2C_eeprom::getExtraWriteCycleTime()
{
return _extraTWR;
}
//
// WRITEPROTECT
//
bool I2C_eeprom::hasWriteProtectPin()
{
return (_writeProtectPin >= 0);
}
void I2C_eeprom::allowWrite()
{
if (hasWriteProtectPin())
{
digitalWrite(_writeProtectPin, LOW);
}
}
void I2C_eeprom::preventWrite()
{
if (hasWriteProtectPin())
{
digitalWrite(_writeProtectPin, HIGH);
}
}
void I2C_eeprom::setAutoWriteProtect(bool b)
{
if (hasWriteProtectPin())
{
_autoWriteProtect = b;
}
}
bool I2C_eeprom::getAutoWriteProtect()
{
return _autoWriteProtect;
}
////////////////////////////////////////////////////////////////////
//
// PRIVATE
// PRIVATE
//
// _pageBlock aligns buffer to page boundaries for writing.
// and to TWI buffer size
// returns 0 = OK otherwise error
int I2C_eeprom::_pageBlock(const uint16_t memoryAddress, const uint8_t* buffer, const uint16_t length, const bool incrBuffer)
// _pageBlock aligns buffer to page boundaries for writing.
// and to I2C buffer size
// returns 0 = OK otherwise error
int I2C_eeprom::_pageBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length, const bool incrBuffer)
{
uint16_t addr = memoryAddress;
uint16_t address = memoryAddress;
uint16_t len = length;
while (len > 0)
{
uint8_t bytesUntilPageBoundary = this->_pageSize - addr % this->_pageSize;
uint8_t bytesUntilPageBoundary = this->_pageSize - address % this->_pageSize;
uint8_t cnt = I2C_BUFFERSIZE;
if (cnt > len) cnt = len;
if (cnt > bytesUntilPageBoundary) cnt = bytesUntilPageBoundary;
uint8_t count = I2C_BUFFERSIZE;
if (count > len) count = len;
if (count > bytesUntilPageBoundary) count = bytesUntilPageBoundary;
int rv = _WriteBlock(addr, buffer, cnt);
int rv = _WriteBlock(address, buffer, count);
if (rv != 0) return rv;
addr += cnt;
if (incrBuffer) buffer += cnt;
len -= cnt;
address += count;
if (incrBuffer) buffer += count;
len -= count;
}
return 0;
}
// supports one and 2 bytes addresses
// supports one and two bytes addresses
void I2C_eeprom::_beginTransmission(const uint16_t memoryAddress)
{
if (this->_isAddressSizeTwoWords)
{
_wire->beginTransmission(_deviceAddress);
// Address High Byte
// Address High Byte
_wire->write((memoryAddress >> 8));
}
else
{
uint8_t addr = _deviceAddress | ((memoryAddress >> 8) & 0x07);
_wire->beginTransmission(addr);
uint8_t address = _deviceAddress | ((memoryAddress >> 8) & 0x07);
_wire->beginTransmission(address);
}
// Address Low Byte (or only byte for chips 16K or smaller that only have one-word addresses)
// Address Low Byte
// (or single byte for chips 16K or smaller that have one-word addresses)
_wire->write((memoryAddress & 0xFF));
}
// pre: length <= this->_pageSize && length <= I2C_BUFFERSIZE;
// returns 0 = OK otherwise error
int I2C_eeprom::_WriteBlock(const uint16_t memoryAddress, const uint8_t* buffer, const uint8_t length)
// pre: length <= this->_pageSize && length <= I2C_BUFFERSIZE;
// returns 0 = OK otherwise error
int I2C_eeprom::_WriteBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length)
{
_waitEEReady();
if (_autoWriteProtect)
{
digitalWrite(_writeProtectPin, LOW);
}
this->_beginTransmission(memoryAddress);
_wire->write(buffer, length);
int rv = _wire->endTransmission();
yield();
if (_autoWriteProtect)
{
digitalWrite(_writeProtectPin, HIGH);
}
_lastWrite = micros();
yield(); // For OS scheduling
// if (rv != 0)
// {
// if (_debug)
// {
// SPRN("mem addr w: ");
// SPRNH(memoryAddress, HEX);
// SPRN("\t");
// SPRNL(rv);
// }
// return -(abs(rv)); // error
// }
return rv;
}
// pre: buffer is large enough to hold length bytes
// returns bytes read
uint8_t I2C_eeprom::_ReadBlock(const uint16_t memoryAddress, uint8_t* buffer, const uint8_t length)
// pre: buffer is large enough to hold length bytes
// returns bytes read
uint8_t I2C_eeprom::_ReadBlock(const uint16_t memoryAddress, uint8_t * buffer, const uint16_t length)
{
_waitEEReady();
this->_beginTransmission(memoryAddress);
int rv = _wire->endTransmission();
if (rv != 0) return 0; // error
// readbytes will always be equal or smaller to length
uint8_t readBytes = _wire->requestFrom(_deviceAddress, length);
uint8_t cnt = 0;
while (cnt < readBytes)
if (rv != 0)
{
buffer[cnt++] = _wire->read();
yield();
// if (_debug)
// {
// SPRN("mem addr r: ");
// SPRNH(memoryAddress, HEX);
// SPRN("\t");
// SPRNL(rv);
// }
return 0; // error
}
// readBytes will always be equal or smaller to length
uint8_t readBytes = 0;
if (this->_isAddressSizeTwoWords)
{
readBytes = _wire->requestFrom((int)_deviceAddress, (int)length);
}
else
{
uint8_t address = _deviceAddress | ((memoryAddress >> 8) & 0x07);
readBytes = _wire->requestFrom((int)address, (int)length);
}
yield(); // For OS scheduling
uint8_t count = 0;
while (count < readBytes)
{
buffer[count++] = _wire->read();
}
return readBytes;
}
// compares content of EEPROM with buffer.
// returns true if equal.
bool I2C_eeprom::_verifyBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_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((int)_deviceAddress, (int)length);
}
else
{
uint8_t address = _deviceAddress | ((memoryAddress >> 8) & 0x07);
readBytes = _wire->requestFrom((int)address, (int)length);
}
yield(); // For OS scheduling
uint8_t count = 0;
while (count < readBytes)
{
if (buffer[count++] != _wire->read())
{
return false;
}
}
return true;
}
void I2C_eeprom::_waitEEReady()
{
#define I2C_WRITEDELAY 5000
// Wait until EEPROM gives ACK again.
// this is a bit faster than the hardcoded 5 milliSeconds
while ((micros() - _lastWrite) <= I2C_WRITEDELAY)
// Wait until EEPROM gives ACK again.
// this is a bit faster than the hardcoded 5 milliSeconds
// TWR = WriteCycleTime
uint32_t waitTime = I2C_WRITEDELAY + _extraTWR * 1000UL;
while ((micros() - _lastWrite) <= waitTime)
{
_wire->beginTransmission(_deviceAddress);
int x = _wire->endTransmission();
if (x == 0) return;
yield();
if (isConnected()) return;
// TODO remove pre 1.7.4 code
// _wire->beginTransmission(_deviceAddress);
// int x = _wire->endTransmission();
// if (x == 0) return;
yield(); // For OS scheduling
}
return;
}
// -- END OF FILE --
// -- END OF FILE --
+122 -46
View File
@@ -2,19 +2,16 @@
//
// FILE: I2C_eeprom.h
// AUTHOR: Rob Tillaart
// VERSION: 1.4.3
// VERSION: 1.9.4
// PURPOSE: Arduino Library for external I2C EEPROM 24LC256 et al.
// URL: https://github.com/RobTillaart/I2C_EEPROM.git
//
// HISTORY: See I2C_eeprom.cpp
// URL: https://github.com/RobTillaart/I2C_EEPROM
#include "Arduino.h"
#include "Wire.h"
#define I2C_EEPROM_VERSION (F("1.4.3"))
#define I2C_EEPROM_VERSION (F("1.9.4"))
#define I2C_DEVICESIZE_24LC512 65536
#define I2C_DEVICESIZE_24LC256 32768
@@ -28,10 +25,40 @@
#define I2C_DEVICESIZE_24LC01 128
// AT24C32 has a WriteCycle Time of max 20 ms
// so one need to set I2C_WRITEDELAY to 20000.
// can also be done on command line.
// (see private _waitEEReady() function)
#ifndef I2C_WRITEDELAY
#define I2C_WRITEDELAY 5000
#endif
// set the flag EN_AUTO_WRITE_PROTECT to 1 to enable the Write Control at compile time
// used if the write_protect pin is explicitly set in the begin() function.
// the flag can be set as command line option.
#ifndef EN_AUTO_WRITE_PROTECT
#define EN_AUTO_WRITE_PROTECT 0
#endif
#ifndef UNIT_TEST_FRIEND
#define UNIT_TEST_FRIEND
#endif
//#define ENABLE_DEBUG
#ifdef ENABLE_DEBUG
#define SPRN Serial.print
#define SPRNL Serial.println
#define SPRNH Serial.print
#define SPRNLH Serial.println
#else
#define SPRN(MSG)
#define SPRNH(MSG,MSG2)
#define SPRNL(MSG)
#define SPRNLH(MSG,MSG2)
#endif
class I2C_eeprom
{
@@ -47,75 +74,124 @@ public:
* It will try to guess page size and address word size based on the size of the device.
*
* @param deviceAddress Byte address of the device.
* @param deviceSize Max size in bytes of the device (divide your device size in Kbits by 8)
* @param deviceSize Max size in bytes of the device (divide your device size in Kbits by 8 to get Kbytes)
* @param wire Select alternative Wire interface
*/
I2C_eeprom(const uint8_t deviceAddress, const uint32_t deviceSize, TwoWire *wire = &Wire);
#if defined (ESP8266) || defined(ESP32)
bool begin(uint8_t sda, uint8_t scl);
#endif
bool begin();
bool begin(int8_t writeProtectPin = -1);
bool isConnected();
uint8_t getAddress();
// writes a byte to memaddr
// user is responsible that address is in range of the EEPROM used.
// writes a byte to memoryAddress
// returns I2C status, 0 = OK
int writeByte(const uint16_t memoryAddress, const uint8_t value);
// writes length bytes from buffer to EEPROM
int writeBlock(const uint16_t memoryAddress, const uint8_t* buffer, const uint16_t length);
// set length bytes in the EEPROM to the same value.
// writes length bytes from buffer to EEPROM
// returns I2C status, 0 = OK
int writeBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length);
// set length bytes in the EEPROM to the same value.
// returns I2C status, 0 = OK
int setBlock(const uint16_t memoryAddress, const uint8_t value, const uint16_t length);
// returns the value stored in memaddr
// returns the value stored in memoryAddress
uint8_t readByte(const uint16_t memoryAddress);
// reads length bytes into buffer
uint16_t readBlock(const uint16_t memoryAddress, uint8_t* buffer, const uint16_t length);
// 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 memory address, writes only if there is a new value.
// return 0 if data is same or written OK, error code otherwise.
// 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.
int updateByte(const uint16_t memoryAddress, const uint8_t value);
// updates a block in memory, writes only if there is a new value.
// only to be used when you expect to write same buffer multiple times.
// test your performance gains!
int updateBlock(const uint16_t memoryAddress, const uint8_t* buffer, const uint16_t length);
// updates a block in memory, writes only if there is a new value.
// only to be used when you expect to write same buffer multiple times.
// test your performance gains!
// returns bytes actually written <= length
uint16_t updateBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length);
uint32_t determineSize(const bool debug = false);
uint32_t getDeviceSize() { return _deviceSize; };
uint8_t getPageSize() { return _pageSize; };
// same functions as above but with verify
// return false if write or verify failed.
bool writeByteVerify(const uint16_t memoryAddress, const uint8_t value);
bool writeBlockVerify(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length);
bool setBlockVerify(const uint16_t memoryAddress, const uint8_t value, const uint16_t length);
bool updateByteVerify(const uint16_t memoryAddress, const uint8_t value);
bool updateBlockVerify(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length);
// Meta data functions
uint32_t getDeviceSize();
uint8_t getPageSize();
uint8_t calculatePageSize(uint32_t deviceSize);
[[deprecated("Use calculatePageSize(deviceSize) instead.")]]
uint8_t getPageSize(uint32_t deviceSize);
uint32_t getLastWrite() { return _lastWrite; };
uint32_t determineSizeNoWrite();
uint32_t determineSize(const bool debug = false);
uint32_t getLastWrite();
// for overruling and debugging.
// forces a power of 2
uint32_t setDeviceSize(uint32_t deviceSize); // returns set size
uint8_t setPageSize(uint8_t pageSize); // returns set size
// TWR = WriteCycleTime
// 5 ms is minimum, one can add extra ms here to adjust timing of both read() and write()
void setExtraWriteCycleTime(uint8_t ms);
uint8_t getExtraWriteCycleTime();
// WRITEPROTECT
// works only if WP pin is defined in begin().
// see readme.md
inline bool hasWriteProtectPin();
void allowWrite();
void preventWrite();
void setAutoWriteProtect(bool b);
bool getAutoWriteProtect();
private:
uint8_t _deviceAddress;
uint32_t _lastWrite; // for waitEEReady
uint32_t _deviceSize;
uint8_t _pageSize;
uint32_t _lastWrite = 0; // for waitEEReady
uint32_t _deviceSize = 0;
uint8_t _pageSize = 0;
uint8_t _extraTWR = 0; // milliseconds
// 24LC32..24LC512 use two bytes for memory address
// 24LC01..24LC16 use one-byte addresses + part of device address
// 24LC32..24LC512 use two bytes for memory address
// 24LC01..24LC16 use one-byte addresses + part of device address
bool _isAddressSizeTwoWords;
/**
* Begins wire transmission and selects the given address to write/read.
*
* @param memoryAddress Address to write/read
*/
void _beginTransmission(const uint16_t memoryAddress);
int _pageBlock(const uint16_t memoryAddress, const uint8_t* buffer, const uint16_t length, const bool incrBuffer);
int _WriteBlock(const uint16_t memoryAddress, const uint8_t* buffer, const uint8_t length);
uint8_t _ReadBlock(const uint16_t memoryAddress, uint8_t* buffer, const uint8_t length);
// 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 uint16_t length);
// returns bytes read.
uint8_t _ReadBlock(const uint16_t memoryAddress, uint8_t * buffer, const uint16_t length);
// compare bytes in EEPROM.
bool _verifyBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length);
// to optimize the write latency of the EEPROM
// to optimize the write latency of the EEPROM
void _waitEEReady();
TwoWire * _wire;
bool _debug = false;
int8_t _writeProtectPin = -1;
bool _autoWriteProtect = EN_AUTO_WRITE_PROTECT;
UNIT_TEST_FRIEND;
};
// -- END OF FILE --
// -- END OF FILE --
+21 -19
View File
@@ -5,13 +5,15 @@
// VERSION: 1.0.0
// PURPOSE: Supplemental utility class for I2C_EEPROM library
//
// URL: https://github.com/RobTillaart/I2C_EEPROM
#include <I2C_eeprom.h>
/**
* @brief This is a utility class for using an eeprom to store a simple
* data structure.
*
*
* The purpose of the utility is to extend the life of an eeprom memory by
* rotating the writes over different pages to reduce the number of writes
* to any individual page.
@@ -23,7 +25,7 @@
* version number which is then used for subsequent reads.
* Whenever data is written the version number is incremented and the next
* slot in sequence is used (or the first slot if going past the end).
*
*
* Note that the data is stored in binary form which means it should not be
* expected that the eeprom can be moved between architectures. Data stored
* in an eeprom will also become invalid if the data structure is changed
@@ -31,10 +33,10 @@
*
* If the data structure has changed or if the eeprom contains other data it
* must first be formatted with a call to format().
*
*
* Finally, since the version number is a long word, this class will
* *derail and fail* to add new versions past 4294967295 writes.
*
*
* @tparam T the type of the data structure to store, should only contain
* **value** members and no constructor/destructor nor other
* methods/functions - e g a pure DTO.
@@ -45,10 +47,10 @@ class I2C_eeprom_cyclic_store
public:
/**
* @brief Initializes the instance
*
*
* This call searches the eeprom for the latest written version and
* sets the current slot accordingly.
*
*
* @param eeprom The instance of I2C_eeprom to use.
* @param pageSize The number of bytes in each write page.
* @param totalPages Specifies the total number of pages to use.
@@ -69,12 +71,12 @@ public:
/**
* @brief Formats the eeprom
*
*
* This must be done if the eeprom already contains data or if the
* structure of the data stored changes.
*
* structure of the data stored changes.
*
* Formatting is done by writing the max version number to each slot,
* thus it performs a write cycle to the first write page of each slot.
* thus it performs a write cycle to the first write page of each slot.
*
* @return True if successful or false if unable to write to eeprom.
*/
@@ -93,14 +95,14 @@ public:
_currentSlot = 0;
_isInitialized = true;
return true;
return true;
}
/**
* @brief Read data from the eeprom into a buffer.
*
*
* The data is read from the current slot of the eeprom.
*
*
* @param buffer A reference to the buffer to read data into.
* @return True if data was read successfully, false otherwise.
*/
@@ -108,9 +110,9 @@ public:
/**
* @brief Read data from the eeprom into a buffer.
*
*
* The data is read from the current slot of the eeprom.
*
*
* @param buffer A pointet to the buffer to read data into.
* @return True if data was read successfully, false otherwise.
*/
@@ -127,9 +129,9 @@ public:
/**
* @brief Write a buffer to the next slot in the eeprom.
*
*
* This updates the current slot of this instance.
*
*
* @param buffer A reference to the buffer to write data from.
* @return True if data was written successfully, false otherwise.
*/
@@ -181,11 +183,11 @@ public:
/**
* @brief Returns metrics for the eeprom usage.
*
*
* Dividing the returned values of \p writeCounter with \p slots yields the average number of
* writes to the individual write pages of the eeprom. This can be used to estimate the remaining
* number of possible writes.
*
*
* @param[out] slots The number of slots used to write the data buffer.
* @param[out] writeCounter The total number of write to the eeprom since the last format (or first use).
* @return True if the instance is initialized, false otherwise.
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2011-2021 Rob Tillaart
Copyright (c) 2011-2025 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+298 -47
View File
@@ -1,87 +1,311 @@
[![Arduino CI](https://github.com/RobTillaart/I2C_EEPROM/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
[![Arduino-lint](https://github.com/RobTillaart/I2C_EEPROM/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/I2C_EEPROM/actions/workflows/arduino-lint.yml)
[![JSON check](https://github.com/RobTillaart/I2C_EEPROM/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/I2C_EEPROM/actions/workflows/jsoncheck.yml)
[![GitHub issues](https://img.shields.io/github/issues/RobTillaart/I2C_EEPROM.svg)](https://github.com/RobTillaart/I2C_EEPROM/issues)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/I2C_EEPROM/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/RobTillaart/I2C_EEPROM.svg?maxAge=3600)](https://github.com/RobTillaart/I2C_EEPROM/releases)
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/robtillaart/library/I2C_EEPROM.svg)](https://registry.platformio.org/libraries/robtillaart/I2C_EEPROM)
# I2C_EEPROM
Arduino Library for external I2C EEPROM - 24LC512, 24LC256, 24LC64/32/16/08/04/02/01
Arduino Library for external I2C EEPROM - 24LC512, 24LC256, 24LC64/32/16/08/04/02/01.
## Description
This library is to access external I2C EEPROM up to 64KB (= 512 Kbit) in size.
MicroChip 24LC512, 24LC256, 24LC64, 24LC32, 24LC16, 24LC08, 24LC04, 24LC02, 24LC01 and equivalents.
This library is used to access an external I2C EEPROM up to 64KB (= 512 Kbit) in size.
The MicroChip 24LC512, 24LC256, 24LC64, 24LC32, 24LC16, 24LC08, 24LC04, 24LC02, 24LC01
and equivalents are tested and working.
Also confirmed working M24512-W, M24512-R, M24512-DF (See #68).
Not supported are the identification page functions.
The **I2C_eeprom_cyclic_store** interface is documented [here](README_cyclic_store.md)
**Warning**
The user is responsible to verify the used memoryAddress (range) exists in the used EEPROM. (read / write / verify functions).
The library does not check this. If the address is larger than the EEPROM size,
the address used will probably be memoryAddress % deviceSize.
### RP2040
There are at least two boards modules for the RP2040 that use different Wire libraries.
One from "Earle F. Philhower" and an "MBED" one. See issues #53 and #55 for details.
In 1.7.3 defines are checked to select between these two and as far as tested this seems
to solve the issue #53 while being backwards compatible.
If a better solution is found, it will be implemented.
### Breaking change 1.9.0
Version 1.9.0 fixed a memory leak in **verifyBlock()**.
### Breaking change 1.8.0
Version 1.8.0 introduced a breaking change.
You cannot set the I2C pins in **begin()** any more.
This reduces the dependency of processor dependent Wire (I2C) implementations.
The user has to call **Wire.begin()** and can optionally set the Wire pins
(if the board supports this), before calling **I2C_eeprom.begin()**.
### Related
- https://github.com/RobTillaart/I2C_24LC1025
- https://github.com/RobTillaart/I2C_CAT24M01
- https://github.com/RobTillaart/I2C_EEPROM
## Schematic
Verify the datasheet for your specific EEPROM.
```cpp
+---U---+
A0 | 1 8 | VCC = 1.7V to 5.5V
A1 | 2 7 | WP = write protect pin
A2 | 3 6 | SCL = I2C clock
(VSS) GND | 4 5 | SDA = I2C data
+-------+
```
## I2C
I2C address = 0x50 .. 0x57 depending on three address lines (A0, A1, A2).
Read the datasheet of your specific EEPROM, section device addressing.
### I2C multiplexing
Sometimes you need to control more devices than possible with the default
address range the device provides.
This is possible with an I2C multiplexer e.g. TCA9548 which creates up
to eight channels (think of it as I2C subnets) which can use the complete
address range of the device.
Drawback of using a multiplexer is that it takes more administration in
your code e.g. which device is on which channel.
This will slow down the access, which must be taken into account when
deciding which devices are on which channel.
Also note that switching between channels will slow down other devices
too if they are behind the multiplexer.
- https://github.com/RobTillaart/TCA9548
## Interface
```cpp
#include "I2C_eeprom.h"
```
The interface is kept quite identical to the I2C_24LC1025 library.
https://github.com/RobTillaart/I2C_24LC1025
Most important difference is that the latter uses 32 bit memory addresses.
### Constructor
- **I2C_eeprom(uint8_t deviceAddress, TwoWire \*wire = &Wire)** constructor, optional Wire interface
- **I2C_eeprom(uint8_t deviceAddress, uint32_t deviceSize, TwoWire \*wire = &Wire)** constructor, with optional Wire interface.
- **bool begin()** initializes the I2C bus and checks if the device is available on the I2C bus.
- **bool begin(uint8_t sda, uint8_t scl)** idem for ESP32 / ESP8266 and alike.
- **bool isConnected()** test to see if device is on the bus.
- **I2C_eeprom(uint8_t deviceAddress, TwoWire \*wire = &Wire)** constructor, to set the
device address and optional Wire interface. The deviceSize == I2C_DEVICESIZE_24LC256 (32KB)
is used as it is the most often used I2C_EEPROM size.
Be aware that if you use other sized EEPROMs you have to use the next constructor,
and name the deviceSize explicitly, otherwise errors might occur.
- **I2C_eeprom(uint8_t deviceAddress, uint32_t deviceSize, TwoWire \*wire = &Wire)**
constructor, idem as above, furthermore the deviceSize can be any of the defines in the
table below or its number equivalent.
The Wire interface is optional, default Wire.
- **bool begin(uint8_t writeProtectPin = -1)** Optionally one can set the **WP**
writeProtect pin. (see section below).
If the **WP** pin is defined, the default behaviour will be to **not** allow writing.
Furthermore it checks if the deviceAddress given in the constructor is available
on the defined I2C bus.
Returns true if deviceAddress is found on the I2C bus, false otherwise.
- **bool isConnected()** returns true if the address given in the constructor is
available on the defined I2C bus.
- **uint8_t getAddress()** returns deviceAddress set in the constructor.
Convenience.
### Core functions
Defined device sizes for constructor, more details see below.
- **int writeByte(uint16_t memoryAddress, uint8_t value)** write a single byte to the specified memory address.
- **int updateByte(uint16_t memoryAddress, uint8_t value)** write a single byte, but only if changed. Returns 0 if value was same or write succeeded.
- **int writeBlock(uint16_t memoryAddress, uint8_t \* buffer, uint16_t length)** write a buffer starting at the specified memory address.
- **int updateBlock(uint16_t memoryAddress, uint8_t \* buffer, uint16_t length)** write a buffer starting at the specified memory address, but only if changed
- **int setBlock(uint16_t memoryAddress, uint8_t value, uint16_t length)** writes the same byte to length places starting at the specified memory address. Returns 0 if OK.
- **uint8_t readByte(uint16_t memoryAddress)** read a single byte from a given address
- **uint16_t readBlock(uint16_t memoryAddress, uint8_t \* buffer, uint16_t length)** read length bytes into buffer starting at specified memory address. Returns the number of bytes read, which should be length.
| Define | bytes | Notes |
|:-------------------------|--------:|:--------|
| I2C_DEVICESIZE_24LC512 | 65536 |
| I2C_DEVICESIZE_24LC256 | 32768 | most used
| I2C_DEVICESIZE_24LC128 | 16384 |
| I2C_DEVICESIZE_24LC64 | 8192 |
| I2C_DEVICESIZE_24LC32 | 4096 |
| I2C_DEVICESIZE_24LC16 | 2048 |
| I2C_DEVICESIZE_24LC08 | 1024 |
| I2C_DEVICESIZE_24LC04 | 512 |
| I2C_DEVICESIZE_24LC02 | 256 |
| I2C_DEVICESIZE_24LC01 | 128 |
### Write functions
- **int writeByte(uint16_t memoryAddress, uint8_t value)** write a single byte to
the specified memory address.
Returns I2C status, 0 = OK.
- **int writeBlock(uint16_t memoryAddress, uint8_t \* buffer, uint16_t length)**
write a buffer starting at the specified memory address.
Returns I2C status, 0 = OK.
- **int setBlock(uint16_t memoryAddress, uint8_t value, uint16_t length)** writes
the same byte to length places starting at the specified memory address.
Returns I2C status, 0 = OK.
### Update functions
Using update instead of write functions does not write if the value is the same.
The price is an extra read() call, but if there is no change the gain is performance.
- **int updateByte(uint16_t memoryAddress, uint8_t value)** write a single byte,
but only if the value has changed.
Returns 0 if value was same or write succeeded.
- **uint16_t updateBlock(uint16_t memoryAddress, uint8_t \* buffer, uint16_t length)**
write a buffer starting at the specified memory address, but only if changed.
Returns bytes actually written <= length.
### Read functions
- **uint8_t readByte(uint16_t memoryAddress)** read a single byte from a given address.
- **uint16_t readBlock(uint16_t memoryAddress, uint8_t \* buffer, uint16_t length)**
read length bytes into buffer starting at specified memory address.
Returns the number of bytes read, which should be length.
The user is responsible that the used buffer can hold length bytes.
### Verify functions
Since 1.6.0. - experimental, needs extensive testing.
Same as write and update functions above. Returns true if successful, false indicates an error.
The user is responsible that the used buffer can hold length bytes.
- **bool writeByteVerify(uint16_t memoryAddress, uint8_t value)**
- **bool writeBlockVerify(uint16_t memoryAddress, uint8_t \* buffer, uint16_t length)**
- **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 memoryAddress for length bytes.
### Other
- **uint32_t getDeviceSize()** idem
- **uint8_t getPageSize()** idem
- **uint8_t getPageSize(uint32_t deviceSize)** idem
- **uint32_t getLastWrite()** idem
- **uint32_t determineSize(bool debug = false)**
function that determins the size of the EEPROM by detecting when a memory address is folded upon memory address 0.
It is based upon the observation that memory wraps around.
The debug flag gives some output to Serial.
- **uint32_t getDeviceSize()** returns the current set deviceSize.
- **uint8_t getPageSize()** returns the current set pageSize.
- **uint8_t calculatePageSize(uint32_t deviceSize)** calculates the pageSize of a device
with deviceSize. Note it does not set the pageSize!
- **uint8_t getPageSize(uint32_t deviceSize)** deprecated, wrapper around calculatePageSize().
- **uint32_t getLastWrite()** returns timestamp in millis since start of program.
- **uint32_t determineSizeNoWrite()** function that determines the size of the EEPROM
by detecting when a selected memory address is not readable. (new in 1.8.1).
- **uint32_t determineSize(bool debug = false)**
function that determines the size of the EEPROM by detecting when a memory address
is folded upon memory address 0.
It is based upon the observation that memory wraps around.
The debug flag prints some output to Serial.
**Warning**: this function has changed (again) in 1.4.0
**Warning**: this function has changed (again) in 1.4.0
Testresults
Test results **determineSize()**
| Type | returns | Memory | Page Size | Notes |
|:--------|:--------|:---------|:-----:|:------|
| - | 0 | | | connect error, check device address / wiring |
| 24LC512 | 65536 | 64 KB | 128 | |
| 24LC256 | 32768 | 32 KB | 64 | |
| 24LC128 | 16384 | 16 KB | 64 | |
| 24LC64 | 8192 | 8 KB | 32 | |
| 24LC32 | 4096 | 4 KB | 32 | not tested with hardware |
| 24LC16 | 2048 | 2 KB | 16 | |
| 24LC08 | 1024 | 1 KB | 16 | |
| 24LC04 | 512 | 512 b | 16 | |
| 24LC02 | 256 | 256 b | 8 | |
| 24LC01 | 128 | 128 b | 8 | |
|:--------|:--------|:---------|:---------:|:------|
| - | 0 | | | connect error, check device address / wiring |
| 24LC512 | 65536 | 64 KB | 128 | |
| 24LC256 | 32768 | 32 KB | 64 | |
| 24LC128 | 16384 | 16 KB | 64 | |
| 24LC64 | 8192 | 8 KB | 32 | |
| 24LC32 | 4096 | 4 KB | 32 | not tested with hardware |
| 24LC16 | 2048 | 2 KB | 16 | |
| 24LC08 | 1024 | 1 KB | 16 | |
| 24LC04 | 512 | 512 b | 16 | |
| 24LC02 | 256 | 256 b | 8 | |
| 24LC01 | 128 | 128 b | 8 | |
The function cannot detect smaller than 128 bit EEPROMS.
#### UpdateBlock()
Experimental since 1.7.1 can be used for debugging and overruling constructor.
- **uint32_t setDeviceSize(uint32_t deviceSize)** overrules constructor setting.
returns set size == 128, 256, ... 32768, 65536
- **uint8_t setPageSize(uint8_t pageSize)** overrules constructor setting.
returns set size == 8, 16, 32, 64, 128.
### UpdateBlock()
(new since 1.4.2)
The function **updateBlock()** reads the block of data and compares it with the new values to see if it needs rewriting.
As the function reads/writes the data in blocks with a maximum length of **I2C_TWIBUFFERSIZE** (== 30 AVR limitation) it does this comparison in chuncks if the length exceeds this number. The result is that an **updateBlock()** call can result e.g. in 4 reads and only 2 writes under the hood.
As the function reads/writes the data in blocks with a maximum length of **I2C_TWIBUFFERSIZE**
(== 30 AVR limitation; 128 for ESP32)
It does this comparison in chunks if the length exceeds the length of the I2C buffer.
The result is that an **updateBlock()** call can result e.g. in 4 reads and only 2 writes under the hood.
If data is changed often between writes, **updateBlock()** is slower than **writeBlock()**.
So you should verify if your sketch can make use of the advantages of **updateBlock()**
### ExtraWriteCycleTime (experimental)
To improve support older I2C EEPROMs e.g. IS24C16 two functions were
added to increase the waiting time before a read and/or write as some
older devices have a larger timeout
than 5 milliseconds which is the minimum.
- **void setExtraWriteCycleTime(uint8_t ms)** idem
- **uint8_t getExtraWriteCycleTime()** idem
It is also possible to adjust the **I2C_WRITEDELAY** in the .h file
or overrule the define on the command line.
### WriteProtectPin WP (experimental)
(since 1.7.4)
The library can control the **WP** = WriteProtect pin of the EEPROM.
To do this one should connect a GPIO pin of the MCU to the **WP** pin of the EEPROM.
Furthermore the **WP** should be defined as a parameter in **begin()**.
If the **WP** pin is defined the default will be to **not** allow writing.
The user has to enable writing either by manual or automatic control.
In the automatic mode the library only allows writing to the EEPROM when it
actually writes to the EEPROM.
So it keeps the EEPROM in a read only mode as much as possible.
This prevents accidental writes due to (noisy) signals on the I2C bus. (#57)
Status
- **bool hasWriteProtectPin()** returns true if **WP** has been set.
Automatic control
- **void setAutoWriteProtect(bool b)** if set to true, the library enables writing
only when the EEPROM is actually written. This setting **overrules** the manual control.
If **setAutoWriteProtect()** is set to false (== default) the manual control is leading.
- **bool getAutoWriteProtect()** get current setting.
Manual control
- **void allowWrite()** allows writing by setting **WP** to LOW.
- **void preventWrite()** disables writing by setting **WP** to HIGH.
## Limitation
The library does not offer multiple EEPROMS as one continuous storage device.
@@ -89,13 +313,40 @@ The library does not offer multiple EEPROMS as one continuous storage device.
## Future
- improve error handling, write functions should return bytes written or so.
- what can we do with the print interface? (investigate)
- investigate multi-EEPROM storage,
- investigate smarter strategy for updateBlock() => find first and last changed position would possibly result in less writes.
#### Must
- improve documentation
#### Should
- investigate multi-EEPROM storage ==> wrapper class!
- improve error handling
- address range check in begin
- write functions should return bytes written (like Print() does)
now they return I2C status... => error / status.
- remove uint8_t getPageSize(uint32_t deviceSize) in 0.2.0. now deprecated.
#### Could
- 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.
- replace defines with const uint8_t / const uint16_t to force type checking?
- sync order .h file and readme.md.
#### Wont
- investigate the print interface?
- circular buffer? (see FRAM library)
- dump function?
## Operational
## Support
See examples
If you appreciate my libraries, you can support the development and maintenance.
Improve the quality of the libraries by providing issues and Pull Requests, or
donate through PayPal or GitHub sponsors.
Thank you,
+26 -6
View File
@@ -1,21 +1,38 @@
[![Arduino CI](https://github.com/RobTillaart/I2C_EEPROM/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
[![Arduino-lint](https://github.com/RobTillaart/I2C_EEPROM/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/I2C_EEPROM/actions/workflows/arduino-lint.yml)
[![JSON check](https://github.com/RobTillaart/I2C_EEPROM/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/I2C_EEPROM/actions/workflows/jsoncheck.yml)
[![GitHub issues](https://img.shields.io/github/issues/RobTillaart/I2C_EEPROM.svg)](https://github.com/RobTillaart/I2C_EEPROM/issues)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/I2C_EEPROM/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/RobTillaart/I2C_EEPROM.svg?maxAge=3600)](https://github.com/RobTillaart/I2C_EEPROM/releases)
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/robtillaart/library/I2C_EEPROM.svg)](https://registry.platformio.org/libraries/robtillaart/I2C_EEPROM)
# I2C_eeprom_cyclic_store
Utility class for storing data using cyclic writes to eeprom memory
Utility class for storing data using cyclic writes to eeprom memory.
## Description
In order to maximize the life expectancy of an eeprom this class implements a method to spread the write operations across as much of the eeprom as possible, rather than writing to the same fixed location.
In order to maximize the life expectancy of an eeprom this class implements
a method to spread the write operations across as much of the eeprom as possible,
rather than writing to the same fixed location.
This is suitable for a situation where a single data structure (buffer), such as settings, configuration or metric data, is written to the eeprom.
This is suitable for a situation where a single data structure (buffer),
such as settings, configuration or metric data, is written to the eeprom.
It operates by partitioning the eeprom into slots large enough to hold the declared buffer (and header) and then writing each new version of the data to the next slot, overwriting any older version already in there. As it reaches the end of the alotted region of the eeprom it wraps around and starts writing from the start of the memory again. When initializing an instance it scans the eeprom to find the last written version and continues from that.
It operates by partitioning the eeprom into slots large enough to hold the
declared buffer (and header) and then writing each new version of the data
to the next slot, overwriting any older version already in there.
As it reaches the end of the alotted region of the eeprom it wraps around
and starts writing from the start of the memory again.
When initializing an instance it scans the eeprom to find the last written
version and continues from that.
In order to use an eeprom that already has data (and if the structure of the buffer changes) the eeprom has to be prepared by formatting the indexes.
In order to use an eeprom that already has data (and if the structure of the
buffer changes) the eeprom has to be prepared by formatting the indexes.
The interface is pretty straightforward
@@ -25,9 +42,12 @@ The interface is pretty straightforward
- **write(buffer)** write buffer to next location on eeprom
- **getMetrics(slots, writeCounter)** get usage metrics
## Limitation
The class does not handle changes in buffer size or structure, nor does it detect an eeprom that has data that wasn't written using the class.
The class does not handle changes in buffer size or structure, nor does
it detect an eeprom that has data that wasn't written using the class.
## Operational
@@ -3,30 +3,41 @@
// AUTHOR: Tomas Hübner
// VERSION: 1.0.0
// PURPOSE: Simple example of how to use cyclic storage.
//
// URL: https://github.com/RobTillaart/I2C_EEPROM
#include <I2C_eeprom.h>
#include <I2C_eeprom_cyclic_store.h>
#define MEMORY_SIZE 0x2000 // Total capacity of the EEPROM
#define PAGE_SIZE 64 // Size of write page of device, use datasheet to find!
#define MEMORY_SIZE 8192 // Total capacity of the EEPROM (8K == 8192 == 0x2000)
#define PAGE_SIZE 64 // Size of write page of device, use datasheet to find!
struct SampleData {
public:
uint32_t counter;
// Must use fixed length string, avoid using the String class.
// Must use fixed length string, avoid using the String class.
char message[32];
};
SampleData data;
I2C_eeprom ee(0x50, MEMORY_SIZE);
I2C_eeprom_cyclic_store<SampleData> cs;
void setup()
{
Serial.begin(115200);
while(!Serial);
while (!Serial); // wait for Serial port to connect. Needed for Leonardo only
Serial.println();
Serial.println(__FILE__);
Serial.print("I2C_EEPROM_VERSION: ");
Serial.println(I2C_EEPROM_VERSION);
Serial.println();
Wire.begin();
ee.begin();
@@ -39,9 +50,9 @@ void setup()
sprintf(data.message, "Initialized to %x", data.counter);
cs.write(data);
}
}
void loop()
{
Serial.println(data.message);
@@ -2,7 +2,7 @@
// FILE: I2C_eeprom_determineSize.ino
// AUTHOR: Rob Tillaart
// PURPOSE: test determinSize() function
//
// URL: https://github.com/RobTillaart/I2C_EEPROM
#include "Wire.h"
@@ -17,9 +17,14 @@ uint32_t start, diff;
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for Serial port to connect. Needed for Leonardo only
Serial.println();
Serial.println(__FILE__);
Serial.print("I2C_EEPROM_VERSION: ");
Serial.println(I2C_EEPROM_VERSION);
Serial.println();
Wire.begin();
ee.begin();
if (! ee.isConnected())
@@ -32,7 +37,7 @@ void setup()
delay(10);
start = micros();
uint32_t size = ee.determineSize(false); // debug param
uint32_t size = ee.determineSize(false); // debug parameter
diff = micros() - start;
Serial.print("TIME: ");
Serial.print(diff);
@@ -55,7 +60,7 @@ void setup()
}
Serial.print("PAGE: ");
uint8_t pageSize = ee.getPageSize(size);
uint8_t pageSize = ee.calculatePageSize(size);
Serial.print(pageSize);
Serial.println(" bytes.");
@@ -67,4 +72,6 @@ void loop()
{
}
// -- END OF FILE --
// -- END OF FILE --
@@ -0,0 +1,84 @@
//
// FILE: I2C_eeprom_determineSizeNoWrite.ino
// AUTHOR: Rob Tillaart
// PURPOSE: test determineSizeNoWrite() function
// URL: https://github.com/RobTillaart/I2C_EEPROM
#include "Wire.h"
#include "I2C_eeprom.h"
I2C_eeprom ee(0x50, I2C_DEVICESIZE_24LC256);
uint32_t start, diff;
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for Serial port to connect. Needed for Leonardo only
Serial.println();
Serial.println(__FILE__);
Serial.print("I2C_EEPROM_VERSION: ");
Serial.println(I2C_EEPROM_VERSION);
Serial.println();
Wire.begin();
ee.begin();
if (! ee.isConnected())
{
Serial.println("ERROR: Can't find eeprom\nstopped...");
while (1);
}
Serial.println("\nDetermine size no write");
delay(100);
start = micros();
uint32_t size = ee.determineSizeNoWrite();
diff = micros() - start;
Serial.print("TIME: ");
Serial.print(diff);
Serial.println(" us.");
if (size == 0)
{
Serial.println("SIZE: could not determine size");
}
else if (size == 1)
{
Serial.println("SIZE: device has default data in first bytes, write some data and retry or use the determineSize method");
}
else if (size == 2)
{
Serial.println("SIZE: device has all the same data in first bytes, write some data and retry");
}
else if (size > 1024)
{
Serial.print("SIZE: ");
Serial.print(size / 1024);
Serial.println(" KB.");
}
else
{
Serial.print("SIZE: ");
Serial.print(size);
Serial.println(" bytes.");
}
Serial.print("PAGE: ");
uint8_t pageSize = ee.calculatePageSize(size);
Serial.print(pageSize);
Serial.println(" bytes.");
Serial.println("Done...");
}
void loop()
{
}
// -- END OF FILE --
@@ -2,7 +2,7 @@
// FILE: I2C_eeprom_format.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo format EEPROM
//
// URL: https://github.com/RobTillaart/I2C_EEPROM
#include "Wire.h"
@@ -17,9 +17,14 @@ uint32_t start, diff;
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for Serial port to connect. Needed for Leonardo only
Serial.println();
Serial.println(__FILE__);
Serial.print("I2C_EEPROM_VERSION: ");
Serial.println(I2C_EEPROM_VERSION);
Serial.println();
Wire.begin();
ee.begin();
if (! ee.isConnected())
@@ -30,7 +35,7 @@ void setup()
Serial.println();
uint32_t size = ee.determineSize(false); // debug param
uint32_t size = ee.determineSize(false); // debug parameter
if (size == 0)
{
Serial.println("SIZE: could not determine size");
@@ -59,10 +64,10 @@ void setup()
if ( ans == 'Y')
{
start = millis();
for (uint32_t i = 0; i < size; i += 128)
for (uint32_t address = 0; address < size; address += 128)
{
if (i % 1024 == 0) Serial.print('.');
ee.setBlock(0, 0xFF, 128);
if (address % 1024 == 0) Serial.print('.');
ee.setBlock(address, 0xFF, 128);
}
diff = millis() - start;
Serial.print("\nTIME: ");
@@ -82,4 +87,5 @@ void loop()
{
}
// -- END OF FILE --
// -- END OF FILE --
@@ -0,0 +1,95 @@
//
// FILE: I2C_eeprom_struct.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo I2C_EEPROM library store /retrieve struct
// URL: https://github.com/RobTillaart/I2C_EEPROM
//
// uses a 24LC256 (32KB) EEPROM
// as this test writes a lot it might wear out EEPROMs eventually.
#include "Wire.h"
#include "I2C_eeprom.h"
I2C_eeprom ee(0x50, I2C_DEVICESIZE_24LC256);
uint32_t start, duration;
struct
{
float temperature;
float humidity;
float pressure;
} measurement;
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for Serial port to connect. Needed for Leonardo only
Serial.println();
Serial.println(__FILE__);
Serial.print("I2C_EEPROM_VERSION: ");
Serial.println(I2C_EEPROM_VERSION);
Serial.println();
Wire.begin();
ee.begin();
if (! ee.isConnected())
{
Serial.println("ERROR: Can't find eeprom (stopped)...");
// while (1);
}
Serial.print("size: \t");
Serial.println(sizeof(measurement));
// clear EEPROM part
ee.setBlock(0, 0, sizeof(measurement));
// make measurement here
measurement.temperature = 22.5;
measurement.humidity = 53.1;
measurement.pressure = 1000.9;
// store it in EEPROM
start = micros();
ee.writeBlock(0, (uint8_t *) &measurement, sizeof(measurement));
duration = micros() - start;
Serial.print("write: \t");
Serial.println(duration);
delay(10);
// clear measurement struct
measurement.temperature = 0;
measurement.humidity = 0;
measurement.pressure = 0;
// retrieve old measurement
start = micros();
ee.readBlock(0, (uint8_t *) &measurement, sizeof(measurement));
duration = micros() - start;
Serial.print("read: \t");
Serial.println(duration);
delay(10);
Serial.print("temp:\t");
Serial.println(measurement.temperature);
Serial.print("hum:\t");
Serial.println(measurement.humidity);
Serial.print("pres:\t");
Serial.println(measurement.pressure);
Serial.println("\ndone...");
}
void loop()
{
}
// -- END OF FILE
+25 -16
View File
@@ -2,18 +2,19 @@
// FILE: I2C_eeprom_test.ino
// AUTHOR: Rob Tillaart
// PURPOSE: show/test I2C_EEPROM library
// URL: https://github.com/RobTillaart/I2C_EEPROM
//
// uses a 24LC256 (32KB) EEPROM
// might need adaptions for other EEPROMS (page size etc)
// uses a 24LC256 (32KB) EEPROM
// might need adaptions for other EEPROMS (page size etc)
#include "Wire.h"
#include "I2C_eeprom.h"
// UNO
// UNO
#define SERIAL_OUT Serial
// Due
// Due
// #define SERIAL_OUT SerialUSB
@@ -25,8 +26,14 @@ uint32_t start, diff, totals = 0;
void setup()
{
SERIAL_OUT.begin(115200);
while (!SERIAL_OUT); // wait for SERIAL_OUT port to connect. Needed for Leonardo only
while (!SERIAL_OUT); // wait for SERIAL_OUT port to connect. Needed for Leonardo only
SERIAL_OUT.println();
SERIAL_OUT.println(__FILE__);
SERIAL_OUT.print("I2C_EEPROM_VERSION: ");
SERIAL_OUT.println(I2C_EEPROM_VERSION);
SERIAL_OUT.println();
Wire.begin();
ee.begin();
if (! ee.isConnected())
@@ -34,14 +41,12 @@ 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());
SERIAL_OUT.println("\nTEST: determine size");
start = micros();
uint32_t size = ee.determineSize();
uint32_t size = ee.determineSize(true);
diff = micros() - start;
SERIAL_OUT.print("TIME: ");
SERIAL_OUT.println(diff);
@@ -63,7 +68,9 @@ void setup()
SERIAL_OUT.println("\nTEST: 64 byte page boundary writeBlock");
ee.setBlock(0, 0, 128);
dumpEEPROM(0, 128);
char data[] = "11111111111111111111";
Serial.println("---");
// char data[] = "11111111111111111111";
char data[] = "33333333333333333333";
ee.writeBlock(60, (uint8_t*) data, 10);
dumpEEPROM(0, 128);
@@ -149,7 +156,7 @@ void setup()
SERIAL_OUT.println(totals);
totals = 0;
// same tests but now with a 5 millisec delay in between.
// same tests but now with a 5 millisec delay in between.
delay(5);
SERIAL_OUT.print("\nTEST: timing writeByte()\t");
@@ -194,7 +201,7 @@ void setup()
SERIAL_OUT.println(totals);
totals = 0;
// does it go well?
// did it go well?
SERIAL_OUT.println(xx);
SERIAL_OUT.println("\tDone...");
@@ -209,7 +216,7 @@ void loop()
void dumpEEPROM(uint16_t memoryAddress, uint16_t length)
{
const int BLOCK_TO_LENGTH = 10;
SERIAL_OUT.print("\t ");
for (int x = 0; x < 10; x++)
{
@@ -218,7 +225,7 @@ void dumpEEPROM(uint16_t memoryAddress, uint16_t length)
}
SERIAL_OUT.println();
// block to defined length
// block to defined length
memoryAddress = memoryAddress / BLOCK_TO_LENGTH * BLOCK_TO_LENGTH;
length = (length + BLOCK_TO_LENGTH - 1) / BLOCK_TO_LENGTH * BLOCK_TO_LENGTH;
@@ -241,4 +248,6 @@ void dumpEEPROM(uint16_t memoryAddress, uint16_t length)
SERIAL_OUT.println();
}
// END OF FILE
// -- END OF FILE --
-128
View File
@@ -1,128 +0,0 @@
Try this (not tested)
[code]
//#include <UTFT.h>
#include <SD.h>
#include <Wire.h>
#include <ArduCAM.h>
#include <avr/pgmspace.h>
#define SD_CS 9
//UTFT(byte model, int RS, int WR, int RD, int CS)
//UTFT myGLCD(ITDB32S,A2,A1,A0,10); // Remember to change the model parameter to suit your display module!
//ArduCAM(byte model,int RS, int WR, int RD, int REG_CS, int FIFO_CS)
ArduCAM myCAM(OV2640,A2,A1,A0,A3,10); // Remember to change the model parameter to suit your canera module!
void setup()
{
Serial.begin(115200); // <<<<<<<<<<<<<<<<<<<<<<<
Serial.println("Start arducam test");
//Initialize I2C Bus
Wire.begin();
//Switch to FIFO Mode
myCAM.write_reg(ARDUCHIP_TIM, MODE_MASK);
//Set sensor to JPEG mode. Note don't all the camera modules support JPEG mode
myCAM.OV2640_set_format(JPEG);
//Initialize Camera Module
myCAM.InitCAM();
myCAM.OV2640_set_JPEG_size(OV2640_320x240);
Serial.println("SD.begin");
//Initialize SD Card
if (!SD.begin(SD_CS))
{
Serial.println("SD card failed");
//while (1); //If failed, stop here
}
Serial.println("SD card success");
Serial.println("End setup");
}
void loop()
{
Serial.print(millis());
Serial.println("\tstart loop");
char str[8];
File outFile;
static int k = 0;
uint8_t temp,temp_last;
uint8_t start_capture = 0;
Serial.print(millis());
Serial.println("\tWait trigger from shutter buttom");
//Wait trigger from shutter buttom
if(myCAM.read_reg(ARDUCHIP_TRIG) & SHUTTER_MASK)
{
//Wait until buttom released
while(myCAM.read_reg(ARDUCHIP_TRIG) & SHUTTER_MASK);
start_capture = 1;
}
Serial.print(millis());
Serial.println("\tStart capture I");
//Start capture when detect a valid shutter press
if(start_capture)
{
//Flush the FIFO
myCAM.flush_fifo();
//Start capture
myCAM.start_capture();
}
if(myCAM.read_reg(ARDUCHIP_TRIG) & CAP_DONE_MASK)
{
//Construct a file name
k = k + 1;
itoa(k, str, 10);
strcat(str,".jpg");
//Open the new file
outFile = SD.open(str,FILE_WRITE);
if (! outFile)
{
Serial.print(millis());
Serial.println("\tfailure outfile");
return;
}
Serial.print(millis());
Serial.println("\toutfile succes");
//Enable FIFO
myCAM.enable_fifo();
uint32_t bytecounter = 0;
//Read the first dummy byte from FIFO
temp = myCAM.read_fifo();
//Read JPEG data from FIFO
while( (temp != 0xD9) | (temp_last != 0xFF) )
{
bytecounter++;
if (bytecounter % 32 == 0) Serial.print('.');
if (bytecounter % 1024 == 0) Serial.println;
temp_last = temp;
temp = myCAM.read_fifo();
//Write image data to file
outFile.write(temp);
}
Serial.println();
//Disable FIFO when all the image data is saved to the file
myCAM.disable_fifo();
//Close the file
outFile.close();
//Clear the capture done flag
myCAM.clear_fifo_flag();
//Clear the start capture flag
start_capture = 0;
}
}
[/code]
@@ -2,7 +2,7 @@
// FILE: I2C_eeprom_test_performance.ino
// AUTHOR: Rob Tillaart
// PURPOSE: test I2C_EEPROM library
//
// URL: https://github.com/RobTillaart/I2C_EEPROM
#include "Wire.h"
@@ -17,10 +17,14 @@ uint32_t start, diff, totals = 0;
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for Serial port to connect. Needed for Leonardo only
while (!Serial); // wait for Serial port to connect. Needed for Leonardo only
Serial.println();
Serial.println(__FILE__);
Serial.print("VERSION: ");
Serial.print("I2C_EEPROM_VERSION: ");
Serial.println(I2C_EEPROM_VERSION);
Serial.println();
Wire.begin();
ee.begin();
if (! ee.isConnected())
@@ -39,6 +43,7 @@ void setup()
Serial.println(speed);
delay(10);
test();
dumpEEPROM(0, 100);
}
Serial.println("\ndone...");
}
@@ -53,8 +58,8 @@ void loop()
void test()
{
char data2[] = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999A";
char data2[] = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999A";
totals = 0;
Serial.print("\nTEST: timing writeByte()\t");
uint32_t start = micros();
@@ -92,7 +97,7 @@ void test()
Serial.println(totals);
totals = 0;
// same tests but now with a 5 millisec delay in between.
// same tests but now with a 5 milliseconds delay in between.
delay(5);
Serial.print("\nTEST: timing writeByte()\t");
@@ -137,7 +142,7 @@ void test()
Serial.println(totals);
totals = 0;
// does it go well?
// did it go well?
Serial.println(xx);
}
@@ -145,7 +150,7 @@ void test()
void dumpEEPROM(uint16_t memoryAddress, uint16_t length)
{
const int BLOCK_TO_LENGTH = 10;
Serial.print("\t ");
for (int x = 0; x < 10; x++)
{
@@ -154,7 +159,7 @@ void dumpEEPROM(uint16_t memoryAddress, uint16_t length)
}
Serial.println();
// block to defined length
// block to defined length
memoryAddress = memoryAddress / BLOCK_TO_LENGTH * BLOCK_TO_LENGTH;
length = (length + BLOCK_TO_LENGTH - 1) / BLOCK_TO_LENGTH * BLOCK_TO_LENGTH;
@@ -177,4 +182,6 @@ void dumpEEPROM(uint16_t memoryAddress, uint16_t length)
Serial.println();
}
// END OF FILE
// -- END OF FILE --
@@ -2,9 +2,10 @@
// FILE: I2C_eeprom_update.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo I2C_EEPROM library - updateByte
// URL: https://github.com/RobTillaart/I2C_EEPROM
//
// uses a 24LC256 (32KB) EEPROM
// uses a 24LC256 (32KB) EEPROM
#include "Wire.h"
#include "I2C_eeprom.h"
@@ -15,14 +16,17 @@ I2C_eeprom ee(0x50, I2C_DEVICESIZE_24LC256);
uint32_t start, dur1, dur2;
void setup()
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for SERIAL_OUT port to connect. Needed for Leonardo only
Serial.begin(115200);
while (!Serial); // wait for Serial port to connect. Needed for Leonardo only
Serial.println();
Serial.println(__FILE__);
Serial.print("VERSION: ");
Serial.print("I2C_EEPROM_VERSION: ");
Serial.println(I2C_EEPROM_VERSION);
Serial.println();
Wire.begin();
ee.begin();
if (! ee.isConnected())
@@ -38,7 +42,7 @@ void setup()
Serial.print("SIZE: ");
Serial.print(size);
Serial.println(" KB");
}
}
else if (size == 0)
{
Serial.println("WARNING: Can't determine eeprom size");
@@ -51,7 +55,7 @@ void setup()
Serial.println("\nTEST: 100x writebyte()");
delay(10);
ee.setBlock(0, 0, 100); // clear first 100 bytes
ee.setBlock(0, 0, 100); // clear first 100 bytes
start = micros();
for (int i = 0; i < 100; i++)
{
@@ -61,9 +65,9 @@ void setup()
Serial.print("DUR1: ");
Serial.println(dur1);
delay(10);
Serial.println("\nTEST: 100x updateByte()");
ee.setBlock(0, 0, 100); // clear first 100 bytes
ee.setBlock(0, 0, 100); // clear first 100 bytes
start = micros();
for (int i = 0; i < 100; i++)
{
@@ -73,12 +77,15 @@ void setup()
Serial.print("DUR2: ");
Serial.println(dur2);
delay(10);
Serial.println("done...");
}
void loop()
void loop()
{
}
// -- END OF FILE
// -- END OF FILE --
@@ -2,11 +2,11 @@
// FILE: I2C_eeprom_updateBlock.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo I2C_EEPROM library - performance gain updateBlock
// URL: https://github.com/RobTillaart/I2C_EEPROM
//
// uses a 24LC256 (32KB) EEPROM
// as this test writes a lot it might wear out EEPROMs eventually.
//
#include "Wire.h"
#include "I2C_eeprom.h"
@@ -18,16 +18,19 @@ uint32_t start, dur1, dur2;
uint8_t ar[100];
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for SERIAL_OUT port to connect. Needed for Leonardo only
while (!Serial); // wait for Serial port to connect. Needed for Leonardo only
Serial.println();
Serial.println(__FILE__);
Serial.print("VERSION: ");
Serial.print("I2C_EEPROM_VERSION: ");
Serial.println(I2C_EEPROM_VERSION);
Serial.println();
Wire.begin();
ee.begin();
if (! ee.isConnected())
{
@@ -47,16 +50,18 @@ void setup()
Serial.println("\ndone...");
}
void loop()
{
}
void test_1(int n)
{
Serial.println(n);
Serial.print("TEST:\twriteBlock()");
delay(10);
ee.setBlock(0, 0, 100); // clear first 100 bytes
ee.setBlock(0, 0, 100); // clear first 100 bytes
start = micros();
for (int i = 0; i < n; i++) ee.writeBlock(0, ar, 100);
dur1 = micros() - start;
@@ -75,7 +80,7 @@ void test_1(int n)
Serial.print("TEST:\tupdateBlock()");
delay(10);
ee.setBlock(0, 0, 100); // clear first 100 bytes
ee.setBlock(0, 0, 100); // clear first 100 bytes
start = micros();
for (int i = 0; i < n; i++) ee.updateBlock(0, ar, 100);
dur1 = micros() - start;
@@ -85,11 +90,12 @@ void test_1(int n)
Serial.println();
}
void test_2()
{
Serial.println("\nTEST: 100x writeBlock()");
delay(10);
ee.setBlock(0, 0, 100); // clear first 100 bytes
ee.setBlock(0, 0, 100); // clear first 100 bytes
start = micros();
for (int i = 0; i < 100; i++)
{
@@ -103,7 +109,7 @@ void test_2()
Serial.println("\nTEST: 100x updateBlock()");
ee.setBlock(0, 0, 100); // clear first 100 bytes
ee.setBlock(0, 0, 100); // clear first 100 bytes
start = micros();
for (int i = 0; i < 100; i++)
{
@@ -119,14 +125,18 @@ void test_2()
void dump(uint32_t from, uint32_t to)
{
for (uint32_t i = from; i < to; i++) // I2C_DEVICESIZE_24LC512
for (uint32_t i = from; i < to; i++) // I2C_DEVICESIZE_24LC512
{
char buffer[24];
if (i % 16 == 0)
{
char buffer[24];
Serial.print('\n');
sprintf(buffer, "%08lX\t", i);
#if defined (ESP8266) || defined(ESP32)
sprintf(buffer, "%08X\t", i); // ESP cast (long unsigned int)
#else
sprintf(buffer, "%08lX\t", i); // AVR needs lX
#endif;
Serial.print(buffer);
}
sprintf(buffer, "%02X\t", ee.readByte(i));
@@ -136,4 +146,5 @@ void dump(uint32_t from, uint32_t to)
}
// -- END OF FILE
// -- END OF FILE --
@@ -0,0 +1,251 @@
//
// FILE: I2C_eeprom_verify.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo I2C_EEPROM library - updateByte
// URL: https://github.com/RobTillaart/I2C_EEPROM
//
// uses a 24LC256 (32KB) EEPROM
#include "Wire.h"
#include "I2C_eeprom.h"
#define NN 100
I2C_eeprom ee(0x50, I2C_DEVICESIZE_24LC256);
uint32_t start, dur1, dur2;
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for Serial port to connect. Needed for Leonardo only
Serial.println();
Serial.println(__FILE__);
Serial.print("I2C_EEPROM_VERSION: ");
Serial.println(I2C_EEPROM_VERSION);
Serial.println();
Wire.begin();
ee.begin();
if (! ee.isConnected())
{
Serial.println("ERROR: Can't find eeprom\nstopped...");
while (1);
}
Serial.print("\nTestruns NN: ");
Serial.print(NN);
Serial.println("\n");
Serial.println("\nTEST: NN x writeByte()");
delay(10);
ee.setBlock(0, 0, 100); // clear first 100 bytes
start = micros();
for (int i = 0; i < NN; i++)
{
ee.writeByte(i, 0);
}
dur1 = micros() - start;
Serial.print("DUR1: ");
Serial.println(dur1);
delay(10);
Serial.println("\nTEST: NN x writeByteVerify()");
delay(10);
ee.setBlock(0, 0, 100); // clear first 100 bytes
start = micros();
for (int i = 0; i < NN; i++)
{
if (ee.writeByteVerify(i, 0) == false)
{
Serial.print("X");
}
}
dur1 = micros() - start;
Serial.print("DUR1: ");
Serial.println(dur1);
delay(10);
//////////////////////////////////////////////////////////////////////
Serial.println("\nTEST: NN x updateByte() same data");
delay(10);
start = micros();
for (int i = 0; i < NN; i++)
{
ee.updateByte(i, 0);
}
dur2 = micros() - start;
Serial.print("DUR2: ");
Serial.println(dur2);
delay(10);
Serial.println("\nTEST: NN x updateByteVerify() same data");
delay(10);
start = micros();
for (int i = 0; i < NN; i++)
{
if (ee.updateByteVerify(i, 0) == false)
{
Serial.print("X");
}
}
dur2 = micros() - start;
Serial.print("DUR2: ");
Serial.println(dur2);
delay(10);
Serial.println("\nTEST: NN x updateByteVerify() not same data");
delay(10);
ee.setBlock(0, 0, 100); // clear first 100 bytes
start = micros();
for (int i = 0; i < NN; i++)
{
if (ee.updateByteVerify(i, i) == false)
{
Serial.print("X");
}
}
dur2 = micros() - start;
Serial.print("DUR2: ");
Serial.println(dur2);
delay(10);
//////////////////////////////////////////////////////////////////////
char buffer[] = "12345678901234567890123456789012345678901234567890"; // 50 bytes
Serial.println("\nTEST: NN x writeBlock()");
delay(10);
ee.setBlock(0, 0, 100); // clear first 100 bytes
start = micros();
for (int i = 0; i < NN; i++)
{
ee.writeBlock(0, (uint8_t *) buffer, 50);
}
dur1 = micros() - start;
Serial.print("DUR1: ");
Serial.println(dur1);
delay(10);
Serial.println("\nTEST: NN x writeBlockVerify()");
delay(10);
ee.setBlock(0, 0, 100); // clear first 100 bytes
start = micros();
for (int i = 0; i < NN; i++)
{
if (ee.writeBlockVerify(0, (uint8_t *) buffer, 50) == false)
{
Serial.print("X");
}
}
dur1 = micros() - start;
Serial.print("DUR1: ");
Serial.println(dur1);
delay(10);
//////////////////////////////////////////////////////////////////////
Serial.println("\nTEST: NN x updateBlock() same data");
delay(10);
start = micros();
for (int i = 0; i < NN; i++)
{
ee.updateBlock(0, (uint8_t *) buffer, 50);
}
dur2 = micros() - start;
Serial.print("DUR2: ");
Serial.println(dur2);
delay(10);
Serial.println("\nTEST: NN x updateBlockVerify() same data");
delay(10);
start = micros();
for (int i = 0; i < NN; i++)
{
if (ee.updateBlockVerify(0, (uint8_t *) buffer, 50) == false)
{
Serial.print("X");
}
}
dur2 = micros() - start;
Serial.print("DUR2: ");
Serial.println(dur2);
delay(10);
strcpy(buffer, "98765432109876543210987654321098765432109876543210"); // 50 bytes
Serial.println("\nTEST: NN x updateBlockVerify() not same data");
delay(10);
ee.setBlock(0, 0, 100); // clear first 100 bytes
start = micros();
for (int i = 0; i < NN; i++)
{
if (ee.updateBlockVerify(0, (uint8_t *) buffer, 50) == false)
{
Serial.print("X");
}
}
dur2 = micros() - start;
Serial.print("DUR2: ");
Serial.println(dur2);
delay(10);
//////////////////////////////////////////////////////////////////////
Serial.println("\nTEST: NN x setBlock() same data");
delay(10);
ee.setBlock(0, 0, 100); // clear first 100 bytes
start = micros();
for (int i = 0; i < NN; i++)
{
ee.setBlock(0, 0, 50);
}
dur2 = micros() - start;
Serial.print("DUR2: ");
Serial.println(dur2);
delay(10);
Serial.println("\nTEST: NN x setBlockVerify() same data");
delay(10);
ee.setBlock(0, 0, 100); // clear first 100 bytes
start = micros();
for (int i = 0; i < NN; i++)
{
if (ee.setBlockVerify(0, 0, 50) == false)
{
Serial.print("X");
}
}
dur2 = micros() - start;
Serial.print("DUR2: ");
Serial.println(dur2);
delay(10);
Serial.println("\nTEST: NN x setBlockVerify() not same data");
delay(10);
start = micros();
for (int i = 0; i < NN; i++)
{
if (ee.setBlockVerify(0, 1, 50) == false)
{
Serial.print("X");
}
}
dur2 = micros() - start;
Serial.print("DUR2: ");
Serial.println(dur2);
delay(10);
Serial.println("done...");
}
void loop()
{
}
// -- END OF FILE --
@@ -0,0 +1,43 @@
I2C_eeprom_verify\I2C_eeprom_verify.ino
VERSION: 1.6.1
TEST: 100x writeByte()
DUR1: 367668
TEST: 100x writeByteVerify()
DUR1: 442276
TEST: 100x updateByte() same data
DUR2: 58472
TEST: 100x updateByteVerify() same data
DUR2: 116464
TEST: 100x updateByteVerify() not same data
DUR2: 510476
TEST: 100x writeBlock()
DUR1: 1216296
TEST: 100x writeBlockVerify()
DUR1: 1814332
TEST: 100x updateBlock() same data
DUR2: 595220
TEST: 100x updateBlockVerify() same data
DUR2: 1190428
TEST: 100x updateBlockVerify() not same data
DUR2: 1205792
TEST: 100x setBlock() same data
DUR2: 1217796
TEST: 100x setBlockVerify() same data
DUR2: 1815424
TEST: 100x setBlockVerify() not same data
DUR2: 1812136
done...
@@ -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...
@@ -0,0 +1,101 @@
//
// FILE: I2C_eeprom_verifyBlock.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo I2C_EEPROM library
// URL: https://github.com/RobTillaart/I2C_EEPROM
//
// 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();
Serial.println(__FILE__);
Serial.print("I2C_EEPROM_VERSION: ");
Serial.println(I2C_EEPROM_VERSION);
Serial.println();
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 --
@@ -1,11 +1,14 @@
//
// FILE: I2C_small_eeprom_test.ino
// AUTHOR: Tyler Freeman
// VERSION: 0.1.1
// VERSION: 0.1.2
// PURPOSE: show/test I2C_EEPROM library with small EEPROMS
// URL: https://github.com/RobTillaart/I2C_EEPROM
// HISTORY
// 0.1.0 2014-05-xx initial version
// 0.1.1 2020-07-14 fix #1 compile for ESP; fix author
// 0.1.2 2025-08-27 add print filename and version number of library
#include <Wire.h>
#include <I2C_eeprom.h>
@@ -38,11 +41,12 @@
I2C_eeprom eeprom(DEVICEADDRESS, EE24LC01MAXBYTES);
void readAndWriteVar() {
SERIAL_DEBUG.println("----------------------------------------------");
void readAndWriteVar() {
SERIAL_DEBUG.println("----------------------------------------------");
SERIAL_DEBUG.print("SINGLE BYTE: writing and retreiving EEPROM on I2C at address ");
SERIAL_DEBUG.println(DEVICEADDRESS);
SERIAL_DEBUG.println("----------------------------------------------");
SERIAL_DEBUG.println("----------------------------------------------");
byte curval = eeprom.readByte(TEST_ADDR);
@@ -59,11 +63,11 @@ void readAndWriteVar() {
curval = eeprom.readByte(TEST_ADDR);
SERIAL_DEBUG.print("new value: ");
SERIAL_DEBUG.println(curval);
SERIAL_DEBUG.println(curval);
}
void readAndWritePage(unsigned int pageAddress, int bufferLen) {
void readAndWritePage(unsigned int pageAddress, int bufferLen) {
// always make the maximum size, just don't use all of it.
byte testBuffer[LONG_BUFFER_LEN + 1];
@@ -91,54 +95,61 @@ void readAndWritePage(unsigned int pageAddress, int bufferLen) {
eeprom.readBlock(pageAddress, testBuffer, bufferLen);
SERIAL_DEBUG.print("new value: ");
SERIAL_DEBUG.println((char*)testBuffer);
SERIAL_DEBUG.println((char*)testBuffer);
}
void setup()
{
SERIAL_DEBUG.begin(57600);
while (!SERIAL_DEBUG); // wait for SERIAL_DEBUG port to connect. Needed for Leonardo only
SERIAL_DEBUG.begin(57600);
while (!SERIAL_DEBUG); // wait for SERIAL_DEBUG port to connect. Needed for Leonardo only
SERIAL_DEBUG.println();
SERIAL_DEBUG.println(__FILE__);
SERIAL_DEBUG.print("I2C_EEPROM_VERSION: ");
SERIAL_DEBUG.println(I2C_EEPROM_VERSION);
SERIAL_DEBUG.println();
SERIAL_DEBUG.println("IT IS BEGINNING");
SERIAL_DEBUG.println("WAIT FOR IT");
Wire.begin();
SERIAL_DEBUG.println("IT IS BEGINNING");
SERIAL_DEBUG.println("WAIT FOR IT");
eeprom.begin();
readAndWriteVar();
SERIAL_DEBUG.println("----------------------------------------------");
SERIAL_DEBUG.println("PAGE:");
SERIAL_DEBUG.println("----------------------------------------------");
SERIAL_DEBUG.println("PAGE:");
SERIAL_DEBUG.print(" writing and retrieving EEPROM Page on I2C at address ");
SERIAL_DEBUG.println(DEVICEADDRESS);
SERIAL_DEBUG.println("----------------------------------------------");
SERIAL_DEBUG.println("----------------------------------------------");
readAndWritePage(TEST_PAGE_ADDR, SHORT_BUFFER_LEN);
SERIAL_DEBUG.println("----------------------------------------------");
SERIAL_DEBUG.println("MULTI-PAGE:");
SERIAL_DEBUG.println("----------------------------------------------");
SERIAL_DEBUG.println("MULTI-PAGE:");
SERIAL_DEBUG.print("writing and retrieving EEPROM Pages on I2C at address ");
SERIAL_DEBUG.println(DEVICEADDRESS);
SERIAL_DEBUG.println("----------------------------------------------");
SERIAL_DEBUG.println("----------------------------------------------");
readAndWritePage(LONG_TEST_PAGE_ADDR, LONG_BUFFER_LEN);
SERIAL_DEBUG.println("----------------------------------------------");
SERIAL_DEBUG.println("MULTI-PAGE UNALINGED: ");
SERIAL_DEBUG.println("----------------------------------------------");
SERIAL_DEBUG.println("MULTI-PAGE UNALINGED: ");
SERIAL_DEBUG.print("writing and retrieving EEPROM Pages on I2C at address ");
SERIAL_DEBUG.println(DEVICEADDRESS);
SERIAL_DEBUG.println("----------------------------------------------");
SERIAL_DEBUG.println("----------------------------------------------");
readAndWritePage(UNALIGNED_TEST_PAGE_ADDR, UNALIGNED_BUFFER_LEN);
SERIAL_DEBUG.println("\nDone...");
}
void loop()
{
// Nothing to do during loop
// Nothing to do during loop
}
+44 -6
View File
@@ -1,7 +1,7 @@
# Syntax Coloring Map For I2C_EEPROM
# Syntax Colouring Map For I2C_EEPROM
# Datatypes (KEYWORD1)
# Data types (KEYWORD1)
I2C_eeprom KEYWORD1
I2C_eeprom_cyclic_store KEYWORD1
@@ -13,17 +13,41 @@ isConnected KEYWORD2
# I2C_eeprom
readByte KEYWORD2
writeByte KEYWORD2
setBlock KEYWORD2
readBlock KEYWORD2
writeBlock KEYWORD2
determineSize KEYWORD2
setBlock KEYWORD2
readByte KEYWORD2
readBlock KEYWORD2
verifyBlock KEYWORD2
updateByte KEYWORD2
updateBlock KEYWORD2
writeByteVerify KEYWORD2
writeBlockVerify KEYWORD2
setBlockVerify KEYWORD2
updateByteVerify KEYWORD2
updateBlockVerify KEYWORD2
determineSize KEYWORD2
determineSizeNoWrite KEYWORD2
getDeviceSize KEYWORD2
getPageSize KEYWORD2
calculatePageSize KEYWORD2
getLastWrite KEYWORD2
setDeviceSize KEYWORD2
setExtraWriteCycleTime KEYWORD2
getExtraWriteCycleTime KEYWORD2
hasWriteProtectPin KEYWORD2
allowWrite KEYWORD2
preventWrite KEYWORD2
setAutoWriteProtect KEYWORD2
getAutoWriteProtect KEYWORD2
# I2C_eeprom_cyclic_store
format KEYWORD2
@@ -31,4 +55,18 @@ read KEYWORD2
write KEYWORD2
getMetrics KEYWORD2
# Constants (LITERAL1)
I2C_EEPROM_VERSION LITERAL1
I2C_DEVICESIZE_24LC512 LITERAL1
I2C_DEVICESIZE_24LC256 LITERAL1
I2C_DEVICESIZE_24LC128 LITERAL1
I2C_DEVICESIZE_24LC64 LITERAL1
I2C_DEVICESIZE_24LC32 LITERAL1
I2C_DEVICESIZE_24LC16 LITERAL1
I2C_DEVICESIZE_24LC08 LITERAL1
I2C_DEVICESIZE_24LC04 LITERAL1
I2C_DEVICESIZE_24LC02 LITERAL1
I2C_DEVICESIZE_24LC01 LITERAL1
+5 -3
View File
@@ -15,7 +15,9 @@
"type": "git",
"url": "https://github.com/RobTillaart/I2C_EEPROM.git"
},
"version":"1.4.3",
"frameworks": "arduino",
"platforms": "*"
"version": "1.9.4",
"license": "MIT",
"frameworks": "*",
"platforms": "*",
"headers": "I2C_eeprom.h"
}
+1 -1
View File
@@ -1,5 +1,5 @@
name=I2C_EEPROM
version=1.4.3
version=1.9.4
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Library for I2C EEPROMS
+107 -4
View File
@@ -38,36 +38,139 @@
unittest_setup()
{
fprintf(stderr, "I2C_EEPROM_VERSION: %s\n", ( char * ) I2C_EEPROM_VERSION);
}
unittest_teardown()
{
}
/*
unittest(test_new_operator)
{
assertEqualINF(exp(800));
assertEqualINF(0.0/0.0);
assertEqualINF(42);
assertEqualNAN(INFINITY - INFINITY);
assertEqualNAN(0.0/0.0);
assertEqualNAN(42);
}
*/
unittest(test_constructor)
{
Wire.resetMocks();
Wire.begin();
I2C_eeprom EE(0x50, 0x8000);
assertTrue(EE.begin());
assertTrue(EE.isConnected());
assertEqual(1, 1);
assertEqual(0, EE.getLastWrite());
assertEqual(64, EE.getPageSize());
}
unittest(test_constants)
{
Wire.resetMocks();
Wire.begin();
I2C_eeprom EE(0x50, 0x8000);
assertEqual(I2C_DEVICESIZE_24LC512, 65536);
assertEqual(I2C_DEVICESIZE_24LC256, 32768);
assertEqual(I2C_DEVICESIZE_24LC128, 16384);
assertEqual(I2C_DEVICESIZE_24LC64, 8192);
assertEqual(I2C_DEVICESIZE_24LC32, 4096);
assertEqual(I2C_DEVICESIZE_24LC16, 2048);
assertEqual(I2C_DEVICESIZE_24LC08, 1024);
assertEqual(I2C_DEVICESIZE_24LC04, 512);
assertEqual(I2C_DEVICESIZE_24LC02, 256);
assertEqual(I2C_DEVICESIZE_24LC01, 128);
}
unittest(test_getPageSize)
{
Wire.resetMocks();
Wire.begin();
I2C_eeprom EE(0x50, 0x8000);
assertEqual(EE.getPageSize(I2C_DEVICESIZE_24LC512), 128);
assertEqual(EE.getPageSize(I2C_DEVICESIZE_24LC256), 64);
assertEqual(EE.getPageSize(I2C_DEVICESIZE_24LC128), 64);
assertEqual(EE.getPageSize(I2C_DEVICESIZE_24LC64), 32);
assertEqual(EE.getPageSize(I2C_DEVICESIZE_24LC32), 32);
assertEqual(EE.getPageSize(I2C_DEVICESIZE_24LC16), 16);
assertEqual(EE.getPageSize(I2C_DEVICESIZE_24LC08), 16);
assertEqual(EE.getPageSize(I2C_DEVICESIZE_24LC04), 16);
assertEqual(EE.getPageSize(I2C_DEVICESIZE_24LC02), 8);
assertEqual(EE.getPageSize(I2C_DEVICESIZE_24LC01), 8);
I2C_eeprom prom(0x50, 0x8123);
assertEqual(prom.getDeviceSize(), 0x8000);
assertEqual(prom.getPageSize(), 64);
}
unittest(test_setDeviceSize)
{
Wire.resetMocks();
Wire.begin();
I2C_eeprom EE(0x50, 0x8000);
assertEqual(EE.setDeviceSize(I2C_DEVICESIZE_24LC512), I2C_DEVICESIZE_24LC512);
assertEqual(EE.setDeviceSize(I2C_DEVICESIZE_24LC256), I2C_DEVICESIZE_24LC256);
assertEqual(EE.setDeviceSize(I2C_DEVICESIZE_24LC128), I2C_DEVICESIZE_24LC128);
assertEqual(EE.setDeviceSize(I2C_DEVICESIZE_24LC64), I2C_DEVICESIZE_24LC64);
assertEqual(EE.setDeviceSize(I2C_DEVICESIZE_24LC32), I2C_DEVICESIZE_24LC32);
assertEqual(EE.setDeviceSize(I2C_DEVICESIZE_24LC16), I2C_DEVICESIZE_24LC16);
assertEqual(EE.setDeviceSize(I2C_DEVICESIZE_24LC08), I2C_DEVICESIZE_24LC08);
assertEqual(EE.setDeviceSize(I2C_DEVICESIZE_24LC04), I2C_DEVICESIZE_24LC04);
assertEqual(EE.setDeviceSize(I2C_DEVICESIZE_24LC02), I2C_DEVICESIZE_24LC02);
assertEqual(EE.setDeviceSize(I2C_DEVICESIZE_24LC01), I2C_DEVICESIZE_24LC01);
assertEqual(EE.setDeviceSize(I2C_DEVICESIZE_24LC512 + 1), I2C_DEVICESIZE_24LC512);
assertEqual(EE.setDeviceSize(I2C_DEVICESIZE_24LC256 + 1), I2C_DEVICESIZE_24LC256);
assertEqual(EE.setDeviceSize(I2C_DEVICESIZE_24LC128 + 1), I2C_DEVICESIZE_24LC128);
assertEqual(EE.setDeviceSize(I2C_DEVICESIZE_24LC64 + 1), I2C_DEVICESIZE_24LC64);
assertEqual(EE.setDeviceSize(I2C_DEVICESIZE_24LC32 + 1), I2C_DEVICESIZE_24LC32);
assertEqual(EE.setDeviceSize(I2C_DEVICESIZE_24LC16 + 1), I2C_DEVICESIZE_24LC16);
assertEqual(EE.setDeviceSize(I2C_DEVICESIZE_24LC08 + 1), I2C_DEVICESIZE_24LC08);
assertEqual(EE.setDeviceSize(I2C_DEVICESIZE_24LC04 + 1), I2C_DEVICESIZE_24LC04);
assertEqual(EE.setDeviceSize(I2C_DEVICESIZE_24LC02 + 1), I2C_DEVICESIZE_24LC02);
assertEqual(EE.setDeviceSize(I2C_DEVICESIZE_24LC01 + 1), I2C_DEVICESIZE_24LC01);
}
unittest(test_setPageSize)
{
Wire.resetMocks();
Wire.begin();
I2C_eeprom EE(0x50, 0x8000);
assertEqual(EE.setPageSize(129), 128);
assertEqual(EE.setPageSize(128), 128);
assertEqual(EE.setPageSize(127), 64);
assertEqual(EE.setPageSize(65), 64);
assertEqual(EE.setPageSize(64), 64);
assertEqual(EE.setPageSize(63), 32);
assertEqual(EE.setPageSize(33), 32);
assertEqual(EE.setPageSize(32), 32);
assertEqual(EE.setPageSize(31), 16);
assertEqual(EE.setPageSize(17), 16);
assertEqual(EE.setPageSize(16), 16);
assertEqual(EE.setPageSize(9), 8);
assertEqual(EE.setPageSize(8), 8);
}
unittest_main()
// --------
// -- END OF FILE --
+34 -14
View File
@@ -9,12 +9,12 @@
// Note: The implementation of the I2C_eeprom_cyclic_store should have been
// made injactable so that a mock or fake for I2C_eeprom could have been used
// instead of having to rely on a test implementation of the Wire singleton.
//
//
// This could have been done by changing the class to take two template
// parameters, the first being one for I2C_eeprom or it's mock and the second
// being the data type to store. For simplicity an alias could have been
// introduced so that users wouldn't have to specify I2C_eeprom but that made
// the editor lose track of the intellisense comments. :-/
// the editor lose track of the intellisense comments. :-/
//
// Thus this remains until someone comes up with a brighter idea.
@@ -40,12 +40,13 @@ unittest_teardown()
}
/**
* Verify that I2C_eeprom_cyclic_store fails to
* Verify that I2C_eeprom_cyclic_store fails to
* initialize when unable to read from eeprom.
*/
unittest(cyclic_store_fails_begin)
{
Wire.resetMocks();
Wire.begin();
auto mosi = Wire.getMosi(I2C_EEPROM_ADDR);
@@ -57,18 +58,19 @@ unittest(cyclic_store_fails_begin)
}
/**
* Verify that I2C_eeprom_cyclic_store successfully
* Verify that I2C_eeprom_cyclic_store successfully
* initializes on empty eeprom.
*/
unittest(cyclic_store_empty_begin)
{
Wire.resetMocks();
Wire.begin();
auto mosi = Wire.getMosi(I2C_EEPROM_ADDR);
I2C_eeprom EE(I2C_EEPROM_ADDR, I2C_EEPROM_SIZE);
EE.begin();
auto miso = Wire.getMiso(I2C_EEPROM_ADDR);
miso->push_back(0xff);
miso->push_back(0xff);
@@ -87,6 +89,7 @@ unittest(cyclic_store_empty_begin)
unittest(cyclic_store_double_page_buffer)
{
Wire.resetMocks();
Wire.begin();
auto mosi = Wire.getMosi(I2C_EEPROM_ADDR);
@@ -100,13 +103,12 @@ unittest(cyclic_store_double_page_buffer)
miso->push_back(0xff);
I2C_eeprom_cyclic_store<uint8_t[40]> CS;
assertEqual(true, CS.begin(EE, 32, 4));
assertTrue(CS.begin(EE, 32, 4));
uint16_t slots;
uint32_t writes;
CS.getMetrics(slots, writes);
assertTrue(CS.getMetrics(slots, writes));
assertEqual(2, slots);
assertEqual(0, writes);
}
@@ -118,6 +120,7 @@ unittest(cyclic_store_double_page_buffer)
unittest(cyclic_store_finds_single_stored_version)
{
Wire.resetMocks();
Wire.begin();
auto mosi = Wire.getMosi(I2C_EEPROM_ADDR);
@@ -156,6 +159,7 @@ unittest(cyclic_store_finds_single_stored_version)
unittest(cyclic_store_finds_last_half_filled_eeprom)
{
Wire.resetMocks();
Wire.begin();
auto mosi = Wire.getMosi(I2C_EEPROM_ADDR);
@@ -206,6 +210,7 @@ unittest(cyclic_store_finds_last_half_filled_eeprom)
unittest(cyclic_store_finds_version_if_last_slot)
{
Wire.resetMocks();
Wire.begin();
auto mosi = Wire.getMosi(I2C_EEPROM_ADDR);
@@ -257,6 +262,7 @@ unittest(cyclic_store_finds_version_if_last_slot)
unittest(cyclic_store_finds_last_wrapped_eeprom)
{
Wire.resetMocks();
Wire.begin();
auto mosi = Wire.getMosi(I2C_EEPROM_ADDR);
@@ -305,12 +311,13 @@ unittest(cyclic_store_finds_last_wrapped_eeprom)
* Verify that I2C_eeprom_cyclic_store successfully finds the last
* entry after writes have wrapped around the end of the eeprom
* when using a buffer that spans two pages. And that it does so
* even if the number of pages is not evenly divisable by the
* even if the number of pages is not evenly divisable by the
* number of pages the buffer span.
*/
unittest(cyclic_store_finds_last_wrapped_eeprom_double_page_buffer)
{
Wire.resetMocks();
Wire.begin();
auto mosi = Wire.getMosi(I2C_EEPROM_ADDR);
@@ -362,6 +369,7 @@ unittest(cyclic_store_finds_last_wrapped_eeprom_double_page_buffer)
unittest(cyclic_store_fails_init_on_too_large_buffer)
{
Wire.resetMocks();
Wire.begin();
I2C_eeprom EE(I2C_EEPROM_ADDR, I2C_EEPROM_SIZE);
EE.begin();
@@ -377,6 +385,7 @@ unittest(cyclic_store_fails_init_on_too_large_buffer)
unittest(cyclic_store_empty_metrics)
{
Wire.resetMocks();
Wire.begin();
auto mosi = Wire.getMosi(I2C_EEPROM_ADDR);
@@ -408,6 +417,7 @@ unittest(cyclic_store_empty_metrics)
unittest(cyclic_store_fails_metrics_when_failed_initialize)
{
Wire.resetMocks();
Wire.begin();
I2C_eeprom EE(I2C_EEPROM_ADDR, I2C_EEPROM_SIZE);
EE.begin();
@@ -428,6 +438,7 @@ unittest(cyclic_store_fails_metrics_when_failed_initialize)
unittest(cyclic_store_fails_metrics_when_not_initialized)
{
Wire.resetMocks();
Wire.begin();
I2C_eeprom EE(I2C_EEPROM_ADDR, I2C_EEPROM_SIZE);
EE.begin();
@@ -441,13 +452,14 @@ unittest(cyclic_store_fails_metrics_when_not_initialized)
}
/**
* Verify that I2C_eeprom_cyclic_store correctly
* Verify that I2C_eeprom_cyclic_store correctly
* increments the number of writes when saving
* new versions.
*/
unittest(cyclic_store_increments_write_counter)
{
Wire.resetMocks();
Wire.begin();
auto mosi = Wire.getMosi(I2C_EEPROM_ADDR);
@@ -490,6 +502,7 @@ unittest(cyclic_store_increments_write_counter)
unittest(cyclic_store_format_single_page)
{
Wire.resetMocks();
Wire.begin();
auto mosi = Wire.getMosi(I2C_EEPROM_ADDR);
@@ -523,6 +536,7 @@ unittest(cyclic_store_format_single_page)
unittest(cyclic_store_format_double_page)
{
Wire.resetMocks();
Wire.begin();
auto mosi = Wire.getMosi(I2C_EEPROM_ADDR);
@@ -557,6 +571,7 @@ unittest(cyclic_store_format_double_page)
unittest(cyclic_store_format_double_page_odd_space)
{
Wire.resetMocks();
Wire.begin();
auto mosi = Wire.getMosi(I2C_EEPROM_ADDR);
@@ -591,12 +606,13 @@ unittest(cyclic_store_format_double_page_odd_space)
unittest(cyclic_store_wrapping_single_page)
{
Wire.resetMocks();
Wire.begin();
auto mosi = Wire.getMosi(I2C_EEPROM_ADDR);
I2C_eeprom EE(I2C_EEPROM_ADDR, I2C_EEPROM_SIZE);
EE.begin();
auto miso = Wire.getMiso(I2C_EEPROM_ADDR);
miso->push_back(0xff);
miso->push_back(0xff);
@@ -636,12 +652,13 @@ unittest(cyclic_store_wrapping_single_page)
unittest(cyclic_store_wrapping_double_page)
{
Wire.resetMocks();
Wire.begin();
auto mosi = Wire.getMosi(I2C_EEPROM_ADDR);
I2C_eeprom EE(I2C_EEPROM_ADDR, I2C_EEPROM_SIZE);
EE.begin();
auto miso = Wire.getMiso(I2C_EEPROM_ADDR);
miso->push_back(0xff);
miso->push_back(0xff);
@@ -678,12 +695,13 @@ unittest(cyclic_store_wrapping_double_page)
unittest(cyclic_store_wrapping_double_page_odd_space)
{
Wire.resetMocks();
Wire.begin();
auto mosi = Wire.getMosi(I2C_EEPROM_ADDR);
I2C_eeprom EE(I2C_EEPROM_ADDR, I2C_EEPROM_SIZE);
EE.begin();
auto miso = Wire.getMiso(I2C_EEPROM_ADDR);
miso->push_back(0xff);
miso->push_back(0xff);
@@ -714,4 +732,6 @@ unittest(cyclic_store_wrapping_double_page_odd_space)
unittest_main()
// --------
// -- END OF FILE --
+28 -2
View File
@@ -8,6 +8,7 @@
// https://github.com/Arduino-CI/arduino_ci/blob/master/REFERENCE.md
//
#include <ArduinoUnitTests.h>
#include "Arduino.h"
@@ -17,6 +18,7 @@ class I2C_eeprom_wrapper;
#include "I2C_eeprom.h"
class I2C_eeprom_wrapper {
public:
static uint8_t pageSize(I2C_eeprom &eeprom) { return eeprom._pageSize; }
@@ -25,6 +27,7 @@ class I2C_eeprom_wrapper {
#define I2C_EEPROM_ADDR 0x50
unittest_setup()
{
}
@@ -33,14 +36,16 @@ unittest_teardown()
{
}
/**
* Verify that an instance gets the default page size
* when the constructor without device size is used.
* The expected outcome is I2C_EEPROM_PAGESIZE
* The expected outcome is I2C_EEPROM_PAGESIZE
*/
unittest(i2c_eeprom_default_page_size)
{
Wire.resetMocks();
Wire.begin();
I2C_eeprom eeprom(I2C_EEPROM_ADDR);
@@ -49,6 +54,7 @@ unittest(i2c_eeprom_default_page_size)
// assertEqual(false, I2C_eeprom_wrapper::isAddressSizeTwoWords(eeprom));
}
/**
* Verify that the constructor calculates the correct
* page size and addressing for a 1K eeprom (e g AT24C01).
@@ -56,6 +62,7 @@ unittest(i2c_eeprom_default_page_size)
unittest(i2c_eeprom_1k_page_size)
{
Wire.resetMocks();
Wire.begin();
I2C_eeprom eeprom(I2C_EEPROM_ADDR, 0x80);
@@ -63,6 +70,7 @@ unittest(i2c_eeprom_1k_page_size)
assertEqual(false, I2C_eeprom_wrapper::isAddressSizeTwoWords(eeprom));
}
/**
* Verify that the constructor calculates the correct
* page size and addressing for a 2K eeprom (e g AT24C02).
@@ -70,6 +78,7 @@ unittest(i2c_eeprom_1k_page_size)
unittest(i2c_eeprom_2k_page_size)
{
Wire.resetMocks();
Wire.begin();
I2C_eeprom eeprom(I2C_EEPROM_ADDR, 0x100);
@@ -77,6 +86,7 @@ unittest(i2c_eeprom_2k_page_size)
assertEqual(false, I2C_eeprom_wrapper::isAddressSizeTwoWords(eeprom));
}
/**
* Verify that the constructor calculates the correct
* page size and addressing for a 4K eeprom (e g AT24C04).
@@ -84,6 +94,7 @@ unittest(i2c_eeprom_2k_page_size)
unittest(i2c_eeprom_4k_page_size)
{
Wire.resetMocks();
Wire.begin();
I2C_eeprom eeprom(I2C_EEPROM_ADDR, 0x200);
@@ -91,6 +102,7 @@ unittest(i2c_eeprom_4k_page_size)
assertEqual(false, I2C_eeprom_wrapper::isAddressSizeTwoWords(eeprom));
}
/**
* Verify that the constructor calculates the correct
* page size and addressing for a 8K eeprom (e g AT24C08).
@@ -98,6 +110,7 @@ unittest(i2c_eeprom_4k_page_size)
unittest(i2c_eeprom_8k_page_size)
{
Wire.resetMocks();
Wire.begin();
I2C_eeprom eeprom(I2C_EEPROM_ADDR, 0x400);
@@ -105,6 +118,7 @@ unittest(i2c_eeprom_8k_page_size)
assertEqual(false, I2C_eeprom_wrapper::isAddressSizeTwoWords(eeprom));
}
/**
* Verify that the constructor calculates the correct
* page size and addressing for a 16K eeprom (e g AT24C16).
@@ -112,6 +126,7 @@ unittest(i2c_eeprom_8k_page_size)
unittest(i2c_eeprom_16k_page_size)
{
Wire.resetMocks();
Wire.begin();
I2C_eeprom eeprom(I2C_EEPROM_ADDR, 0x800);
@@ -119,6 +134,7 @@ unittest(i2c_eeprom_16k_page_size)
assertEqual(false, I2C_eeprom_wrapper::isAddressSizeTwoWords(eeprom));
}
/**
* Verify that the constructor calculates the correct
* page size and addressing for a 32K eeprom (e g AT24C32).
@@ -126,6 +142,7 @@ unittest(i2c_eeprom_16k_page_size)
unittest(i2c_eeprom_32k_page_size)
{
Wire.resetMocks();
Wire.begin();
I2C_eeprom eeprom(I2C_EEPROM_ADDR, 0x1000);
@@ -133,6 +150,7 @@ unittest(i2c_eeprom_32k_page_size)
assertEqual(true, I2C_eeprom_wrapper::isAddressSizeTwoWords(eeprom));
}
/**
* Verify that the constructor calculates the correct
* page size and addressing for a 64K eeprom (e g AT24C64).
@@ -140,6 +158,7 @@ unittest(i2c_eeprom_32k_page_size)
unittest(i2c_eeprom_64k_page_size)
{
Wire.resetMocks();
Wire.begin();
I2C_eeprom eeprom(I2C_EEPROM_ADDR, 0x2000);
@@ -147,6 +166,7 @@ unittest(i2c_eeprom_64k_page_size)
assertEqual(true, I2C_eeprom_wrapper::isAddressSizeTwoWords(eeprom));
}
/**
* Verify that the constructor calculates the correct
* page size and addressing for a 128K eeprom (e g AT24C128).
@@ -154,6 +174,7 @@ unittest(i2c_eeprom_64k_page_size)
unittest(i2c_eeprom_128k_page_size)
{
Wire.resetMocks();
Wire.begin();
I2C_eeprom eeprom(I2C_EEPROM_ADDR, 0x4000);
@@ -161,6 +182,7 @@ unittest(i2c_eeprom_128k_page_size)
assertEqual(true, I2C_eeprom_wrapper::isAddressSizeTwoWords(eeprom));
}
/**
* Verify that the constructor calculates the correct
* page size and addressing for a 256K eeprom (e g AT24C256).
@@ -168,6 +190,7 @@ unittest(i2c_eeprom_128k_page_size)
unittest(i2c_eeprom_256k_page_size)
{
Wire.resetMocks();
Wire.begin();
I2C_eeprom eeprom(I2C_EEPROM_ADDR, 0x8000);
@@ -175,6 +198,9 @@ unittest(i2c_eeprom_256k_page_size)
assertEqual(true, I2C_eeprom_wrapper::isAddressSizeTwoWords(eeprom));
}
unittest_main()
// ------------------
// -- END OF FILE --