1
0
mirror of https://github.com/taigrr/arduinolibs synced 2025-01-18 04:33:12 -08:00

Support for 24LCXX EEPROM's via I2C

This commit is contained in:
Rhys Weatherley 2012-06-10 14:02:36 +10:00
parent 0e8cf83d0f
commit 41b9b3da39
6 changed files with 499 additions and 1 deletions

View File

@ -688,7 +688,7 @@ EXAMPLE_RECURSIVE = NO
# directories that contain image that are included in the documentation (see # directories that contain image that are included in the documentation (see
# the \image command). # the \image command).
IMAGE_PATH = ../libraries/BlinkLED/examples/Cylon ../libraries/BlinkLED/examples/Cylon4 ../libraries/BlinkLED/examples/StarTrek ../libraries/BlinkLED/examples/Charlieplex ../libraries/LCD/examples/HelloWorld ../libraries/LCD/examples/Form ../libraries/RTC/examples/AlarmClock ../libraries/DMD ../libraries/IR IMAGE_PATH = ../libraries/BlinkLED/examples/Cylon ../libraries/BlinkLED/examples/Cylon4 ../libraries/BlinkLED/examples/StarTrek ../libraries/BlinkLED/examples/Charlieplex ../libraries/LCD/examples/HelloWorld ../libraries/LCD/examples/Form ../libraries/RTC/examples/AlarmClock ../libraries/DMD ../libraries/IR ../libraries/I2C
# The INPUT_FILTER tag can be used to specify a program that doxygen should # The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program # invoke to filter for each input file. Doxygen will invoke the filter program

View File

@ -75,6 +75,7 @@ I2C master.
\li SoftI2C class that implements the master side of the I2C protocol \li SoftI2C class that implements the master side of the I2C protocol
in software on any arbitrary pair of pins for DATA and CLOCK. in software on any arbitrary pair of pins for DATA and CLOCK.
This class supports both 7-bit and 10-bit I2C addresses. This class supports both 7-bit and 10-bit I2C addresses.
\li EEPROM24 class for reading and writing 24LCXX family EEPROM's.
\section main_RTC Realtime Clock Library \section main_RTC Realtime Clock Library

310
libraries/I2C/EEPROM24.cpp Normal file
View File

@ -0,0 +1,310 @@
/*
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "EEPROM24.h"
#include "I2CMaster.h"
/**
* \class EEPROM24 EEPROM24.h <EEPROM24.h>
* \brief Reading and writing EEPROM's from the 24LCXX family.
*
* The 24LCXX family of EEPROM's provide a variety of memory sizes from
* 16 bytes up to 128 kBytes that can be accessed via the I2C protocol.
* These chips can be used to augment the 1 kByte or so of builtin EEPROM
* memory that is typical on Arduino boards. The EEPROM should be wired
* to an Arduino Uno as follows:
*
* \image html eeprom_circuit.png
*
* Access to a 24LCXX chip is initialized as follows:
*
* \code
* SoftI2C i2c(A4, A5);
* EEPROM24 eeprom(i2c, EEPROM_24LC256);
* \endcode
*
* Once initialized, read() and write() can be used to manipulate the
* contents of the EEPROM's memory.
*
* The following EEPROM types are supported by this class:
*
* <table>
* <tr><td>Chip</td><td>Type</td><td>Size</td></tr>
* <tr><td>24lc00</td><td>\c EEPROM_24LC00</td><td>16 bytes</td></tr>
* <tr><td>24lc01</td><td>\c EEPROM_24LC01</td><td>128 bytes</td></tr>
* <tr><td>24lc014</td><td>\c EEPROM_24LC014</td><td>128 bytes</td></tr>
* <tr><td>24lc02</td><td>\c EEPROM_24LC02</td><td>256 bytes</td></tr>
* <tr><td>24lc024</td><td>\c EEPROM_24LC024</td><td>256 bytes</td></tr>
* <tr><td>24lc025</td><td>\c EEPROM_24LC025</td><td>256 bytes</td></tr>
* <tr><td>24lc04</td><td>\c EEPROM_24LC04</td><td>512 bytes</td></tr>
* <tr><td>24lc08</td><td>\c EEPROM_24LC08</td><td>1 kByte</td></tr>
* <tr><td>24lc16</td><td>\c EEPROM_24LC16</td><td>2 kBytes</td></tr>
* <tr><td>24lc32</td><td>\c EEPROM_24LC32</td><td>4 kBytes</td></tr>
* <tr><td>24lc64</td><td>\c EEPROM_24LC64</td><td>8 kBytes</td></tr>
* <tr><td>24lc128</td><td>\c EEPROM_24LC128</td><td>16 kBytes</td></tr>
* <tr><td>24lc256</td><td>\c EEPROM_24LC256</td><td>32 kBytes</td></tr>
* <tr><td>24lc512</td><td>\c EEPROM_24LC512</td><td>64 kBytes</td></tr>
* <tr><td>24lc1025</td><td>\c EEPROM_24LC1025</td><td>128 kBytes</td></tr>
* <tr><td>24lc1026</td><td>\c EEPROM_24LC1026</td><td>128 kBytes</td></tr>
* </table>
*
* There can be multiple 24LCXX chips on the same I2C bus, as long as their
* A0, A1, and A2 address pins are set to different values. For example,
* two 24LC256 chips can be used to provide the same memory capacity as a
* single 24LC512 chip. The optional <i>bank</i> parameter to the constructor
* is used to assign different bank addresses to each chip:
*
* \code
* SoftI2C i2c(A4, A5);
* EEPROM24 eeprom0(i2c, EEPROM_24LC256, 0);
* EEPROM24 eeprom1(i2c, EEPROM_24LC256, 1);
* \endcode
*
* \sa I2CMaster
*/
/**
* \brief Constructs a new EEPROM access object on \a bus for an EEPROM
* of the specified \a type.
*
* The \a bank can be used to choose between multiple EEPROM's on
* \a bus of the specified \a type. The \a bank corresponds to the value
* that is set on the EEPROM's A0, A1, and A2 address pins. Note that
* some EEPROM's have less than 3 address pins; consult the datasheet
* for more information.
*/
EEPROM24::EEPROM24(I2CMaster &bus, unsigned long type, uint8_t bank)
: _bus(&bus)
, _size((type & 0xFFFF) * ((type >> 16) & 0x0FFF))
, _pageSize((type >> 16) & 0x0FFF)
, _mode((uint8_t)((type >> 28) & 0x0F))
, i2cAddress(0x50)
{
// Adjust the I2C address for the memory bank of the chip.
switch (_mode) {
case EE_BSEL_NONE:
i2cAddress += (bank & 0x07);
break;
case EE_BSEL_8BIT_ADDR: {
uint8_t addrBits = 8;
unsigned long size = 0x0100;
while (size < _size) {
++addrBits;
size <<= 1;
}
if (addrBits < 11)
i2cAddress += ((bank << (addrBits - 8)) & 0x07);
break; }
case EE_BSEL_17BIT_ADDR:
i2cAddress += ((bank << 1) & 0x06);
break;
case EE_BSEL_17BIT_ADDR_ALT:
i2cAddress += bank & 0x03;
break;
}
}
/**
* \fn unsigned long EEPROM24::size() const
* \brief Returns the size of the EEPROM in bytes.
*
* \sa pageSize()
*/
/**
* \fn unsigned long EEPROM24::pageSize() const
* \brief Returns the size of a single EEPROM page in bytes.
*
* Writes that are a multiple of the page size and aligned on a page
* boundary will typically be more efficient than non-aligned writes.
*
* \sa size()
*/
/**
* \brief Returns true if the EEPROM is available on the I2C bus;
* false otherwise.
*
* This function can be used to probe the I2C bus to determine if the
* EEPROM is present or not.
*
* \sa read(), write()
*/
bool EEPROM24::available()
{
// Perform a "Current Address Read" on the EEPROM. We don't care about
// the returned byte. We only care if the read request was ACK'ed or not.
if (!_bus->startRead(i2cAddress, 1))
return false;
_bus->read();
return true;
}
/**
* \brief Reads a single byte from the EEPROM at \a address.
*
* \sa write()
*/
uint8_t EEPROM24::read(unsigned long address)
{
if (address >= _size)
return 0;
writeAddress(address);
if (!_bus->startRead(i2cAddress, 1))
return 0;
return _bus->read();
}
/**
* \brief Reads a block of \a length bytes from the EEPROM at \a address
* into the specified \a data buffer.
*
* Returns the number of bytes that were read, which may be short if
* \a address + \a length is greater than size() or the EEPROM is
* not available on the I2C bus.
*
* \sa write(), available()
*/
size_t EEPROM24::read(unsigned long address, void *data, size_t length)
{
if (address >= _size || !length)
return 0;
if ((address + length) > _size)
length = (size_t)(_size - address);
writeAddress(address);
if (!_bus->startRead(i2cAddress, length))
return 0;
uint8_t *d = (uint8_t *)data;
unsigned int count = 0;
while (_bus->available()) {
*d++ = _bus->read();
++count;
}
return count;
}
/**
* \brief Writes a byte \a value to \a address in the EEPROM.
*
* Returns true if the byte was written successfully, or false if
* \a address is out of range or the EEPROM is not available on the I2C bus.
*
* \sa read(), available()
*/
bool EEPROM24::write(unsigned long address, uint8_t value)
{
if (address >= _size)
return false;
writeAddress(address);
_bus->write(value);
return waitForWrite();
}
/**
* \brief Writes \a length bytes from a \a data buffer to \a address
* in the EEPROM.
*
* Returns the number of bytes that were written, which may be short if
* \a address + \a length is greater than size() or the EEPROM is not
* available on the I2C bus.
*
* Best performance will be achieved if \a address and \a length are a
* multiple of pageSize().
*
* \sa read(), available(), pageSize()
*/
size_t EEPROM24::write(unsigned long address, const void *data, size_t length)
{
if (address >= _size)
return 0;
if ((address + length) > _size)
length = (size_t)(_size - address);
bool needAddress = true;
size_t result = 0;
size_t page = 0;
const uint8_t *d = (const uint8_t *)data;
while (length > 0) {
if (needAddress) {
writeAddress(address);
needAddress = false;
}
_bus->write(*d++);
++address;
++page;
if ((address & (_pageSize - 1)) == 0) {
// At the end of a page, so perform a flush.
if (!waitForWrite())
return result; // Could not write this page.
needAddress = true;
result += page;
page = 0;
}
--length;
}
if (!needAddress) {
if (!waitForWrite())
return result; // Could not write the final page.
}
return result + page;
}
void EEPROM24::writeAddress(unsigned long address)
{
switch (_mode) {
case EE_BSEL_NONE:
_bus->startWrite(i2cAddress);
_bus->write((uint8_t)(address >> 8));
_bus->write((uint8_t)address);
break;
case EE_BSEL_8BIT_ADDR:
_bus->startWrite(i2cAddress | (((uint8_t)(address >> 8)) & 0x07));
_bus->write((uint8_t)address);
break;
case EE_BSEL_17BIT_ADDR:
_bus->startWrite(i2cAddress | (((uint8_t)(address >> 16)) & 0x01));
_bus->write((uint8_t)(address >> 8));
_bus->write((uint8_t)address);
break;
case EE_BSEL_17BIT_ADDR_ALT:
_bus->startWrite(i2cAddress | (((uint8_t)(address >> 14)) & 0x04));
_bus->write((uint8_t)(address >> 8));
_bus->write((uint8_t)address);
break;
}
}
bool EEPROM24::waitForWrite()
{
// 1000 iterations is going to be approximately 100ms when the I2C
// clock is 100 kHz. If there has been no response in that time
// then we assume that the write has failed and timeout.
if (!_bus->endWrite())
return false;
unsigned count = 1000;
while (count > 0) {
_bus->startWrite(i2cAddress);
if (_bus->endWrite())
return true;
--count;
}
return false;
}

87
libraries/I2C/EEPROM24.h Normal file
View File

@ -0,0 +1,87 @@
/*
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef EEPROM24_h
#define EEPROM24_h
#include <inttypes.h>
#include <stddef.h>
class I2CMaster;
// Block select modes.
#define EE_BSEL_NONE 0
#define EE_BSEL_8BIT_ADDR 1
#define EE_BSEL_17BIT_ADDR 2
#define EE_BSEL_17BIT_ADDR_ALT 3
// Create an EEPROM descriptor from byte size, page size, and block select mode.
#define _EE24(byteSize, pageSize, mode) \
(((byteSize) / (pageSize)) | (((unsigned long)(pageSize)) << 16) | \
(((unsigned long)(mode)) << 28))
// Type descriptors for the 24LCXX range of EEPROM's.
#define EEPROM_24LC00 _EE24(16UL, 1, EE_BSEL_8BIT_ADDR)
#define EEPROM_24LC01 _EE24(128UL, 8, EE_BSEL_8BIT_ADDR)
#define EEPROM_24LC014 _EE24(128UL, 16, EE_BSEL_8BIT_ADDR)
#define EEPROM_24LC02 _EE24(256UL, 8, EE_BSEL_8BIT_ADDR)
#define EEPROM_24LC024 _EE24(256UL, 16, EE_BSEL_8BIT_ADDR)
#define EEPROM_24LC025 _EE24(256UL, 16, EE_BSEL_8BIT_ADDR)
#define EEPROM_24LC04 _EE24(512UL, 16, EE_BSEL_8BIT_ADDR)
#define EEPROM_24LC08 _EE24(1024UL, 16, EE_BSEL_8BIT_ADDR)
#define EEPROM_24LC16 _EE24(2048UL, 16, EE_BSEL_8BIT_ADDR)
#define EEPROM_24LC32 _EE24(4096UL, 32, EE_BSEL_NONE)
#define EEPROM_24LC64 _EE24(8192UL, 32, EE_BSEL_NONE)
#define EEPROM_24LC128 _EE24(16384UL, 32, EE_BSEL_NONE)
#define EEPROM_24LC256 _EE24(32768UL, 64, EE_BSEL_NONE)
#define EEPROM_24LC512 _EE24(65536UL, 128, EE_BSEL_NONE)
#define EEPROM_24LC1025 _EE24(131072UL, 128, EE_BSEL_17BIT_ADDR_ALT)
#define EEPROM_24LC1026 _EE24(131072UL, 128, EE_BSEL_17BIT_ADDR)
class EEPROM24
{
public:
EEPROM24(I2CMaster &bus, unsigned long type, uint8_t bank = 0);
unsigned long size() const { return _size; }
unsigned long pageSize() const { return _pageSize; }
bool available();
uint8_t read(unsigned long address);
size_t read(unsigned long address, void *data, size_t length);
bool write(unsigned long address, uint8_t value);
size_t write(unsigned long address, const void *data, size_t length);
private:
I2CMaster *_bus;
unsigned long _size;
unsigned long _pageSize;
uint8_t _mode;
uint8_t i2cAddress;
void writeAddress(unsigned long address);
bool waitForWrite();
};
#endif

View File

@ -0,0 +1,100 @@
#FIG 3.2 Produced by xfig version 3.2.5b
Landscape
Center
Metric
A4
100.00
Single
-2
1200 2
6 3105 3555 3195 3645
1 3 0 1 0 -1 0 0 20 0.000 1 0.0000 3150 3600 30 30 3150 3600 3150 3630
-6
6 3105 3780 3195 3870
1 3 0 1 0 -1 0 0 20 0.000 1 0.0000 3150 3825 30 30 3150 3825 3150 3855
-6
6 3105 4005 3195 4095
1 3 0 1 0 -1 0 0 20 0.000 1 0.0000 3150 4050 30 30 3150 4050 3150 4080
-6
6 3060 4095 3240 4365
2 1 0 1 0 -1 0 0 -1 0.000 0 0 -1 0 0 2
3135 4365 3165 4365
2 1 0 1 0 -1 0 0 -1 0.000 0 0 -1 0 0 2
3100 4320 3200 4320
2 1 0 1 0 -1 0 0 -1 0.000 0 0 -1 0 0 2
3060 4275 3240 4275
2 1 0 1 0 -1 0 0 -1 0.000 0 0 -1 0 0 2
3150 4095 3150 4275
-6
6 5400 3285 5715 3465
2 1 0 1 0 -1 0 0 -1 0.000 0 0 -1 0 0 2
5580 3375 5715 3375
2 1 0 1 0 -1 0 0 -1 0.000 0 0 -1 0 0 2
5535 3375 5400 3375
2 1 0 1 0 -1 0 0 -1 0.000 0 0 -1 0 0 2
5580 3285 5580 3465
2 1 0 1 0 -1 0 0 -1 0.000 0 0 -1 0 0 2
5535 3285 5535 3465
-6
6 5760 3600 5940 3870
2 1 0 1 0 -1 0 0 -1 0.000 0 0 -1 0 0 2
5835 3870 5865 3870
2 1 0 1 0 -1 0 0 -1 0.000 0 0 -1 0 0 2
5800 3825 5900 3825
2 1 0 1 0 -1 0 0 -1 0.000 0 0 -1 0 0 2
5760 3780 5940 3780
2 1 0 1 0 -1 0 0 -1 0.000 0 0 -1 0 0 2
5850 3600 5850 3780
-6
6 5130 3330 5220 3420
1 3 0 1 0 -1 0 0 20 0.000 1 0.0000 5175 3375 30 30 5175 3375 5175 3405
-6
6 5805 3555 5895 3645
1 3 0 1 0 -1 0 0 20 0.000 1 0.0000 5850 3600 30 30 5850 3600 5850 3630
-6
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
3150 3600 3825 3600
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
3150 3825 3825 3825
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
3150 4050 3825 4050
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
3825 3150 4725 3150 4725 4275 3825 4275 3825 3150
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
3825 3375 3150 3375 3150 4140
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
1 1 1.00 60.00 120.00
4725 3375 5175 3375 5175 2700
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
5400 3375 5085 3375
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
5850 3375 5670 3375
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
4725 3600 5850 3600 5850 3375
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
1 1 1.00 60.00 120.00
4725 4050 5175 4050 5175 4500
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
1 1 1.00 60.00 120.00
4725 3825 5625 3825 5625 4500
4 0 0 50 -1 0 12 0.0000 4 135 105 3690 4005 4\001
4 0 0 50 -1 0 12 0.0000 4 135 105 4770 4005 5\001
4 0 0 50 -1 0 12 0.0000 4 135 105 4770 3780 6\001
4 0 0 50 -1 0 12 0.0000 4 135 105 4770 3555 7\001
4 0 0 50 -1 0 12 0.0000 4 135 105 4770 3330 8\001
4 0 0 50 -1 0 12 0.0000 4 135 105 3690 3780 3\001
4 0 0 50 -1 0 12 0.0000 4 135 105 3690 3555 2\001
4 0 0 50 -1 0 12 0.0000 4 135 105 3690 3330 1\001
4 0 0 50 -1 0 8 0.0000 4 90 180 3870 3420 A0\001
4 0 0 50 -1 0 8 0.0000 4 90 180 3870 3645 A1\001
4 0 0 50 -1 0 8 0.0000 4 90 180 3870 3870 A2\001
4 0 0 50 -1 0 8 0.0000 4 90 315 3870 4095 GND\001
4 0 0 50 -1 0 8 0.0000 4 90 210 4500 3645 WP\001
4 0 0 50 -1 0 8 0.0000 4 90 285 4410 3420 VCC\001
4 0 0 50 -1 0 8 0.0000 4 90 255 4455 3870 SCL\001
4 0 0 50 -1 0 8 0.0000 4 90 285 4455 4095 SDA\001
4 0 0 50 -1 0 12 0.0000 4 135 735 3915 3060 24LCXX\001
4 0 0 50 -1 0 12 0.0000 4 135 240 5040 2610 5V\001
4 0 0 50 -1 0 12 0.0000 4 135 525 5310 3195 100nF\001
4 0 0 50 -1 0 12 0.0000 4 135 240 5040 4680 A4\001
4 0 0 50 -1 0 12 0.0000 4 135 240 5490 4680 A5\001

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB