Problems understaning SPI and Reading EEPROM

Hi really helpful people of the forum,

Im stuck again.
I have a 93LC46 EEPROM that i would like to read and write to. Read first, then write. Walk before run. I would think that there is already data in it as it has been salvaged from an old NIC.

I have been reading up on SPI on the library page and about its commands. Also have been going over the datasheet for the device.
link: http://ww1.microchip.com/downloads/en/devicedoc/21712b.pdf
and this document: http://mcu.sunplusmcu.com/soft/65_en_Application_note/AN_SPMC65_O0323_en_V1.2.pdf
Also i have been trying to learn from and adapt info from this page:
http://arduino.cc/en/Tutorial/SPIEEPROM
Ive tried his sketch, but im afraid that there are differences in the chips.

I have hooked up the arduino like this:
Arduino 93LC46
pin10 → pin1 (select)
pin11 → pin3 (MOSI → DI)
pin12 → pin4 (MISO → DO)
pin13 → pin2 (CLK → CLK)
pin5 → gnd (gnd)
pin6 → gnd (Org)
pin7 → nc
pin8 → 5v

I read in the datasheet that you have to first send it a startup command (CS and DI HIGH) before it will accept any inputs (read, write, clear, etc).
Im not sure how to do this, can it be just digitalWriting those pins high then LOW again.

Next problem, all the SPI stuff i read says that CS is when the pin is pulled low. In the datasheet, though, its opposite.

Now the biggest problem, I dont understand the code to read and write to it. I have to send it a “1” to signify that a command is coming, then the command (“10” for read and “01” for write) then it will want the address. (page 4 of datasheet)
All the examples SPI sketches show something like this:

const byte READ = 0b11111100;     // SCP1000's read command
const byte WRITE = 0b00000010;   // SCP1000's write command

how do i get to that sort of format, do i need to, why is there a ‘b’ in there?

Heres the code i have been playing with all night, I know it looks like i have no idea what im doing with this and thats because i dont.

/*
 Circuit:
 MOSI: pin 11
 MISO: pin 12
 SCK: pin 13

 */

// the sensor communicates using SPI, so include the library:
#include <SPI.h>

const int chipSelectPin = 10;

void setup() {
  Serial.begin(9600);
  digitalWrite(10, HIGH);
  digitalWrite(11, HIGH);
  digitalWrite(12, HIGH);
  delay(100);
  digitalWrite(10, LOW);
  digitalWrite(11, LOW);
  digitalWrite(12, LOW);
  
  // start the SPI library:
  SPI.begin();
  
  // initalize the  data ready and chip select pins:
  pinMode(chipSelectPin, OUTPUT);
  delay(100);
}

void loop() {


  // don't do anything until the data ready pin is Low:
 
      digitalWrite(chipSelectPin, HIGH);
       SPI.transfer(0x1);
       SPI.transfer(0x10);
       int tempData = SPI.transfer(A6);
    // take the chip select low to de-select:
      digitalWrite(chipSelectPin, LOW);

   

    // display the tempdata:
    Serial.println(tempData);
    delay(500);
  }

Any help to get even a little bit closer to understanding this would be great!

That chip isn't an SPI EEPROM. Although the three wire interface looks like an SPI bus, there are differences. The first is that the SS pin (CS) is active HIGH while an SPI SS is active LOW. The next is that the data transfer is not in bytes. A read command in 8bit mode (ORG to GND) uses 10bit to send the start bit, opcode and address to the chip. With the SPI hardware you can only send whole bytes (at least with the SPI library).

If you want to read or write that chip you may have to implement that protocol in software.

Ohhh. :~ righto. thanks for that, makes total sense. I think it was the document from sunplus that was making me believe I could do it.

pylon:
If you want to read or write that chip you may have to implement that protocol in software.

Is that going to be hard to do? Or do you think im better just to get an SPI EEPROM so i can use the library?

Is that going to be hard to do? Or do you think im better just to get an SPI EEPROM so i can use the library?

That depends on your skills and your budget. If you're not used to low level programming your life's probably going to be more calm if you buy SPI EEPROMs. Otherwise it would be a good training to expand your skills :).

Hi all,
Here a piece of code (for Olimexino using libmapple which is the same as the one used by Arduino) that allows read and write for a 93LC46B1 EEPROM chip memory.

I used it to reprogram my garage door transmitter :slight_smile:

#define PIN_CS D2
#define PIN_CLK D4
#define PIN_DI D5
#define PIN_DO D6

boolean _clockEnabled;
int _clockNextLevel;

int _readData = 0; // 0 = disabled, 1,2,3 = send opcode, 4,5,6,7,8,9 = send addr, ... read value
uint8 _readDataAddr = 0;
uint16 _readDataData = 0;

int _enableWrite = 0; // 0 = disabled
int _disableWrite = 0; // 0 = disabled

int _writeData = 0;
uint8 _writeDataAddr = 0;
uint16 _writeDataData = 0;

void setup() {
    pinMode(PIN_CS, OUTPUT);
    pinMode(PIN_CLK, OUTPUT);
    pinMode(PIN_DI, OUTPUT);
    pinMode(PIN_DO, INPUT);
    
    _clockEnabled = false;
}

int _addressToRead = 0;
void loop() {
    updateClock(); // Mandatory function
    
    // Usage exemple : Be carreful : readAddress(), enableWrite(), disableWrite() and WriteAddress() are asynchronous.
    if (SerialUSB.available()) {
      int c = SerialUSB.read();
      if (c == 'r') readAddress(42); // Read address 42
      if (c == 'e') enableWrite(); // Enable write access! Required before any writeAddress call
      if (c == 'd') disableWrite(); // Disable write access!
      if (c == 'w') writeAddress(42, 6969); // Write 6969 to address 42
    }
}

void updatePinStatus()
{
  // Enable write command
  if (_enableWrite > 0)
  {
    _enableWrite++;
    switch(_enableWrite - 1)
    {
      case 1: digitalWrite(PIN_DI, HIGH); break;
      case 2: digitalWrite(PIN_DI, LOW); break;
      case 3: digitalWrite(PIN_DI, LOW); break;
      
      case 4: digitalWrite(PIN_DI, HIGH); break;
      case 5: digitalWrite(PIN_DI, HIGH); break;
      
      case 6: digitalWrite(PIN_DI, HIGH); break; //X
      case 7: digitalWrite(PIN_DI, HIGH); break; //X
      case 8: digitalWrite(PIN_DI, HIGH); break; //X
      case 9: digitalWrite(PIN_DI, HIGH); break; //X
      case 10: digitalWrite(PIN_DI, HIGH); break; //X
      case 11: digitalWrite(PIN_DI, HIGH); break; //X
      case 12:
        stopClock();
        _enableWrite = 0;
        delayMicroseconds(10); // Necessary according the datasheet (at least 250ns)
        enableWriteComplete();
        break;
    }
  }
  
    // Disable write command
  if (_disableWrite > 0)
  {
    _disableWrite++;
    switch(_disableWrite - 1)
    {
      case 1: digitalWrite(PIN_DI, HIGH); break;
      case 2: digitalWrite(PIN_DI, LOW); break;
      case 3: digitalWrite(PIN_DI, LOW); break;
      
      case 4: digitalWrite(PIN_DI, LOW); break;
      case 5: digitalWrite(PIN_DI, LOW); break;
      
      case 6: digitalWrite(PIN_DI, HIGH); break; //X
      case 7: digitalWrite(PIN_DI, HIGH); break; //X
      case 8: digitalWrite(PIN_DI, HIGH); break; //X
      case 9: digitalWrite(PIN_DI, HIGH); break; //X
      case 10: digitalWrite(PIN_DI, HIGH); break; //X
      case 11: digitalWrite(PIN_DI, HIGH); break; //X
      case 12:
        stopClock();
        _disableWrite = 0;
        delayMicroseconds(10); // Necessary according the datasheet (at least 250ns)
        disableWriteComplete();
        break;
    }
  }
  
  if (_writeData > 0) {
    _writeData++;
    switch(_writeData - 1)
    {
      case 1: digitalWrite(PIN_DI, HIGH); break;
      case 2: digitalWrite(PIN_DI, LOW); break;
      case 3: digitalWrite(PIN_DI, HIGH); break;
      
      case 4: digitalWrite(PIN_DI, (_writeDataAddr >> 5) & 0x01); break;
      case 5: digitalWrite(PIN_DI, (_writeDataAddr >> 4) & 0x01); break;
      case 6: digitalWrite(PIN_DI, (_writeDataAddr >> 3) & 0x01); break;
      case 7: digitalWrite(PIN_DI, (_writeDataAddr >> 2) & 0x01); break;
      case 8: digitalWrite(PIN_DI, (_writeDataAddr >> 1) & 0x01); break;
      case 9: digitalWrite(PIN_DI, (_writeDataAddr >> 0) & 0x01); break;
      
      case 10: digitalWrite(PIN_DI, (_writeDataData >> 15) & 0x01); break;
      case 11: digitalWrite(PIN_DI, (_writeDataData >> 14) & 0x01); break;
      case 12: digitalWrite(PIN_DI, (_writeDataData >> 13) & 0x01); break;
      case 13: digitalWrite(PIN_DI, (_writeDataData >> 12) & 0x01); break;
      case 14: digitalWrite(PIN_DI, (_writeDataData >> 11) & 0x01); break;
      case 15: digitalWrite(PIN_DI, (_writeDataData >> 10) & 0x01); break;
      case 16: digitalWrite(PIN_DI, (_writeDataData >> 9) & 0x01); break;
      case 17: digitalWrite(PIN_DI, (_writeDataData >> 8) & 0x01); break;
      case 18: digitalWrite(PIN_DI, (_writeDataData >> 7) & 0x01); break;
      case 19: digitalWrite(PIN_DI, (_writeDataData >> 6) & 0x01); break;
      case 20: digitalWrite(PIN_DI, (_writeDataData >> 5) & 0x01); break;
      case 21: digitalWrite(PIN_DI, (_writeDataData >> 4) & 0x01); break;
      case 22: digitalWrite(PIN_DI, (_writeDataData >> 3) & 0x01); break;
      case 23: digitalWrite(PIN_DI, (_writeDataData >> 2) & 0x01); break;
      case 24: digitalWrite(PIN_DI, (_writeDataData >> 1) & 0x01); break;
      case 25: digitalWrite(PIN_DI, (_writeDataData >> 0) & 0x01); break;
      case 26:
        digitalWrite(PIN_DI, LOW);
        digitalWrite(PIN_CS, LOW);
        break;
      case 27:
        digitalWrite(PIN_CS, HIGH);
        break;
      default:
        if (digitalRead(PIN_DO) == HIGH) {
          stopClock();
          _writeData = 0;
          writeAddressComplete();
          _writeDataAddr = 0;
          _writeDataData = 0;
        }
        break; 
    }
  }

  // Send address to read (16bits)
  if (_readData > 0) {
    _readData++;
    switch(_readData - 1)
    {
      case 1: digitalWrite(PIN_DI, HIGH); break;
      case 2: digitalWrite(PIN_DI, HIGH); break;
      case 3: digitalWrite(PIN_DI, LOW); break;
      
      case 4: digitalWrite(PIN_DI, (_readDataAddr >> 5) & 0x01); break;
      case 5: digitalWrite(PIN_DI, (_readDataAddr >> 4) & 0x01); break;
      case 6: digitalWrite(PIN_DI, (_readDataAddr >> 3) & 0x01); break;
      case 7: digitalWrite(PIN_DI, (_readDataAddr >> 2) & 0x01); break;
      case 8: digitalWrite(PIN_DI, (_readDataAddr >> 1) & 0x01); break;
      case 9: digitalWrite(PIN_DI, (_readDataAddr >> 0) & 0x01); break;
      
      case 10: digitalWrite(PIN_DI, LOW); break;
      
      case 11: _readDataData += digitalRead(PIN_DO) << 15; break;
      case 12: _readDataData += digitalRead(PIN_DO) << 14; break;
      case 13: _readDataData += digitalRead(PIN_DO) << 13; break;
      case 14: _readDataData += digitalRead(PIN_DO) << 12; break;
      case 15: _readDataData += digitalRead(PIN_DO) << 11; break;
      case 16: _readDataData += digitalRead(PIN_DO) << 10; break;
      case 17: _readDataData += digitalRead(PIN_DO) << 9; break;
      case 18: _readDataData += digitalRead(PIN_DO) << 8; break;
      case 19: _readDataData += digitalRead(PIN_DO) << 7; break;
      case 20: _readDataData += digitalRead(PIN_DO) << 6; break;
      case 21: _readDataData += digitalRead(PIN_DO) << 5; break;
      case 22: _readDataData += digitalRead(PIN_DO) << 4; break;
      case 23: _readDataData += digitalRead(PIN_DO) << 3; break;
      case 24: _readDataData += digitalRead(PIN_DO) << 2; break;
      case 25: _readDataData += digitalRead(PIN_DO) << 1; break;
      case 26: _readDataData += digitalRead(PIN_DO) << 0; break;
      case 27:
        stopClock();
        _readData = 0;
        readAddressComplete();
        _readDataAddr = 0;
        _readDataData = 0;
        break;
    }
  }
}


void readAddress(uint8 addr) {
  _readData = 1;
  _readDataAddr = addr;
  _readDataData = 0;
  startClock();
}

void writeAddress(uint8 addr, uint16 data) {
  _writeData = 1;
  _writeDataAddr = addr;
  _writeDataData = data;
  startClock();
}

void disableWrite() {
  _disableWrite = 1;
  startClock();
}

void enableWrite() {
  _enableWrite = 1;
  startClock();
}

void readAddressComplete() {
  SerialUSB.print("Read address [");
  SerialUSB.print(_readDataAddr);
  SerialUSB.print("] = ");
  SerialUSB.println(_readDataData);
}

void writeAddressComplete() {
  SerialUSB.print("Write address [");
  SerialUSB.print(_writeDataAddr);
  SerialUSB.print("] = ");
  SerialUSB.println(_writeDataData);
}

void enableWriteComplete() {
  SerialUSB.println("Write mode enabled");
}

void disableWriteComplete() {
  SerialUSB.println("Write mode disabled");
}

void startClock() {
    digitalWrite(PIN_CS, HIGH);
    digitalWrite(PIN_DI, LOW);
    digitalWrite(PIN_CLK, LOW);
    _clockEnabled = true;
    _clockNextLevel = HIGH;
}

void stopClock() {
    digitalWrite(PIN_CS, LOW);
    digitalWrite(PIN_DI, LOW);
    digitalWrite(PIN_CLK, LOW);
    _clockEnabled = false;
    _clockNextLevel = LOW;
}

void updateClock() {
  if (!_clockEnabled)
    return ;
    
    digitalWrite(PIN_CLK, _clockNextLevel);
    if (_clockNextLevel == LOW) updatePinStatus();
    _clockNextLevel = (_clockNextLevel == HIGH) ? LOW : HIGH;
    delayMicroseconds(100); // Master clock period / 2
}