Defines | Typedefs | Functions

eeprom-wl.h File Reference

EEPROM access functions including wear leveling. More...

#include "config-params.h"

Go to the source code of this file.

Defines

#define EE_PARAM_BUFFER_SIZE   (8)
 Number of levels in the buffer.
#define EE_STATUS_BUFFER_SIZE   EE_PARAM_BUFFER_SIZE
#define EE_BYTE_SIZE   (1)
 Defines for different sizes of parameters.
#define EE_WORD_SIZE   (2)
#define EE_DWORD_SIZE   (4)
#define EE_STATIC_PARAM_1   (0)
 List of static config parameters NOT using wear leveling, usually written once (e.g. calibration data).
#define EE_STATIC_PARAM_2   (EE_STATIC_PARAM_1 + EE_STATIC_PARAM_1_SIZE)
#define EE_STATIC_PARAM_3   (EE_STATIC_PARAM_2 + EE_STATIC_PARAM_2_SIZE)
#define EE_STATIC_PARAM_4   (EE_STATIC_PARAM_3 + EE_STATIC_PARAM_3_SIZE)
#define EE_STATIC_PARAM_5   (EE_STATIC_PARAM_4 + EE_STATIC_PARAM_4_SIZE)
#define EE_STATIC_PARAM_6   (EE_STATIC_PARAM_5 + EE_STATIC_PARAM_5_SIZE)
#define EE_STATIC_PARAM_7   (EE_STATIC_PARAM_6 + EE_STATIC_PARAM_6_SIZE)
#define EE_STATIC_PARAM_LAST   (EE_STATIC_PARAM_7 + EE_STATIC_PARAM_7_SIZE)
#define EE_PARAM_BUFFER_START   (64)
 Size of reserved space for static config parameters.
#define EE_PARAM_1   EE_PARAM_BUFFER_START
 List of config parameters using circular buffers for wear leveling.
#define EE_PARAM_2   (EE_PARAM_1 + EE_PARAM_1_SIZE * EE_PARAM_BUFFER_SIZE + EE_STATUS_BUFFER_SIZE)
#define EE_PARAM_3   (EE_PARAM_2 + EE_PARAM_2_SIZE * EE_PARAM_BUFFER_SIZE + EE_STATUS_BUFFER_SIZE)
#define EE_PARAM_4   (EE_PARAM_3 + EE_PARAM_3_SIZE * EE_PARAM_BUFFER_SIZE + EE_STATUS_BUFFER_SIZE)
#define EE_PARAM_5   (EE_PARAM_4 + EE_PARAM_4_SIZE * EE_PARAM_BUFFER_SIZE + EE_STATUS_BUFFER_SIZE)
#define EE_PARAM_6   (EE_PARAM_5 + EE_PARAM_5_SIZE * EE_PARAM_BUFFER_SIZE + EE_STATUS_BUFFER_SIZE)
#define EE_PARAM_7   (EE_PARAM_6 + EE_PARAM_6_SIZE * EE_PARAM_BUFFER_SIZE + EE_STATUS_BUFFER_SIZE)
#define EE_PARAM_LAST   (EE_PARAM_7 + EE_PARAM_7_SIZE * EE_PARAM_BUFFER_SIZE + EE_STATUS_BUFFER_SIZE)
#define EE_ECHO   (1)
#define EE_WRITE   (1)

Typedefs

typedef uint8_t * ee_addr_t
 type of EEPROM address

Functions

uint8_t read_config_byte (ee_addr_t parameter, ee_addr_t *address)
 read config parameter from EEPROM
uint16_t read_config_word (ee_addr_t parameter, ee_addr_t *address)
uint32_t read_config_dword (ee_addr_t parameter, ee_addr_t *address)
void write_config_byte (ee_addr_t parameter, ee_addr_t *address, uint8_t data)
 write config parameter to EEPROM
void write_config_word (ee_addr_t parameter, ee_addr_t *address, uint16_t data)
void write_config_dword (ee_addr_t parameter, ee_addr_t *address, uint32_t data)
void ee_find_current_buffer_address (ee_addr_t parameter, ee_addr_t *EeBufPtr, uint8_t param_size)
 find current EEPROM buffer position
void ee_read_buffer (ee_addr_t address, void *data, uint8_t param_size)
 read from EEPROM buffer
void ee_write_byte (ee_addr_t address, uint8_t data)
 write raw byte to EEPROM address
void ee_write_buffer (ee_addr_t parameter, ee_addr_t *address, void *data, uint8_t param_size)
 write to EEPROM buffer

Detailed Description

EEPROM access functions including wear leveling.

The EEPROM is intended to hold all configuration parameters. Config parameters are defined in "config-params.h". There's no need to change the defines below, unless you want add more config parameters.

Please be aware of the difference: There are static parameters unlikely to change like calibration data and variable ones for config data that might change frequently. The latter ones require some wear leveling.

Static parameters can be accessed using the "eeprom_{read|write}_byte" functions provided by avr-libc.

Access to config data using wear leveling is provided by some functions: "read_config_{byte|word|dword}" and "write_config_{byte|word|dword}" All buffer handling is done internally.

Wear leveling is done using two circular buffers, one for the parameter itself and the other one holds a status byte indicating current buffer position. See Atmel's Application Note AVR101 for details.


Define Documentation

#define EE_PARAM_BUFFER_SIZE   (8)

Number of levels in the buffer.

Warning:
If you want to change the buffer size, the content of the EEPROM must be erased, otherwise the config parameters will be messed up!

Function Documentation

void ee_find_current_buffer_address ( ee_addr_t  parameter,
ee_addr_t EeBufPtr,
uint8_t  param_size 
)

find current EEPROM buffer position

Parameters:
parameter buffer start address of config parameter
EeBufPtr EEPROM buffer pointer
param_size size of config parameter (length in bytes)

{
        char temp;
        ee_addr_t EeBufEnd;

        // Point to the status buffer
        *EeBufPtr = parameter + EE_PARAM_BUFFER_SIZE * param_size;
        // The first address outside the buffer
        EeBufEnd = *EeBufPtr + EE_STATUS_BUFFER_SIZE;

        // Identify the last written element of the status buffer
        do {
                temp = eeprom_read_byte (*EeBufPtr);
#if EE_ECHO > 1
                printf_P (PSTR("  ee_find_buf @0x%04X:0x%02X\r\n"), *EeBufPtr, temp);
#endif
                (*EeBufPtr)++;
                // Break if end of buffer, so we don't compare out-of-bounds
                if (*EeBufPtr == EeBufEnd)
                        break;
        } while (eeprom_read_byte (*EeBufPtr) == temp + 1);

        // Point to the last used element of the parameter buffer
        *EeBufPtr = parameter + param_size *
                                (*EeBufPtr - EeBufEnd + EE_STATUS_BUFFER_SIZE - 1);
}

void ee_read_buffer ( ee_addr_t  address,
void *  data,
uint8_t  param_size 
)

read from EEPROM buffer

Parameters:
address EEPROM buffer address to read from
data data read from EEPROM
param_size size of config parameter (length in bytes)

{
        for (uint8_t i=0; i<param_size; i++)
        {
                while (!eeprom_is_ready());
                EEAR = (uint16_t)(address + i);
                EECR |= (1<<EERE);
                *(uint8_t *)(data + i) = EEDR;

#if EE_ECHO > 1
                printf_P (PSTR("  ee_read_byte @0x%04X:0x%02X\r\n"), address + i, *(uint8_t *)(data + i));
#endif
        }

}

void ee_write_buffer ( ee_addr_t  parameter,
ee_addr_t address,
void *  data,
uint8_t  param_size 
)

write to EEPROM buffer

Parameters:
parameter buffer start address of config parameter
address EEPROM buffer address to write to
data value of config parameter
param_size size of config parameter (length in bytes)

{
        unsigned char EeOldStatusValue, EeOldBufElement;

        // Number of old buffer element [1...EE_PARAM_BUFFER_SIZE]
        EeOldBufElement = (*address - parameter) / param_size + 1;

        // Store the old status value and move pointer to the next element in the buffer
        EeOldStatusValue = eeprom_read_byte (parameter + EeOldBufElement - 1 +
                                             EE_PARAM_BUFFER_SIZE * param_size);


        (*address) += param_size;
        if (*address == parameter + EE_PARAM_BUFFER_SIZE * param_size)
        {
                // Wraparound if necessary.
                *address = parameter;
                EeOldBufElement = 0;
        }

        // If self-programming is used in the application, insert code here to wait for any
        // self-programming operations to finish before writing to the EEPROM.
        // Also make sure that interrupts are disabled during EEPROM write if interrupts
        // are used in the application, otherwise the 4-cycle limit could be exceeded.

#ifdef EE_WRITE
        /* Update the parameter in the EEPROM buffer */
        for (uint8_t i=0; i<param_size; i++)
        {
                ee_write_byte ((*address) + i, *(uint8_t *)(data + i));
        }

        /* Update the status buffer */
        ee_write_byte (parameter + EeOldBufElement +
                       EE_PARAM_BUFFER_SIZE * param_size, EeOldStatusValue + 1);
#endif
}

void ee_write_byte ( ee_addr_t  address,
uint8_t  data 
)

write raw byte to EEPROM address

Parameters:
address EEPROM address to write to
data value of config parameter

{
        eeprom_write_byte ((uint8_t *)address, data);
#if EE_ECHO > 1
        printf_P (PSTR("  ee_write_byte @0x%04X:0x%02X\r\n"), address, data);
#endif
}

uint8_t read_config_byte ( ee_addr_t  parameter,
ee_addr_t address 
)

read config parameter from EEPROM

Use this function to read a config byte from EEPROM like this: uint16_t BufPtrYourParam = CFG_YOUR_PARAM; cfg_byte = read_config_byte(CFG_YOUR_PARAM, &BufPtrYourParam);

Parameters:
parameter buffer start address of config parameter
address EEPROM address to read from
Returns:
data value of config parameter

{
        uint8_t data;

        ee_find_current_buffer_address (parameter, address, EE_BYTE_SIZE);
        ee_read_buffer (*address, &data, EE_BYTE_SIZE);
#if EE_ECHO > 0
        printf_P (PSTR("config: read byte 0x%04X@0x%04X:0x%02X\r\n"),
                                                parameter, *address, data);
#endif
        return data;
}

void write_config_byte ( ee_addr_t  parameter,
ee_addr_t address,
uint8_t  data 
)

write config parameter to EEPROM

Use this function to write a config byte to EEPROM like this: uint16_t BufPtrYourParam = CFG_YOUR_PARAM; write_config_byte(CFG_YOUR_PARAM, &BufPtrYourParam, cfg_byte);

Parameters:
parameter buffer start address of config parameter
address EEPROM address to write to
data value of config parameter

{
        uint8_t olddata;

        ee_find_current_buffer_address (parameter, address, EE_BYTE_SIZE);
#if EE_ECHO > 0
        printf_P (PSTR("config: write byte 0x%04X@0x%04X:0x%02X\r\n"),
                                                parameter, *address, data);
#endif
        // check if value changed in EEPROM
        ee_read_buffer (*address, &olddata, EE_BYTE_SIZE);
        if (data != olddata) {
                ee_write_buffer (parameter, address, &data, EE_BYTE_SIZE);
        }
#if EE_ECHO > 0
        else {
                printf_P (PSTR("config: value didn't change\r\n"));
        }
#endif
}