ArduinoLibs
EEPROM24.cpp
00001 /*
00002  * Copyright (C) 2012 Southern Storm Software, Pty Ltd.
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a
00005  * copy of this software and associated documentation files (the "Software"),
00006  * to deal in the Software without restriction, including without limitation
00007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00008  * and/or sell copies of the Software, and to permit persons to whom the
00009  * Software is furnished to do so, subject to the following conditions:
00010  *
00011  * The above copyright notice and this permission notice shall be included
00012  * in all copies or substantial portions of the Software.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00015  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00017  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00019  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00020  * DEALINGS IN THE SOFTWARE.
00021  */
00022 
00023 #include "EEPROM24.h"
00024 #include "I2CMaster.h"
00025 
00095 EEPROM24::EEPROM24(I2CMaster &bus, unsigned long type, uint8_t bank)
00096     : _bus(&bus)
00097     , _size((type & 0xFFFF) * ((type >> 16) & 0x0FFF))
00098     , _pageSize((type >> 16) & 0x0FFF)
00099     , _mode((uint8_t)((type >> 28) & 0x0F))
00100     , i2cAddress(0x50)
00101 {
00102     // Adjust the I2C address for the memory bank of the chip.
00103     switch (_mode) {
00104     case EE_BSEL_NONE:
00105         i2cAddress += (bank & 0x07);
00106         break;
00107     case EE_BSEL_8BIT_ADDR: {
00108         uint8_t addrBits = 8;
00109         unsigned long size = 0x0100;
00110         while (size < _size) {
00111             ++addrBits;
00112             size <<= 1;
00113         }
00114         if (addrBits < 11)
00115             i2cAddress += ((bank << (addrBits - 8)) & 0x07);
00116         break; }
00117     case EE_BSEL_17BIT_ADDR:
00118         i2cAddress += ((bank << 1) & 0x06);
00119         break;
00120     case EE_BSEL_17BIT_ADDR_ALT:
00121         i2cAddress += bank & 0x03;
00122         break;
00123     }
00124 }
00125 
00152 bool EEPROM24::available()
00153 {
00154     // Perform a "Current Address Read" on the EEPROM.  We don't care about
00155     // the returned byte.  We only care if the read request was ACK'ed or not.
00156     if (!_bus->startRead(i2cAddress, 1))
00157         return false;
00158     _bus->read();
00159     return true;
00160 }
00161 
00167 uint8_t EEPROM24::read(unsigned long address)
00168 {
00169     if (address >= _size)
00170         return 0;
00171     writeAddress(address);
00172     if (!_bus->startRead(i2cAddress, 1))
00173         return 0;
00174     return _bus->read();
00175 }
00176 
00187 size_t EEPROM24::read(unsigned long address, void *data, size_t length)
00188 {
00189     if (address >= _size || !length)
00190         return 0;
00191     if ((address + length) > _size)
00192         length = (size_t)(_size - address);
00193     writeAddress(address);
00194     if (!_bus->startRead(i2cAddress, length))
00195         return 0;
00196     uint8_t *d = (uint8_t *)data;
00197     unsigned int count = 0;
00198     while (_bus->available()) {
00199         *d++ = _bus->read();
00200         ++count;
00201     }
00202     return count;
00203 }
00204 
00213 bool EEPROM24::write(unsigned long address, uint8_t value)
00214 {
00215     if (address >= _size)
00216         return false;
00217     writeAddress(address);
00218     _bus->write(value);
00219     return waitForWrite();
00220 }
00221 
00235 size_t EEPROM24::write(unsigned long address, const void *data, size_t length)
00236 {
00237     if (address >= _size)
00238         return 0;
00239     if ((address + length) > _size)
00240         length = (size_t)(_size - address);
00241     bool needAddress = true;
00242     size_t result = 0;
00243     size_t page = 0;
00244     const uint8_t *d = (const uint8_t *)data;
00245     while (length > 0) {
00246         if (needAddress) {
00247             writeAddress(address);
00248             needAddress = false;
00249         }
00250         _bus->write(*d++);
00251         ++address;
00252         ++page;
00253         if ((address & (_pageSize - 1)) == 0) {
00254             // At the end of a page, so perform a flush.
00255             if (!waitForWrite())
00256                 return result;  // Could not write this page.
00257             needAddress = true;
00258             result += page;
00259             page = 0;
00260         }
00261         --length;
00262     }
00263     if (!needAddress) {
00264         if (!waitForWrite())
00265             return result;  // Could not write the final page.
00266     }
00267     return result + page;
00268 }
00269 
00270 void EEPROM24::writeAddress(unsigned long address)
00271 {
00272     switch (_mode) {
00273     case EE_BSEL_NONE:
00274         _bus->startWrite(i2cAddress);
00275         _bus->write((uint8_t)(address >> 8));
00276         _bus->write((uint8_t)address);
00277         break;
00278     case EE_BSEL_8BIT_ADDR:
00279         _bus->startWrite(i2cAddress | (((uint8_t)(address >> 8)) & 0x07));
00280         _bus->write((uint8_t)address);
00281         break;
00282     case EE_BSEL_17BIT_ADDR:
00283         _bus->startWrite(i2cAddress | (((uint8_t)(address >> 16)) & 0x01));
00284         _bus->write((uint8_t)(address >> 8));
00285         _bus->write((uint8_t)address);
00286         break;
00287     case EE_BSEL_17BIT_ADDR_ALT:
00288         _bus->startWrite(i2cAddress | (((uint8_t)(address >> 14)) & 0x04));
00289         _bus->write((uint8_t)(address >> 8));
00290         _bus->write((uint8_t)address);
00291         break;
00292     }
00293 }
00294 
00295 bool EEPROM24::waitForWrite()
00296 {
00297     // 1000 iterations is going to be approximately 100ms when the I2C
00298     // clock is 100 kHz.  If there has been no response in that time
00299     // then we assume that the write has failed and timeout.
00300     if (!_bus->endWrite())
00301         return false;
00302     unsigned count = 1000;
00303     while (count > 0) {
00304         _bus->startWrite(i2cAddress);
00305         if (_bus->endWrite())
00306             return true;
00307         --count;
00308     }
00309     return false;
00310 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator