[SOLVED] Help with SPI library please

I am trying to work with an eeprom, CAT25160. Here is the link to its datasheet for reference.

For now, I am working on a simple test project to right 5 bytes to the eprom, and then read them back. I write the following, or at least I think I am.

Address Value
0 10
1 11
2 12
3 13
4 14

I write them one at a time, with a 5 second delay in between each write to make sure that the writes have time to complete.

In the read routine, whatever value I pass to the read routine seems to come back to me sometimes, but not sure why? I am not sure if the write or read routine is wrong, but could use some help.

This is the output of the program, and I will paste the complete source below. Any help is appreciated.

Writing 0
Writing 1
Writing 2
Writing 3
Writing 4
Address 0
Value 0
Address 1
Value 85
Address 2
Value 85
Address 3
Value 85
Address 4
Value 255

Thank you,
Tim

#include <SPI.h>

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

//for chip CAT25160
const byte WRITE_ENABLE = 0b00000110; // enable write operations
const byte WRITE_DISABLE = 0b00000100; // disable write operations
const byte READ_STATUS_REGISTER = 0b00000101; //read status register
const byte WRITE_STATUS_REGISTER = 0b00000001; //write status register
const byte READ = 0b00000011; // read command
const byte WRITE = 0b00000010; // write command

byte eeprom_output_data;
byte eeprom_input_data=0;
int address=0;
int I;
int value;

void setup() {
// set the slaveSelectPin as an output:
pinMode (SLAVESELECT, OUTPUT);
// initialize SPI:
SPI.begin();
Serial.begin(9600);

digitalWrite(SLAVESELECT,LOW);
// send in the address and value via SPI:
SPI.transfer(WRITE_ENABLE);
// take the SS pin high to de-select the chip:
digitalWrite(SLAVESELECT,HIGH);

for (int counter = 0; counter < 5; counter++) {
address = counter;
value = counter+10;
write_eeprom(address, value);
// 'short delay to give write time to finish
delay(5000);
Serial.print("Writing ");
Serial.println(address,DEC);

}

}

void loop() {

for (int counter = 0; counter < 5; counter++) {
read_eeprom(counter);
delay(1000);
}
//delay so numbers are flying by over and over too much
delay(20000);
}

int write_eeprom(int address, int value) {
// take the SS pin low to select the chip:
digitalWrite(SLAVESELECT,LOW);
// send in the address and value via SPI:
SPI.transfer(WRITE);
SPI.transfer(address);
SPI.transfer(value);
// take the SS pin high to de-select the chip:
digitalWrite(SLAVESELECT,HIGH);
}

int read_eeprom(int address) {
// take the SS pin low to select the chip:
byte retValue;
digitalWrite(SLAVESELECT,LOW);
// send in the address and value via SPI:
SPI.transfer(READ);
SPI.transfer(address);
retValue = SPI.transfer(0x55);

Serial.print("Address ");
Serial.println(address,DEC);
Serial.print("Value ");
Serial.println(retValue, DEC);

// take the SS pin high to de-select the chip:
digitalWrite(SLAVESELECT,HIGH);
return retValue;
}

After a day of getting nowhere, I posted,then something hit me. I should have been using a 16 bit address, so I have changed the code to as below. I also hardcode some writes and reads to make sure I didn't have a loop problem. I am writing and reading to address 0 okay, but none others. Here is my output.
Writing adddress 0 Value 10
Writing adddress 1 Value 20
Writing adddress 2 Value 30
Writing adddress 3 Value 40
Writing adddress 4 Value 50
Finished Writing
Reading Address 0 Value 10
Reading Address 1 Value 97
Reading Address 2 Value 98
Reading Address 3 Value 99
Reading Address 4 Value 100

I wrote 10, 20, 30, 40, 50, but didn't get it back. I am not sure where the other numbers come from. Ideas anyone?

Here is code as it stands now.

#include <SPI.h>

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

//for chip CAT25160
const byte WRITE_ENABLE = 0b00000110; // enable write operations
const byte WRITE_DISABLE = 0b00000100; // disable write operations
const byte READ_STATUS_REGISTER = 0b00000101; //read status register
const byte WRITE_STATUS_REGISTER = 0b00000001; //write status register
const byte READ = 0b00000011; // read command
const byte WRITE = 0b00000010; // write command

byte bytValue;

void setup() {
// set the slaveSelectPin as an output:
pinMode (SLAVESELECT, OUTPUT);
// initialize SPI:
SPI.begin();
SPI.setBitOrder(MSBFIRST);
// SPI.setBitOrder(LSBFIRST);

SPI.setDataMode(SPI_MODE0);

Serial.begin(9600);

digitalWrite(SLAVESELECT,LOW);
// send in the address and value via SPI:
SPI.transfer(WRITE_ENABLE);
// take the SS pin high to de-select the chip:
digitalWrite(SLAVESELECT,HIGH);

write_eeprom(0,10);
delay(5000);
write_eeprom(1,20);
delay(5000);
write_eeprom(2,30);
delay(5000);
write_eeprom(3,40);
delay(5000);
write_eeprom(4,50);
delay(5000);

Serial.println("Finished Writing");

}

void loop() {

byte result;

read_eeprom(0);
delay(1000);
read_eeprom(1);
delay(1000);
read_eeprom(2);
delay(1000);
read_eeprom(3);
delay(1000);
read_eeprom(4);
delay(1000);

//delay so numbers are flying by over and over too much
delay(20000);
}

int write_eeprom(byte waddress, byte wvalue) {
// take the SS pin low to select the chip:
digitalWrite(SLAVESELECT,LOW);
// send in the address and value via SPI:
// SPI.transfer(WRITE_ENABLE);
SPI.transfer(WRITE);
//high byte of address
//SPI.transfer(waddress);
SPI.transfer(0);
SPI.transfer(waddress);
SPI.transfer(wvalue);
// take the SS pin high to de-select the chip:
digitalWrite(SLAVESELECT,HIGH);

Serial.print("Writing adddress ");
Serial.print(waddress, DEC);
Serial.print(" Value ");
Serial.println(wvalue,DEC);

}

int read_eeprom(byte raddress) {
// take the SS pin low to select the chip:
byte retValue;
digitalWrite(SLAVESELECT,LOW);
// send in the address and value via SPI:
SPI.transfer(READ);
//high byte of address
//SPI.transfer(raddress);
SPI.transfer(0);
SPI.transfer(raddress);

retValue = SPI.transfer(0xFF);

Serial.print("Reading Address ");
Serial.print(raddress,DEC);
Serial.print(" Value ");
Serial.println(retValue, DEC);

// take the SS pin high to de-select the chip:
digitalWrite(SLAVESELECT,HIGH);
return retValue;
}

Take these out, SPI takes over these pins.

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

Check your data sheet to make sure you are sending enough address bytes over:

SPI.transfer(address); << this only sends 1 byte

if the chip needs more, than your following command will also be used for address,

SPI.transfer(value);

and then you deselect the chip before actually giving it data.

4 byte transfers look good now. Do you have Hold/ and WP/ pulled high?

Hello and thanks for replying.

I took out the 3 declares, but no change. I have Hold/ and WP/ both tied to 5V.

One thing I have noticed is I can read and write to element 0 without problem, but none other. I have tried many things, reversing byte order and such, but no luck. I started with a blank chip, and now this is my output. I must have accidently got the odd numbers in while trying to get it to work.

My chip takes a 16 bit address which I believe I accounted for in my 2nd post.

Any other ideas?

Writing adddress 0 Value 11
Writing adddress 1 Value 20
Writing adddress 2 Value 30
Writing adddress 3 Value 40
Writing adddress 4 Value 50
Finished Writing
Reading Address 0 Value 11
Reading Address 1 Value 255
Reading Address 2 Value 255
Reading Address 3 Value 255
Reading Address 4 Value 255

What did you mean by 4 byte transfers? I thought you could only transfer 1 byte at a time.

Can you post your current code, with code tags? Select it and hit the # button in the forum. Also, if I may say, 5 second delays are ridiculous. You may as well use pen and paper.

I did some stuff about SPI and EEPROM here:

There may be some hints for you there.

I am not seeing a problem.
You've got the WP/ & Hold/ lines high.
You've got CS/ switching Hi/Lo as needed.
You've got the WriteEnable register set.
You have 4 bytes with each transfer (command, address, address, data).
You have enough time for the writes to complete.

You could try reading the status registers, check the ready bits.

Here is code reposted with code tags (hopefully). I gave a quick look to Nick Gammon's example, and it looks good. I will go over it in detail more. Yes, I realize the 5 second delays are ridiculous. During this dev stage, I just wanted to make sure the timing wasn't the issue.

I'll also try checking the status bits. I am thinking something must be going on there, but with the problems I was having, I wasn't sure I could rely on its answer.

Thanks guys.

#include <SPI.h>


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

//for chip CAT25160
const byte WRITE_ENABLE = 0b00000110;  // enable write operations
const byte WRITE_DISABLE = 0b00000100;  // disable write operations
const byte READ_STATUS_REGISTER = 0b00000101;  //read status register
const byte WRITE_STATUS_REGISTER = 0b00000001;  //write status register
const byte READ = 0b00000011;     // read command
const byte WRITE = 0b00000010;   // write command

byte bytValue;

void setup() {
  // set the slaveSelectPin as an output:
  pinMode (SLAVESELECT, OUTPUT);
  // initialize SPI:
  SPI.begin(); 
  SPI.setBitOrder(MSBFIRST);
// SPI.setBitOrder(LSBFIRST);

SPI.setDataMode(SPI_MODE0);

  
  
  Serial.begin(9600);
  
 
 // digitalWrite(SLAVESELECT,LOW);
  //  send in the address and value via SPI:
  //SPI.transfer(WRITE_ENABLE);
  // take the SS pin high to de-select the chip:
  digitalWrite(SLAVESELECT,HIGH); 

  write_eeprom(0,11);
  delay(5000);
  write_eeprom(1,20);
delay(5000);
  write_eeprom(2,30);
delay(5000);
  write_eeprom(3,40);
 delay(5000);
 write_eeprom(4,50);
 delay(5000);
 
 Serial.println("Finished Writing");
 
   
    }

  



void loop() {
  
  byte result;
   

read_eeprom(0);
delay(1000);
read_eeprom(1);
delay(1000);
read_eeprom(2);
delay(1000);
read_eeprom(3);
delay(1000);
read_eeprom(4);
delay(1000);


for (int I=0; I<20; I++)
{
  read_eeprom(I);
 }

 //delay so numbers are flying by over and over too much
delay(20000);
}


int write_eeprom(byte waddress, byte wvalue) {
  // take the SS pin low to select the chip:
  digitalWrite(SLAVESELECT,LOW);
  //  send in the address and value via SPI:
  SPI.transfer(WRITE_ENABLE);
  SPI.transfer(WRITE);
   //high byte of address
SPI.transfer(waddress);
  SPI.transfer(0);    
 // SPI.transfer(waddress);
  SPI.transfer(wvalue);
//    SPI.transfer(12);
  //    SPI.transfer(13);
    //    SPI.transfer(14);
  // take the SS pin high to de-select the chip:
  digitalWrite(SLAVESELECT,HIGH); 
  
  Serial.print("Writing adddress ");
  Serial.print(waddress, DEC);
  Serial.print("  Value  ");
  Serial.println(wvalue,DEC);
  
}



byte read_eeprom(int raddress) {
  // take the SS pin low to select the chip:
  byte retValue;
  digitalWrite(SLAVESELECT,LOW);
  //  send in the address and value via SPI:
  SPI.transfer(READ);
  //high byte of address
 //SPI.transfer(raddress);
 SPI.transfer(0);
  SPI.transfer(raddress);
 
retValue = SPI.transfer(0xFF);

Serial.print("Reading Address ");
  Serial.print(raddress,DEC);  
  Serial.print("    Value ");
  Serial.println(retValue, DEC);
  
  // take the SS pin high to de-select the chip:
  digitalWrite(SLAVESELECT,HIGH); 
  return retValue;
}

Your code:

int write_eeprom(byte waddress, byte wvalue) {

// take the SS pin low to select the chip:
  digitalWrite(SLAVESELECT,LOW);
  //  send in the address and value via SPI:
  SPI.transfer(WRITE_ENABLE);
  SPI.transfer(WRITE);

The datasheet:

Care must be taken to take the CS input high after the WREN instruction, as otherwise the Write Enable Latch will not be properly set.

You aren't doing that.

I think he had that correct in the earlier sketch, that write was done in setup.

Yes, well it's commented out now. :slight_smile:

Any other ideas?

Writing adddress 0 Value 11
Writing adddress 1 Value 20
Writing adddress 2 Value 30
Writing adddress 3 Value 40
Writing adddress 4 Value 50
Finished Writing
Reading Address 0 Value 11

Yes. You need to put the write-enable back how you had it.

Judging by page 7 of the datasheet you need to send the most significant byte of the address first, which you are not doing. Something like this, from my page I quoted above:

int write_eeprom(unsigned int waddress, byte wvalue) 
{
  digitalWrite(SLAVESELECT,LOW);
  SPI.transfer(WRITE);   
  SPI.transfer ((waddress >> 8) & 0xFF);         // high order byte
  SPI.transfer (waddress & 0xFF);      // low order byte
  SPI.transfer(wvalue);    // data
  digitalWrite(SLAVESELECT,HIGH); 
}

Hi guys,

Many thanks for the help. I finally got it worked out. First, I may have posted some code while I was in the middle of trying things, so sorry if any confusion.

I did a partial rewrite based on Nick's link.

My end problem was that the Write enabled flag was reset back to zero after any write, and I wasn't properly setting it back to 1 before the next write. It required bringing the select line back to high to take effect, but I was only bringing the line back to high after trying to write the data, therefore the write was never really enabled.

I would like to mark this solved on the forum, but I don't know how. If either of you would like to let me know, I would appreciate it.

Again, thank you both for your help,
Tim

I would like to mark this solved on the forum, but I don't know how.

Go to your original posting and hit the modify button, you can then edit the subject line and hit save.

Lefty

Thanks Lefty!

Hi guys,

I had a request to add my final working code, so hopefully better late than never. I hope this helps someone in the future.

There are 2 different programs, although some functions are duplicated. This one writes to the chip.

#include <SPI.h>


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

//for chip CAT25160
const byte WRITE_ENABLE = 0b00000110;  // enable write operations
const byte WRITE_DISABLE = 0b00000100;  // disable write operations
const byte READ_STATUS_REGISTER = 0b00000101;  //read status register
const byte WRITE_STATUS_REGISTER = 0b00000001;  //write status register
const byte READ = 0b00000011;     // read command
const byte WRITE = 0b00000010;   // write command


int valueToWrite[] = {2, 4, 6};
int i;
int addr;

void setup() {
  
  byte byteFromMemory;
  
  // set the slaveSelectPin as an output:
  pinMode (SLAVESELECT, OUTPUT);
  // initialize SPI:
  SPI.begin(); 
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE0);

  Serial.begin(9600);
  
   // global unprotect
  writeStatus (0);


 // write values -> 0-2
  for (i=0; i<=2; i++)
  {
  addr = 0 + i;
  writeEEPROM(addr, valueToWrite[i]);  
  }
  
   
  Serial.println("Values Written");
  

  // fill rest with FF's -> 3-2047
  for (i=3; i<=2047; i++)
  {
  addr = i;
  writeEEPROM(addr, 255);  
  }
  

Serial.println("All Writes Completed");
  
  
  
}

void loop() {

  
}

// wait until chip not busy
void notBusy()
{
  byte status;
  digitalWrite(SLAVESELECT,LOW);
  SPI.transfer(READ_STATUS_REGISTER);
   // wait until bit cleared
  while (SPI.transfer(0) & 1)
   {
     delay(100);
   }
   digitalWrite(SLAVESELECT,HIGH);
}


//enable writing
void writeEnable()
{
  notBusy();
  digitalWrite(SLAVESELECT,LOW);
  //  send in the address and value via SPI:
  SPI.transfer(WRITE_ENABLE);
  // take the SS pin high to de-select the chip:
  digitalWrite(SLAVESELECT,HIGH); 
  
}

// read status register
byte readStatus(void)
{
  byte status;
  digitalWrite(SLAVESELECT,LOW);
  //  send in the address and value via SPI:
  status = SPI.transfer(READ_STATUS_REGISTER);
  // take the SS pin high to de-select the chip:
  digitalWrite(SLAVESELECT,HIGH); 
  return status;
}

// write status register
void writeStatus (const byte status)
{
   writeEnable ();
   notBusy ();  // wait until ready
   digitalWrite (SLAVESELECT, LOW);
   SPI.transfer (WRITE_STATUS_REGISTER);       
   SPI.transfer (status);       
   digitalWrite (SLAVESELECT, HIGH);  
}  // end of writeStatus

// write one byte to eprom
void writeEEPROM (const int addr, byte writeDataByte) 
{
  // now write to it
  writeEnable ();
  
  notBusy ();  // wait until ready
  digitalWrite (SLAVESELECT, LOW);
  
  SPI.transfer (WRITE);       
  SPI.transfer ((addr >> 8) & 0xFF);       
  SPI.transfer (addr & 0xFF);       
  SPI.transfer (writeDataByte);       
  digitalWrite (SLAVESELECT, HIGH);  
  notBusy (); 
} // end of writeEEPROM


// read bytes from eeprom
byte readEEPROM (int addr)
{
  byte bytRead;
  notBusy ();  // wait until ready
  digitalWrite (SLAVESELECT, LOW);
  SPI.transfer(READ);
  SPI.transfer ((addr >> 8) & 0xFF);       
  SPI.transfer (addr & 0xFF);       
  // send any byte to pop off "don't care" byte
  bytRead= SPI.transfer(0x00);
  // get data
//  bytRead= SPI.transfer(0);
  digitalWrite (SLAVESELECT, HIGH);  
  return bytRead;
}  // end of readEEPROM

/////////////////////////////////////////////////////////////////////////
This program reads from the chip.

#include <SPI.h>


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

//for chip CAT25160
const byte WRITE_ENABLE = 0b00000110;  // enable write operations
const byte WRITE_DISABLE = 0b00000100;  // disable write operations
const byte READ_STATUS_REGISTER = 0b00000101;  //read status register
const byte WRITE_STATUS_REGISTER = 0b00000001;  //write status register
const byte READ = 0b00000011;     // read command
const byte WRITE = 0b00000010;   // write command

int addr;
byte arr512[512];
int serialActive;

void setup() {

  byte byteFromMemory;
  int arrElementNo;

  // set the slaveSelectPin as an output:
  pinMode (SLAVESELECT, OUTPUT);
  // initialize SPI:
  SPI.begin(); 
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE0);



  // read all bytes into array to be outputted
  // once serial port is opened
  for (addr=0; addr<=511;addr++)
  {


    // Note, there is not enough memory in eprom to store 2048 values in array
    //just reading first 512 here for demonstration

    byteFromMemory= readEEPROM(addr);

    arrElementNo = addr % 512;

    if (addr < 512)
    {
      arr512[arrElementNo] = byteFromMemory;
    }
    else 
    {
      arr512[arrElementNo] =arr512[arrElementNo] & byteFromMemory;
    }


  }


  // debug statement
  //  Serial.begin(9600);
  //Serial.println("All bytes read from memory");


  // reset address to start for loop
  addr=0;

  // initialize as serial has not started yet
  serialActive=0;

  Serial.begin(9600);
  }

  void loop() {

    //int arrMemory[2048];
    //int arr512[512];

    // send something besides zero sync bytes at first open
    // reading program can start with a non-zero value
    // before catching first sync bytes

    byte syncByte;
    syncByte = 0x55;    
    //a non-zero sync byte

    byte value;
    value=0;


    // first report 10 sync bytes before starting loop over so that you will know that data loop is restarting
    if (addr == 0)
    {
      // sync bytes
      value =0;
      Serial.write(syncByte);
      Serial.write(syncByte);
      Serial.write(syncByte);
      Serial.write(syncByte);
      Serial.write(syncByte);
      Serial.write(syncByte);
      Serial.write(syncByte);
      Serial.write(syncByte);
      Serial.write(syncByte);
      Serial.write(syncByte);
    }

    // Serial.println(addr, DEC);

    value = arr512[addr];

    Serial.write(value);

//    Serial.print("  ");
//    Serial.print(addr, DEC);
//    Serial.print("  ");
//    Serial.println(value, DEC);


    // advance to the next address of the EEPROM
    addr = addr + 1;

    // there are only 512 bytes of EEPROM, from 0 to 511, so if we're
    // on address 512, wrap around to address 0
    if (addr == 512)
    {
      addr = 0;
      delay(5000);
    }

    delay(10);
  }

// wait until chip not busy
void notBusy()
{
  byte status;
  digitalWrite(SLAVESELECT,LOW);
  SPI.transfer(READ_STATUS_REGISTER);
  // wait until bit cleared
  while (SPI.transfer(0) & 1)
  {
    delay(100);
  }
  digitalWrite(SLAVESELECT,HIGH);
}


//enable writing
void writeEnable()
{
  notBusy();
  digitalWrite(SLAVESELECT,LOW);
  //  send in the address and value via SPI:
  SPI.transfer(WRITE_ENABLE);
  // take the SS pin high to de-select the chip:
  digitalWrite(SLAVESELECT,HIGH); 

}

// read status register
byte readStatus(void)
{
  byte status;
  digitalWrite(SLAVESELECT,LOW);
  //  send in the address and value via SPI:
  status = SPI.transfer(READ_STATUS_REGISTER);
  // take the SS pin high to de-select the chip:
  digitalWrite(SLAVESELECT,HIGH); 
  return status;
}

// write status register
void writeStatus (const byte status)
{
  writeEnable ();
  notBusy ();  // wait until ready
  digitalWrite (SLAVESELECT, LOW);
  SPI.transfer (WRITE_STATUS_REGISTER);       
  SPI.transfer (status);       
  digitalWrite (SLAVESELECT, HIGH);  
}  // end of writeStatus

// write one byte to eprom
void writeEEPROM (const int addr, byte writeDataByte) 
{
  // now write to it
  writeEnable ();

  notBusy ();  // wait until ready
  digitalWrite (SLAVESELECT, LOW);

  SPI.transfer (WRITE);       
  SPI.transfer ((addr >> 8) & 0xFF);       
  SPI.transfer (addr & 0xFF);       
  SPI.transfer (writeDataByte);       
  digitalWrite (SLAVESELECT, HIGH);  
  notBusy (); 
} // end of writeEEPROM


// read bytes from eeprom
byte readEEPROM (int addr)
{
  byte bytRead;
  notBusy ();  // wait until ready
  digitalWrite (SLAVESELECT, LOW);
  SPI.transfer(READ);
  SPI.transfer ((addr >> 8) & 0xFF);       
  SPI.transfer (addr & 0xFF);       
  // send any byte to pop off "don't care" byte
  bytRead= SPI.transfer(0x00);
  // get data
  //  bytRead= SPI.transfer(0);
  digitalWrite (SLAVESELECT, HIGH);  
  return bytRead;
}  // end of readEEPROM