Go Down

Topic: Interface SRAM 23k256 to Arduino Duemilanove (Read 3 times) previous topic - next topic

emasixtysix

I'm new in the Arduino programming, I'm just an hobbyst. So please be gentle, also with my english.
Anyway, I want post an argument which could be useful for many developers involved in storing physical data from sensors, in particular the amount of data and the speed of reading/writing.
For this purpose I read about the new Microchip SRAM's 23K256 and suppose it's a very good solution to improve the limit of the Arduino Duemilanove board (which has only 2K of ram).
So I invite an interested reader to take a look at Datasheet of this powerful ram chip.
I post this article because I encountered problems in interfacing it with Arduino Duemilanove, ...nothing is going as in theory it should go.
I enclose next my code. What is wrong?

#define CS 10 // Arduino pin 10 - 23K256 CS pin

#define MOSI 11 // Arduino pin 11 - 23K256 MOSI pin

#define MISO 12 // Arduino pin 12 - 23K256 MISO pin

#define SCK 13 // Arduino pin 13 - 23K256 SCK pin


byte value;

byte clr;


char spi_transfer(volatile char data)

{

SPDR = data; // Start the transmission

while (!(SPSR & (1<<SPIF))) // Wait the end of the transmission

 {};

return SPDR; // return the received byte

}


void setup()

{

Serial.begin(9600);

pinMode(MOSI, OUTPUT);

pinMode(SCK, OUTPUT);

pinMode(CS, OUTPUT);

pinMode(MISO, INPUT);

digitalWrite(CS, HIGH); //disable device


//Configure SPI control register (SPCR)

SPCR = B1010000;

// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |

// | SPIE | SPE | DORD | MSTR | CPOL | CPHA | SPR1 | SPR0 |

// SPIE - Enables the SPI interrupt when 1

// SPE - Enables the SPI when 1

// DORD - Sends data least Significant Bit First when 1, most Significant Bit first when 0

// MSTR - Sets the Arduino in master mode when 1, slave mode when 0

// CPOL - Sets the data clock to be idle when high if set to 1, idle when low if set to 0

// CPHA - Samples data on the falling edge of the data clock when 1, rising edge when 0'

// SPR1 and SPR0 - Sets the SPI speed, 00 is fastest (4MHz) 11 is slowest (250KHz)

//--------------------------------

clr=SPSR;

clr=SPDR;

digitalWrite(CS,LOW);delay(10);

spi_transfer(0x01);

spi_transfer(0x41);

digitalWrite(CS,HIGH);

delay(10);

}


void loop()

{

 digitalWrite(CS,HIGH);

 delay(100);


 Serial.print("Read Status Register Config -> ");

 digitalWrite(CS,LOW);

 spi_transfer(0x05);

 value=spi_transfer(0xFF);

 digitalWrite(CS,HIGH);

 Serial.println(value,DEC);

 delay(100);


 Serial.println("Write data to RAM ");

 digitalWrite(CS,LOW);

 spi_transfer(0x02); //write command

 spi_transfer(0x00); //MSB address byte

 spi_transfer(0x00); //LSB address byte

 for (int i=1; i<=10; i++)

  {

     spi_transfer(0x33); //example data to write

  }

 digitalWrite(CS,HIGH);

 delay(100);

 Serial.println("Read data from RAM ");

 digitalWrite(CS,LOW);

 spi_transfer(0x03); //read command

 spi_transfer(0x00); //MSB address byte

 spi_transfer(0x00); //LSB address byte

 for (int i=1; i<=10; i++)

  {

     value=spi_transfer(0xFF); //send a dummy byte and receive byte stored

     Serial.print(value,DEC); Serial.print(" ");

  }

 digitalWrite(CS,HIGH);

 Serial.println();Serial.println();

 delay(2000);

}


I obtain non-sense values from the Read Status Register routine, to verify the right configuration (Serial storage mode) and also from Read command.
I suppose the answer must require a better knowledge than mine, and a very deepened study of the matter.
Thank you in advance.

mrmeval

http://www.arduino.cc/en/Tutorial/SPIEEPROM

It should be possible to use it similar to this but I've not gotten very far with Arudino yet.
If it was designed by man it can be repaired by man.

MORA

#2
Oct 06, 2009, 02:18 pm Last Edit: Oct 06, 2009, 02:25 pm by MORA Reason: 1
I have tried with this code on arduino, and also with similar code on a Atmega128.

I am currently using 10k inline resistors for the level convert and a 1k inline+10 to 3v3 for CS.
4k7 pullup to 3v3 on MISO.

I dont have a scope to check what is actually on the wire, so its blind luck if its code or hardware that is the problem.

Have you checked the spi mode is correct?

Code: [Select]

#define DATAOUT 11//MOSI
#define DATAIN  12//MISO
#define SPICLOCK  13//sck
#define SLAVESELECT 10//ss

//opcodes
#define WRITE  2
#define READ   3


char spi_transfer(volatile char data)
{
 SPDR = data;                    // Start the transmission
 while (!(SPSR & (1<<SPIF)))     // Wait for the end of the transmission
 {
   Serial.print('.',BYTE);
 };
 return SPDR;                    // return the received byte
}

void setup()
{
Serial.begin(9600);

Serial.print('h',BYTE);
Serial.print('i',BYTE);
Serial.print('\n',BYTE);//debug

pinMode(DATAOUT, OUTPUT);
pinMode(DATAIN, INPUT);
pinMode(SPICLOCK,OUTPUT);
pinMode(SLAVESELECT,OUTPUT);
digitalWrite(SLAVESELECT,HIGH); //disable device  
delay(100);
}

void loop()
{  

 digitalWrite(SLAVESELECT,LOW);
 spi_transfer(0x41);
 digitalWrite(SLAVESELECT,HIGH);


 
 delay(1000);
SPCR = (1<<SPE)|(1<<MSTR);
byte clr=SPSR;
clr=SPDR;
delay(10);

digitalWrite(SLAVESELECT,LOW);
spi_transfer(WRITE);
spi_transfer(0);
spi_transfer(0);
spi_transfer(1);
spi_transfer(2);
spi_transfer(3);
spi_transfer(4);
spi_transfer(5);
digitalWrite(SLAVESELECT,HIGH);

delay(3000);
digitalWrite(SLAVESELECT,LOW);
spi_transfer(READ);
spi_transfer(0);//address
spi_transfer(0);//address
char data1 = spi_transfer(0xFF); //get data byte
char data2 = spi_transfer(0xFF); //get data byte
char data3 = spi_transfer(0xFF); //get data byte
char data4 = spi_transfer(0xFF); //get data byte
char data5 = spi_transfer(0xFF); //get data byte
digitalWrite(SLAVESELECT,HIGH);

Serial.print(data1,DEC);
Serial.print('\n',BYTE);
Serial.print(data2,DEC);
Serial.print('\n',BYTE);
Serial.print(data3,DEC);
Serial.print('\n',BYTE);
Serial.print(data4,DEC);
Serial.print('\n',BYTE);
Serial.print(data5,DEC);
Serial.print('\n',BYTE);
}


If I comment out the init code for seq access and hold disabled, it returns -1, otherwise its stuck in the wait loop.

But I think the -1 is really from the spi function, not the sram itself.

emasixtysix

After some frustrating tests in interfacing the Microchip SRAM 23K256 with Arduino duemilanove, the results are without success.
I'm quite confused about this simple hardware and software interfacing, as reported in the Datasheet and in Application notes.
From the Hardware point of view, I used the next wiring:
- an in-line resistor of 1K on pin CS (SLAVESELECT) plus a 10K pull-up resistor to 3,3 volt;
- an in-line resistor of 10K on pin MOSI (DATAIN);
- an in-line resistor of 10K on pin SCLK (SERIALCLOCK);
- direct connection to pin MISO (DATAOUT);
- a power of 3,3 volts coming directly from the proper pin on Arduino, connected to pin Vdd of 23K256 chip;
- SPI mode 1 (CPOL=0 and CPHA=1).
I also tried to simplify the code, just limiting it to only two simple steps:
1) configuring the Write Status Register of the SRAM;
2) reading the above configuration.
In the next code I post, I first send the command Write Status Register (0x01), then send the configuration Sequential mode and Hold pin disabled (0x41).
In second place, I send the Read Status Register Command (0x05) and finally send a dummy byte (0xFF) to obtain a byte from the MISO pin.
Unfortunately I do not obtain the value 0x41 (65 in decimal format), as I should expect !
I just obtain -1 or 0.
The solution of the above two steps is crucial for the next phase of storing true data coming from an high resolution ADC.
Is there anybody interested with this challenge?

#define DATAOUT 11//MOSI
#define DATAIN  12//MISO
#define SPICLOCK  13//sck
#define SLAVESELECT 10//ss

byte clr;
char value;

char spi_transfer(volatile char data)
{
 SPDR = data;                    // Start the transmission
 while (!(SPSR & (1<<SPIF)))     // Wait for the end of the transmission
 {
   //Serial.print('.');
 };
 return SPDR;                    // return the received byte
}

void setup()
{
Serial.begin(9600);
pinMode(DATAOUT, OUTPUT);
pinMode(DATAIN, INPUT);
pinMode(SPICLOCK,OUTPUT);
pinMode(SLAVESELECT,OUTPUT);
digitalWrite(SLAVESELECT,HIGH); //disable device  
delay(10);
SPCR= (1<<SPE)|(1<<MSTR)|(0<<CPOL)|(1<<CPHA);  //SPI mode 1
clr=SPSR;
clr=SPDR;
delay(10);
}


void loop()
{  
 digitalWrite(SLAVESELECT,LOW);
 spi_transfer(0x01); Serial.println("send 0x01 Write Status Register Command ");
 delay(100);
 spi_transfer(0x41); Serial.println("send 0x41 Select Sequential mode, Hold disabled");
 digitalWrite(SLAVESELECT,HIGH);
 delay(100);

 digitalWrite(SLAVESELECT,LOW);
 spi_transfer(0x05); Serial.println("send 0x05 Read Status Register Command ");
 delay(100);
 value=spi_transfer(0xFF);
 digitalWrite(SLAVESELECT,HIGH);
 Serial.print("Data from Status Register -> "); //should obtain 0x41 or 65 in dec mode
 Serial.println(value,DEC);
 Serial.println();
 delay(3000);
}

LichP

#4
Nov 08, 2009, 09:21 pm Last Edit: Nov 08, 2009, 09:22 pm by LichP Reason: 1
I've written a library that interfaces with this chip which I've uploaded to the playground. I'd include a link but the board won't let me as this is my first post ...

--
Phil

LichP


posix1965

hi, does this library work with arduino 017? I can't get this one working.
The IDE does not recognize it as a library,even though it was placed in the libraries folder.

thanks.

Grumpy_Mike

#7
Jan 26, 2010, 04:05 pm Last Edit: Jan 26, 2010, 04:05 pm by Grumpy_Mike Reason: 1
Yes it works, put them in a folder called SpiRAM and then at the start of the sketch put the lines:-
Quote

#include "Spi.h"
#include "SpiRAM.h"


As the note says you need the Spi library in first.

posix1965

Thanks for your response. I had all of that in already, I must have something else wrong.

pd2kplus10

Anyone know if using an SPI SRAM chip would be any faster than using an I2C EEPROM chip?

  Right now I'm experimenting with an I2C EEPROM chip of the same size. It works great, but it takes 5ms to write a single byte. I know I could write it about 30 bytes at a time, but one is easier.

 I imagine this SPI SRAM chip is capable writing a single byte in less than 5ms.


thanks,
Phil

MicrocontrollerGuy

Writing to SRAM should be much faster than writing to EEPROM. Looking at the data sheet for the 23K256, the only limitation I see is that the clock frequency at 3.0V has to be below 20MHz for the industrial version and below 16MHz for the automotive version. In other words, it can accept data as fast as the Arduino can push it out. Just keep in mind that while your EEPROM will retain data for decades, the SRAM will lose its data as soon as Vcc drops below 1.2V.

majolsurf

I measured the 23K256 transfer process to be around 260us.  Not great but far better than 5ms!

Below is a link to some work I've done with the 23K256, a CPLD, and the Arduino.  I have a method of injecting addressing in the 23K256 data stream and expanding memory.  I have tested up to 256KB, the theoretical limit is 2MB.  The practical limit is far less due to cost and real estate.

http://majolsurf.net/wordpress/?p=930

rolando

Hi all,

I'm trying to make this work with Arduino 021, but so far no success. I want to use the included SPI library instead of "Spi.h" that the library in the playground uses. So far this is my code:
Code: [Select]

# SPIRAM.h
#include <WProgram.h>
#include <SPI.h>

// SRAM opcodes
#define READ  0b00000011
#define WRITE 0b00000010
#define RDSR  0b00000101
#define WRSR  0b00000001

#define HOLD 1
#define BYTE_MODE (0x00 | HOLD)
#define PAGE_MODE (0x80 | HOLD)
#define STRM_MODE (0x40 | HOLD)

class SPIRAM {
public:
 SPIRAM();
 void writeByte(uint8_t address, uint8_t data);
 uint8_t readByte(uint8_t address);
private:
 void setMode(uint8_t mode);
 
 uint8_t mode_;
};


Code: [Select]

# SPIRAM.cpp
#include "pins_arduino.h"
#include "SPIRAM.h"

SPIRAM::SPIRAM() {
 digitalWrite(SS, LOW);
 SPI.begin();
 SPI.setBitOrder(MSBFIRST);
 SPI.setDataMode(SPI_MODE1);
 mode_ = BYTE_MODE;
}

void SPIRAM::writeByte(uint8_t address, byte data) {
 setMode(BYTE_MODE);
 digitalWrite(SS, LOW);
 SPI.transfer(WRITE);
 SPI.transfer((byte)(address >> 8));
 SPI.transfer(address);
 SPI.transfer(data);
 digitalWrite(SS, HIGH);
}

byte SPIRAM::readByte(uint8_t address) {
 byte data;
 
 setMode(BYTE_MODE);
 digitalWrite(SS, LOW);
 SPI.transfer(READ);
 SPI.transfer((byte)(address >> 8));
 SPI.transfer(address);
 data = SPI.transfer(0x00);
 digitalWrite(SS, HIGH);
 return data;
}

// write the status register (bites 7 and 6)
void SPIRAM::setMode(uint8_t mode) {
 if (mode != mode_) {
   digitalWrite(SS, LOW);
   SPI.transfer(WRSR);
   SPI.transfer(mode);
   digitalWrite(SS, HIGH);
   mode_ = mode;
 }
}


Code: [Select]

#SRAMTest.pde
#include <SPI.h>
#include "SPIRAM.h"

SPIRAM spiRAM;

void setup() {
 Serial.begin(9600);
}

void loop() {
 char data_to_chip[17] = "Testing 90123456";
 char data_from_chip[17] = "";
 int i;
 
 for (i=0; i < 17; i++) {
   spiRAM.writeByte(i, data_to_chip[i]);
 }
 
 // read back data
 for (i=0 ; i < 17; i++) {
   data_from_chip[17] = spiRAM.readByte(i);
 }
 data_from_chip[i] = '\0';
 Serial.print("data: ");
 Serial.println(data_from_chip);
 delay(3000);
}


On the hardware side, I'm using this (taken from this post):



I just want to test the sram with a simple write/read byte and the go to page/stream.

Any idea where could be my problem?
thanks!

rolando

This is what I'm getting back from the sram:

Code: [Select]

will write data 'T' to address 0
will write data 'e' to address 1
will write data 's' to address 2
will write data 't' to address 3
will write data 'i' to address 4
will write data 'n' to address 5
will write data 'g' to address 6
will write data ' ' to address 7
will write data '9' to address 8
will write data '0' to address 9
will write data '1' to address A
will write data '2' to address B
will write data '3' to address C
will write data '4' to address D
will write data '5' to address E
will write data '6' to address F
will write data '' to address 10
read data '0' from address 0
read data '0' from address 1
read data 'FC' from address 2
read data 'F8' from address 3
read data 'FF' from address 4
read data 'FD' from address 5
read data 'FF' from address 6
read data 'FC' from address 7
read data '70' from address 8
read data 'FF' from address 9
read data 'FF' from address A
read data 'FF' from address B
read data 'E7' from address C
read data 'FF' from address D
read data 'FF' from address E
read data 'FF' from address F
read data 'FF' from address 10

mrmeval

http://www.ramtron.com/products/nonvolatile-memory/serial-product.aspx?id=6
If it was designed by man it can be repaired by man.

Go Up