ArduinoLibs
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
EEPROM24.cpp
1 /*
2  * Copyright (C) 2012 Southern Storm Software, Pty Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include "EEPROM24.h"
24 #include "I2CMaster.h"
25 
95 EEPROM24::EEPROM24(I2CMaster &bus, unsigned long type, uint8_t bank)
96  : _bus(&bus)
97  , _size((type & 0xFFFF) * ((type >> 16) & 0x0FFF))
98  , _pageSize((type >> 16) & 0x0FFF)
99  , _mode((uint8_t)((type >> 28) & 0x0F))
100  , i2cAddress(0x50)
101 {
102  // Adjust the I2C address for the memory bank of the chip.
103  switch (_mode) {
104  case EE_BSEL_NONE:
105  i2cAddress += (bank & 0x07);
106  break;
107  case EE_BSEL_8BIT_ADDR: {
108  uint8_t addrBits = 8;
109  unsigned long size = 0x0100;
110  while (size < _size) {
111  ++addrBits;
112  size <<= 1;
113  }
114  if (addrBits < 11)
115  i2cAddress += ((bank << (addrBits - 8)) & 0x07);
116  break; }
117  case EE_BSEL_17BIT_ADDR:
118  i2cAddress += ((bank << 1) & 0x06);
119  break;
120  case EE_BSEL_17BIT_ADDR_ALT:
121  i2cAddress += bank & 0x03;
122  break;
123  }
124 }
125 
153 {
154  // Perform a "Current Address Read" on the EEPROM. We don't care about
155  // the returned byte. We only care if the read request was ACK'ed or not.
156  if (!_bus->startRead(i2cAddress, 1))
157  return false;
158  _bus->read();
159  return true;
160 }
161 
167 uint8_t EEPROM24::read(unsigned long address)
168 {
169  if (address >= _size)
170  return 0;
171  writeAddress(address);
172  if (!_bus->startRead(i2cAddress, 1))
173  return 0;
174  return _bus->read();
175 }
176 
187 size_t EEPROM24::read(unsigned long address, void *data, size_t length)
188 {
189  if (address >= _size || !length)
190  return 0;
191  if ((address + length) > _size)
192  length = (size_t)(_size - address);
193  writeAddress(address);
194  if (!_bus->startRead(i2cAddress, length))
195  return 0;
196  uint8_t *d = (uint8_t *)data;
197  unsigned int count = 0;
198  while (_bus->available()) {
199  *d++ = _bus->read();
200  ++count;
201  }
202  return count;
203 }
204 
213 bool EEPROM24::write(unsigned long address, uint8_t value)
214 {
215  if (address >= _size)
216  return false;
217  writeAddress(address);
218  _bus->write(value);
219  return waitForWrite();
220 }
221 
235 size_t EEPROM24::write(unsigned long address, const void *data, size_t length)
236 {
237  if (address >= _size)
238  return 0;
239  if ((address + length) > _size)
240  length = (size_t)(_size - address);
241  bool needAddress = true;
242  size_t result = 0;
243  size_t page = 0;
244  const uint8_t *d = (const uint8_t *)data;
245  while (length > 0) {
246  if (needAddress) {
247  writeAddress(address);
248  needAddress = false;
249  }
250  _bus->write(*d++);
251  ++address;
252  ++page;
253  if ((address & (_pageSize - 1)) == 0) {
254  // At the end of a page, so perform a flush.
255  if (!waitForWrite())
256  return result; // Could not write this page.
257  needAddress = true;
258  result += page;
259  page = 0;
260  }
261  --length;
262  }
263  if (!needAddress) {
264  if (!waitForWrite())
265  return result; // Could not write the final page.
266  }
267  return result + page;
268 }
269 
270 void EEPROM24::writeAddress(unsigned long address)
271 {
272  switch (_mode) {
273  case EE_BSEL_NONE:
274  _bus->startWrite(i2cAddress);
275  _bus->write((uint8_t)(address >> 8));
276  _bus->write((uint8_t)address);
277  break;
278  case EE_BSEL_8BIT_ADDR:
279  _bus->startWrite(i2cAddress | (((uint8_t)(address >> 8)) & 0x07));
280  _bus->write((uint8_t)address);
281  break;
282  case EE_BSEL_17BIT_ADDR:
283  _bus->startWrite(i2cAddress | (((uint8_t)(address >> 16)) & 0x01));
284  _bus->write((uint8_t)(address >> 8));
285  _bus->write((uint8_t)address);
286  break;
287  case EE_BSEL_17BIT_ADDR_ALT:
288  _bus->startWrite(i2cAddress | (((uint8_t)(address >> 14)) & 0x04));
289  _bus->write((uint8_t)(address >> 8));
290  _bus->write((uint8_t)address);
291  break;
292  }
293 }
294 
295 bool EEPROM24::waitForWrite()
296 {
297  // 1000 iterations is going to be approximately 100ms when the I2C
298  // clock is 100 kHz. If there has been no response in that time
299  // then we assume that the write has failed and timeout.
300  if (!_bus->endWrite())
301  return false;
302  unsigned count = 1000;
303  while (count > 0) {
304  _bus->startWrite(i2cAddress);
305  if (_bus->endWrite())
306  return true;
307  --count;
308  }
309  return false;
310 }
unsigned long size() const
Returns the size of the EEPROM in bytes.
Definition: EEPROM24.h:65
uint8_t read(unsigned long address)
Reads a single byte from the EEPROM at address.
Definition: EEPROM24.cpp:167
virtual void write(uint8_t value)=0
Writes a single byte value on the I2C bus.
virtual bool startRead(unsigned int address, unsigned int count)=0
Starts a read operation for count bytes by sending the start condition and the I2C control byte...
EEPROM24(I2CMaster &bus, unsigned long type, uint8_t bank=0)
Constructs a new EEPROM access object on bus for an EEPROM of the specified type. ...
Definition: EEPROM24.cpp:95
bool write(unsigned long address, uint8_t value)
Writes a byte value to address in the EEPROM.
Definition: EEPROM24.cpp:213
virtual unsigned int available()=0
Returns the number of bytes that are still available for reading.
virtual void startWrite(unsigned int address)
Starts a write operation by sending a start condition and the I2C control byte.
virtual bool endWrite()=0
Ends the current write operation.
Abstract base class for I2C master implementations.
Definition: I2CMaster.h:28
bool available()
Returns true if the EEPROM is available on the I2C bus; false otherwise.
Definition: EEPROM24.cpp:152
virtual uint8_t read()=0
Reads a single byte from the I2C bus.