+ improved waitEEReady() -> on average far lower write latency
+ added determineSize -> behind #ifdef to keep base lib small
+ improved comments
+ corrected return type readBlock()
+ updated test sketch
This commit is contained in:
Rob Tillaart 2013-11-06 17:46:04 +01:00
parent afcb60364c
commit a8fc6d45e9
4 changed files with 122 additions and 33 deletions

View File

@ -1,7 +1,7 @@
//
// FILE: I2C_eeprom.cpp
// AUTHOR: Rob Tillaart
// VERSION: 1.0.04
// VERSION: 1.0.05
// PURPOSE: Simple I2C_eeprom library for Arduino with EEPROM 24LC256 et al.
//
// HISTORY:
@ -14,22 +14,19 @@
// 1.0.02 - 2013-11-03 optimize internal buffers, refactor
// 1.0.03 - 2013-11-03 refactor 5 millis() write-latency
// 1.0.04 - 2013-11-03 fix bug in readBlock, moved waitEEReady() -> more efficient.
// 1.0.05 - 2013-11-06 improved waitEEReady(), added determineSize()
//
// Released to the public domain
//
#include <I2C_eeprom.h>
////////////////////////////////////////////////////////////////////
//
// PUBLIC
//
I2C_eeprom::I2C_eeprom(uint8_t device)
{
_deviceAddress = device;
Wire.begin();
TWBR = 12; // 12 = 400Khz 72 = 100 FCPU/16+(2*TWBR)
_lastWrite = 0;
// TWBR = 12; // 12=400Khz 32=200 72=100 152=50 F_CPU/16+(2*TWBR)
}
int I2C_eeprom::writeByte(uint16_t address, uint8_t data)
@ -56,14 +53,14 @@ int I2C_eeprom::writeBlock(uint16_t address, uint8_t* buffer, uint16_t length)
uint8_t I2C_eeprom::readByte(uint16_t address)
{
uint8_t rdata;
_ReadBlock(address, &rdata, 1); // todo check return value..
_ReadBlock(address, &rdata, 1);
return rdata;
}
// maybe let's not read more than 30 or 32 uint8_ts at a time!
int I2C_eeprom::readBlock(uint16_t address, uint8_t* buffer, uint16_t length)
uint16_t I2C_eeprom::readBlock(uint16_t address, uint8_t* buffer, uint16_t length)
{
int rv = 0;
uint16_t rv = 0;
while (length > 0)
{
uint8_t cnt = min(length, I2C_TWIBUFFERSIZE);
@ -75,13 +72,54 @@ int I2C_eeprom::readBlock(uint16_t address, uint8_t* buffer, uint16_t length)
return rv;
}
#ifdef I2C_EEPROM_EXTENDED
// returns 64, 32, 16, 8, 4, 2, 1, 0
// 0 is smaller than 1K
uint8_t I2C_eeprom::determineSize()
{
uint8_t rv = 0; // unknown
uint8_t orgValues[8];
uint16_t addr;
// remember old values, non destructive
for (uint8_t i=0; i<8; i++)
{
addr = (512 << i) + 1;
orgValues[i] = readByte(addr);
}
// scan page folding
for (uint8_t i=0; i<8; i++)
{
rv = i;
uint16_t addr1 = (512 << i) + 1;
uint16_t addr2 = (512 << (i+1)) + 1;
writeByte(addr1, 0xAA);
writeByte(addr2, 0x55);
if (readByte(addr1) == 0x55) // folded!
{
break;
}
}
// restore original values
for (uint8_t i=0; i<8; i++)
{
uint16_t addr = (512 << i) + 1;
writeByte(addr, orgValues[i]);
}
return 0x01 << (rv-1);
}
#endif
////////////////////////////////////////////////////////////////////
//
// PRIVATE
//
// _pageBlock aligns buffer to page boundaries for writing.
// and TWI buffer size
// and to TWI buffer size
// returns 0 = OK otherwise error
int I2C_eeprom::_pageBlock(uint16_t address, uint8_t* buffer, uint16_t length, bool incrBuffer)
{
int rv = 0;
@ -102,6 +140,7 @@ int I2C_eeprom::_pageBlock(uint16_t address, uint8_t* buffer, uint16_t length, b
}
// pre: length <= I2C_EEPROM_PAGESIZE && length <= I2C_TWIBUFFERSIZE;
// returns 0 = OK otherwise error
int I2C_eeprom::_WriteBlock(uint16_t address, uint8_t* buffer, uint8_t length)
{
waitEEReady();
@ -119,13 +158,14 @@ int I2C_eeprom::_WriteBlock(uint16_t address, uint8_t* buffer, uint8_t length)
Wire.send(buffer[cnt]);
#endif
int rv = Wire.endTransmission();
_lastWrite = micros();
return rv;
}
// pre: buffer is large enough to hold length bytes
int I2C_eeprom::_ReadBlock(uint16_t address, uint8_t* buffer, uint8_t length)
// returns bytes written
uint8_t I2C_eeprom::_ReadBlock(uint16_t address, uint8_t* buffer, uint8_t length)
{
waitEEReady();
@ -137,10 +177,11 @@ int I2C_eeprom::_ReadBlock(uint16_t address, uint8_t* buffer, uint8_t length)
Wire.send((int)(address >> 8));
Wire.send((int)(address & 0xFF));
#endif
Wire.endTransmission();
int rv = Wire.endTransmission();
if (rv != 0) return 0; // error
Wire.requestFrom(_deviceAddress, length);
int cnt = 0;
uint8_t cnt = 0;
uint32_t before = millis();
while ((cnt < length) && ((millis() - before) < I2C_EEPROM_TIMEOUT))
{
@ -155,18 +196,16 @@ int I2C_eeprom::_ReadBlock(uint16_t address, uint8_t* buffer, uint8_t length)
void I2C_eeprom::waitEEReady()
{
#define I2C_WRITEDELAY 5
#define I2C_WRITEDELAY 5000
// Wait until EEPROM gives ACK again.
// this is a bit faster than the hardcoded 5 millis
int x = 0;
uint32_t start = millis();
do
// this is a bit faster than the hardcoded 5 milli
while ((micros() - _lastWrite) <= I2C_WRITEDELAY)
{
Wire.beginTransmission(_deviceAddress);
x = Wire.endTransmission();
int x = Wire.endTransmission();
if (x == 0) break;
}
while ( (x != 0) && ((millis() - start) <= I2C_WRITEDELAY));
}
//

View File

@ -4,7 +4,7 @@
// FILE: I2C_eeprom.h
// AUTHOR: Rob Tillaart
// PURPOSE: Simple I2C_eeprom library for Arduino with EEPROM 24LC256 et al.
// VERSION: 1.0.04
// VERSION: 1.0.05
// HISTORY: See I2C_eeprom.cpp
// URL: http://arduino.cc/playground/Main/LibraryForI2CEEPROM
//
@ -21,18 +21,21 @@
#include "Wiring.h"
#endif
#define I2C_EEPROM_VERSION "1.0.04"
#define I2C_EEPROM_VERSION "1.0.05"
// I2C_EEPROM_PAGESIZE must be multiple of 2 e.g. 16, 32 or 64
// 24LC256 -> 64 bytes
#define I2C_EEPROM_PAGESIZE 64
// TWI buffer needs 2 bytes for address
// TWI buffer needs max 2 bytes for address
#define I2C_TWIBUFFERSIZE 30
// to break blocking read/write
#define I2C_EEPROM_TIMEOUT 1000
// comment next line to keep lib small
#define I2C_EEPROM_EXTENDED
class I2C_eeprom
{
public:
@ -43,14 +46,19 @@ public:
int setBlock(uint16_t address, uint8_t value, uint16_t length);
uint8_t readByte(uint16_t address);
int readBlock(uint16_t address, uint8_t* buffer, uint16_t length);
uint16_t readBlock(uint16_t address, uint8_t* buffer, uint16_t length);
#ifdef I2C_EEPROM_EXTENDED
uint8_t determineSize();
#endif
private:
uint8_t _deviceAddress;
uint32_t _lastWrite; // for waitEEReady
int _pageBlock(uint16_t address, uint8_t* buffer, uint16_t length, bool incrBuffer);
int _WriteBlock(uint16_t address, uint8_t* buffer, uint8_t length);
int _ReadBlock(uint16_t address, uint8_t* buffer, uint8_t length);
uint8_t _ReadBlock(uint16_t address, uint8_t* buffer, uint8_t length);
void waitEEReady();
};

View File

@ -1,7 +1,7 @@
//
// FILE: I2C_eeprom_test.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// VERSION: 0.1.05
// PURPOSE: show/test I2C_EEPROM library
//
@ -63,7 +63,7 @@ void setup()
dumpEEPROM(0, 128);
Serial.println();
Serial.print("\n\tI2C speed:\t");
Serial.print("\nI2C speed:\t");
Serial.println(16000/(16+2*TWBR));
Serial.print("TWBR:\t");
Serial.println(TWBR);
@ -73,24 +73,28 @@ void setup()
uint32_t start = micros();
ee.writeByte(10, 1);
uint32_t diff = micros() - start;
Serial.print("TIME: ");
Serial.println(diff);
Serial.print("TEST: timing writeBlock(50)\t");
start = micros();
ee.writeBlock(10, (uint8_t *) &data2, 50);
diff = micros() - start;
Serial.print("TIME: ");
Serial.println(diff);
Serial.print("TEST: timing readByte()\t\t");
start = micros();
ee.readByte(10);
diff = micros() - start;
Serial.print("TIME: ");
Serial.println(diff);
Serial.print("TEST: timing readBlock(50)\t");
start = micros();
ee.readBlock(10, (uint8_t *) &data2, 50);
diff = micros() - start;
Serial.print("TIME: ");
Serial.println(diff);
// same tests but now with a 5 millisec delay in between.
@ -100,6 +104,7 @@ void setup()
start = micros();
ee.writeByte(10, 1);
diff = micros() - start;
Serial.print("TIME: ");
Serial.println(diff);
delay(5);
@ -108,6 +113,7 @@ void setup()
start = micros();
ee.writeBlock(10, (uint8_t *) &data2, 50);
diff = micros() - start;
Serial.print("TIME: ");
Serial.println(diff);
delay(5);
@ -116,6 +122,7 @@ void setup()
start = micros();
ee.readByte(10);
diff = micros() - start;
Serial.print("TIME: ");
Serial.println(diff);
delay(5);
@ -124,10 +131,24 @@ void setup()
start = micros();
int xx = ee.readBlock(10, (uint8_t *) &data2, 50);
diff = micros() - start;
Serial.print("TIME: ");
Serial.println(diff);
// does it go well?
Serial.println(xx);
Serial.println("\nTEST: determine size");
start = micros();
int size = ee.determineSize();
diff = micros() - start;
Serial.print("TIME: ");
Serial.println(diff);
Serial.print("SIZE: ");
Serial.print(size);
Serial.println(" KB");
Serial.println("\tDone...");
}
@ -160,6 +181,3 @@ void dumpEEPROM(uint16_t addr, uint16_t length)
Serial.println();
}
// END OF FILE

View File

@ -0,0 +1,24 @@
#######################################
# Syntax Coloring Map For I2C_EEPROM
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
I2C_eeprom KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
readByte KEYWORD2
writeByte KEYWORD2
setBlock KEYWORD2
readBlock KEYWORD2
writeBlock KEYWORD2
determineSize KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################