Skip to content

Commit 47ed1b5

Browse files
committed
Variety of speed increases. Fixed >512k EEPROM writes/reads. Add I2C buffer setting.
There were a handful of bugs that caused the 0xFFFF (512k bit / 64k byte) threshold to fail to read/write correctly. Additionally, massive speed improvements. Write now checks if EEPROM is ready at start of write rather than polling at end of write. setI2CBuffer was added to allow for platforms (Artemis) that support greater than 32 byte I2C writes. With 128 byte writes we are hitting ~30kB per second which is pretty respectable.
1 parent 130f41a commit 47ed1b5

File tree

3 files changed

+54
-24
lines changed

3 files changed

+54
-24
lines changed

keywords.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ enablePollForWriteComplete KEYWORD2
2929
disablePollForWriteComplete KEYWORD2
3030
get KEYWORD2
3131
put KEYWORD2
32+
setI2CBufferSize KEYWORD2
33+
getI2CBufferSize KEYWORD2
3234

3335
#######################################
3436
# Constants (LITERAL1)

src/SparkFun_External_EEPROM.cpp

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -56,18 +56,25 @@ uint32_t ExternalEEPROM::length()
5656
}
5757

5858
//Returns true if device is detected
59-
bool ExternalEEPROM::isConnected()
59+
bool ExternalEEPROM::isConnected(uint8_t i2cAddress)
6060
{
61-
settings.i2cPort->beginTransmission((uint8_t)settings.deviceAddress);
61+
if (i2cAddress == 255)
62+
i2cAddress = settings.deviceAddress; //We can't set the default to settings.deviceAddress so we use 255 instead
63+
64+
settings.i2cPort->beginTransmission((uint8_t)i2cAddress);
6265
if (settings.i2cPort->endTransmission() == 0)
6366
return (true);
6467
return (false);
6568
}
6669

6770
//Returns true if device is not answering (currently writing)
68-
bool ExternalEEPROM::isBusy()
71+
//Caller can pass in an i2c address. This is helpful for larger EEPROMs that have two addresses (see block bit 2).
72+
bool ExternalEEPROM::isBusy(uint8_t i2cAddress)
6973
{
70-
if (isConnected())
74+
if (i2cAddress == 255)
75+
i2cAddress = settings.deviceAddress; //We can't set the default to settings.deviceAddress so we use 255 instead
76+
77+
if (isConnected(i2cAddress))
7178
return (false);
7279
return (true);
7380
}
@@ -108,7 +115,14 @@ void ExternalEEPROM::disablePollForWriteComplete()
108115
{
109116
settings.pollForWriteComplete = false;
110117
}
111-
118+
void ExternalEEPROM::setI2CBufferSize(uint16_t numberOfBytes)
119+
{
120+
settings.i2cBufferSize = numberOfBytes;
121+
}
122+
uint16_t ExternalEEPROM::getI2CBufferSize()
123+
{
124+
return settings.i2cBufferSize;
125+
}
112126
//Read a byte from a given location
113127
uint8_t ExternalEEPROM::read(uint32_t eepromLocation)
114128
{
@@ -118,25 +132,33 @@ uint8_t ExternalEEPROM::read(uint32_t eepromLocation)
118132
}
119133

120134
//Bulk read from EEPROM
121-
//Handles breaking up read amt into 32 byte chunks
135+
//Handles breaking up read amt into 32 byte chunks (can override with serI2CBufferSize)
122136
//Handles a read that straddles the 512kbit barrier
123137
void ExternalEEPROM::read(uint32_t eepromLocation, uint8_t *buff, uint16_t bufferSize)
124138
{
139+
//See if EEPROM is available or still writing a previous request
140+
uint8_t i2cAddress = settings.deviceAddress;
141+
while (isBusy(i2cAddress) == true) //Poll device
142+
delayMicroseconds(100); //This shortens the amount of time waiting between writes but hammers the I2C bus
143+
125144
uint16_t received = 0;
126145
while (received < bufferSize)
127146
{
128147
//Limit the amount to write to a page size
129148
int amtToRead = bufferSize - received;
130-
if (amtToRead > 32) //Arduino I2C buffer size limit
131-
amtToRead = 32;
149+
if (amtToRead > settings.i2cBufferSize) //Arduino I2C buffer size limit
150+
amtToRead = settings.i2cBufferSize;
132151

133152
//Check if we are dealing with large (>512kbit) EEPROMs
134153
uint8_t i2cAddress = settings.deviceAddress;
135154
if (settings.memorySize_bytes > 0xFFFF)
136155
{
137156
//Figure out if we are going to cross the barrier with this read
138-
if (0xFFFF - (eepromLocation + received) < amtToRead) //0xFFFF - 0xFFFA < 32
139-
amtToRead = 0xFFFF - (eepromLocation + received); //Limit the read amt to go right up to edge of barrier
157+
if (eepromLocation + received < 0xFFFF)
158+
{
159+
if (0xFFFF - (eepromLocation + received) < amtToRead) //0xFFFF - 0xFFFA < 32
160+
amtToRead = 0xFFFF - (eepromLocation + received); //Limit the read amt to go right up to edge of barrier
161+
}
140162

141163
//Figure out if we are accessing the lower half or the upper half
142164
if (eepromLocation + received > 0xFFFF)
@@ -165,15 +187,22 @@ void ExternalEEPROM::write(uint32_t eepromLocation, uint8_t dataToWrite)
165187
}
166188

167189
//Write large bulk amounts
190+
//Limits writes to the I2C buffer size (default is 32 bytes)
168191
void ExternalEEPROM::write(uint32_t eepromLocation, const uint8_t *dataToWrite, uint16_t bufferSize)
169192
{
170193
//Error check
171194
if (eepromLocation + bufferSize >= settings.memorySize_bytes)
172195
bufferSize = settings.memorySize_bytes - eepromLocation;
173196

174197
uint16_t maxWriteSize = settings.pageSize_bytes;
175-
if (maxWriteSize > 30)
176-
maxWriteSize = 30; //Arduino has 32 byte limit. We loose two to the EEPROM address
198+
if (maxWriteSize > settings.i2cBufferSize - 2)
199+
maxWriteSize = settings.i2cBufferSize - 2; //Arduino has 32 byte limit. We loose two to the EEPROM address
200+
201+
uint8_t i2cAddress = settings.deviceAddress;
202+
203+
//See if EEPROM is available or still writing a previous request
204+
while (isBusy(i2cAddress) == true) //Poll device
205+
delayMicroseconds(100); //This shortens the amount of time waiting between writes but hammers the I2C bus
177206

178207
//Break the buffer into page sized chunks
179208
uint16_t recorded = 0;
@@ -194,12 +223,13 @@ void ExternalEEPROM::write(uint32_t eepromLocation, const uint8_t *dataToWrite,
194223
}
195224

196225
//Check if we are dealing with large (>512kbit) EEPROMs
197-
uint8_t i2cAddress = settings.deviceAddress;
198226
if (settings.memorySize_bytes > 0xFFFF)
199227
{
200228
//Figure out if we are accessing the lower half or the upper half
201229
if (eepromLocation + recorded > 0xFFFF)
230+
{
202231
i2cAddress |= 0b100; //Set the block bit to 1
232+
}
203233
}
204234
settings.i2cPort->beginTransmission(i2cAddress);
205235

@@ -213,13 +243,7 @@ void ExternalEEPROM::write(uint32_t eepromLocation, const uint8_t *dataToWrite,
213243

214244
recorded += amtToWrite;
215245

216-
if (settings.pollForWriteComplete == true)
217-
{
218-
while (isBusy() == true) //Poll device
219-
delayMicroseconds(100); //This shortens the amount of time waiting between writes but hammers the I2C bus
220-
//delay(1);
221-
}
222-
else
246+
if (settings.pollForWriteComplete == false)
223247
delay(settings.pageWriteTime_ms); //Delay the amount of time to record a page
224248
}
225249
}

src/SparkFun_External_EEPROM.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ struct struct_memorySettings
3737
uint16_t pageSize_bytes;
3838
uint8_t pageWriteTime_ms;
3939
bool pollForWriteComplete;
40+
uint16_t i2cBufferSize;
4041
};
4142

4243
class ExternalEEPROM
@@ -48,8 +49,8 @@ class ExternalEEPROM
4849
void write(uint32_t eepromLocation, const uint8_t *dataToWrite, uint16_t blockSize);
4950

5051
bool begin(uint8_t deviceAddress = 0b1010000, TwoWire &wirePort = Wire); //By default use the Wire port
51-
bool isConnected();
52-
bool isBusy();
52+
bool isConnected(uint8_t i2cAddress = 255);
53+
bool isBusy(uint8_t i2cAddress = 255);
5354
void erase(uint8_t toWrite = 0x00); //Erase the entire memory. Optional: write a given byte to each spot.
5455

5556
//void settings(struct_memorySettings newSettings); //Set all the settings using the settings struct
@@ -62,18 +63,20 @@ class ExternalEEPROM
6263
uint8_t getPageWriteTime();
6364
void enablePollForWriteComplete(); //Most EEPROMs all I2C polling of when a write has completed
6465
void disablePollForWriteComplete();
66+
void setI2CBufferSize(uint16_t numberOfBytes); //How big is your Wire buffer? Default is 32 but Artemis supports 256 bytes.
67+
uint16_t getI2CBufferSize();
6568

6669
//Functionality to 'get' and 'put' objects to and from EEPROM.
6770
template <typename T>
68-
T &get(uint16_t idx, T &t)
71+
T &get(uint32_t idx, T &t)
6972
{
7073
uint8_t *ptr = (uint8_t *)&t;
7174
read(idx, ptr, sizeof(T)); //Address, data, sizeOfData
7275
return t;
7376
}
7477

7578
template <typename T>
76-
const T &put(uint16_t idx, const T &t) //Address, data
79+
const T &put(uint32_t idx, const T &t) //Address, data
7780
{
7881
const uint8_t *ptr = (const uint8_t *)&t;
7982
write(idx, ptr, sizeof(T)); //Address, data, sizeOfData
@@ -89,6 +92,7 @@ class ExternalEEPROM
8992
.pageSize_bytes = 64,
9093
.pageWriteTime_ms = 5,
9194
.pollForWriteComplete = true,
95+
.i2cBufferSize = 32, //Arduino default is 32 bytes
9296
};
9397
};
9498

0 commit comments

Comments
 (0)