[SOLVED] Using external EEPROM via SPI

Greetings!

I’m pretty new to this, and this is the first time I’ve tried to use SPI or work with an EEPROM chip.

After scouring the datasheet, I am fairly certain my SPI settings are correct, but I cannot get a simple write/retrieve routine to work. The bytes that come back from the device are not the bytes that I set.

There is obviously something that I am missing, but I can’t figure out what it is. I would really appreciate any feedback or suggestions.

The device in question is the Microchip 25LC2014 EEPROM (Datasheet)

Here is my code, in its entirety:

#include "application.h"

/* executes once at startup */
void setup() {
  Serial.begin(115200);

  // setup SPI
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockSpeed(1,MHZ);
  SPI.setDataMode(SPI_MODE3);
  SPI.begin(SPI_MODE_MASTER);

  Serial.println("Starting up...");
  delay(2000);
}

void writeEnable() {
  byte rec;
  digitalWrite(A2,LOW); // select this device on the SPI bus
  rec = SPI.transfer(6);  // send write enable command
  Serial.printf("Got back from write enable command: %d\n",rec);
  digitalWrite(A2,HIGH); // de-select this device on the SPI bus to enable latch
  delay(100); // wait for latch to set
  digitalWrite(A2,LOW); // select this device on the SPI bus
  rec = SPI.transfer(2); // send the write command
  Serial.printf("Got back from write command: %d\n",rec);
}
void selectAddress(size_t address) {
  byte rec;
  rec = SPI.transfer((char)(address>>16)); // send MSB
  Serial.printf("Got back from address command 1: %d\n",rec);
  rec = SPI.transfer((char)(address>>8)); // send next bit
  Serial.printf("Got back from address command 2: %d\n",rec);
  rec = SPI.transfer((char)(address)); // send LSB
  Serial.printf("Got back from address command 3: %d\n",rec);
}

void writeDisable() {
  digitalWrite(A2,HIGH); // release the chip
}

/* executes continuously after setup() runs */
void loop() {
  byte rec;
  uint8_t rx_buffer[12] = {};
  uint8_t tx_buffer[12] = {};

  for (int i = 0; i < sizeof(tx_buffer); i++)
    tx_buffer[i] = random(254);

  Serial.print("Generated: ");
  for (int i = 0; i < sizeof(tx_buffer); i++) {
    Serial.print(tx_buffer[i]);
    Serial.print(",");
  }
  Serial.printf("\n");

  writeEnable();
  selectAddress(128);
  for (int i = 0; i < sizeof(tx_buffer); i++) {
    rec = SPI.transfer(tx_buffer[i]);
    Serial.printf("Sent byte: %d\n",rec);
  }
  writeDisable();
  delay(100);

  digitalWrite(A2,LOW); // select this device on the SPI bus
  rec = SPI.transfer(3); // send read command
  Serial.printf("Got back from read command: %d\n",rec);
  selectAddress(128);
  for (int i = 0; i < sizeof(rx_buffer); i++) {
    rx_buffer[i] = SPI.transfer(0);
    Serial.printf("Received byte: %d\n",rx_buffer[i]);
  }
  digitalWrite(A2,HIGH); // deselect this device on the SPI bus
  delay(100);

  Serial.print("Retrieved: ");

  for (int i = 0; i < sizeof(rx_buffer); i++) {
    Serial.print(rx_buffer[i]);
    Serial.print(",");
  }
  Serial.printf("\n\n");

  delay(5000);
}

I have tried both forms of the SPI.transfer method (loop myself vs DMA), but neither one seems to work. I don’t know whether the issue is that the data isn’t being set properly or if it is that the data isn’t being read properly after set. Unfortunately, I do not have access to an oscilloscope, so I’m flying a bit blind right now.

Here’s an example of the output from running the program:

Generated: 37,183,108,211,2,110,122,182,124,199,235,109,
Got back from write enable command: 254
Got back from write command: 2
Got back from address command 1: 0
Got back from address command 2: 0
Got back from address command 3: 128
Sent byte: 37
Sent byte: 183
Sent byte: 108
Sent byte: 211
Sent byte: 2
Sent byte: 110
Sent byte: 122
Sent byte: 182
Sent byte: 124
Sent byte: 196
Sent byte: 235
Sent byte: 109
Got back from read command: 3
Got back from address command 1: 0
Got back from address command 2: 0
Got back from address command 3: 128
Received byte: 0
Received byte: 0
Received byte: 0
Received byte: 0
Received byte: 0
Received byte: 0
Received byte: 0
Received byte: 0
Received byte: 0
Received byte: 0
Received byte: 0
Received byte: 0
Retrieved: 0,0,0,0,0,0,0,0,0,0,0,0,

I do not know if SPI.transfer() simply returns what was passed to it, or if it returns what it read from the device. My EEPROM says to send clock pulses to read bytes after sending the read command+address bytes. Perhaps I need to use a different way of reading, rather than using SPI.transfer?

Thanks in advance for any help!

I got it! It turns out I wasn’t waiting for the write to complete, which caused everything to go all skiwampus. It seems to be working perfectly now!

For those who are interested, this function will return whether or not a write is in progress. Loop until it is false and you’ll be good to go!

bool isWIP() {
  byte data;
  digitalWrite(SS,LOW);
  SPI.transfer(RDSR);
  data = SPI.transfer(0xFF);
  digitalWrite(SS,HIGH);

  return (data & (1 << 0));
}

You can also use the callback function of the DMA version of SPI.transfer() to get “notified” when a DMA write has finsished.
If you pass NULL the call will be synchronous.