How to write to 93LC46B EEPROM from an Arduino using SPI

I have a question regarding eeproms and an Arduino (I am using Arduino Uno). I have the following eeprom: 93LC46B. From the datasheet I understand that in order to write the integers 1 and 2 to the first address I need to send the following bits:

• 1 : starting bit
• 01 : write opcode
• 000000 : first address
• 00110001 : 1
• 00110010 : 2

The result is 1010000000011000100110010

I have the following code but I can't seem to find out how to send the bits, can anyone help?

#include "SPI.h"
int ss=10;

void setup()
{
pinMode(ss, OUTPUT);
digitalWrite(ss, LOW);
SPI.begin();
SPI.setBitOrder(MSBFIRST);

digitalWrite(ss, HIGH);
//what to send?
digitalWrite(ss, LOW);
}


So I updated my code but I still can't get a desired output. This is the code:

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

//opcodes
#define WRITE 0x40

byte eeprom_output_data;
byte clr;

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

pinMode(DATAOUT, OUTPUT);
pinMode(DATAIN, INPUT);
pinMode(SPICLOCK, OUTPUT);
pinMode(SLAVESELECT, OUTPUT);
digitalWrite(SLAVESELECT, LOW); //disable device

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

digitalWrite(SLAVESELECT, HIGH);
digitalWrite(DATAOUT, HIGH);
digitalWrite(SPICLOCK, HIGH);
delay(1);
digitalWrite(SPICLOCK, LOW);

spi_transfer(WRITE); //01000000
spi_transfer(0x10);
spi_transfer(0x11);

digitalWrite(SLAVESELECT,LOW); //release chip
delay(3000);

Serial.print(eeprom_output_data,DEC);
Serial.print('\n');
delay(500); //pause for readability
}

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
}

{
int data;

digitalWrite(SLAVESELECT, HIGH);
digitalWrite(DATAOUT, HIGH);
digitalWrite(SPICLOCK, HIGH);
delay(1);
digitalWrite(SPICLOCK, LOW);

data = spi_transfer(0xFF); //get data byte
digitalWrite(SLAVESELECT, LOW); //release chip, signal end transfer
return data;
}

void loop()
{
}

• Which arduino are you using? – angelatlarge Apr 8 '13 at 20:56
• an arduino uno. – Jeroen Apr 8 '13 at 20:57

To write SPI data using library one uses the SPI library's transfer() function: it takes a byte argument and actually sends it over the SPI bus. You can specify more arguments, namely what to do with SS pin, but this doesn't seem to concern you.

The Arduino SPI EEPROM example might also be useful.

If you need to send data that isn't 8-bytes, it would be exceedingly convenient if the data size (in bits) was a multiple of 8. In this case, the data is sent in 8-bit (or one-byte) chunks. The simplest way to do it is to treat your data as a byte array:

byte data[] = {0x00, 0x00, 0x00, 0x00};  // this is 24 bits (8bits/byte * 4 bytes)

// Transfer 24 bits of data
for (int i=0; i<4; i++) {
transfer(data[i]);   // Send 8 bits
}


Question: I'm very confused by this "8*4=24" bit above and below. This doesn't make sense to me. Also, isn't it SPI.transfer, not just transfer ?

Sending data that isn't a multiple of 8 bits is a bit tricky with SPI on Arduino/AVR. But it appears that indeed, your EEPROM requires 25 bit data for writing. Since Arduino SPI only allows data to be sent in 8-bit chunks, the solution is to generate the start condition before you send the SPI data using the SPI library:

  // This is our setup
pinMode(ss, OUTPUT);
digitalWrite(ss, LOW);

// Generate the start condition
digitalWrite(ss, HIGH);
digitalWrite(SPI_MOSI, HIGH);
digitalWrite(SPI_CLK, HIGH);
delay(1); // pause
digitalWrite(SPI_CLK, LOW);
// done with the start condition

// Normal SPI write
// no need to twiddle SS bits since SS is already high
SPI.begin();
SPI.setBitOrder(MSBFIRST);
... // send stuff here
digitalWrite(ss, LOW);


This technique is called bit-banging: raising and lowering of digital outputs in software in accordance with some protocol specification in order to interface with some peripheral or communicate with another chip. In fact, you could bit-bang all the data yourself using digitalWrite(), and bypass the SPI library altogether. It isn't really difficult, and we are already doing that to generate the start condition. What this would look like for every bit:

digitalWrite(SPI_CLOCK, LOW);
digitalWrite(SPI_MOSI, yourBitValueHere);
digitalWrite(SPI_CLOCK, HIGH);
delay(1);


SPI_MOSI would be the pin connected to your EEPROM's DI pin, or the SPI DATA pin on your Arduino. SPI_CLOCK would be the pin connected to your EEPROM's CLK pin. If you are not using the SPI library you could connect any digital output pins to the EEPROM. The spi library is limited to using Arduino's SPI pins, I believe.

• I know about the transfer function, but as you said it takes a byte which is 8 bits and I have 25 bits. I read the example you linked, but I came across the same problem, that I'm not sure how to chop up the bits and send them. – Jeroen Apr 8 '13 at 20:28
• Why do you need 25 bits? The WRITE instruction takes either 8 or 16 bits of data, and the instruction itself is 8 bits. Where is 25 coming from? – angelatlarge Apr 8 '13 at 20:40
• The datasheet specifies a starting bit, but I'm guessing I understood that wrong. Is the starting bit pulling the slave select high? – Jeroen Apr 8 '13 at 20:47
• Thanks alot for the answer! :) It makes much more sense now. – Jeroen Apr 8 '13 at 21:39
• So I tried again with the help your help, but I'm still not getting the output I'm expecting. Could you maybe take another look? I updated my question with the code I have now (based on the tutorial you linked in your answer). – Jeroen Apr 9 '13 at 10:18