Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
grbl/eeprom.c@0:8f0d870509fe, 2017-09-04 (annotated)
- Committer:
- Sergunb
- Date:
- Mon Sep 04 12:04:13 2017 +0000
- Revision:
- 0:8f0d870509fe
Initial commit
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| Sergunb | 0:8f0d870509fe | 1 | // This file has been prepared for Doxygen automatic documentation generation. |
| Sergunb | 0:8f0d870509fe | 2 | /*! \file ******************************************************************** |
| Sergunb | 0:8f0d870509fe | 3 | * |
| Sergunb | 0:8f0d870509fe | 4 | * Atmel Corporation |
| Sergunb | 0:8f0d870509fe | 5 | * |
| Sergunb | 0:8f0d870509fe | 6 | * \li File: eeprom.c |
| Sergunb | 0:8f0d870509fe | 7 | * \li Compiler: IAR EWAAVR 3.10c |
| Sergunb | 0:8f0d870509fe | 8 | * \li Support mail: avr@atmel.com |
| Sergunb | 0:8f0d870509fe | 9 | * |
| Sergunb | 0:8f0d870509fe | 10 | * \li Supported devices: All devices with split EEPROM erase/write |
| Sergunb | 0:8f0d870509fe | 11 | * capabilities can be used. |
| Sergunb | 0:8f0d870509fe | 12 | * The example is written for ATmega48. |
| Sergunb | 0:8f0d870509fe | 13 | * |
| Sergunb | 0:8f0d870509fe | 14 | * \li AppNote: AVR103 - Using the EEPROM Programming Modes. |
| Sergunb | 0:8f0d870509fe | 15 | * |
| Sergunb | 0:8f0d870509fe | 16 | * \li Description: Example on how to use the split EEPROM erase/write |
| Sergunb | 0:8f0d870509fe | 17 | * capabilities in e.g. ATmega48. All EEPROM |
| Sergunb | 0:8f0d870509fe | 18 | * programming modes are tested, i.e. Erase+Write, |
| Sergunb | 0:8f0d870509fe | 19 | * Erase-only and Write-only. |
| Sergunb | 0:8f0d870509fe | 20 | * |
| Sergunb | 0:8f0d870509fe | 21 | * $Revision: 1.6 $ |
| Sergunb | 0:8f0d870509fe | 22 | * $Date: Friday, February 11, 2005 07:16:44 UTC $ |
| Sergunb | 0:8f0d870509fe | 23 | ****************************************************************************/ |
| Sergunb | 0:8f0d870509fe | 24 | #include "grbl.h" |
| Sergunb | 0:8f0d870509fe | 25 | #ifdef AVRTARGET |
| Sergunb | 0:8f0d870509fe | 26 | #include <avr/io.h> |
| Sergunb | 0:8f0d870509fe | 27 | #include <avr/interrupt.h> |
| Sergunb | 0:8f0d870509fe | 28 | /* These EEPROM bits have different names on different devices. */ |
| Sergunb | 0:8f0d870509fe | 29 | #ifndef EEPE |
| Sergunb | 0:8f0d870509fe | 30 | #define EEPE EEWE //!< EEPROM program/write enable. |
| Sergunb | 0:8f0d870509fe | 31 | #define EEMPE EEMWE //!< EEPROM master program/write enable. |
| Sergunb | 0:8f0d870509fe | 32 | #endif |
| Sergunb | 0:8f0d870509fe | 33 | |
| Sergunb | 0:8f0d870509fe | 34 | /* These two are unfortunately not defined in the device include files. */ |
| Sergunb | 0:8f0d870509fe | 35 | #define EEPM1 5 //!< EEPROM Programming Mode Bit 1. |
| Sergunb | 0:8f0d870509fe | 36 | #define EEPM0 4 //!< EEPROM Programming Mode Bit 0. |
| Sergunb | 0:8f0d870509fe | 37 | |
| Sergunb | 0:8f0d870509fe | 38 | /* Define to reduce code size. */ |
| Sergunb | 0:8f0d870509fe | 39 | #define EEPROM_IGNORE_SELFPROG //!< Remove SPM flag polling. |
| Sergunb | 0:8f0d870509fe | 40 | #endif |
| Sergunb | 0:8f0d870509fe | 41 | #ifdef WIN32 |
| Sergunb | 0:8f0d870509fe | 42 | #include <stdio.h> |
| Sergunb | 0:8f0d870509fe | 43 | #include <string.h> |
| Sergunb | 0:8f0d870509fe | 44 | #endif |
| Sergunb | 0:8f0d870509fe | 45 | #ifdef STM32F103C8 |
| Sergunb | 0:8f0d870509fe | 46 | #include <string.h> |
| Sergunb | 0:8f0d870509fe | 47 | #include "stm32eeprom.h" |
| Sergunb | 0:8f0d870509fe | 48 | #include "settings.h" |
| Sergunb | 0:8f0d870509fe | 49 | #endif |
| Sergunb | 0:8f0d870509fe | 50 | #if defined(WIN32) || defined (STM32F103C8) |
| Sergunb | 0:8f0d870509fe | 51 | unsigned char EE_Buffer[0x400]; |
| Sergunb | 0:8f0d870509fe | 52 | #endif |
| Sergunb | 0:8f0d870509fe | 53 | #if defined(WIN32) |
| Sergunb | 0:8f0d870509fe | 54 | #ifndef NOEEPROMSUPPORT |
| Sergunb | 0:8f0d870509fe | 55 | void eeprom_flush() |
| Sergunb | 0:8f0d870509fe | 56 | { |
| Sergunb | 0:8f0d870509fe | 57 | FILE *out = fopen("eeprom.bin", "wb"); |
| Sergunb | 0:8f0d870509fe | 58 | fwrite(EE_Buffer, 1, 0x400, out); |
| Sergunb | 0:8f0d870509fe | 59 | fclose(out); |
| Sergunb | 0:8f0d870509fe | 60 | } |
| Sergunb | 0:8f0d870509fe | 61 | #endif |
| Sergunb | 0:8f0d870509fe | 62 | void eeprom_init() |
| Sergunb | 0:8f0d870509fe | 63 | { |
| Sergunb | 0:8f0d870509fe | 64 | #ifndef NOEEPROMSUPPORT |
| Sergunb | 0:8f0d870509fe | 65 | FILE *in = fopen("eeprom.bin", "rb"); |
| Sergunb | 0:8f0d870509fe | 66 | if (in != NULL) |
| Sergunb | 0:8f0d870509fe | 67 | { |
| Sergunb | 0:8f0d870509fe | 68 | fread(EE_Buffer, 1, 0x400, in); |
| Sergunb | 0:8f0d870509fe | 69 | fclose(in); |
| Sergunb | 0:8f0d870509fe | 70 | } |
| Sergunb | 0:8f0d870509fe | 71 | else |
| Sergunb | 0:8f0d870509fe | 72 | { |
| Sergunb | 0:8f0d870509fe | 73 | memset(EE_Buffer, 0xff, 0x400); |
| Sergunb | 0:8f0d870509fe | 74 | } |
| Sergunb | 0:8f0d870509fe | 75 | #else |
| Sergunb | 0:8f0d870509fe | 76 | memset(EE_Buffer, 0x0, 0x400); |
| Sergunb | 0:8f0d870509fe | 77 | #endif |
| Sergunb | 0:8f0d870509fe | 78 | } |
| Sergunb | 0:8f0d870509fe | 79 | #endif |
| Sergunb | 0:8f0d870509fe | 80 | |
| Sergunb | 0:8f0d870509fe | 81 | #ifdef STM32F103C8 |
| Sergunb | 0:8f0d870509fe | 82 | #ifndef NOEEPROMSUPPORT |
| Sergunb | 0:8f0d870509fe | 83 | void eeprom_flush() |
| Sergunb | 0:8f0d870509fe | 84 | { |
| Sergunb | 0:8f0d870509fe | 85 | uint32_t nAddress = EEPROM_START_ADDRESS; |
| Sergunb | 0:8f0d870509fe | 86 | uint16_t *pBuffer = (uint16_t *)EE_Buffer; |
| Sergunb | 0:8f0d870509fe | 87 | uint16_t nSize = PAGE_SIZE; |
| Sergunb | 0:8f0d870509fe | 88 | |
| Sergunb | 0:8f0d870509fe | 89 | FLASH_Status FlashStatus = FLASH_COMPLETE; |
| Sergunb | 0:8f0d870509fe | 90 | |
| Sergunb | 0:8f0d870509fe | 91 | /* Erase Page0 */ |
| Sergunb | 0:8f0d870509fe | 92 | FlashStatus = FLASH_ErasePage(EEPROM_START_ADDRESS); |
| Sergunb | 0:8f0d870509fe | 93 | |
| Sergunb | 0:8f0d870509fe | 94 | /* If erase operation was failed, a Flash error code is returned */ |
| Sergunb | 0:8f0d870509fe | 95 | if (FlashStatus != FLASH_COMPLETE) |
| Sergunb | 0:8f0d870509fe | 96 | { |
| Sergunb | 0:8f0d870509fe | 97 | return; |
| Sergunb | 0:8f0d870509fe | 98 | } |
| Sergunb | 0:8f0d870509fe | 99 | |
| Sergunb | 0:8f0d870509fe | 100 | while (nSize > 0) |
| Sergunb | 0:8f0d870509fe | 101 | { |
| Sergunb | 0:8f0d870509fe | 102 | if (*pBuffer != 0xffff) |
| Sergunb | 0:8f0d870509fe | 103 | { |
| Sergunb | 0:8f0d870509fe | 104 | FLASH_ProgramHalfWord(nAddress, *pBuffer++); |
| Sergunb | 0:8f0d870509fe | 105 | } |
| Sergunb | 0:8f0d870509fe | 106 | else |
| Sergunb | 0:8f0d870509fe | 107 | { |
| Sergunb | 0:8f0d870509fe | 108 | pBuffer++; |
| Sergunb | 0:8f0d870509fe | 109 | } |
| Sergunb | 0:8f0d870509fe | 110 | if (*pBuffer != 0xffff) |
| Sergunb | 0:8f0d870509fe | 111 | { |
| Sergunb | 0:8f0d870509fe | 112 | FLASH_ProgramHalfWord(nAddress + 2, *pBuffer++); |
| Sergunb | 0:8f0d870509fe | 113 | } |
| Sergunb | 0:8f0d870509fe | 114 | else |
| Sergunb | 0:8f0d870509fe | 115 | { |
| Sergunb | 0:8f0d870509fe | 116 | pBuffer++; |
| Sergunb | 0:8f0d870509fe | 117 | } |
| Sergunb | 0:8f0d870509fe | 118 | nSize -= 4; |
| Sergunb | 0:8f0d870509fe | 119 | nAddress += 4; |
| Sergunb | 0:8f0d870509fe | 120 | } |
| Sergunb | 0:8f0d870509fe | 121 | } |
| Sergunb | 0:8f0d870509fe | 122 | void eeprom_init() |
| Sergunb | 0:8f0d870509fe | 123 | { |
| Sergunb | 0:8f0d870509fe | 124 | uint16_t VarIdx = 0; |
| Sergunb | 0:8f0d870509fe | 125 | uint8_t *pTmp = EE_Buffer; |
| Sergunb | 0:8f0d870509fe | 126 | |
| Sergunb | 0:8f0d870509fe | 127 | for (VarIdx = 0; VarIdx < PAGE_SIZE; VarIdx++) |
| Sergunb | 0:8f0d870509fe | 128 | { |
| Sergunb | 0:8f0d870509fe | 129 | *pTmp++ = (*(__IO uint8_t*)(EEPROM_START_ADDRESS + VarIdx)); |
| Sergunb | 0:8f0d870509fe | 130 | } |
| Sergunb | 0:8f0d870509fe | 131 | |
| Sergunb | 0:8f0d870509fe | 132 | if (EE_Buffer[0] != SETTINGS_VERSION) |
| Sergunb | 0:8f0d870509fe | 133 | { |
| Sergunb | 0:8f0d870509fe | 134 | pTmp = EE_Buffer; |
| Sergunb | 0:8f0d870509fe | 135 | |
| Sergunb | 0:8f0d870509fe | 136 | for (VarIdx = 0; VarIdx < PAGE_SIZE; VarIdx++) |
| Sergunb | 0:8f0d870509fe | 137 | { |
| Sergunb | 0:8f0d870509fe | 138 | *pTmp++ = 0xFF; |
| Sergunb | 0:8f0d870509fe | 139 | } |
| Sergunb | 0:8f0d870509fe | 140 | } |
| Sergunb | 0:8f0d870509fe | 141 | } |
| Sergunb | 0:8f0d870509fe | 142 | #endif |
| Sergunb | 0:8f0d870509fe | 143 | #endif |
| Sergunb | 0:8f0d870509fe | 144 | |
| Sergunb | 0:8f0d870509fe | 145 | /*! \brief Read byte from EEPROM. |
| Sergunb | 0:8f0d870509fe | 146 | * |
| Sergunb | 0:8f0d870509fe | 147 | * This function reads one byte from a given EEPROM address. |
| Sergunb | 0:8f0d870509fe | 148 | * |
| Sergunb | 0:8f0d870509fe | 149 | * \note The CPU is halted for 4 clock cycles during EEPROM read. |
| Sergunb | 0:8f0d870509fe | 150 | * |
| Sergunb | 0:8f0d870509fe | 151 | * \param addr EEPROM address to read from. |
| Sergunb | 0:8f0d870509fe | 152 | * \return The byte read from the EEPROM address. |
| Sergunb | 0:8f0d870509fe | 153 | */ |
| Sergunb | 0:8f0d870509fe | 154 | unsigned char eeprom_get_char( unsigned int addr ) |
| Sergunb | 0:8f0d870509fe | 155 | { |
| Sergunb | 0:8f0d870509fe | 156 | #ifdef AVRTARGET |
| Sergunb | 0:8f0d870509fe | 157 | do {} while( EECR & (1<<EEPE) ); // Wait for completion of previous write. |
| Sergunb | 0:8f0d870509fe | 158 | EEAR = addr; // Set EEPROM address register. |
| Sergunb | 0:8f0d870509fe | 159 | EECR = (1<<EERE); // Start EEPROM read operation. |
| Sergunb | 0:8f0d870509fe | 160 | return EEDR; // Return the byte read from EEPROM. |
| Sergunb | 0:8f0d870509fe | 161 | #endif |
| Sergunb | 0:8f0d870509fe | 162 | #if defined(WIN32) || defined(STM32F103C8) |
| Sergunb | 0:8f0d870509fe | 163 | return EE_Buffer[addr]; |
| Sergunb | 0:8f0d870509fe | 164 | #endif |
| Sergunb | 0:8f0d870509fe | 165 | } |
| Sergunb | 0:8f0d870509fe | 166 | |
| Sergunb | 0:8f0d870509fe | 167 | /*! \brief Write byte to EEPROM. |
| Sergunb | 0:8f0d870509fe | 168 | * |
| Sergunb | 0:8f0d870509fe | 169 | * This function writes one byte to a given EEPROM address. |
| Sergunb | 0:8f0d870509fe | 170 | * The differences between the existing byte and the new value is used |
| Sergunb | 0:8f0d870509fe | 171 | * to select the most efficient EEPROM programming mode. |
| Sergunb | 0:8f0d870509fe | 172 | * |
| Sergunb | 0:8f0d870509fe | 173 | * \note The CPU is halted for 2 clock cycles during EEPROM programming. |
| Sergunb | 0:8f0d870509fe | 174 | * |
| Sergunb | 0:8f0d870509fe | 175 | * \note When this function returns, the new EEPROM value is not available |
| Sergunb | 0:8f0d870509fe | 176 | * until the EEPROM programming time has passed. The EEPE bit in EECR |
| Sergunb | 0:8f0d870509fe | 177 | * should be polled to check whether the programming is finished. |
| Sergunb | 0:8f0d870509fe | 178 | * |
| Sergunb | 0:8f0d870509fe | 179 | * \note The EEPROM_GetChar() function checks the EEPE bit automatically. |
| Sergunb | 0:8f0d870509fe | 180 | * |
| Sergunb | 0:8f0d870509fe | 181 | * \param addr EEPROM address to write to. |
| Sergunb | 0:8f0d870509fe | 182 | * \param new_value New EEPROM value. |
| Sergunb | 0:8f0d870509fe | 183 | */ |
| Sergunb | 0:8f0d870509fe | 184 | void eeprom_put_char( unsigned int addr, unsigned char new_value ) |
| Sergunb | 0:8f0d870509fe | 185 | { |
| Sergunb | 0:8f0d870509fe | 186 | #ifdef AVRTARGET |
| Sergunb | 0:8f0d870509fe | 187 | char old_value; // Old EEPROM value. |
| Sergunb | 0:8f0d870509fe | 188 | char diff_mask; // Difference mask, i.e. old value XOR new value. |
| Sergunb | 0:8f0d870509fe | 189 | |
| Sergunb | 0:8f0d870509fe | 190 | cli(); // Ensure atomic operation for the write operation. |
| Sergunb | 0:8f0d870509fe | 191 | |
| Sergunb | 0:8f0d870509fe | 192 | do {} while( EECR & (1<<EEPE) ); // Wait for completion of previous write. |
| Sergunb | 0:8f0d870509fe | 193 | #ifndef EEPROM_IGNORE_SELFPROG |
| Sergunb | 0:8f0d870509fe | 194 | do {} while( SPMCSR & (1<<SELFPRGEN) ); // Wait for completion of SPM. |
| Sergunb | 0:8f0d870509fe | 195 | #endif |
| Sergunb | 0:8f0d870509fe | 196 | |
| Sergunb | 0:8f0d870509fe | 197 | EEAR = addr; // Set EEPROM address register. |
| Sergunb | 0:8f0d870509fe | 198 | EECR = (1<<EERE); // Start EEPROM read operation. |
| Sergunb | 0:8f0d870509fe | 199 | old_value = EEDR; // Get old EEPROM value. |
| Sergunb | 0:8f0d870509fe | 200 | diff_mask = old_value ^ new_value; // Get bit differences. |
| Sergunb | 0:8f0d870509fe | 201 | |
| Sergunb | 0:8f0d870509fe | 202 | // Check if any bits are changed to '1' in the new value. |
| Sergunb | 0:8f0d870509fe | 203 | if( diff_mask & new_value ) { |
| Sergunb | 0:8f0d870509fe | 204 | // Now we know that _some_ bits need to be erased to '1'. |
| Sergunb | 0:8f0d870509fe | 205 | |
| Sergunb | 0:8f0d870509fe | 206 | // Check if any bits in the new value are '0'. |
| Sergunb | 0:8f0d870509fe | 207 | if( new_value != 0xff ) { |
| Sergunb | 0:8f0d870509fe | 208 | // Now we know that some bits need to be programmed to '0' also. |
| Sergunb | 0:8f0d870509fe | 209 | |
| Sergunb | 0:8f0d870509fe | 210 | EEDR = new_value; // Set EEPROM data register. |
| Sergunb | 0:8f0d870509fe | 211 | EECR = (1<<EEMPE) | // Set Master Write Enable bit... |
| Sergunb | 0:8f0d870509fe | 212 | (0<<EEPM1) | (0<<EEPM0); // ...and Erase+Write mode. |
| Sergunb | 0:8f0d870509fe | 213 | EECR |= (1<<EEPE); // Start Erase+Write operation. |
| Sergunb | 0:8f0d870509fe | 214 | } else { |
| Sergunb | 0:8f0d870509fe | 215 | // Now we know that all bits should be erased. |
| Sergunb | 0:8f0d870509fe | 216 | |
| Sergunb | 0:8f0d870509fe | 217 | EECR = (1<<EEMPE) | // Set Master Write Enable bit... |
| Sergunb | 0:8f0d870509fe | 218 | (1<<EEPM0); // ...and Erase-only mode. |
| Sergunb | 0:8f0d870509fe | 219 | EECR |= (1<<EEPE); // Start Erase-only operation. |
| Sergunb | 0:8f0d870509fe | 220 | } |
| Sergunb | 0:8f0d870509fe | 221 | } else { |
| Sergunb | 0:8f0d870509fe | 222 | // Now we know that _no_ bits need to be erased to '1'. |
| Sergunb | 0:8f0d870509fe | 223 | |
| Sergunb | 0:8f0d870509fe | 224 | // Check if any bits are changed from '1' in the old value. |
| Sergunb | 0:8f0d870509fe | 225 | if( diff_mask ) { |
| Sergunb | 0:8f0d870509fe | 226 | // Now we know that _some_ bits need to the programmed to '0'. |
| Sergunb | 0:8f0d870509fe | 227 | |
| Sergunb | 0:8f0d870509fe | 228 | EEDR = new_value; // Set EEPROM data register. |
| Sergunb | 0:8f0d870509fe | 229 | EECR = (1<<EEMPE) | // Set Master Write Enable bit... |
| Sergunb | 0:8f0d870509fe | 230 | (1<<EEPM1); // ...and Write-only mode. |
| Sergunb | 0:8f0d870509fe | 231 | EECR |= (1<<EEPE); // Start Write-only operation. |
| Sergunb | 0:8f0d870509fe | 232 | } |
| Sergunb | 0:8f0d870509fe | 233 | } |
| Sergunb | 0:8f0d870509fe | 234 | |
| Sergunb | 0:8f0d870509fe | 235 | sei(); // Restore interrupt flag state. |
| Sergunb | 0:8f0d870509fe | 236 | #endif |
| Sergunb | 0:8f0d870509fe | 237 | #if defined(WIN32) || defined(STM32F103C8) |
| Sergunb | 0:8f0d870509fe | 238 | EE_Buffer[addr] = new_value; |
| Sergunb | 0:8f0d870509fe | 239 | #endif |
| Sergunb | 0:8f0d870509fe | 240 | } |
| Sergunb | 0:8f0d870509fe | 241 | |
| Sergunb | 0:8f0d870509fe | 242 | // Extensions added as part of Grbl |
| Sergunb | 0:8f0d870509fe | 243 | |
| Sergunb | 0:8f0d870509fe | 244 | |
| Sergunb | 0:8f0d870509fe | 245 | void memcpy_to_eeprom_with_checksum(unsigned int destination, char *source, unsigned int size) { |
| Sergunb | 0:8f0d870509fe | 246 | unsigned char checksum = 0; |
| Sergunb | 0:8f0d870509fe | 247 | for(; size > 0; size--) { |
| Sergunb | 0:8f0d870509fe | 248 | checksum = (checksum << 1) || (checksum >> 7); |
| Sergunb | 0:8f0d870509fe | 249 | checksum += *source; |
| Sergunb | 0:8f0d870509fe | 250 | eeprom_put_char(destination++, *(source++)); |
| Sergunb | 0:8f0d870509fe | 251 | } |
| Sergunb | 0:8f0d870509fe | 252 | eeprom_put_char(destination, checksum); |
| Sergunb | 0:8f0d870509fe | 253 | #if defined(WIN32) || defined(STM32F103C8) |
| Sergunb | 0:8f0d870509fe | 254 | #ifndef NOEEPROMSUPPORT |
| Sergunb | 0:8f0d870509fe | 255 | eeprom_flush(); |
| Sergunb | 0:8f0d870509fe | 256 | #endif |
| Sergunb | 0:8f0d870509fe | 257 | #endif |
| Sergunb | 0:8f0d870509fe | 258 | } |
| Sergunb | 0:8f0d870509fe | 259 | |
| Sergunb | 0:8f0d870509fe | 260 | int memcpy_from_eeprom_with_checksum(char *destination, unsigned int source, unsigned int size) { |
| Sergunb | 0:8f0d870509fe | 261 | unsigned char data, checksum = 0; |
| Sergunb | 0:8f0d870509fe | 262 | for(; size > 0; size--) { |
| Sergunb | 0:8f0d870509fe | 263 | data = eeprom_get_char(source++); |
| Sergunb | 0:8f0d870509fe | 264 | checksum = (checksum << 1) || (checksum >> 7); |
| Sergunb | 0:8f0d870509fe | 265 | checksum += data; |
| Sergunb | 0:8f0d870509fe | 266 | *(destination++) = data; |
| Sergunb | 0:8f0d870509fe | 267 | } |
| Sergunb | 0:8f0d870509fe | 268 | return(checksum == eeprom_get_char(source)); |
| Sergunb | 0:8f0d870509fe | 269 | } |
| Sergunb | 0:8f0d870509fe | 270 | |
| Sergunb | 0:8f0d870509fe | 271 | // end of file |