New SPI EEPROM Library

Hi,

I have developed a library to support SPI EEPROM IC's. I only have a 25LC1024 so it's the only one tested by now. It should support 16 and 24-bits memory addressing using the type parameter on class constructor. It's inspired/based on code by Heather Dewey-Hagborg available on http://www.arduino.cc/en/Tutorial/SPIEEPROM.

I wrote some documentation but it's far from completed.

Available on:
https://bitbucket.org/trunet/spieeprom/

Help is welcome.

KNOWN BUGS:

  • You can write a char/byte array at this time but if the write command attempts to write across a physical page boundary, the result is that the data wraps around to the beginning of the current page

TODO:

  • think on a way to deal with pages/page size

Thanks,

I couldn't find the part: 25LS1024

But from the other page I see you meant 25LC1024.

I don't have a need for it yet, but will certainly try yours out if I get there.

What's the major advantage of yours over the example in arduino? That it's more generalizable to all EEPROMs?

Typo... I corrected my post.

Some already implemented features and some planned:

  • automatic conversion from int, long, float, ... to 1 or more bytes
  • it checks if it already wrote on EEPROM using WIP(write in progress) register
  • sequential read
  • page write with protection to don't write across pages(it does not work and start overwriting)
  • I'll try to make some kind of wear leveling on EEPROM. my suggestion is to use built-in address but it'll only work if the device is permanently on

do all manufacturers of eeproms use the same opcodes?

The eeprom I want to work with describes a 25 pulse wait, is this standard SPI or would that be eeprom independant for each manufacturer.

Thanks for the library and example code. It got me thinking. Nice article and structure. I like it. :smiley:

I don't know. As I said, I just have some 25LC1024.

I appreciate if you test it and if you have problems, try to open an issue on bitbucket with datasheet I can try to figured out what's happening and correct the library to work with some of them.

KNOWN BUGS:

  • You can write a char/byte array at this time but if the write command attempts to write across a physical page boundary, the result is that the data wraps around to the beginning of the current page

TODO:

  • think on a way to deal with pages/page size

Check my lib - Arduino Playground - LibraryForI2CEEPROM - how I solved this same problem.

robtillaart:
Check my lib - Arduino Playground - LibraryForI2CEEPROM - how I solved this same problem.

What about we merge the library and make one that works with both I2C and SPI?

Could be done but I think 99% of the sketches using EEPROM use either I2C or SPI, not both. So merging the libs would unnecessary increase the footprint for both.

OK, you could merge and select the right part using #ifdef's but that would not be userfriendly imho.

Think you just need to rewrite the private parts of the class to communicate blocks (of max BLOCKSIZE ) in SPI - and remove the wire.begin() in the constructor

but feel free to give it a try :wink:

Tou're right. The footprint size will be a problem.

Maybe we can maintain as separated projects but with the same classes/methods.

I'll implement Arduino Playground - EEPROMWriteAnything on my library, it'll return the size and the user can save float or struct variables directly. He only needs to know the address and size to calculate where to save next chunk of data instead of using tons of methods for each variable type.

In some of my spare time I've been thinking about another EEPROM library interface. (currently it is on the shelf as I have too much other things to do)

The idea is to create a linked list in the EEPROM of "allocated" memory. Each node is identified by a char[8]; when the node is created its size is defined and its location is determined.

Struct node
{
char[9] name;
uint16_t startPage; // every chunck starts at page boundary so - 1 - point to byte PAGESIZE (16/32?); this allows for max 64K nodes.
uint16_t size;
uint16_t addressOfNextNode;
uint8_t deleted; // flag that this chunk is freed.
}
The first node would be on address 0 of course.

If I get this working I can write something like

bool succes;
succes = readEEPROM("myappcnf", (void*) &myconfig);
succes = readEEPROM("lutclr", (void*) &lookUpTableRGB2CMYK);

and something like

succes = createEEPROM("GagaMidi", 1024); // create a node and a internal ref to a chunk of 1024 bytes
succes = WriteEEPROM("GagagMidi", (void*) &midiArray); // and copy midiArray in it

If another sketch wants to use EEPROM it will never overwrite used EEPROM ... (never say never :slight_smile:

what do you think of this idea?

what do you think of this idea?

Cool, sounds like a basic database structure/access. Would it have to 'know' what avr processor is being used to determine eeprom max size so as to not wrap around ?

Lefty

Would it have to 'know' what avr processor is being used to determine eeprom max size so as to not wrap around ?

Yep it needs to know the EEPROM size, both internal and external EEPROM. I was thinking that the library could determine this and allocate the first node with EEPROMsize info and a signature that the EEPROM is "formatted"

in pseudocode

if ( signature available)
{
  size = read EEPROMzsize from first block.
}
else
{
   size = determineSize();
   write size and signature to first block;
}

determineSize()
{
  write 0xFF to address 0x00;
  unsigned long i;
  for (i = 1; i< MAXLONG; i<<1)
  {
     write 0xAA to address i;                // assume addresses are multiples of 2..
     if (address 0x00 == 0xFF)  break;  // address 00 will eventually be overwritten by AA
  }
  if i<MAXLONG  return i;
  return 0xFFFFFFFFF;
}

Hmm, I just banged out a library this weekend (called SPIEEP) to interface with the 25LC512 chip, might take a look at this one and see if I can merge it. I did solve the problem of writing across page boundaries (a loop that divides & conquers the write or read) in my implementation, also wrote a cool "test_chip()" method that puts it through its paces (including deep-sleep mode & wakeup). Mine only deals with byte's and byte-arrays though, which does makes things simple enough for page-boundary calculations/etc.

Here's my current version: http://spirilis.net/stuff/arduino/SPIEEP.zip

FWIW, sounds like Microchip's 25****** lineup all use the same instruction set, although lower-capacity chips don't seem to have some of the fancier features such as deep-sleep, return-from-deep-sleep (so my test_chip() function would fail) and chip erase, page-erase, segment-erase and such. But the read/write functions should work identically assuming you initialize the library with the right page-size 'n stuff.

256Kbit (32KB) example: http://www.mouser.com/ProductDetail/Microchip-Technology/25AA256-I-P/?qs=sGAEpiMZZMuVhdAcoizlRQmfcE3zL6VtaRPJnBU30sc%3D

Ooh actually found my first exception: http://www.mouser.com/ProductDetail/Microchip-Technology/25LC040A-I-P/?qs=sGAEpiMZZMuVhdAcoizlRSetfYkAy0SVR0ltHS3iTmA%3D
This is a 512-byte EEPROM, and the 9th bit of the address is embedded in the instruction, then it uses an 8-bit address. That would take some code exceptions. Basic instructions are the same, I guess the class would need a flag indicating whether part of the address stays inside the instruction and test that flag/compute the proper instruction code before submitting it.

Looks like that 4Kbit (512 byte) EEPROM is the only exception, as their 8+ Kbit units all use 16-bit addresses until you exceed 512Kbit (64KB). That should be easy to catch/make exception.

Checked out the SPIEEPROM code, looks like my code went a bit further so I decided to add support for int, long, float, and double to mine.

Decided to start using bitbucket too. Check my version out:

https://bitbucket.org/spirilis/spieep
(I usually rename the 'spieep' dir to SPIEEP all uppercase btw, not sure how to make that happen by default)

In addition to read, write, readn, writen, read_page, write_page, I now have:

read_int, write_int, readn_int, writen_int, read_int_offset, write_int_offset, readn_int_offset and writen_int_offset
along with long, float, and double variants of all those functions.

The EEPROM "address" you supply to each of those int/long/float/double variants gets multiplied by the size of those variables, so you could for instance use the whole EEPROM as one huge array of double's, accessing each item's address by incrementing a variable one at a time (rather than having to compute byte addresses yourself). The "offset" variants allows you to specify a origin byte-level address where the int/long/float/double address should start counting.

Or in plain code:
read_int(p) runs the underlying readn() with (byte) address = p * sizeof(int)
read_int_offset(offset, p) runs the underlying readn() with (byte) address = p * sizeof(int) + offset

Since these functions use my readn and writen functions, they can work across page boundaries without requiring any further consideration.

I haven't actually tested the int/long/float/double variants yet, just forewarning... I will do that later :slight_smile:
Hope this helps!

Tested writing & reading longs last night, seems to work correctly.

Added support for the 25LC040 to my library this morning, it'll set a simple bool in the class if it sees addrwidth = 8 bits & totalsize = 512 bytes and during any reads & writes it'll test that bool before writing the instruction (and add the 9th addrbit to the instruction if the bool is true).

Tweaked/updated some things in the code; disabled testing for Deep Power Down functionality if the EEPROM in question has less than 64KB capacity (b/c all Microchip 25LC series chips below the 512Mbit model don't seem to have it), changed some variable types in the write/read functions to avoid a few bit-width gotchas.

Added pretty thorough documentation to my wiki: https://bitbucket.org/spirilis/spieep/wiki/Home

Hi friends,

I know that this topic is a bit old, but I´m stuck in aproblem I can not fix.

Well, I Havea circuit with a GPS, an IIC sd1306 and SPI 25c128 EEPROM memory.

I would like to record my GPS positions on this eeprom, using the SPIEEPROM lib.

My simple program is like this :

#include <SPIEEP.h>
#include <SPI.h>

SPIEEP eep(32, 64, 16384); // Microchip 25C128

#define EEPROM_CSPIN 10  // Chip Select attached to pin 10

void setup() {
  Serial.begin(9600);
  eep.begin_spi(EEPROM_CSPIN);
}

void loop() {
  float buf[5];
  float Aux;
  int i;

 // Just to test
  buf[1] = 12.654;
  buf[2] = 34.567;


  // Not required for EEPROM read/write, but necessary
  // to print out the buffer contents via Serial.println
  
  if (!eep.write_float(0, buf[1])) {
    Serial.print("Error writing the following buffer: ");
    Serial.println(buf[1], 5);
  }

  if (!eep.write_float(32, buf[2])) {
    Serial.print("Error writing the following buffer: ");
    Serial.println(buf[2], 5);
  }


  Aux = eep.read_float(0);
  Serial.print("Buf[1]=");
  Serial.println(Aux, 5);

  Aux = eep.read_float(32);
  Serial.print("Buf[2]=");
  Serial.println(Aux, 5);


  while(1) ;
}


When I run the code, I always get the same result, showing zeroes :

Buf[1]=0.00000
Buf[2]=0.00000

Did some one used the library with float numbers without problem ?

Or, do you recomend another aproach ?

Thank you very much !

Sérgio Pinheiro