Luigi Santivetti | 69972f9 | 2019-11-12 22:55:40 +0000 | [diff] [blame^] | 1 | // This file has been prepared for Doxygen automatic documentation generation.
|
| 2 | /*! \file ********************************************************************
|
| 3 | *
|
| 4 | * Atmel Corporation
|
| 5 | *
|
| 6 | * \li File: eeprom.c
|
| 7 | * \li Compiler: IAR EWAAVR 3.10c
|
| 8 | * \li Support mail: avr@atmel.com
|
| 9 | *
|
| 10 | * \li Supported devices: All devices with split EEPROM erase/write
|
| 11 | * capabilities can be used.
|
| 12 | * The example is written for ATmega48.
|
| 13 | *
|
| 14 | * \li AppNote: AVR103 - Using the EEPROM Programming Modes.
|
| 15 | *
|
| 16 | * \li Description: Example on how to use the split EEPROM erase/write
|
| 17 | * capabilities in e.g. ATmega48. All EEPROM
|
| 18 | * programming modes are tested, i.e. Erase+Write,
|
| 19 | * Erase-only and Write-only.
|
| 20 | *
|
| 21 | * $Revision: 1.6 $
|
| 22 | * $Date: Friday, February 11, 2005 07:16:44 UTC $
|
| 23 | ****************************************************************************/
|
| 24 | #include <avr/io.h>
|
| 25 | #include <avr/interrupt.h>
|
| 26 |
|
| 27 | /* These EEPROM bits have different names on different devices. */
|
| 28 | #ifndef EEPE
|
| 29 | #define EEPE EEWE //!< EEPROM program/write enable.
|
| 30 | #define EEMPE EEMWE //!< EEPROM master program/write enable.
|
| 31 | #endif
|
| 32 |
|
| 33 | /* These two are unfortunately not defined in the device include files. */
|
| 34 | #define EEPM1 5 //!< EEPROM Programming Mode Bit 1.
|
| 35 | #define EEPM0 4 //!< EEPROM Programming Mode Bit 0.
|
| 36 |
|
| 37 | /* Define to reduce code size. */
|
| 38 | #define EEPROM_IGNORE_SELFPROG //!< Remove SPM flag polling.
|
| 39 |
|
| 40 | /*! \brief Read byte from EEPROM.
|
| 41 | *
|
| 42 | * This function reads one byte from a given EEPROM address.
|
| 43 | *
|
| 44 | * \note The CPU is halted for 4 clock cycles during EEPROM read.
|
| 45 | *
|
| 46 | * \param addr EEPROM address to read from.
|
| 47 | * \return The byte read from the EEPROM address.
|
| 48 | */
|
| 49 | unsigned char eeprom_get_char( unsigned int addr )
|
| 50 | {
|
| 51 | do {} while( EECR & (1<<EEPE) ); // Wait for completion of previous write.
|
| 52 | EEAR = addr; // Set EEPROM address register.
|
| 53 | EECR = (1<<EERE); // Start EEPROM read operation.
|
| 54 | return EEDR; // Return the byte read from EEPROM.
|
| 55 | }
|
| 56 |
|
| 57 | /*! \brief Write byte to EEPROM.
|
| 58 | *
|
| 59 | * This function writes one byte to a given EEPROM address.
|
| 60 | * The differences between the existing byte and the new value is used
|
| 61 | * to select the most efficient EEPROM programming mode.
|
| 62 | *
|
| 63 | * \note The CPU is halted for 2 clock cycles during EEPROM programming.
|
| 64 | *
|
| 65 | * \note When this function returns, the new EEPROM value is not available
|
| 66 | * until the EEPROM programming time has passed. The EEPE bit in EECR
|
| 67 | * should be polled to check whether the programming is finished.
|
| 68 | *
|
| 69 | * \note The EEPROM_GetChar() function checks the EEPE bit automatically.
|
| 70 | *
|
| 71 | * \param addr EEPROM address to write to.
|
| 72 | * \param new_value New EEPROM value.
|
| 73 | */
|
| 74 | void eeprom_put_char( unsigned int addr, unsigned char new_value )
|
| 75 | {
|
| 76 | char old_value; // Old EEPROM value.
|
| 77 | char diff_mask; // Difference mask, i.e. old value XOR new value.
|
| 78 |
|
| 79 | cli(); // Ensure atomic operation for the write operation.
|
| 80 |
|
| 81 | do {} while( EECR & (1<<EEPE) ); // Wait for completion of previous write.
|
| 82 | #ifndef EEPROM_IGNORE_SELFPROG
|
| 83 | do {} while( SPMCSR & (1<<SELFPRGEN) ); // Wait for completion of SPM.
|
| 84 | #endif
|
| 85 |
|
| 86 | EEAR = addr; // Set EEPROM address register.
|
| 87 | EECR = (1<<EERE); // Start EEPROM read operation.
|
| 88 | old_value = EEDR; // Get old EEPROM value.
|
| 89 | diff_mask = old_value ^ new_value; // Get bit differences.
|
| 90 |
|
| 91 | // Check if any bits are changed to '1' in the new value.
|
| 92 | if( diff_mask & new_value ) {
|
| 93 | // Now we know that _some_ bits need to be erased to '1'.
|
| 94 |
|
| 95 | // Check if any bits in the new value are '0'.
|
| 96 | if( new_value != 0xff ) {
|
| 97 | // Now we know that some bits need to be programmed to '0' also.
|
| 98 |
|
| 99 | EEDR = new_value; // Set EEPROM data register.
|
| 100 | EECR = (1<<EEMPE) | // Set Master Write Enable bit...
|
| 101 | (0<<EEPM1) | (0<<EEPM0); // ...and Erase+Write mode.
|
| 102 | EECR |= (1<<EEPE); // Start Erase+Write operation.
|
| 103 | } else {
|
| 104 | // Now we know that all bits should be erased.
|
| 105 |
|
| 106 | EECR = (1<<EEMPE) | // Set Master Write Enable bit...
|
| 107 | (1<<EEPM0); // ...and Erase-only mode.
|
| 108 | EECR |= (1<<EEPE); // Start Erase-only operation.
|
| 109 | }
|
| 110 | } else {
|
| 111 | // Now we know that _no_ bits need to be erased to '1'.
|
| 112 |
|
| 113 | // Check if any bits are changed from '1' in the old value.
|
| 114 | if( diff_mask ) {
|
| 115 | // Now we know that _some_ bits need to the programmed to '0'.
|
| 116 |
|
| 117 | EEDR = new_value; // Set EEPROM data register.
|
| 118 | EECR = (1<<EEMPE) | // Set Master Write Enable bit...
|
| 119 | (1<<EEPM1); // ...and Write-only mode.
|
| 120 | EECR |= (1<<EEPE); // Start Write-only operation.
|
| 121 | }
|
| 122 | }
|
| 123 |
|
| 124 | sei(); // Restore interrupt flag state.
|
| 125 | }
|
| 126 |
|
| 127 | // Extensions added as part of Grbl
|
| 128 |
|
| 129 |
|
| 130 | void memcpy_to_eeprom_with_checksum(unsigned int destination, char *source, unsigned int size) {
|
| 131 | unsigned char checksum = 0;
|
| 132 | for(; size > 0; size--) {
|
| 133 | checksum = (checksum << 1) || (checksum >> 7);
|
| 134 | checksum += *source;
|
| 135 | eeprom_put_char(destination++, *(source++));
|
| 136 | }
|
| 137 | eeprom_put_char(destination, checksum);
|
| 138 | }
|
| 139 |
|
| 140 | int memcpy_from_eeprom_with_checksum(char *destination, unsigned int source, unsigned int size) {
|
| 141 | unsigned char data, checksum = 0;
|
| 142 | for(; size > 0; size--) {
|
| 143 | data = eeprom_get_char(source++);
|
| 144 | checksum = (checksum << 1) || (checksum >> 7);
|
| 145 | checksum += data;
|
| 146 | *(destination++) = data;
|
| 147 | }
|
| 148 | return(checksum == eeprom_get_char(source));
|
| 149 | }
|
| 150 |
|
| 151 | // end of file
|