5
\$\begingroup\$

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 READ  0x80
#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);

  eeprom_output_data = read_eeprom();
  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
}

byte read_eeprom()
{
  //READ EEPROM
  int data;

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

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

void loop()
{
}
\$\endgroup\$
2
  • \$\begingroup\$ Which arduino are you using? \$\endgroup\$ Commented Apr 8, 2013 at 20:56
  • \$\begingroup\$ an arduino uno. \$\endgroup\$
    – Jeroen
    Commented Apr 8, 2013 at 20:57

1 Answer 1

5
\$\begingroup\$

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.

\$\endgroup\$
6
  • \$\begingroup\$ 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. \$\endgroup\$
    – Jeroen
    Commented Apr 8, 2013 at 20:28
  • \$\begingroup\$ 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? \$\endgroup\$ Commented Apr 8, 2013 at 20:40
  • \$\begingroup\$ The datasheet specifies a starting bit, but I'm guessing I understood that wrong. Is the starting bit pulling the slave select high? \$\endgroup\$
    – Jeroen
    Commented Apr 8, 2013 at 20:47
  • \$\begingroup\$ Thanks alot for the answer! :) It makes much more sense now. \$\endgroup\$
    – Jeroen
    Commented Apr 8, 2013 at 21:39
  • \$\begingroup\$ 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). \$\endgroup\$
    – Jeroen
    Commented Apr 9, 2013 at 10:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.