WebbotLib AVR library
WebbotLib It just does it
  C++ documentation  C documentation

spiEEPROM.h

Provides generic support for EEPROM devices accessed over an SPI bus.
Note that these device are often advertised showing the capacity as the number of 'bits' they provide. Such as 512k bits. Since we are dealing in 8 bit bytes then you need to divide this figure by 8. So 512k bits => 64k bytes. Not sure why they are sold that way - maybe its because of 32 bit vs 16 bit vs 8 bit processors?
So why would you need one?
Generic SPI EEPROM.png
These devices are quite cheap (a dollar or two) and typically come in an 8 pin format and are therefore physically quite small but can store a reasonably large amount of data - so they are good for storing 'work in progress'. Your processor may come with some 'on board' EEPROM space but typically it will be quite small. So if you need more capacity then here is your solution.
The diagram shows a typical pin out for such a device but you may want to check the data sheet for the device you have purchased.
Besides a Ground and Supply voltage (typically 1.8v to 5.5v) you will also see the MISO, MOSI and SCLK pins which are the heart of the SPI bus (the MISO and MOSI pins may be labelled Data Out, or DO, and Data In, or DI, respectively). You will also see a chip select, or CS, pin that is used to select the device. So that accounts for 6 of the pins on the device, There are two others: HOLD and WP. HOLD can be connected to its neighbouring supply pin and WP can be connected to its neighbouring Ground pin.
There are a few other things you need to check from the datasheet before you can use the device:
The address size may be 1, 2, 3 or 4 bytes (ie 8, 16, 24 or 32 bits) and is normally dictated by the number of bytes of storage:
The page size is always a power of 2 and is normally 128, 256 or 512 bytes - it chops the device up into a number of similar sized pages. A single write to the device must all be in the same page. This value is passed to WebbotLib when creating the device so that your code doesn't have to worry about the restriction - WebbotLib 'just does it'.
Assuming we want to create a device called 'myEEPROM' with an address size of 2 bytes, a page size of 128 bytes, and a total capacity of 64k and we are using the F1 I/O pin to select the device then:
#include "Storage/spiEEPROM.h"
// Create the device
SPI_EEPROM myEEPROM = MAKE_SPI_EEPROM(F1, 2, 128, 64 * KB);
 
// Build a list of the devices that are on the same bus - in this case only one
SPI_DEVICE_LIST PROGMEM devices[] = { &myEEPROM._device_ };
 
// Create the hardware bus
SPI spiBus = MAKE_SPI(devices);
 
// Initialise the driver in my start up code
void appInitHardware(void){
    // Initialise the SPI bus in master mode
    spiBusInit(&spi,TRUE);
}
You can now read and write bytes to the EEPROM.

 

Function

 


uint8_t spiEEPROM_readByte(SPI_EEPROM* eeprom, EEPROM_ADDR addr)

Read a single byte from the EEPROM.
The parameters specify the EEPROM device to read, and the 32 bit address of the byte in the EEPROM that you want to read.
So to read bytes 120 to 130 from the EEPROM then:
for(EEPROM_ADDR addr = 120; addr <= 130; addr++){
    uint8_t byte = spiEEPROM_readByte( &myEEPROM, addr);
}

void spiEEPROM_writeByte(SPI_EEPROM* eeprom, EEPROM_ADDR addr, uint8_t data)

Write a single byte to the EEPROM.
The parameters specify the EEPROM device, the 32 bit address of the byte in the EEPROM that you want to write, and the value.
So to write a random value to byte 100 in the EEPROM then:
uint8_t val = random();
spiEEPROM_writeByte(&myEEPROM, 100, val);
Note that writes to the EEPROM are relatively slow. So if you are writing a sequence of bytes to an EEPROM then it is faster to use the spiEEPROM_writeBytes command to write them in one go.

void spiEEPROM_readBytes(SPI_EEPROM* eeprom, EEPROM_ADDR addr, void* dest, size_t numBytes)

Read a sequence of bytes from the EEPROM.
The parameters specify the EEPROM device to read, the 32 bit address of the first byte in the EEPROM that you want to read, the address where you want to read the data to, and the number of bytes to read.
So to read the 11 bytes starting at 120 from the EEPROM into memory then:
// Create a buffer to store the bytes
uint8_t buffer[11];
// Read from the eeprom into buffer
spiEEPROM_readBytes(&myEEPROM, 120, buffer, 11);

void spiEEPROM_writeBytes(SPI_EEPROM* eeprom, EEPROM_ADDR addr, const void* src, size_t numBytes)

Write a sequence of bytes to the EEPROM.
The parameters specify the EEPROM device to write to, the 32 bit address of the first byte in the EEPROM that you want to write to, the address where you want to write the data from, and the number of bytes to write.
So to write the 11 bytes to the address starting at 120 in the EEPROM from memory then:
// Create a buffer
uint8_t buffer[11];
// -- Code here puts values in the buffer --
// Write the buffer to EEPROM
spiEEPROM_writeBytes(&myEEPROM, 120, buffer, 11);
Often an EEPROM is used to store an array of values where each value is the same size. So lets create a routine to log changes for the ADC inputs. So each 'value' can be stored in the following structure:
typedef struct s_adc_log{
    TICK_COUNT time; // The current time
    uint8_t adcs[8]; // 8 adc values
} ADC_LOG;
Create a variable to hold one of these 'values':
ADC_LOG log;
Create a variable to store the current address in the EEPROM we are writing to:
EEPROM_ADDR addr; // Will be initialised to 0
Create a function to populate the data and return 'TRUE' if the data has changed:
boolean getValues(){
    boolean changed = FALSE;
    for(uint8_t n = 0; n < 8; n++){
        uint8_t val = a2dConvert8bit(ADC_NUMBER_TO_CHANNEL(n));
        if( val != log.adcs[n] ){
            // The value has changed
            log.adcs[n] = val;
            changed = TRUE;
        }
    }
    return changed;
}
Create a function to write the value to EEPROM:-
void write(TICK_COUNT time){
    // Put in the time stamp
    log.time = time;
    // Write to eeprom
    spiEEPROM_writeBytes(&myEEPROM, addr, &log, sizeof(ADC_LOG));
    // bump address for next time
    addr += sizeof(ADC_LOG);
}
In your startup code - write out the initial value:
TICK_COUNT appInitSoftware(TICK_COUNT loopStart){
    getValues();
    write(loopStart);
}
In your main loop - only write out the values if they have changed:
TICK_COUNT appControl(LOOP_COUNT loopCount, TICK_COUNT loopStart){
    if(getValues()){
        write(loopStart);
    }
}

EEPROM_ADDR spiEEPROM_totalBytes(const SPI_EEPROM* eeprom)

Returns the total number of bytes in the EEPROM.

Valid XHTML 1.0 Transitional