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 :-).
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.
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
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?
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.
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
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.
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!
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.
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)