Class to provide simple access to I2C EEPROM chiles like Microchip's 24LC range or AMTELS AT24C range. Chips up to 64Kb in size are directly supported. Updated to Mbed OS v 5.1
Diff: I2CEeprom.cpp
- Revision:
- 2:f3188aaccf80
- Parent:
- 1:b23f5561266c
- Child:
- 3:b2a132553b02
--- a/I2CEeprom.cpp Sun Jul 19 09:34:04 2015 +0000 +++ b/I2CEeprom.cpp Sat Mar 28 00:53:14 2020 +0000 @@ -13,177 +13,166 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +#include <iostream> +#include <algorithm> + #include "I2CEeprom.h" -I2CEeprom::I2CEeprom(PinName sda, PinName scl, int address, size_t pageSize, size_t chipSize, int busSpeed): - m_i2c(sda, scl), +namespace +{ + +inline bool little_endian() +{ + int n = 1; + // little endian if true + return(*(char *)&n == 1); +} + +void convert_address(size_t const & addressIn, char* arOut) +{ + constexpr size_t int_size = sizeof(size_t); + union uu { + uu(size_t a) : address{a} {} + size_t address; + const char ar[int_size]; + } u{addressIn}; + static_assert(sizeof(u) == int_size,""); + if( little_endian()) { + arOut[1] = u.ar[0]; + arOut[0] = u.ar[1]; + } else { + // std::cout << "big endian\n"; + arOut[1] = u.ar[int_size - 1]; // lsb + arOut[0] = u.ar[int_size - 2]; //nextsb + } +} +} + +I2CEeprom::I2CEeprom( + I2C & i2c, + int address, + size_t pageSize, + size_t chipSize, + uint8_t writeCycleTime_ms + ): + m_i2c{i2c}, m_i2cAddress(address), m_chipSize(chipSize), - m_pageSize(pageSize) + m_pageSize(pageSize), + m_writeCycleTime_ms{writeCycleTime_ms} +{} + +size_t I2CEeprom::read(size_t address, char &value) { - m_i2c.frequency(busSpeed); -} - -size_t I2CEeprom::read(size_t address, char &value) { // Check the address and size fit onto the chip. if (!checkSpace(address, 1)) return 0; - - char values[] = { (address >> 8), (address & 0xFF) }; + char values[2]; + convert_address(address,values); if (m_i2c.write(m_i2cAddress, values, 2) == 0) { if (m_i2c.read(m_i2cAddress, &value, 1) == 0) { return 1; } } - return 0; } -size_t I2CEeprom::read(size_t address, char *buffer, size_t size) { +size_t I2CEeprom::read(size_t address, char *buffer, size_t size) +{ // Check the address and size fit onto the chip. if (!checkSpace(address, size)) return 0; - - char values[] = { (address >> 8), (address & 0xFF) }; + char values[2]; + convert_address(address,values); if (m_i2c.write(m_i2cAddress, values, 2) == 0) { if (m_i2c.read(m_i2cAddress, buffer, size) == 0) { return size; } } - return 0; } - -size_t I2CEeprom::write(size_t address, char value) { +// works ok +size_t I2CEeprom::write(size_t address, char value) +{ // Check the address and size fit onto the chip. if (!checkSpace(address, 1)) return 0; - - char values[] = { (address >> 8), (address & 0xFF), value }; + char values[3]; + convert_address(address,values); + values[2] = value; if (m_i2c.write(m_i2cAddress, values, 3) != 0) { return 0; } - + waitForWrite(); - return 1; } -size_t I2CEeprom::write(size_t address, const char *buffer, size_t size) { - // Check the address and size fit onto the chip. - if (!checkSpace(address, size)) + +size_t I2CEeprom::ll_write(size_t address, const char *buffer, size_t size) +{ + // TODO: change i2c address bits dependent on eeprom data address + // if size > 64k + // write 2 bytes ee address + data size + char* tempBuffer = new char [size + 2]; + if ( tempBuffer == nullptr) { + delete [] tempBuffer; + std::cout << "EE i2c write malloc buf failed \n"; return 0; - - const char *page = buffer; - size_t left = size; - - // Whle we have some more data to write. - while (left != 0) { - // Calculate the number of bytes we can write in the current page. - // If the address is not page aligned then write enough to page - // align it. - size_t toWrite; - if ((address % m_pageSize) != 0) { - toWrite = (((address / m_pageSize) + 1) * m_pageSize) - address; - if (toWrite > size) { - toWrite = size; - } - } else { - if (left <= m_pageSize) { - toWrite = left; - } else { - toWrite = m_pageSize; - } - } - - //printf("Writing [%.*s] at %d size %d\n\r", toWrite, page, address, toWrite); - // Start the page write with the addres ine one write call. - char values[] = { (address >> 8), (address & 0xFF) }; - if (m_i2c.write(m_i2cAddress, values, 2, true) != 0) { - // Write failed to return bytes written so far. - return size - left; - } + } + convert_address(address,tempBuffer); + memcpy(tempBuffer+2,buffer,size); - // Write the bytes out one at a time to avoid having to copy them to - // another buffer. - for (int count = 0; count != toWrite; ++count) { - if (m_i2c.write(*page) == 0) { - // Write failed to return bytes written so far. - return size - left; - } - ++page; - } - - // Stop the transaction now we've completed the page - // write. - m_i2c.stop(); - - waitForWrite(); - - // Update the counters with the amount we've just written - left -= toWrite; - address += toWrite; + if (m_i2c.write(m_i2cAddress, tempBuffer, size+2) != 0) { + delete [] tempBuffer; + std::cout << "EE i2c write failed\n"; + return 0; } - + delete [] tempBuffer; + waitForWrite(); return size; } -size_t I2CEeprom::fill(size_t address, char value, size_t size) { +// ret num written +size_t I2CEeprom::write(size_t address, const char *buffer, size_t size) +{ // Check the address and size fit onto the chip. - if (!checkSpace(address, size)) + if (!checkSpace(address, size)) { return 0; - - size_t left = size; - - while (left != 0) { - size_t toWrite; - if ((address % m_pageSize) != 0) { - toWrite = (((address / m_pageSize) + 1) * 64) - address; - if (toWrite > size) { - toWrite = size; - } + } + size_t bytesLeft = size; + size_t numBytesToWrite + = std::min( size, m_pageSize - (address % m_pageSize)); + while(bytesLeft) { + if ( ll_write(address,buffer, numBytesToWrite) + == numBytesToWrite) { + buffer += numBytesToWrite; + address += numBytesToWrite; + bytesLeft -= numBytesToWrite; + numBytesToWrite = std::min(bytesLeft,m_pageSize); } else { - if (left <= m_pageSize) { - toWrite = left; - } else { - toWrite = m_pageSize; - } + break; } - - //printf("Writing %d at %d size %d\n\r", value, address, toWrite); - char values[] = { (address >> 8), (address & 0xFF) }; - if (m_i2c.write(m_i2cAddress, values, 2, true) != 0) { - return size - left; - } - - for (int count = 0; count != toWrite; ++count) { - if (m_i2c.write(value) == 0) - return size - left; - } - - m_i2c.stop(); - - waitForWrite(); - - left -= toWrite; - address += toWrite; } - - return size; + return size - bytesLeft; } -void I2CEeprom::waitForWrite() { +void I2CEeprom::waitForWrite() +{ + ThisThread::sleep_for(m_writeCycleTime_ms); // The chip doesn't ACK while writing to the actual EEPROM // so loop trying to do a zero byte write until it is ACKed // by the chip. while (m_i2c.write(m_i2cAddress, 0, 0) != 0) { // Wait for ack. - wait_ms(1); + ThisThread::sleep_for(1); } } -bool I2CEeprom::checkSpace(size_t address, size_t size) { - // Only check if chip size is non-zero. +bool I2CEeprom::checkSpace(size_t address, size_t size) +{ + // Only check, if chip size is non-zero. if (m_chipSize != 0) { // Check that the address start in the chip and doesn't // extend past. @@ -192,7 +181,6 @@ else return true; } - + return true; } -