HOWTO: Using an external serial eeprom with an AVR chip

This article demonstrates how to use a Microchip 25LC080 serial eeprom with an attiny2313. The code was written using gcc. This code will write one byte to the eeprom, then read it back in.

Code:

#include <util/delay.h>
#include <avr/interrupt.h>
#define NOP asm("nop");
#define SPIEE_CS 4
#define SPIEE_CS_PORT PORTB
#define SPI_EEPROM_WREN 0x6
#define SPI_EEPROM_RDSR 0x5
#define SPI_EEPROM_WRITE 0x2
#define SPI_EEPROM_READ 0x3
uint8_t spieeprom_read (uint16_t);
uint8_t spi_transfer (uint8_t);
uint8_t spieeprom_write (uint16_t, uint8_t);

int
main (void)
{
DDRD = 0xFF; // all output on PORT D
DDRB = 0xDF; // input on MOSI/DI (for SPI), all others output

// deselect EEPROM
PORTB |= (1 << SPIEE_CS);

// Load data to the eeprom. We will load one byte to memory position 100.
// we will load the number 51 to the eeprom
spieeprom_write (100, 51);
_delay_loop_2 (5000);

// Read the data back from the eeprom. Read one byte from memory position 100
uint8_t buff = spieeprom_read (100);

// Light up some leds
PORTD = buff;

while (1)
{
}
}

uint8_t
spieeprom_read (uint16_t addr)
{
// pull CS low to activate eeprom
SPIEE_CS_PORT &= ~(1 << SPIEE_CS);
NOP;
NOP;
NOP;
NOP; // wait 500 ns, CS setup time
// send READ command 0000 0011
spi_transfer (SPI_EEPROM_READ);

// Send in the memory address we will start to read from
// This is a 16 bit address. We must send in 8 bits at a time
spi_transfer (addr >> 8); // send high bits of address
spi_transfer (addr & 0xFF); // send low bits of address

// We will read back one byte
uint8_t buff = spi_transfer (0);

// Once done with the read, set the CS high to terminate the operation
SPIEE_CS_PORT |= (1 << SPIEE_CS);
return buff;
}

uint8_t
spieeprom_write (uint16_t addr, uint8_t data)
{
uint8_t i;

// Before performing the write, first check to see if eeprom is in the middle of
// a read. Send in the Read Status (RDSR 0000 0101). Check the returned status
// to see if it is ok to do a write.
do
{
asm ("wdr");
// Activate eeprom by pulling CS low
SPIEE_CS_PORT &= ~(1 << SPIEE_CS);
NOP;
NOP;
NOP;
NOP; // wait 500 ns, CS setup time
spi_transfer (SPI_EEPROM_RDSR); // write "READ STATUS REG" cmd
i = spi_transfer (0); // read status

SPIEE_CS_PORT |= (1 << SPIEE_CS); // pull CS high

}
while ((i & 0x1) != 0);

// pull CS low to activate eeprom
SPIEE_CS_PORT &= ~(1 << SPIEE_CS);
NOP;
NOP;
NOP;
NOP; // wait 500 ns, CS setup time

// Set the write enable latch by issuing the WREN command 0000 0110
// then bring CS back high
spi_transfer (SPI_EEPROM_WREN); // send command
SPIEE_CS_PORT |= (1 << SPIEE_CS); // pull CS high
NOP;
NOP;
NOP;
NOP; // wait 500 ns, CS setup time

// Once the latch is set, proceed by setting CS low and
// sending the WRITE command 0000 0010
SPIEE_CS_PORT &= ~(1 << SPIEE_CS); // pull CS low
spi_transfer (SPI_EEPROM_WRITE); // send WRITE command

// Send in the memory address you will write to.
// The address is 16bits, so send in 8 bites at a time
spi_transfer (addr >> 8); // send high bits of address
spi_transfer (addr & 0xFF); // send low bits of address

spi_transfer (data); // send data
NOP;
NOP;
NOP;
NOP; // wait 500 ns, CS setup time
// pull CS high to terminate operation
SPIEE_CS_PORT |= (1 << SPIEE_CS);

return 0;
}


// Transfer the data to the eeprom using SPI
uint8_t
spi_transfer (uint8_t c)
{
USIDR = c;
USISR = (1 << USIOIF);
while (!(USISR & (1 << USIOIF)))
{
USICR = (1 << USIWM0) | (1 << USICS1) | (1 << USICLK) | (1 << USITC);
}
return USIDR;
}

25LC080 eeprom


Has anyone tried this code?

Has anyone tried this code? I don't understand, because if the AVR is master, that means MISO should be the input (Master-in-slave-out), instead of MOSI. This doesn't seem to square with:
http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus

atmega 64 + external non volatile memory interface

i am using Atmega64L. i want to extend my non volatile memory. can u give some ideas about interface or codings

try dataflash

Look at Atmels' dataflash. http://www.arduino.cc/playground/Code/Dataflash

I haven't tried it yet, but it looks like a fairly easy way to get extra non volatile memory.

thanks
chad

Enjoy AVR related articles

I really enjoy these AVR related articles where you do stuff like this. I recently started to play with AVR's and I've learned alot from your articles. Keep up the good work. Any chance of an article on interfacing to 1-wire devices to retrieve information such as temperature or to use a 1-wire counter?

links for 1-wire

The 1-wire stuff looks cool, but I doubt if I will work with one anytime soon. Here are some links you might check out though:
avr wiki 1 wire
and
avrfreaks 1 wire

thanks
chad

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

More information about formatting options

Captcha
This question is used to make sure you are a human visitor and to prevent spam submissions.
Copy the characters (respecting upper/lower case) from the image.