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.

Dependents:   Nucleo_praktyki

Fork of I2CEeprom by Robin Hourahane

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 #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