GY-63_MS5611/libraries/I2C_EEPROM/I2C_eeprom.cpp

467 lines
11 KiB
C++
Raw Normal View History

//
2013-09-30 10:38:08 -04:00
// FILE: I2C_eeprom.cpp
// AUTHOR: Rob Tillaart
2022-10-31 11:53:19 -04:00
// VERSION: 1.6.2
2020-11-27 05:16:22 -05:00
// PURPOSE: Arduino Library for external I2C EEPROM 24LC256 et al.
// URL: https://github.com/RobTillaart/I2C_EEPROM.git
2013-09-30 10:38:08 -04:00
//
2022-10-31 11:53:19 -04:00
// HISTORY: see changelog.md
2021-12-19 14:05:24 -05:00
2013-09-30 10:38:08 -04:00
2022-06-12 06:47:07 -04:00
#include "I2C_eeprom.h"
2013-09-30 10:38:08 -04:00
2022-10-31 11:53:19 -04:00
// Not used directly
2021-01-29 06:31:58 -05:00
#define I2C_PAGESIZE_24LC512 128
#define I2C_PAGESIZE_24LC256 64
#define I2C_PAGESIZE_24LC128 64
#define I2C_PAGESIZE_24LC64 32
#define I2C_PAGESIZE_24LC32 32
#define I2C_PAGESIZE_24LC16 16
#define I2C_PAGESIZE_24LC08 16
#define I2C_PAGESIZE_24LC04 16
#define I2C_PAGESIZE_24LC02 8
#define I2C_PAGESIZE_24LC01 8
2021-07-01 04:58:13 -04:00
// I2C buffer needs max 2 bytes for EEPROM address
// 1 byte for EEPROM register address is available in transmit buffer
2021-02-06 09:52:51 -05:00
#if defined(ESP32) || defined(ESP8266)
#define I2C_BUFFERSIZE 128
#else
2021-12-19 14:05:24 -05:00
#define I2C_BUFFERSIZE 30 // AVR, STM
2021-02-06 09:52:51 -05:00
#endif
2021-01-29 06:31:58 -05:00
2022-06-12 06:47:07 -04:00
////////////////////////////////////////////////////////////////////
//
2022-10-31 11:53:19 -04:00
// PUBLIC FUNCTIONS
2022-06-12 06:47:07 -04:00
//
I2C_eeprom::I2C_eeprom(const uint8_t deviceAddress, TwoWire * wire)
2013-09-30 10:38:08 -04:00
{
2021-01-29 06:31:58 -05:00
I2C_eeprom(deviceAddress, I2C_PAGESIZE_24LC256, wire);
}
2021-01-29 06:31:58 -05:00
2022-06-12 06:47:07 -04:00
I2C_eeprom::I2C_eeprom(const uint8_t deviceAddress, const uint32_t deviceSize, TwoWire * wire)
{
_deviceAddress = deviceAddress;
2021-01-29 06:31:58 -05:00
_deviceSize = deviceSize;
_pageSize = getPageSize(_deviceSize);
_wire = wire;
2022-10-31 11:53:19 -04:00
// Chips 16Kbit (2048 Bytes) or smaller only have one-word addresses.
2021-07-01 04:58:13 -04:00
this->_isAddressSizeTwoWords = deviceSize > I2C_DEVICESIZE_24LC16;
}
2021-01-29 06:31:58 -05:00
2020-11-27 05:16:22 -05:00
#if defined (ESP8266) || defined(ESP32)
2021-01-29 06:31:58 -05:00
bool I2C_eeprom::begin(uint8_t sda, uint8_t scl)
{
2021-01-29 06:31:58 -05:00
if ((sda < 255) && (scl < 255))
{
_wire->begin(sda, scl);
}
else
{
_wire->begin();
}
2020-11-27 05:16:22 -05:00
_lastWrite = 0;
2021-01-29 06:31:58 -05:00
return isConnected();
2013-09-30 10:38:08 -04:00
}
2020-11-27 05:16:22 -05:00
#endif
2013-09-30 10:38:08 -04:00
2021-01-29 06:31:58 -05:00
bool I2C_eeprom::begin()
2020-11-27 05:16:22 -05:00
{
2021-01-29 06:31:58 -05:00
_wire->begin();
2020-11-27 05:16:22 -05:00
_lastWrite = 0;
2021-01-29 06:31:58 -05:00
return isConnected();
2020-11-27 05:16:22 -05:00
}
2021-01-29 06:31:58 -05:00
bool I2C_eeprom::isConnected()
{
_wire->beginTransmission(_deviceAddress);
return (_wire->endTransmission() == 0);
}
2022-06-12 06:47:07 -04:00
2022-06-07 11:43:11 -04:00
/////////////////////////////////////////////////////////////
//
// WRITE SECTION
//
2022-06-12 06:47:07 -04:00
// returns I2C status, 0 = OK
int I2C_eeprom::writeByte(const uint16_t memoryAddress, const uint8_t data)
2013-09-30 10:38:08 -04:00
{
2020-11-27 05:16:22 -05:00
int rv = _WriteBlock(memoryAddress, &data, 1);
return rv;
2013-09-30 10:38:08 -04:00
}
2021-01-29 06:31:58 -05:00
2022-06-12 06:47:07 -04:00
// returns I2C status, 0 = OK
int I2C_eeprom::setBlock(const uint16_t memoryAddress, const uint8_t data, const uint16_t length)
2013-09-30 10:38:08 -04:00
{
2021-02-06 09:52:51 -05:00
uint8_t buffer[I2C_BUFFERSIZE];
for (uint8_t i = 0; i < I2C_BUFFERSIZE; i++)
2020-11-27 05:16:22 -05:00
{
buffer[i] = data;
}
int rv = _pageBlock(memoryAddress, buffer, length, false);
return rv;
2013-09-30 10:38:08 -04:00
}
2021-01-29 06:31:58 -05:00
2022-06-12 06:47:07 -04:00
// returns I2C status, 0 = OK
int I2C_eeprom::writeBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length)
{
2020-11-27 05:16:22 -05:00
int rv = _pageBlock(memoryAddress, buffer, length, true);
return rv;
}
2021-01-29 06:31:58 -05:00
2022-06-07 11:43:11 -04:00
/////////////////////////////////////////////////////////////
//
// READ SECTION
//
2022-06-12 06:47:07 -04:00
// returns the value stored in memoryAddress
uint8_t I2C_eeprom::readByte(const uint16_t memoryAddress)
2013-09-30 10:38:08 -04:00
{
2020-11-27 05:16:22 -05:00
uint8_t rdata;
_ReadBlock(memoryAddress, &rdata, 1);
return rdata;
2013-09-30 10:38:08 -04:00
}
2021-01-29 06:31:58 -05:00
2022-06-12 06:47:07 -04:00
// returns bytes read.
uint16_t I2C_eeprom::readBlock(const uint16_t memoryAddress, uint8_t * buffer, const uint16_t length)
2013-09-30 10:38:08 -04:00
{
2020-11-27 05:16:22 -05:00
uint16_t addr = memoryAddress;
uint16_t len = length;
uint16_t rv = 0;
while (len > 0)
{
2021-02-06 09:52:51 -05:00
uint8_t cnt = I2C_BUFFERSIZE;
2020-11-27 05:16:22 -05:00
if (cnt > len) cnt = len;
rv += _ReadBlock(addr, buffer, cnt);
addr += cnt;
buffer += cnt;
len -= cnt;
}
return rv;
2013-09-30 10:38:08 -04:00
}
2021-01-29 06:31:58 -05:00
2022-06-07 11:43:11 -04:00
/////////////////////////////////////////////////////////////
//
// UPDATE SECTION
//
2022-06-12 06:47:07 -04:00
2022-06-07 11:43:11 -04:00
// returns 0 == OK
2021-01-29 06:31:58 -05:00
int I2C_eeprom::updateByte(const uint16_t memoryAddress, const uint8_t data)
{
2021-01-29 06:31:58 -05:00
if (data == readByte(memoryAddress)) return 0;
return writeByte(memoryAddress, data);
}
2022-06-07 11:43:11 -04:00
2022-06-12 06:47:07 -04:00
// returns bytes written.
uint16_t I2C_eeprom::updateBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length)
2021-02-03 11:20:20 -05:00
{
uint16_t addr = memoryAddress;
uint16_t len = length;
uint16_t rv = 0;
while (len > 0)
{
2021-02-06 09:52:51 -05:00
uint8_t buf[I2C_BUFFERSIZE];
uint8_t cnt = I2C_BUFFERSIZE;
2021-12-19 14:05:24 -05:00
2021-02-03 11:20:20 -05:00
if (cnt > len) cnt = len;
rv += _ReadBlock(addr, buf, cnt);
if (memcmp(buffer, buf, cnt) != 0)
{
_pageBlock(addr, buffer, cnt, true);
}
addr += cnt;
buffer += cnt;
len -= cnt;
}
return rv;
}
2022-06-07 11:43:11 -04:00
/////////////////////////////////////////////////////////////
//
// VERIFY SECTION
//
2022-06-12 06:47:07 -04:00
// return false if write or verify failed.
2022-06-07 11:43:11 -04:00
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);
}
2022-06-12 06:47:07 -04:00
// return false if write or verify failed.
bool I2C_eeprom::writeBlockVerify(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length)
2022-06-07 11:43:11 -04:00
{
if (writeBlock(memoryAddress, buffer, length) != 0) return false;
uint8_t data[length];
if (readBlock(memoryAddress, data, length) != length) return false;
return memcmp(data, buffer, length) == 0;
}
2022-06-12 06:47:07 -04:00
// return false if write or verify failed.
2022-06-07 11:43:11 -04:00
bool I2C_eeprom::setBlockVerify(const uint16_t memoryAddress, const uint8_t value, const uint16_t length)
{
if (setBlock(memoryAddress, value, length) != 0) return false;
uint8_t data[length];
if (readBlock(memoryAddress, data, length) != length) return false;
2022-06-12 06:47:07 -04:00
for (uint16_t i = 0; i < length; i++)
2022-06-07 11:43:11 -04:00
{
if (data[i] != value) return false;
}
return true;
}
2022-06-12 06:47:07 -04:00
// return false if write or verify failed.
2022-06-07 11:43:11 -04:00
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);
}
2022-06-12 06:47:07 -04:00
// return false if write or verify failed.
bool I2C_eeprom::updateBlockVerify(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length)
2022-06-07 11:43:11 -04:00
{
if (updateBlock(memoryAddress, buffer, length) != length) return false;
uint8_t data[length];
if (readBlock(memoryAddress, data, length) != length) return false;
return memcmp(data, buffer, length) == 0;
}
/////////////////////////////////////////////////////////////
//
// METADATA SECTION
//
2022-10-31 11:53:19 -04:00
// returns size in bytes
// returns 0 if not connected
2021-01-29 06:31:58 -05:00
//
// tested for
// 2 byte address
// 24LC512 64 KB YES
// 24LC256 32 KB YES
// 24LC128 16 KB YES
// 24LC64 8 KB YES
// 24LC32 4 KB YES* - no hardware test, address scheme identical to 24LC64.
//
// 1 byte address (uses part of deviceAddress byte)
// 24LC16 2 KB YES
// 24LC08 1 KB YES
// 24LC04 512 B YES
// 24LC02 256 B YES
// 24LC01 128 B YES
uint32_t I2C_eeprom::determineSize(const bool debug)
{
2020-11-27 05:16:22 -05:00
// try to read a byte to see if connected
2021-01-29 06:31:58 -05:00
if (! isConnected()) return 0;
2021-01-29 06:31:58 -05:00
uint8_t patAA = 0xAA;
uint8_t pat55 = 0x55;
2021-01-29 06:31:58 -05:00
for (uint32_t size = 128; size <= 65536; size *= 2)
2020-11-27 05:16:22 -05:00
{
2021-01-29 06:31:58 -05:00
bool folded = false;
2022-10-31 11:53:19 -04:00
// store old values
2021-01-29 06:31:58 -05:00
bool addressSize = _isAddressSizeTwoWords;
2021-07-01 04:58:13 -04:00
_isAddressSizeTwoWords = size > I2C_DEVICESIZE_24LC16; // 2048
2021-01-29 06:31:58 -05:00
uint8_t buf = readByte(size);
2022-10-31 11:53:19 -04:00
// test folding
2021-01-29 06:31:58 -05:00
uint8_t cnt = 0;
writeByte(size, pat55);
if (readByte(0) == pat55) cnt++;
writeByte(size, patAA);
if (readByte(0) == patAA) cnt++;
folded = (cnt == 2);
if (debug)
{
2021-01-29 06:31:58 -05:00
Serial.print(size, HEX);
Serial.print('\t');
Serial.println(readByte(size), HEX);
}
2022-10-31 11:53:19 -04:00
// restore old values
2021-01-29 06:31:58 -05:00
writeByte(size, buf);
_isAddressSizeTwoWords = addressSize;
if (folded) return size;
2020-11-27 05:16:22 -05:00
}
2021-01-29 06:31:58 -05:00
return 0;
}
2021-01-29 06:31:58 -05:00
uint8_t I2C_eeprom::getPageSize(uint32_t deviceSize)
{
2022-10-31 11:53:19 -04:00
// determine page size from device size
// based on Microchip 24LCXX data sheets.
2021-01-29 06:31:58 -05:00
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;
2022-10-31 11:53:19 -04:00
// I2C_DEVICESIZE_24LC512
2021-01-29 06:31:58 -05:00
return 128;
}
2013-09-30 10:38:08 -04:00
////////////////////////////////////////////////////////////////////
//
2022-10-31 11:53:19 -04:00
// PRIVATE
2013-09-30 10:38:08 -04:00
//
2021-12-19 14:05:24 -05:00
// _pageBlock aligns buffer to page boundaries for writing.
// and to I2C buffer size
// returns 0 = OK otherwise error
2022-06-12 06:47:07 -04:00
int I2C_eeprom::_pageBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint16_t length, const bool incrBuffer)
{
2020-11-27 05:16:22 -05:00
uint16_t addr = memoryAddress;
uint16_t len = length;
while (len > 0)
{
uint8_t bytesUntilPageBoundary = this->_pageSize - addr % this->_pageSize;
2021-02-06 09:52:51 -05:00
uint8_t cnt = I2C_BUFFERSIZE;
2020-11-27 05:16:22 -05:00
if (cnt > len) cnt = len;
if (cnt > bytesUntilPageBoundary) cnt = bytesUntilPageBoundary;
2020-11-27 05:16:22 -05:00
int rv = _WriteBlock(addr, buffer, cnt);
if (rv != 0) return rv;
addr += cnt;
if (incrBuffer) buffer += cnt;
len -= cnt;
}
return 0;
}
2021-01-29 06:31:58 -05:00
2021-12-19 14:05:24 -05:00
// supports one and two bytes addresses
void I2C_eeprom::_beginTransmission(const uint16_t memoryAddress)
{
if (this->_isAddressSizeTwoWords)
{
2021-01-29 06:31:58 -05:00
_wire->beginTransmission(_deviceAddress);
2020-11-27 05:16:22 -05:00
// Address High Byte
2021-01-29 06:31:58 -05:00
_wire->write((memoryAddress >> 8));
}
else
{
uint8_t addr = _deviceAddress | ((memoryAddress >> 8) & 0x07);
_wire->beginTransmission(addr);
}
2021-07-01 04:58:13 -04:00
// Address Low Byte (or single byte for chips 16K or smaller that have one-word addresses)
2021-01-29 06:31:58 -05:00
_wire->write((memoryAddress & 0xFF));
}
2021-01-29 06:31:58 -05:00
2021-12-19 14:05:24 -05:00
// pre: length <= this->_pageSize && length <= I2C_BUFFERSIZE;
// returns 0 = OK otherwise error
2022-06-12 06:47:07 -04:00
int I2C_eeprom::_WriteBlock(const uint16_t memoryAddress, const uint8_t * buffer, const uint8_t length)
{
2020-11-27 05:16:22 -05:00
_waitEEReady();
2019-09-03 05:41:28 -04:00
2020-11-27 05:16:22 -05:00
this->_beginTransmission(memoryAddress);
2021-01-29 06:31:58 -05:00
_wire->write(buffer, length);
int rv = _wire->endTransmission();
2022-06-12 06:47:07 -04:00
_lastWrite = micros();
2022-10-31 11:53:19 -04:00
yield(); // For OS scheduling
2019-09-03 05:41:28 -04:00
2022-06-12 06:47:07 -04:00
// if (rv != 0)
// {
// if (_debug)
// {
// Serial.print("mem addr w: ");
// Serial.print(memoryAddress, HEX);
// Serial.print("\t");
// Serial.println(rv);
// }
// return -(abs(rv)); // error
// }
2020-11-27 05:16:22 -05:00
return rv;
2013-09-30 10:38:08 -04:00
}
2021-01-29 06:31:58 -05:00
2021-12-19 14:05:24 -05:00
// pre: buffer is large enough to hold length bytes
// returns bytes read
2022-06-12 06:47:07 -04:00
uint8_t I2C_eeprom::_ReadBlock(const uint16_t memoryAddress, uint8_t * buffer, const uint8_t length)
2013-09-30 10:38:08 -04:00
{
2020-11-27 05:16:22 -05:00
_waitEEReady();
2020-11-27 05:16:22 -05:00
this->_beginTransmission(memoryAddress);
2021-01-29 06:31:58 -05:00
int rv = _wire->endTransmission();
2022-06-12 06:47:07 -04:00
if (rv != 0)
{
// if (_debug)
// {
// Serial.print("mem addr r: ");
// Serial.print(memoryAddress, HEX);
// Serial.print("\t");
// Serial.println(rv);
// }
return 0; // error
}
2021-07-01 04:58:13 -04:00
// readBytes will always be equal or smaller to length
uint8_t readBytes = 0;
if (this->_isAddressSizeTwoWords)
{
readBytes = _wire->requestFrom(_deviceAddress, length);
}
else
{
uint8_t addr = _deviceAddress | ((memoryAddress >> 8) & 0x07);
readBytes = _wire->requestFrom(addr, length);
}
2022-10-31 11:53:19 -04:00
yield(); // For OS scheduling
2020-11-27 05:16:22 -05:00
uint8_t cnt = 0;
while (cnt < readBytes)
{
2021-01-29 06:31:58 -05:00
buffer[cnt++] = _wire->read();
2020-11-27 05:16:22 -05:00
}
return readBytes;
2013-09-30 10:38:08 -04:00
}
2013-09-30 10:43:17 -04:00
2021-01-29 06:31:58 -05:00
2020-11-27 05:16:22 -05:00
void I2C_eeprom::_waitEEReady()
{
#define I2C_WRITEDELAY 5000
2021-11-08 07:26:03 -05:00
// 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; // do the math once.
while ((micros() - _lastWrite) <= waitTime)
2020-11-27 05:16:22 -05:00
{
2021-01-29 06:31:58 -05:00
_wire->beginTransmission(_deviceAddress);
int x = _wire->endTransmission();
2020-11-27 05:16:22 -05:00
if (x == 0) return;
2022-10-31 11:53:19 -04:00
yield(); // For OS scheduling
2020-11-27 05:16:22 -05:00
}
return;
}
2021-12-19 14:05:24 -05:00
2020-11-27 05:16:22 -05:00
// -- END OF FILE --
2021-12-19 14:05:24 -05:00