diff --git a/libraries/I2C_24LC1025/CHANGELOG..md b/libraries/I2C_24LC1025/CHANGELOG..md index 56768aede..a1096f630 100644 --- a/libraries/I2C_24LC1025/CHANGELOG..md +++ b/libraries/I2C_24LC1025/CHANGELOG..md @@ -5,11 +5,23 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [0.2.5] - 2023-09-09 +- Sync I2C_EEPROM +- 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 + + ## [0.2.4] - 2023-05-11 - redo support for RP2040 - see issue #53 / #55 I2C_EEPROM - ## [0.2.3] - 2023-05-02 - improve support for RP2040 - move code from .h to .cpp diff --git a/libraries/I2C_24LC1025/I2C_24LC1025.cpp b/libraries/I2C_24LC1025/I2C_24LC1025.cpp index d74a90068..a474549fa 100644 --- a/libraries/I2C_24LC1025/I2C_24LC1025.cpp +++ b/libraries/I2C_24LC1025/I2C_24LC1025.cpp @@ -1,7 +1,7 @@ // // FILE: I2C_24LC1025.cpp // AUTHOR: Rob Tillaart -// VERSION: 0.2.4 +// VERSION: 0.2.5 // PURPOSE: I2C_24LC1025 library for Arduino with EEPROM I2C_24LC1025 et al. // URL: https://github.com/RobTillaart/I2C_24LC1025 @@ -33,7 +33,7 @@ I2C_24LC1025::I2C_24LC1025(uint8_t deviceAddress, TwoWire * wire) #if defined(ESP8266) || defined(ESP32) -bool I2C_24LC1025::begin(uint8_t sda, uint8_t scl) +bool I2C_24LC1025::begin(uint8_t sda, uint8_t scl, int8_t writeProtectPin) { if ((sda < 255) && (scl < 255)) { @@ -44,12 +44,18 @@ bool I2C_24LC1025::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_24LC1025::begin(uint8_t sda, uint8_t scl) +bool I2C_24LC1025::begin(uint8_t sda, uint8_t scl, int8_t writeProtectPin) { if ((sda < 255) && (scl < 255)) { @@ -58,15 +64,28 @@ bool I2C_24LC1025::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_24LC1025::begin() +bool I2C_24LC1025::begin(int8_t writeProtectPin) { _wire->begin(); _lastWrite = 0; + _writeProtectPin = writeProtectPin; + if (_writeProtectPin >= 0) + { + pinMode(_writeProtectPin, OUTPUT); + preventWrite(); + } return isConnected(); } @@ -149,7 +168,6 @@ uint32_t I2C_24LC1025::readBlock(const uint32_t memoryAddress, uint8_t * buffer, addr += cnt; buffer += cnt; len -= cnt; - yield(); // For OS scheduling } return rv; } @@ -188,7 +206,6 @@ uint32_t I2C_24LC1025::updateBlock(const uint32_t memoryAddress, const uint8_t * addr += cnt; buffer += cnt; len -= cnt; - yield(); // For OS scheduling } return rv; } @@ -251,7 +268,7 @@ bool I2C_24LC1025::updateBlockVerify(const uint32_t memoryAddress, const uint8_t } -//////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////// // // METADATA SECTION // @@ -285,10 +302,51 @@ uint8_t I2C_24LC1025::getExtraWriteCycleTime() } +// +// WRITEPROTECT +// +bool I2C_24LC1025::hasWriteProtectPin() +{ + return (_writeProtectPin >= 0); +} + + +void I2C_24LC1025::allowWrite() +{ + if (hasWriteProtectPin()) + { + digitalWrite(_writeProtectPin, LOW); + } +} + + +void I2C_24LC1025::preventWrite() +{ + if (hasWriteProtectPin()) + { + digitalWrite(_writeProtectPin, HIGH); + } +} + + +void I2C_24LC1025::setAutoWriteProtect(bool b) +{ + if (hasWriteProtectPin()) + { + _autoWriteProtect = b; + } +} + + +bool I2C_24LC1025::getAutoWriteProtect() +{ + return _autoWriteProtect; +} + //////////////////////////////////////////////////////////////////// // -// PRIVATE +// PRIVATE // // _pageBlock aligns buffer to page boundaries for writing. @@ -348,13 +406,23 @@ void I2C_24LC1025::_beginTransmission(uint32_t memoryAddress) int I2C_24LC1025::_WriteBlock(uint32_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(); + yield(); // For OS scheduling // if (rv != 0) // { @@ -389,16 +457,16 @@ uint8_t I2C_24LC1025::_ReadBlock(uint32_t memoryAddress, uint8_t * buffer, const // Serial.print("\t"); // Serial.println(rv); // } - return 0; // error + return 0; // error } // readBytes will always be equal or smaller to length uint8_t readBytes = _wire->requestFrom(_actualAddress, length); + yield(); // For OS scheduling uint8_t cnt = 0; while (cnt < readBytes) { buffer[cnt++] = _wire->read(); - yield(); } return readBytes; } @@ -412,14 +480,16 @@ void I2C_24LC1025::_waitEEReady() 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 previous code + // _wire->beginTransmission(_deviceAddress); + // int x = _wire->endTransmission(); + // if (x == 0) return; + yield(); // For OS scheduling } return; } -// -- END OF FILE -- +// -- END OF FILE -- diff --git a/libraries/I2C_24LC1025/I2C_24LC1025.h b/libraries/I2C_24LC1025/I2C_24LC1025.h index 88d5375dc..e66d5ac38 100644 --- a/libraries/I2C_24LC1025/I2C_24LC1025.h +++ b/libraries/I2C_24LC1025/I2C_24LC1025.h @@ -2,7 +2,7 @@ // // FILE: I2C_24LC1025.h // AUTHOR: Rob Tillaart -// VERSION: 0.2.4 +// VERSION: 0.2.5 // PURPOSE: I2C_24LC1025 library for Arduino with EEPROM 24LC1025 et al. // URL: https://github.com/RobTillaart/I2C_24LC1025 @@ -11,7 +11,7 @@ #include "Wire.h" -#define I2C_24LC1025_VERSION (F("0.2.4")) +#define I2C_24LC1025_VERSION (F("0.2.5")) #define I2C_DEVICESIZE_24LC1025 131072 @@ -20,6 +20,7 @@ // to adjust low level timing (use with care) // can also be done on command line. +// (see private _waitEEReady() function) #ifndef I2C_WRITEDELAY #define I2C_WRITEDELAY 5000 #endif @@ -34,28 +35,30 @@ class I2C_24LC1025 // MBED test ==> see #55, #53 I2C_EEPROM #if defined(ESP8266) || defined(ESP32) || (defined(ARDUINO_ARCH_RP2040) && !defined(__MBED__)) - bool begin(uint8_t sda, uint8_t scl); + // set the I2C pins explicitly (overrule) + bool begin(uint8_t sda, uint8_t scl, int8_t writeProtectPin = -1); #endif - bool begin(); - bool isConnected(); + // use default I2C pins. + bool begin(int8_t writeProtectPin = -1); + bool isConnected(); // writes a byte to memoryAddress // returns I2C status, 0 = OK - int writeByte(const uint32_t memoryAddress, const uint8_t value); + int writeByte(const uint32_t memoryAddress, const uint8_t value); // writes length bytes from buffer to EEPROM // returns I2C status, 0 = OK - int writeBlock(const uint32_t memoryAddress, const uint8_t *buffer, const uint32_t length); + int writeBlock(const uint32_t memoryAddress, const uint8_t *buffer, const uint32_t length); // set length bytes in the EEPROM to the same value. // returns I2C status, 0 = OK - int setBlock(const uint32_t memoryAddress, const uint8_t value, const uint32_t length); + int setBlock(const uint32_t memoryAddress, const uint8_t value, const uint32_t length); // returns the value stored in memoryAddress - uint8_t readByte(const uint32_t memoryAddress); + uint8_t readByte(const uint32_t memoryAddress); // reads length bytes into buffer // returns bytes read. - uint32_t readBlock(const uint32_t memoryAddress, uint8_t * buffer, const uint32_t length); + uint32_t readBlock(const uint32_t memoryAddress, uint8_t * buffer, const uint32_t length); // updates a byte at memoryAddress, writes only if there is a new value. @@ -88,6 +91,17 @@ class I2C_24LC1025 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; uint8_t _actualAddress; // a.k.a. controlByte @@ -98,12 +112,12 @@ class I2C_24LC1025 int _error = 0; // TODO. - void _beginTransmission(uint32_t memoryAddress); + void _beginTransmission(uint32_t memoryAddress); // returns I2C status, 0 = OK - int _pageBlock(uint32_t memoryAddress, const uint8_t * buffer, const uint16_t length, const bool incrBuffer); + int _pageBlock(uint32_t memoryAddress, const uint8_t * buffer, const uint16_t length, const bool incrBuffer); // returns I2C status, 0 = OK - int _WriteBlock(uint32_t memoryAddress, const uint8_t * buffer, const uint8_t length); + int _WriteBlock(uint32_t memoryAddress, const uint8_t * buffer, const uint8_t length); // returns bytes read. uint8_t _ReadBlock(uint32_t memoryAddress, uint8_t * buffer, const uint8_t length); @@ -112,7 +126,10 @@ class I2C_24LC1025 TwoWire * _wire; - bool _debug = false; + bool _debug = false; + + int8_t _writeProtectPin = -1; + bool _autoWriteProtect = false; }; diff --git a/libraries/I2C_24LC1025/README.md b/libraries/I2C_24LC1025/README.md index 8bda520be..065c85d6c 100644 --- a/libraries/I2C_24LC1025/README.md +++ b/libraries/I2C_24LC1025/README.md @@ -2,8 +2,11 @@ [![Arduino CI](https://github.com/RobTillaart/I2C_24LC1025/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci) [![Arduino-lint](https://github.com/RobTillaart/I2C_24LC1025/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/I2C_24LC1025/actions/workflows/arduino-lint.yml) [![JSON check](https://github.com/RobTillaart/I2C_24LC1025/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/I2C_24LC1025/actions/workflows/jsoncheck.yml) +[![GitHub issues](https://img.shields.io/github/issues/RobTillaart/I2C_24LC1025.svg)](https://github.com/RobTillaart/I2C_24LC1025/issues) + [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/I2C_24LC1025/blob/master/LICENSE) [![GitHub release](https://img.shields.io/github/release/RobTillaart/I2C_24LC1025.svg?maxAge=3600)](https://github.com/RobTillaart/I2C_24LC1025/releases) +[![PlatformIO Registry](https://badges.registry.platformio.org/packages/robtillaart/library/I2C_24LC1025.svg)](https://registry.platformio.org/libraries/robtillaart/I2C_24LC1025) # I2C_24LC1025 - I2C 1MB EEPROM @@ -29,6 +32,23 @@ This library follows the I2C_EEPROM library, see links below. - https://github.com/RobTillaart/I2C_EEPROM +## Schematic + +```cpp + +---U---+ + A0 | 1 8 | VCC = +5V + A1 | 2 7 | WP = write protect pin + A2 | 3 6 | SCL = I2C clock + GND | 4 5 | SDA = I2C data + +-------+ + +default address = 0x50 .. 0x53 depending on A0 and A1 address lines. +A2 must be connected to VCC (5V). + +Read the datasheet, section device addressing, about A2 and B0 (block bit) +``` + + ## Interface ```cpp @@ -38,39 +58,53 @@ This library follows the I2C_EEPROM library, see links below. The interface is kept quite identical to the I2C_EEPROM library. https://github.com/RobTillaart/I2C_EEPROM -Most important change is 32 bit memory addresses. +Most important difference is 32 bit memory addresses. ### Constructor - **I2C_24LC1025(uint8_t deviceAddress, TwoWire \*wire = &Wire)** constructor, 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 / RP2040 and alike. +- **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. +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. - ### Write functions -- **int writeByte(uint32_t memoryAddress, uint8_t value)** write a single byte to the specified memory address. +- **int writeByte(uint32_t memoryAddress, uint8_t value)** write a single byte to +the specified memory address. Returns I2C status, 0 = OK. -- **int writeBlock(uint32_t memoryAddress, uint8_t \* buffer, uint32_t length)** write a buffer starting at the specified memory address. +- **int writeBlock(uint32_t memoryAddress, uint8_t \* buffer, uint32_t length)** +write a buffer starting at the specified memory address. Returns I2C status, 0 = OK. -- **int setBlock(uint32_t memoryAddress, uint8_t value, uint32_t length)** writes the same byte to length places starting at the specified memory address. +- **int setBlock(uint32_t memoryAddress, uint8_t value, uint32_t length)** writes +the same byte to length places starting at the specified memory address. Returns I2C status, 0 = OK. ### Update functions -- **int updateByte(uint32_t memoryAddress, uint8_t value)** write a single byte, but only if changed. +- **int updateByte(uint32_t memoryAddress, uint8_t value)** write a single byte, +but only if changed. Returns 0 if value was same or write succeeded. -- **uint32_t updateBlock(uint32_t memoryAddress, uint8_t \* buffer, uint32_t length)** write a buffer starting at the specified memory address, but only if changed. +- **uint32_t updateBlock(uint32_t memoryAddress, uint8_t \* buffer, uint32_t length)** +write a buffer starting at the specified memory address, but only if changed. Returns bytes written. ### Read functions - **uint8_t readByte(uint32_t memoryAddress)** read a single byte from a given address -- **uint32_t readBlock(uint32_t memoryAddress, uint8_t \* buffer, uint32_t length)** read length bytes into buffer starting at specified memory address. +- **uint32_t readBlock(uint32_t memoryAddress, uint8_t \* buffer, uint32_t length)** +read length bytes into buffer starting at specified memory address. Returns the number of bytes read, which should be length. @@ -94,7 +128,7 @@ Same as write and update functions above. Returns true if successful, false indi - **uint32_t getLastWrite()** idem -#### UpdateBlock() +### UpdateBlock() (new since 0.1.3) @@ -109,15 +143,50 @@ 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 older devices have a larger timeout +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 0.2.5) + +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 diff --git a/libraries/I2C_24LC1025/keywords.txt b/libraries/I2C_24LC1025/keywords.txt index b286cff01..dcb5ac085 100644 --- a/libraries/I2C_24LC1025/keywords.txt +++ b/libraries/I2C_24LC1025/keywords.txt @@ -31,9 +31,18 @@ getDeviceSize KEYWORD2 getPageSize KEYWORD2 getLastWrite KEYWORD2 +setExtraWriteCycleTime KEYWORD2 +getExtraWriteCycleTime KEYWORD2 + +hasWriteProtectPin KEYWORD2 +allowWrite KEYWORD2 +preventWrite KEYWORD2 +setAutoWriteProtect KEYWORD2 +getAutoWriteProtect KEYWORD2 # Constants (LITERAL1) I2C_24LC1025_VERSION LITERAL1 + I2C_DEVICESIZE_24LC1025 LITERAL1 I2C_PAGESIZE_24LC1025 LITERAL1 diff --git a/libraries/I2C_24LC1025/library.json b/libraries/I2C_24LC1025/library.json index 437b3709e..39e3bdc6b 100644 --- a/libraries/I2C_24LC1025/library.json +++ b/libraries/I2C_24LC1025/library.json @@ -15,9 +15,9 @@ "type": "git", "url": "https://github.com/RobTillaart/I2C_24LC1025" }, - "version": "0.2.4", + "version": "0.2.5", "license": "MIT", - "frameworks": "arduino", + "frameworks": "*", "platforms": "*", "headers": "I2C_24LC1025.h" } diff --git a/libraries/I2C_24LC1025/library.properties b/libraries/I2C_24LC1025/library.properties index bd9e67649..9dc592d4b 100644 --- a/libraries/I2C_24LC1025/library.properties +++ b/libraries/I2C_24LC1025/library.properties @@ -1,5 +1,5 @@ name=I2C_24LC1025 -version=0.2.4 +version=0.2.5 author=Rob Tillaart maintainer=Rob Tillaart sentence=Library for 24FC1025 I2C EEPROM