|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- /*-----------------------------------------------------------------------------*
- * extEEPROM.cpp - Arduino library to support external I2C EEPROMs. *
- * *
- * This library will work with most I2C serial EEPROM chips between 2k bits *
- * and 2048k bits (2M bits) in size. Multiple EEPROMs on the bus are supported *
- * as a single address space. I/O across block, page and device boundaries *
- * is supported. Certain assumptions are made regarding the EEPROM *
- * device addressing. These assumptions should be true for most EEPROMs *
- * but there are exceptions, so read the datasheet and know your hardware. *
- * *
- * The library should also work for EEPROMs smaller than 2k bits, assuming *
- * that there is only one EEPROM on the bus and also that the user is careful *
- * to not exceed the maximum address for the EEPROM. *
- * *
- * Library tested with: *
- * Microchip 24AA02E48 (2k bit) *
- * 24xx32 (32k bit, thanks to Richard M) *
- * Microchip 24LC256 (256k bit) *
- * Microchip 24FC1026 (1M bit, thanks to Gabriele B on the Arduino forum) *
- * ST Micro M24M02 (2M bit) *
- * *
- * Library will NOT work with Microchip 24xx1025 as its control byte does not *
- * conform to the following assumptions. *
- * *
- * Device addressing assumptions: *
- * 1. The I2C address sequence consists of a control byte followed by one *
- * address byte (for EEPROMs <= 16k bits) or two address bytes (for *
- * EEPROMs > 16k bits). *
- * 2. The three least-significant bits in the control byte (excluding the R/W *
- * bit) comprise the three most-significant bits for the entire address *
- * space, i.e. all chips on the bus. As such, these may be chip-select *
- * bits or block-select bits (for individual chips that have an internal *
- * block organization), or a combination of both (in which case the *
- * block-select bits must be of lesser significance than the chip-select *
- * bits). *
- * 3. Regardless of the number of bits needed to address the entire address *
- * space, the three most-significant bits always go in the control byte. *
- * Depending on EEPROM device size, this may result in one or more of the *
- * most significant bits in the I2C address bytes being unused (or "don't *
- * care"). *
- * 4. An EEPROM contains an integral number of pages. *
- * *
- * To use the extEEPROM library, the Arduino Wire library must also *
- * be included. *
- * *
- * Jack Christensen 23Mar2013 v1 *
- * 29Mar2013 v2 - Updated to span page boundaries (and therefore also *
- * device boundaries, assuming an integral number of pages per device) *
- * 08Jul2014 v3 - Generalized for 2kb - 2Mb EEPROMs. *
- * *
- * Paolo Paolucci 22-10-2015 v3.1 *
- * 09-01-2016 v3.2 Add update function. *
- * *
- * External EEPROM Library by Jack Christensen is licensed under CC BY-SA 4.0, *
- * http://creativecommons.org/licenses/by-sa/4.0/ *
- *-----------------------------------------------------------------------------*/
-
- #include "extEEPROM.h"
-
- // workaround, BUFFER_LENGTH is not defined in Wire.h for SAMD controllers
- #ifndef BUFFER_LENGTH
- #define BUFFER_LENGTH 32
- #endif
-
- // Constructor.
- // - deviceCapacity is the capacity of a single EEPROM device in
- // kilobits (kb) and should be one of the values defined in the
- // eeprom_size_t enumeration in the extEEPROM.h file. (Most
- // EEPROM manufacturers use kbits in their part numbers.)
- // - nDevice is the number of EEPROM devices on the I2C bus (all must
- // be identical).
- // - pageSize is the EEPROM's page size in bytes.
- // - eepromAddr is the EEPROM's I2C address and defaults to 0x50 which is common.
- extEEPROM::extEEPROM(eeprom_size_t deviceCapacity, byte nDevice, unsigned int pageSize,
- uint8_t eepromAddr)
- {
- communication = NULL;
- _dvcCapacity = deviceCapacity;
- _nDevice = nDevice;
- _pageSize = pageSize;
- _eepromAddr = eepromAddr;
- _totalCapacity = _nDevice * _dvcCapacity * 1024UL / 8;
- _nAddrBytes = deviceCapacity > kbits_16 ? 2 :
- 1; //two address bytes needed for eeproms > 16kbits
-
- //determine the bitshift needed to isolate the chip select bits from the address to put into the control byte
- uint16_t kb = _dvcCapacity;
- if ( kb <= kbits_16 ) {
- _csShift = 8;
- } else if ( kb >= kbits_512 ) {
- _csShift = 16;
- } else {
- kb >>= 6;
- _csShift = 12;
- while ( kb >= 1 ) {
- ++_csShift;
- kb >>= 1;
- }
- }
- }
-
- //initialize the I2C bus and do a dummy write (no data sent)
- //to the device so that the caller can determine whether it is responding.
- //when using a 400kHz bus speed and there are multiple I2C devices on the
- //bus (other than EEPROM), call extEEPROM::begin() after any initialization
- //calls for the other devices to ensure the intended I2C clock speed is set.
- byte extEEPROM::begin(twiClockFreq_t twiFreq, TwoWire *_comm)
- {
- communication = _comm;
- communication->begin();
- communication->setClock(twiFreq);
- communication->beginTransmission(_eepromAddr);
- if (_nAddrBytes == 2) {
- communication->write((byte)0); //high addr byte
- }
- communication->write((byte)0); //low addr byte
- return communication->endTransmission();
- }
-
- //Write bytes to external EEPROM.
- //If the I/O would extend past the top of the EEPROM address space,
- //a status of EEPROM_ADDR_ERR is returned. For I2C errors, the status
- //from the Arduino Wire library is passed back through to the caller.
- byte extEEPROM::write(unsigned long addr, byte *values, unsigned int nBytes)
- {
- uint8_t txStatus = 0; //transmit status
-
- if (addr + nBytes > _totalCapacity) { //will this write go past the top of the EEPROM?
- return EEPROM_ADDR_ERR; //yes, tell the caller
- }
-
- while (nBytes > 0) {
- const uint16_t nPage = _pageSize - ( addr & (_pageSize - 1) );
- //find min(nBytes, nPage, BUFFER_LENGTH) -- BUFFER_LENGTH is defined in the Wire library.
- uint16_t nWrite = nBytes < nPage ? nBytes : nPage;
- nWrite = BUFFER_LENGTH - _nAddrBytes < nWrite ? BUFFER_LENGTH - _nAddrBytes : nWrite;
- const uint8_t ctrlByte = _eepromAddr | (byte) (addr >> _csShift);
- communication->beginTransmission(ctrlByte);
- if (_nAddrBytes == 2) {
- communication->write( (byte) (addr >> 8) ); //high addr byte
- }
- communication->write( (byte) addr ); //low addr byte
- communication->write(values, nWrite);
- txStatus = communication->endTransmission();
- if (txStatus != 0) {
- return txStatus;
- }
-
- //wait up to 50ms for the write to complete
- for (uint8_t i=100; i; --i) {
- delayMicroseconds(500); //no point in waiting too fast
- communication->beginTransmission(ctrlByte);
- if (_nAddrBytes == 2) {
- communication->write((byte)0); //high addr byte
- }
- communication->write((byte)0); //low addr byte
- txStatus = communication->endTransmission();
- if (txStatus == 0) {
- break;
- }
- }
- if (txStatus != 0) {
- return txStatus;
- }
-
- addr += nWrite; //increment the EEPROM address
- values += nWrite; //increment the input data pointer
- nBytes -= nWrite; //decrement the number of bytes left to write
- }
- return txStatus;
- }
-
- //Read bytes from external EEPROM.
- //If the I/O would extend past the top of the EEPROM address space,
- //a status of EEPROM_ADDR_ERR is returned. For I2C errors, the status
- //from the Arduino Wire library is passed back through to the caller.
- byte extEEPROM::read(unsigned long addr, byte *values, unsigned int nBytes)
- {
- if (addr + nBytes > _totalCapacity) { //will this read take us past the top of the EEPROM?
- return EEPROM_ADDR_ERR; //yes, tell the caller
- }
-
- while (nBytes > 0) {
- const uint16_t nPage = _pageSize - ( addr & (_pageSize - 1) );
- uint16_t nRead = nBytes < nPage ? nBytes : nPage;
- nRead = BUFFER_LENGTH < nRead ? BUFFER_LENGTH : nRead;
- byte ctrlByte = _eepromAddr | (byte) (addr >> _csShift);
- communication->beginTransmission(ctrlByte);
- if (_nAddrBytes == 2) {
- communication->write( (byte) (addr >> 8) ); //high addr byte
- }
- communication->write( (byte) addr ); //low addr byte
- const byte rxStatus = communication->endTransmission();
- if (rxStatus != 0) {
- return rxStatus; //read error
- }
-
- communication->requestFrom(ctrlByte, nRead);
- for (byte i=0; i<nRead; i++) {
- values[i] = communication->read();
- }
-
- addr += nRead; //increment the EEPROM address
- values += nRead; //increment the input data pointer
- nBytes -= nRead; //decrement the number of bytes left to write
- }
- return 0;
- }
-
- //Write a single byte to external EEPROM.
- //If the I/O would extend past the top of the EEPROM address space,
- //a status of EEPROM_ADDR_ERR is returned. For I2C errors, the status
- //from the Arduino Wire library is passed back through to the caller.
- byte extEEPROM::write(unsigned long addr, byte value)
- {
- return write(addr, &value, 1);
- }
-
- //Read a single byte from external EEPROM.
- //If the I/O would extend past the top of the EEPROM address space,
- //a status of EEPROM_ADDR_ERR is returned. For I2C errors, the status
- //from the Arduino Wire library is passed back through to the caller.
- //To distinguish error values from valid data, error values are returned as negative numbers.
- int extEEPROM::read(unsigned long addr)
- {
- uint8_t data;
- int ret;
-
- ret = read(addr, &data, 1);
- return ret == 0 ? data : -ret;
- }
-
- //Update bytes to external EEPROM.
- //For I2C errors, the status from the Arduino Wire library is passed back through to the caller.
- byte extEEPROM::update(unsigned long addr, byte *values, unsigned int nBytes)
- {
- for (unsigned int i = 0; i < nBytes; i++) {
- const uint8_t newValue = values[i];
- if (newValue != read(addr + i)) {
- write(addr + i, newValue);
- }
- }
- return true;
- }
-
- //Update a single byte to external EEPROM.
- //For I2C errors, the status from the Arduino Wire library is passed back through to the caller.
- byte extEEPROM::update(unsigned long addr, byte value)
- {
- return (value != read(addr) ? write(addr, &value, 1) : 0);
- }
-
- //For I2C errors, the status from the Arduino Wire library is passed back through to the caller.
- unsigned long extEEPROM::length( void )
- {
- return _totalCapacity * 8;
- }
|