Andy Little / I2CEeprom

Dependents:   storage_test

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers I2CEeprom.cpp Source File

I2CEeprom.cpp

00001 /* Simple access class for I2C EEPROM chips like Microchip 24LC
00002  * Copyright (c) 2015 Robin Hourahane
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include <iostream>
00018 #include <algorithm>
00019 
00020 #include "I2CEeprom.h "
00021 
00022 namespace
00023 {
00024 
00025 //return true if system is little-endian
00026 inline bool little_endian()
00027 {
00028     int n = 1;
00029     // little endian if true
00030     return(*(char *)&n == 1);
00031 }
00032 
00033 // Put EEprom address into 2 char array
00034 // in corrcet endiannness
00035 void convert_address(size_t const & addressIn, char* arOut)
00036 {
00037     constexpr size_t int_size = sizeof(size_t);
00038     union uu {
00039         uu(size_t a) : address{a} {}
00040         size_t address;
00041         const char ar[int_size];
00042     } u{addressIn};
00043     static_assert(sizeof(u) == int_size,"");
00044     if( little_endian()) {
00045         arOut[1] = u.ar[0];
00046         arOut[0] = u.ar[1];
00047     } else {
00048         //  std::cout << "big endian\n";
00049         arOut[1] = u.ar[int_size - 1]; // lsb
00050         arOut[0] = u.ar[int_size - 2]; //nextsb
00051     }
00052 }
00053 }
00054 
00055 I2CEeprom::I2CEeprom(
00056     I2C & i2c,
00057     int address,
00058     size_t pageSize,
00059     size_t chipSize,
00060     uint8_t writeCycleTime_ms
00061 ):
00062     m_i2c{i2c},
00063     m_i2cAddress(address),
00064     m_chipSize(chipSize),
00065     m_pageSize(pageSize),
00066     m_writeCycleTime_ms{writeCycleTime_ms}
00067 {}
00068 
00069 size_t I2CEeprom::read(size_t address, char &value)
00070 {
00071     if (checkSpace(address, 1)) {
00072         char values[2];
00073         convert_address(address,values);
00074         if (m_i2c.write(m_i2cAddress, values, 2) == 0) {
00075             if (m_i2c.read(m_i2cAddress, &value, 1) == 0) {
00076                 return 1;
00077             }
00078         }
00079     }
00080     return 0;
00081 }
00082 
00083 size_t I2CEeprom::read(size_t address, char *buffer, size_t size)
00084 {
00085     if (checkSpace(address, size)) {
00086         char values[2];
00087         convert_address(address,values);
00088         if (m_i2c.write(m_i2cAddress, values, 2) == 0) {
00089             if (m_i2c.read(m_i2cAddress, buffer, size) == 0) {
00090                 return size;
00091             }
00092         }
00093     }
00094     return 0;
00095 }
00096 
00097 size_t I2CEeprom::write(size_t address, char value)
00098 {
00099     if (checkSpace(address, 1)) {
00100         char values[3];
00101         convert_address(address,values);
00102         values[2] = value;
00103         if (m_i2c.write(m_i2cAddress, values, 3) != 0) {
00104             return 0;
00105         }
00106         waitForWrite();
00107         return 1;
00108     } else {
00109         return 0;
00110     }
00111 }
00112 
00113 size_t I2CEeprom::ll_write(size_t address, const char *buffer, size_t size)
00114 {
00115     if (m_i2c.write(m_i2cAddress, buffer, size) == 0) {
00116         waitForWrite();
00117         return size;
00118     } else {
00119         std::cout << "EE i2c write failed\n";
00120         return 0;
00121     }
00122 }
00123 
00124 size_t I2CEeprom::write(size_t address, const char *buffer, size_t size)
00125 {
00126     if (checkSpace(address, size)) {
00127         size_t const malloc_size = std::min(size,m_pageSize) + 2U;
00128         char * tempBuffer = new char [malloc_size];
00129         if ( tempBuffer == nullptr) {
00130             std::cout << "EE i2c buf malloc failed\n";
00131             return 0;
00132         }
00133         size_t bytesLeft = size;
00134         size_t numBytesToWrite
00135             = std::min( size, m_pageSize - (address % m_pageSize));
00136         while( bytesLeft ) {
00137             convert_address(address,tempBuffer);
00138             memcpy(tempBuffer + 2,buffer, numBytesToWrite);
00139             if ( ll_write(address,tempBuffer, numBytesToWrite + 2U)
00140                     == numBytesToWrite + 2U) {
00141                 buffer += numBytesToWrite;
00142                 address += numBytesToWrite;
00143                 bytesLeft -= numBytesToWrite;
00144                 numBytesToWrite = std::min(bytesLeft,m_pageSize);
00145             } else {
00146                 std::cout << "EE i2c write failed\n";
00147                 break;
00148             }
00149         }
00150         delete [] tempBuffer;
00151         return size - bytesLeft;
00152     } else {
00153         return 0;
00154     }
00155 }
00156 
00157 void I2CEeprom::waitForWrite()
00158 {
00159     ThisThread::sleep_for(m_writeCycleTime_ms);
00160     // The chip doesn't ACK while writing to the actual EEPROM
00161     // so loop trying to do a zero byte write until it is ACKed
00162     // by the chip.
00163     while (m_i2c.write(m_i2cAddress, 0, 0) != 0) {
00164         ThisThread::sleep_for(1);
00165     }
00166 }