Spi RAM library update

Recently I added an updated SpiRAM library at http://playground.arduino.cc/Main/SpiRAM. It has the same functionality as the original version, but is up to date with 1.0.5 and the latest SPI library and has some working examples. It currently only supports the 23C256. The testing done is only minimal and the speed setting can probably be improved. It worked for my 23C256 :-).

Any testing or comments are welcome,

Fred Jan

Attach:SpiRAM2.zip is an empty zip file ....

Attach:SpiRAM2.zip is an empty zip file ....

It already was empty, I added a spiRAM3.zip ate the end. But to reduce possible confusing, I actually changed the main text and removed the existing empty zip. It wasn't mine.

Fred Jan

a quick scan => some thoughts

  • You could rewrite the enable and disable in such a way it remembers the port and the pin (you can calculate them in the constructor) making them much faster.
  • you could make the enable /disable inline functions (e.g. in the .h file), might be a bit faster
  • the return value of write_byte can be void. it has no use to return the byte passed as parameter.
  • some loops can be micro optimized
// Page transfer functions
void SpiRAM::read_page(int address, char *buffer)
{
  // Set byte mode
  _set_mode(PAGE_MODE);  <<<<<<<< conflicts with comments line before :)
  
  // Write address, read data
  enable();
  SPI.transfer(READ);
  SPI.transfer((char)(address >> 8));
  SPI.transfer((char)address);
  for (uint8_t i = 0; i < 32; i++) {  <<<<<<< smaller datatype for i, faster
    buffer[i] = SPI.transfer(0xFF);
  }    
  disable();
}
  • what is the difference between read_page and read_stream? Can't one be expressed in terms of the other? Smaller footprint by merging read and write functions seems possible, like this:
void SpiRAM::write_page(int address, char *buffer)
{
  _do_write(PAGE_MODE,  buffer, 32);
}

void SpiRAM::write_stream(int address, char *buffer, int length)
{
  _do_write(STREAM_MODE,  buffer, length);
}

void SpiRam::_do_write(int mode, char* buffer, int length)
{
  _set_mode(mode);
  enable();
  SPI.transfer(WRITE);
  SPI.transfer((char)(address >> 8));
  SPI.transfer((char)address);
  for (int i = 0; i < length; i++) SPI.transfer(buffer[i]); 
  disable();
}
  • as the set_mode() is always used in a read or write you can strip the enable/disable from the setmode IFF you move the enable() in the calling functions
char SpiRAM::read_byte(int address)
{
  enable();
  _set_mode(BYTE_MODE);

  SPI.transfer(READ);
  SPI.transfer((char)(address >> 8));
  SPI.transfer((char)address);
  char read_byte = SPI.transfer(0xFF);
  disable();
  return read_byte;
}

void SpiRAM::_set_mode(char mode)
{
  if (mode != _current_mode)
  {
    SPI.transfer(WRSR);
    SPI.transfer(mode);
    _current_mode = mode;
  }
}

Finally I would add (.h) a #define SPIRAM_LIB_VERSION "0.3.00" or something like that to be able to track version

my 2 cents,

Thanks for the comments.

It was not my intention to take over maintenance of a library I found useful, but a bit in disarray. All points are valid, but I am not implement them now, as it would also require proper testing and my time is limited too. It is probably best if the SpiRAM library gets integrated into the SPI library, but I agree the code should be better shape before that.

Some comments:

  • what is the difference between read_page and read_stream?

According to the 23A256 datasheet, *_page is only on one page, and reading past the boundary wraps to the beginning. *_stream ignores the page boundaries.

Finally I would add (.h) a #define SPIRAM_LIB_VERSION "0.3.00" or something like that to be able to track version

This can be done without breaking any code :-). There is probably a way to replace a file, but how?

Fred Jan

You might add a link to this thread on the playground, so the relation is kept.

Mega2560 fix /w examples

best regards,
stah

SpiRAM31.zip (4.94 KB)

Just a dumb question but well i have to know it :cold_sweat:
Reading and writing on RAM is it similar to do it on a EEPROM?

"Similar" - yes. But in diffrent protocol and a little bit faster :slight_smile:

stah:
"Similar" - yes. But in diffrent protocol and a little bit faster :slight_smile:

Cool, thanks =)

After a lot of testing and learning I have updated the library for the SpiRAM to include also the 128kByte chip http://www.microchip.com/wwwproducts/Devices.aspx?product=23LCV1024 and others from that family.
In this chip the address is bigger than 16bit so I updated the entire library to use long instead of int where needed.
I have also included a new mode, to read a stream of bytes, but process them without the need for a buffer.
If you consider it a job well done, I will upload it to the playground website.
I have evolved on the work of electrickery and stah and included some of the remarks of Rob.

Please let me know?
Thanks and Enjoy,
M10

SpiRAM32.zip (11 KB)

Great library! Thanks a lot!!! 8)

Here is some test code for measuring timing. Try to change SPI_CLOCK_DIV2 to something like SPI_CLOCK_DIV64 and you will see the difference.

Here are my benchmarks for SPI_CLOCK_DIV2:

Starting SpiRAM read/write timing test
Reading one byte: 28.417us
Writing one byte: 29.362us
Reading one page (32 Bytes): 100.750us
Writing one page (32 Bytes): 100.651us

... and for SPI_CLOCK_DIV64:

Starting SpiRAM read/write timing test
Reading one byte: 183.404us
Writing one byte: 184.349us
Reading one page (32 Bytes): 1217.030us
Writing one page (32 Bytes): 1216.950us

Have fun!

SpiRamPerformanceTest.ino (2.32 KB)

Hello
really interesting post, since I was seeking for a solution to store some arrays in an external flash memory.

Though I kindly ask you if you can kindly help me with a code sample that shows how to take advantage of your code to store different arrays into the external EEPROM with SPI.

I need to read and store some bi dimensional arrays with some samples values and be able to load the given array (array1 or array2 etc).

P.S. which about those serial EEPROMs , do you know which is the maximum size of those 8 pins? Thank you.

Thank you for any help/explanation

Cor

Hey guys,

I have started using the library but wanted to expand it a little.

Could do with your help! As warned above i started a new thread as this one has been inactive for ages but i thought i'd post a link in case any of you still follow it!

http://forum.arduino.cc/index.php?topic=325681.0

Hi All

I got myself a 23LCV1024 and installed these libraries

I am running it on an ATMEGA1284

I already have an SDCard running (loading files from the card - all works fine)

I have connected up the chip (all the right way around) but cannot get even the simplest test working

It looks like whatever I try and do with the clock to slow it down, it doesnt seem to understand

Not sure if the '1284 cores work with SPI as I have to force the SPI pins as outputs and force the clock div just to get the SD card to read

	/*SET MOSI, SCK AND CS AS OUTPUT, REST OF REGISTER INPUT*/
	DDRB = (1<<DDB5) | (1<<DDB7) | (1<<DDB4);
	/*ENABLE SPI, MASTER, SET CLOCK RATE FCK/128 */
	SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0);

when trying to access the SPIRAM, if I try any other clock other than SPI_CLOCK_DIV4 the clock is considerably faster (I scoped it), its like there is no division at all

Anyone else come across this with the ATMEGA1284 ?

Thanks in advance for any help

EDIT : I have checked the SS pin, and that is low during access (or attempted access) so that is ok too

mcnobby:
EDIT : I have checked the SS pin, and that is low during access (or attempted access) so that is ok too

I haven't used the 1284 but the SPI interface detailed in the datasheet looks the same as in other Atmega chips.

I'm not sure what you mean about the SS pin. Is it an input pin or an output pin? In master mode, if the SS is an output pin then the processor's SPI hardware doesn't care whether SS is high or low. But if SS is configured as an input pin then it has to be held high or else the processor will think another master is in control and will not output it's clock.

Sorry, by SSPin I mean the ChipSelect I guess

Oh, you mean the chip select for the SPI RAM.

I was just trying to think of why the SPI clock divider wasn't working for you and noticed that there is nothing about setting up the 1284's SS pin in your SPI configuration code snippet.

Its all a bit of a mystery to me, not sure if the cores are completely tested for SPI
I think I am going to test everything with a UNO and see if that works (also give me chance to check my wiring etc)

I thought it used the same core library code as the Uno. The registers appear to be identical.