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.
Fork of I2CEeprom by
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 #include "I2CEeprom.h" 00017 00018 I2CEeprom::I2CEeprom(I2C *i2c_inst, int address, size_t pageSize, size_t chipSize, int busSpeed): 00019 m_i2c(i2c_inst), 00020 m_i2cAddress(address), 00021 m_chipSize(chipSize), 00022 m_pageSize(pageSize) 00023 { 00024 m_i2c->frequency(busSpeed); 00025 } 00026 00027 size_t I2CEeprom::read(size_t address, char &value) { 00028 // Check the address and size fit onto the chip. 00029 if (!checkSpace(address, 1)) 00030 return 0; 00031 00032 char values[] = { (address >> 8), (address & 0xFF) }; 00033 if (m_i2c->write(m_i2cAddress, values, 2) == 0) { 00034 if (m_i2c->read(m_i2cAddress, &value, 1) == 0) { 00035 return 1; 00036 } 00037 } 00038 00039 return 0; 00040 } 00041 00042 size_t I2CEeprom::read(size_t address, char *buffer, size_t size) { 00043 // Check the address and size fit onto the chip. 00044 if (!checkSpace(address, size)) 00045 return 0; 00046 00047 char values[] = { (address >> 8), (address & 0xFF) }; 00048 if (m_i2c->write(m_i2cAddress, values, 2) == 0) { 00049 if (m_i2c->read(m_i2cAddress, buffer, size) == 0) { 00050 return size; 00051 } 00052 } 00053 00054 return 0; 00055 } 00056 00057 size_t I2CEeprom::write(size_t address, char value) { 00058 // Check the address and size fit onto the chip. 00059 if (!checkSpace(address, 1)) 00060 return 0; 00061 00062 char values[] = { (address >> 8), (address & 0xFF), value }; 00063 if (m_i2c->write(m_i2cAddress, values, 3) != 0) { 00064 return 0; 00065 } 00066 00067 waitForWrite(); 00068 00069 return 1; 00070 } 00071 00072 size_t I2CEeprom::write(size_t address, const char *buffer, size_t size) { 00073 // Check the address and size fit onto the chip. 00074 if (!checkSpace(address, size)) 00075 return 0; 00076 00077 const char *page = buffer; 00078 size_t left = size; 00079 00080 // Whle we have some more data to write. 00081 while (left != 0) { 00082 // Calculate the number of bytes we can write in the current page. 00083 // If the address is not page aligned then write enough to page 00084 // align it. 00085 size_t toWrite; 00086 if ((address % m_pageSize) != 0) { 00087 toWrite = (((address / m_pageSize) + 1) * m_pageSize) - address; 00088 if (toWrite > size) { 00089 toWrite = size; 00090 } 00091 } else { 00092 if (left <= m_pageSize) { 00093 toWrite = left; 00094 } else { 00095 toWrite = m_pageSize; 00096 } 00097 } 00098 00099 //printf("Writing [%.*s] at %d size %d\n\r", toWrite, page, address, toWrite); 00100 // Start the page write with the addres ine one write call. 00101 char values[] = { (address >> 8), (address & 0xFF) }; 00102 if (m_i2c->write(m_i2cAddress, values, 2, true) != 0) { 00103 // Write failed to return bytes written so far. 00104 return size - left; 00105 } 00106 00107 // Write the bytes out one at a time to avoid having to copy them to 00108 // another buffer. 00109 for (int count = 0; count != toWrite; ++count) { 00110 if (m_i2c->write(*page) == 0) { 00111 // Write failed to return bytes written so far. 00112 return size - left; 00113 } 00114 ++page; 00115 } 00116 00117 // Stop the transaction now we've completed the page 00118 // write. 00119 m_i2c->stop(); 00120 00121 waitForWrite(); 00122 00123 // Update the counters with the amount we've just written 00124 left -= toWrite; 00125 address += toWrite; 00126 } 00127 00128 return size; 00129 } 00130 00131 size_t I2CEeprom::fill(size_t address, char value, size_t size) { 00132 // Check the address and size fit onto the chip. 00133 if (!checkSpace(address, size)) 00134 return 0; 00135 00136 size_t left = size; 00137 00138 while (left != 0) { 00139 size_t toWrite; 00140 if ((address % m_pageSize) != 0) { 00141 toWrite = (((address / m_pageSize) + 1) * 64) - address; 00142 if (toWrite > size) { 00143 toWrite = size; 00144 } 00145 } else { 00146 if (left <= m_pageSize) { 00147 toWrite = left; 00148 } else { 00149 toWrite = m_pageSize; 00150 } 00151 } 00152 00153 //printf("Writing %d at %d size %d\n\r", value, address, toWrite); 00154 char values[] = { (address >> 8), (address & 0xFF) }; 00155 if (m_i2c->write(m_i2cAddress, values, 2, true) != 0) { 00156 return size - left; 00157 } 00158 00159 for (int count = 0; count != toWrite; ++count) { 00160 if (m_i2c->write(value) == 0) 00161 return size - left; 00162 } 00163 00164 m_i2c->stop(); 00165 00166 waitForWrite(); 00167 00168 left -= toWrite; 00169 address += toWrite; 00170 } 00171 00172 return size; 00173 } 00174 00175 void I2CEeprom::waitForWrite() { 00176 // The chip doesn't ACK while writing to the actual EEPROM 00177 // so loop trying to do a zero byte write until it is ACKed 00178 // by the chip. 00179 while (m_i2c->write(m_i2cAddress, 0, 0) != 0) { 00180 // Wait for ack. 00181 wait_ms(1); 00182 } 00183 } 00184 00185 bool I2CEeprom::checkSpace(size_t address, size_t size) { 00186 // Only check if chip size is non-zero. 00187 if (m_chipSize != 0) { 00188 // Check that the address start in the chip and doesn't 00189 // extend past. 00190 if ((address >= m_chipSize) || ((address + size) >= m_chipSize)) 00191 return false; 00192 else 00193 return true; 00194 } 00195 00196 return true; 00197 } 00198
Generated on Wed Jul 20 2022 22:26:41 by 1.7.2