SPI EEPROM Addressing Issue

Hi all,

I'm trying to do some data logging to an Atmel AT25640A eeprom using SPI. I've got the interface up and running no problem, but I can't seem to address more than 256 memory locations.

The AT25640A is an 8x8192 (64kbit) chip, but I get wrap around at multiples of 256 if i write to location 0 (so addresses 0, 256, 512, 768, ... have the same value). I've tried twiddling various data types, but no luck. My code's below, which mostly follows the SPI EEPROM tutorial on the Arduino site for the AT25HP512 (same instruction set).

//Test how many slots there are to print times to

#define DATAOUT 11 //MOSI
#define DATAIN 12 //MISO
#define SPICLOCK 13 // SCK
#define SS0 10//Slave select 0

//Opcodes
#define WREN 6 //write enable
#define WRDI 4 //write disable
#define RDSR 5 //read status register
#define WRSR 1 //write status register
#define READ 3 //read
#define WRITE 2//write

byte clr;
byte test = 0b1;

void setup() {
  Serial.begin(9600);
  pinMode(DATAOUT, OUTPUT);
  pinMode(DATAIN, INPUT);
  pinMode(SPICLOCK, OUTPUT);
  pinMode(SS0, OUTPUT);
  digitalWrite(SS0, HIGH); //disable device
  
  //SPCR = 0101000
  SPCR = (1<<SPE)|(1<<MSTR);
  clr = SPSR; //clear spi status register
  clr = SPDR; // clear spi data register
  delay(10); //wait for eeprom to finish writing
   
  Serial.println("serial active\n");
  
  /*Serial.print("clearing eeprom: ");
  for (int i = 0; i<8192; i++){
    write_eeprom(i, 0b0);
    Serial.print(i, DEC);
    Serial.print(", ");
  }
  Serial.println("...done");
  */
  Serial.print("writing to eeprom");
  write_eeprom(0, test);
  Serial.println("...done");
  
}

void loop(){
  int i =0;
  byte data;
  for (i=0; i<8192; i++){
    data = read_eeprom(i);
    if (data == test  || data == -1){
    Serial.print(i, DEC);
    Serial.print(":");
    Serial.print(data, DEC);
    Serial.print("\t");
    } else { continue;}
     delay(10);
    }
    Serial.println("\nPause in loop");
    delay(5000);
    
  }

unsigned int spi_transfer(volatile unsigned int data){
    SPDR = data;
    while (!(SPSR & (1<<SPIF)))
    {
    };
    return SPDR;
  }
  
 void write_eeprom(unsigned int EEPROM_address, byte data){
   digitalWrite(SS0, LOW); //select device
   spi_transfer((char)(WREN)); //write enable
   digitalWrite(SS0, HIGH); 
   delay(10);
   
   digitalWrite(SS0, LOW);
   spi_transfer((char)(WRITE)); //write
   spi_transfer((EEPROM_address+1)); //MSB
   spi_transfer((EEPROM_address)); //LSB
   spi_transfer((char)(data));
   digitalWrite(SS0, HIGH);
   
   delay(10); //wait for EEPROM to finish writing
 }
 
 byte read_eeprom(unsigned int EEPROM_address){
   digitalWrite(SS0, LOW);
   spi_transfer((char)(READ));
   spi_transfer((EEPROM_address+1)); //MSB
   spi_transfer((EEPROM_address)); //lsb
   
   byte data = (char)(spi_transfer(0xFF));
   
   digitalWrite(SS0, HIGH);
   
   return data;
 }

Thanks in advance!

My guess is that the SPI transfer function is only transferring 8 bits over before the deselecting the chip select. Therefore memory is not seeing the most significant byte of the address and treating them as zero.
However, it is only a guess, but it looks like something is stopping the MSB getting through.

EDIT
Looking at you code you are sending the address in two bytes. According to my reading of the data sheet this has to be sent as a 16 bit value.

From the ATmega168 data sheet :

"A serial frame for the MSPIM is defined to be one character of 8 data bits. The USART in MSPIM
mode has two valid frame formats:
? 8-bit data with MSB first
? 8-bit data with LSB first
A frame starts with the least or most significant data bit. Then the next data bits, up to a total of
eight, are succeeding, ending with the most or least significant bit accordingly. When a complete
frame is transmitted, a new frame can directly follow it, or the communication line can be set to
an idle (high) state." (pg 201-202)

Sounds like the mcu is cutting off the MSB being transmitted. It goes on to say that 16bit transfers are possible. I'm looking into it an will report my findings at a later time.

-EDIT- whoops, i was looking at the USART MSPIM section, reading the SPI section now.

The read timing on page 13 shows 16 bytes being sent in one go.

I think its a problem with the Arduino, using standard SPI, it triggers an end of transmission after 8 bits are shifted out (163) which stops the SCK.

There doesn't seem to be anyway around this using the standard SPI registers, but the datasheet indicates the USART can be set up as an SPI master, and transmit 16bits in two 8-bit words (202).

The SPDR on the arduino is only 8bits long.

The other option is just to toggle the pins by hand. That is don't use the built in SPI commands but bit bang it.

I'm trying the USART method because it seems to be pretty easy to rewrite the existing configuration and transfer function to do so.

One problem I'm having though is to setup the configuration, the original code simply calls to the SPI control reg (SPCR) and data register (SPDR), but when I try to use the USART control registers (UCSRnA and UCSRnB) I get an undefined variable error. I don't see any library imports or other definition for SPCR/SPDR but they work fine.

Any ideas on this? I can set the registers with assembly instructions, but I'm not terribly familiar with assembly and I'd rather not do it that way.

Thanks