Laurent Meunier / I2CEeprom

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(PinName sda, PinName scl, int address, size_t pageSize, size_t chipSize, int busSpeed):
00019     m_i2c(sda, scl),
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 
00103         m_i2c.start();
00104         if (m_i2c.write(m_i2cAddress) == 0) {
00105             return size - left;
00106         }
00107         if (m_i2c.write(values[0]) == 0) {
00108             return size - left;
00109         }
00110         if (m_i2c.write(values[1]) == 0) {
00111             return size - left;
00112         }
00113 
00114         // Write the bytes out one at a time to avoid having to copy them to
00115         // another buffer.        
00116         for (int count = 0; count != toWrite; ++count) {
00117             if (m_i2c.write(*page) == 0) {
00118             // Write failed to return bytes written so far.
00119                 return size - left;
00120             }
00121             ++page;
00122         }
00123         
00124         // Stop the transaction now we've completed the page
00125         // write.
00126         m_i2c.stop();
00127         
00128         waitForWrite();
00129         
00130         // Update the counters with the amount we've just written
00131         left -= toWrite;
00132         address += toWrite;
00133     }
00134     
00135     return size;
00136 }
00137 
00138 size_t I2CEeprom::fill(size_t address, char value, size_t size) {
00139     // Check the address and size fit onto the chip.
00140     if (!checkSpace(address, size))
00141         return 0;
00142         
00143     size_t left = size;
00144     
00145     while (left != 0) {
00146         size_t toWrite;
00147         if ((address % m_pageSize) != 0) {
00148             toWrite = (((address / m_pageSize) + 1) * 64) - address;
00149             if (toWrite > size) {
00150                 toWrite = size;
00151             }
00152         } else {
00153             if (left <= m_pageSize) {
00154                 toWrite = left;
00155             } else {
00156                 toWrite = m_pageSize;
00157             }
00158         }
00159         
00160         //printf("Writing %d at %d size %d\n\r", value, address, toWrite);
00161         char values[] = { (address >> 8), (address & 0xFF) };
00162 
00163         m_i2c.start();
00164         if (m_i2c.write(m_i2cAddress) == 0) {
00165             return size - left;
00166         }
00167         if (m_i2c.write(values[0]) == 0) {
00168             return size - left;
00169         }
00170         if (m_i2c.write(values[1]) == 0) {
00171             return size - left;
00172         }
00173         
00174         for (int count = 0; count != toWrite; ++count) {
00175             if (m_i2c.write(value) == 0)
00176                 return size - left;
00177         }
00178         
00179         m_i2c.stop();
00180         
00181         waitForWrite();
00182         
00183         left -= toWrite;
00184         address += toWrite;
00185     }
00186     
00187     return size;
00188 }
00189 
00190 void I2CEeprom::waitForWrite() {
00191     // The chip doesn't ACK while writing to the actual EEPROM
00192     // so loop trying to do a zero byte write until it is ACKed
00193     // by the chip.
00194     while (m_i2c.write(m_i2cAddress, 0, 0) != 0) {
00195         // Wait for ack.
00196         wait_ms(1);
00197     }
00198 }
00199 
00200 bool I2CEeprom::checkSpace(size_t address, size_t size) {
00201     // Only check if chip size is non-zero.
00202     if (m_chipSize != 0) {
00203         // Check that the address start in the chip and doesn't
00204         // extend past.
00205         if ((address >= m_chipSize) || ((address + size) >= m_chipSize))
00206             return false;
00207         else
00208             return true;
00209     }
00210     
00211     return true;
00212 }
00213