diff --git a/libraries/I2C_EEPROM/CHANGELOG.md b/libraries/I2C_EEPROM/CHANGELOG.md index 5f759ee2..1602ed21 100644 --- a/libraries/I2C_EEPROM/CHANGELOG.md +++ b/libraries/I2C_EEPROM/CHANGELOG.md @@ -6,13 +6,25 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [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 diff --git a/libraries/I2C_EEPROM/I2C_eeprom.cpp b/libraries/I2C_EEPROM/I2C_eeprom.cpp index 985231f9..7b98dd52 100644 --- a/libraries/I2C_EEPROM/I2C_eeprom.cpp +++ b/libraries/I2C_EEPROM/I2C_eeprom.cpp @@ -1,7 +1,7 @@ // // FILE: I2C_eeprom.cpp // AUTHOR: Rob Tillaart -// VERSION: 1.7.3 +// VERSION: 1.7.4 // PURPOSE: Arduino Library for external I2C EEPROM 24LC256 et al. // URL: https://github.com/RobTillaart/I2C_EEPROM.git @@ -55,7 +55,7 @@ I2C_eeprom::I2C_eeprom(const uint8_t deviceAddress, const uint32_t deviceSize, T #if defined(ESP8266) || defined(ESP32) -bool I2C_eeprom::begin(uint8_t sda, uint8_t scl) +bool I2C_eeprom::begin(uint8_t sda, uint8_t scl, int8_t writeProtectPin) { // if (_wire == 0) Serial.println("zero"); // test #48 if ((sda < 255) && (scl < 255)) @@ -67,12 +67,18 @@ bool I2C_eeprom::begin(uint8_t sda, uint8_t scl) _wire->begin(); } _lastWrite = 0; + _writeProtectPin = writeProtectPin; + if (_writeProtectPin >= 0) + { + pinMode(_writeProtectPin, OUTPUT); + preventWrite(); + } return isConnected(); } #elif defined(ARDUINO_ARCH_RP2040) && !defined(__MBED__) -bool I2C_eeprom::begin(uint8_t sda, uint8_t scl) +bool I2C_eeprom::begin(uint8_t sda, uint8_t scl, int8_t writeProtectPin) { if ((sda < 255) && (scl < 255)) { @@ -81,17 +87,29 @@ bool I2C_eeprom::begin(uint8_t sda, uint8_t scl) _wire->begin(); } _lastWrite = 0; + _writeProtectPin = writeProtectPin; + if (_writeProtectPin >= 0) + { + pinMode(_writeProtectPin, OUTPUT); + preventWrite(); + } return isConnected(); } #endif -bool I2C_eeprom::begin() +bool I2C_eeprom::begin(int8_t writeProtectPin) { // if (_wire == 0) Serial.println("zero"); // test #48 _wire->begin(); _lastWrite = 0; + _writeProtectPin = writeProtectPin; + if (_writeProtectPin >= 0) + { + pinMode(_writeProtectPin, OUTPUT); + preventWrite(); + } return isConnected(); } @@ -399,6 +417,47 @@ uint8_t I2C_eeprom::getExtraWriteCycleTime() } +// +// 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; +} + //////////////////////////////////////////////////////////////////// // @@ -457,10 +516,20 @@ void I2C_eeprom::_beginTransmission(const uint16_t memoryAddress) int I2C_eeprom::_WriteBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint8_t length) { _waitEEReady(); + if (_autoWriteProtect) + { + digitalWrite(_writeProtectPin, LOW); + } this->_beginTransmission(memoryAddress); _wire->write(buffer, length); int rv = _wire->endTransmission(); + + if (_autoWriteProtect) + { + digitalWrite(_writeProtectPin, HIGH); + } + _lastWrite = micros(); yield(); // For OS scheduling @@ -529,9 +598,11 @@ void I2C_eeprom::_waitEEReady() uint32_t waitTime = I2C_WRITEDELAY + _extraTWR * 1000UL; while ((micros() - _lastWrite) <= waitTime) { - _wire->beginTransmission(_deviceAddress); - int x = _wire->endTransmission(); - if (x == 0) return; + 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; diff --git a/libraries/I2C_EEPROM/I2C_eeprom.h b/libraries/I2C_EEPROM/I2C_eeprom.h index bb794326..f8914f67 100644 --- a/libraries/I2C_EEPROM/I2C_eeprom.h +++ b/libraries/I2C_EEPROM/I2C_eeprom.h @@ -2,7 +2,7 @@ // // FILE: I2C_eeprom.h // AUTHOR: Rob Tillaart -// VERSION: 1.7.3 +// VERSION: 1.7.4 // PURPOSE: Arduino Library for external I2C EEPROM 24LC256 et al. // URL: https://github.com/RobTillaart/I2C_EEPROM.git @@ -11,7 +11,7 @@ #include "Wire.h" -#define I2C_EEPROM_VERSION (F("1.7.3")) +#define I2C_EEPROM_VERSION (F("1.7.4")) #define I2C_DEVICESIZE_24LC512 65536 @@ -63,10 +63,10 @@ public: // MBED test ==> see #55, #53 #if defined(ESP8266) || defined(ESP32) || (defined(ARDUINO_ARCH_RP2040) && !defined(__MBED__)) // set the I2C pins explicitly (overrule) - bool begin(uint8_t sda, uint8_t scl); + bool begin(uint8_t sda, uint8_t scl, int8_t writeProtectPin = -1); #endif // use default I2C pins. - bool begin(); + bool begin(int8_t writeProtectPin = -1); bool isConnected(); @@ -127,6 +127,16 @@ public: 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 = 0; // for waitEEReady @@ -134,6 +144,7 @@ private: 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 bool _isAddressSizeTwoWords; @@ -154,6 +165,9 @@ private: bool _debug = false; + int8_t _writeProtectPin = -1; + bool _autoWriteProtect = false; + UNIT_TEST_FRIEND; }; diff --git a/libraries/I2C_EEPROM/keywords.txt b/libraries/I2C_EEPROM/keywords.txt index 9a84930d..4dbd71fc 100644 --- a/libraries/I2C_EEPROM/keywords.txt +++ b/libraries/I2C_EEPROM/keywords.txt @@ -37,6 +37,13 @@ getLastWrite KEYWORD2 setExtraWriteCycleTime KEYWORD2 getExtraWriteCycleTime KEYWORD2 +hasWriteProtectPin KEYWORD2 +allowWrite KEYWORD2 +preventWrite KEYWORD2 +setAutoWriteProtect KEYWORD2 +getAutoWriteProtect KEYWORD2 + + # I2C_eeprom_cyclic_store format KEYWORD2 read KEYWORD2 diff --git a/libraries/I2C_EEPROM/library.json b/libraries/I2C_EEPROM/library.json index 9a853065..34ce9098 100644 --- a/libraries/I2C_EEPROM/library.json +++ b/libraries/I2C_EEPROM/library.json @@ -15,9 +15,9 @@ "type": "git", "url": "https://github.com/RobTillaart/I2C_EEPROM.git" }, - "version": "1.7.3", + "version": "1.7.4", "license": "MIT", - "frameworks": "arduino", + "frameworks": "*", "platforms": "*", "headers": "I2C_eeprom.h" } diff --git a/libraries/I2C_EEPROM/library.properties b/libraries/I2C_EEPROM/library.properties index 45c9250a..8797c4a3 100644 --- a/libraries/I2C_EEPROM/library.properties +++ b/libraries/I2C_EEPROM/library.properties @@ -1,5 +1,5 @@ name=I2C_EEPROM -version=1.7.3 +version=1.7.4 author=Rob Tillaart maintainer=Rob Tillaart sentence=Library for I2C EEPROMS diff --git a/libraries/I2C_EEPROM/readme.md b/libraries/I2C_EEPROM/readme.md index b3ff6c24..4cd233f7 100644 --- a/libraries/I2C_EEPROM/readme.md +++ b/libraries/I2C_EEPROM/readme.md @@ -2,8 +2,12 @@ [![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 @@ -67,13 +71,17 @@ Most important difference is 32 bit memory addresses. 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 with the default pins. +- **bool begin(uint8_t writeProtectPin = -1)** initializes the I2C bus with the default pins. Furthermore it checks if the deviceAddress is available on the I2C bus. Returns true if deviceAddress is found on the bus, false otherwise. -- **bool begin(uint8_t sda, uint8_t scl)** for ESP32 / ESP8266 / RP2040 and alike. +Optionally one can set the **WP** writeProtect pin. (see section below). +If the **WP** pin is defined the default will be to **not** allow writing. +- **bool begin(uint8_t sda, uint8_t scl, uint8_t writeProtectPin = -1)** for ESP32 / ESP8266 / RP2040 and alike. Initializes the I2C bus with the specified pins, thereby overruling the default pins. Furthermore it checks if the deviceAddress is available on the I2C bus. Returns true if deviceAddress is found on the bus, false otherwise. +Optionally one can set the **WP** writeProtect pin. (see section below). +If the **WP** pin is defined the default will be to **not** allow writing. - **bool isConnected()** test to see if deviceAddress is found on the bus. @@ -162,7 +170,7 @@ returns set size == 128, 256, ... 32768, 65536 returns set size == 8, 16, 32, 64, 128. -#### UpdateBlock() +### UpdateBlock() (new since 1.4.2) @@ -177,7 +185,7 @@ If data is changed often between writes, **updateBlock()** is slower than **writ So you should verify if your sketch can make use of the advantages of **updateBlock()** -#### ExtraWriteCycleTime (experimental) +### 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 @@ -191,6 +199,36 @@ Since 1.7.2 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. @@ -220,10 +258,20 @@ See examples - investigate smarter strategy for **updateBlock()** => find first and last changed position could possibly result in less writes. - can **setBlock()** use strategies from **updateBlock()** -- **\_waitEEReady();** can return bool and could use isConnected() internally. - - added value? + + +#### Wont + - investigate the print interface? - circular buffer? (see FRAM library) - dump function? -#### Wont + +## Support + +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, +