// This file has been prepared for Doxygen automatic documentation generation. | |
/*! \file ******************************************************************** | |
* | |
* Atmel Corporation | |
* | |
* \li File: eeprom.c | |
* \li Compiler: IAR EWAAVR 3.10c | |
* \li Support mail: avr@atmel.com | |
* | |
* \li Supported devices: All devices with split EEPROM erase/write | |
* capabilities can be used. | |
* The example is written for ATmega48. | |
* | |
* \li AppNote: AVR103 - Using the EEPROM Programming Modes. | |
* | |
* \li Description: Example on how to use the split EEPROM erase/write | |
* capabilities in e.g. ATmega48. All EEPROM | |
* programming modes are tested, i.e. Erase+Write, | |
* Erase-only and Write-only. | |
* | |
* $Revision: 1.6 $ | |
* $Date: Friday, February 11, 2005 07:16:44 UTC $ | |
****************************************************************************/ | |
#include <avr/io.h> | |
#include <avr/interrupt.h> | |
/* These EEPROM bits have different names on different devices. */ | |
#ifndef EEPE | |
#define EEPE EEWE //!< EEPROM program/write enable. | |
#define EEMPE EEMWE //!< EEPROM master program/write enable. | |
#endif | |
/* These two are unfortunately not defined in the device include files. */ | |
#define EEPM1 5 //!< EEPROM Programming Mode Bit 1. | |
#define EEPM0 4 //!< EEPROM Programming Mode Bit 0. | |
/* Define to reduce code size. */ | |
#define EEPROM_IGNORE_SELFPROG //!< Remove SPM flag polling. | |
/*! \brief Read byte from EEPROM. | |
* | |
* This function reads one byte from a given EEPROM address. | |
* | |
* \note The CPU is halted for 4 clock cycles during EEPROM read. | |
* | |
* \param addr EEPROM address to read from. | |
* \return The byte read from the EEPROM address. | |
*/ | |
unsigned char eeprom_get_char( unsigned int addr ) | |
{ | |
do {} while( EECR & (1<<EEPE) ); // Wait for completion of previous write. | |
EEAR = addr; // Set EEPROM address register. | |
EECR = (1<<EERE); // Start EEPROM read operation. | |
return EEDR; // Return the byte read from EEPROM. | |
} | |
/*! \brief Write byte to EEPROM. | |
* | |
* This function writes one byte to a given EEPROM address. | |
* The differences between the existing byte and the new value is used | |
* to select the most efficient EEPROM programming mode. | |
* | |
* \note The CPU is halted for 2 clock cycles during EEPROM programming. | |
* | |
* \note When this function returns, the new EEPROM value is not available | |
* until the EEPROM programming time has passed. The EEPE bit in EECR | |
* should be polled to check whether the programming is finished. | |
* | |
* \note The EEPROM_GetChar() function checks the EEPE bit automatically. | |
* | |
* \param addr EEPROM address to write to. | |
* \param new_value New EEPROM value. | |
*/ | |
void eeprom_put_char( unsigned int addr, unsigned char new_value ) | |
{ | |
char old_value; // Old EEPROM value. | |
char diff_mask; // Difference mask, i.e. old value XOR new value. | |
cli(); // Ensure atomic operation for the write operation. | |
do {} while( EECR & (1<<EEPE) ); // Wait for completion of previous write. | |
#ifndef EEPROM_IGNORE_SELFPROG | |
do {} while( SPMCSR & (1<<SELFPRGEN) ); // Wait for completion of SPM. | |
#endif | |
EEAR = addr; // Set EEPROM address register. | |
EECR = (1<<EERE); // Start EEPROM read operation. | |
old_value = EEDR; // Get old EEPROM value. | |
diff_mask = old_value ^ new_value; // Get bit differences. | |
// Check if any bits are changed to '1' in the new value. | |
if( diff_mask & new_value ) { | |
// Now we know that _some_ bits need to be erased to '1'. | |
// Check if any bits in the new value are '0'. | |
if( new_value != 0xff ) { | |
// Now we know that some bits need to be programmed to '0' also. | |
EEDR = new_value; // Set EEPROM data register. | |
EECR = (1<<EEMPE) | // Set Master Write Enable bit... | |
(0<<EEPM1) | (0<<EEPM0); // ...and Erase+Write mode. | |
EECR |= (1<<EEPE); // Start Erase+Write operation. | |
} else { | |
// Now we know that all bits should be erased. | |
EECR = (1<<EEMPE) | // Set Master Write Enable bit... | |
(1<<EEPM0); // ...and Erase-only mode. | |
EECR |= (1<<EEPE); // Start Erase-only operation. | |
} | |
} else { | |
// Now we know that _no_ bits need to be erased to '1'. | |
// Check if any bits are changed from '1' in the old value. | |
if( diff_mask ) { | |
// Now we know that _some_ bits need to the programmed to '0'. | |
EEDR = new_value; // Set EEPROM data register. | |
EECR = (1<<EEMPE) | // Set Master Write Enable bit... | |
(1<<EEPM1); // ...and Write-only mode. | |
EECR |= (1<<EEPE); // Start Write-only operation. | |
} | |
} | |
sei(); // Restore interrupt flag state. | |
} | |
// Extensions added as part of Grbl | |
void memcpy_to_eeprom_with_checksum(unsigned int destination, char *source, unsigned int size) { | |
unsigned char checksum = 0; | |
for(; size > 0; size--) { | |
checksum = (checksum << 1) || (checksum >> 7); | |
checksum += *source; | |
eeprom_put_char(destination++, *(source++)); | |
} | |
eeprom_put_char(destination, checksum); | |
} | |
int memcpy_from_eeprom_with_checksum(char *destination, unsigned int source, unsigned int size) { | |
unsigned char data, checksum = 0; | |
for(; size > 0; size--) { | |
data = eeprom_get_char(source++); | |
checksum = (checksum << 1) || (checksum >> 7); | |
checksum += data; | |
*(destination++) = data; | |
} | |
return(checksum == eeprom_get_char(source)); | |
} | |
// end of file |