====== EEPROM ====== //Required knowledge: [HW] [[et:hardware:homelab:controller]] // ===== Theory ===== [{{ :et:examples:storage:eeprom2.png?250|Atmel EEPROM memory chip}}] EEPROM (//Electrically Eraseable Programmable Read Only Memory//) is an electrically erasable memory device typically used for storing a small amount of data. The advantage of EEPROM is that the data remains even after power is lost. It is commonly used to keep various settings that are modified by the program. Otherwise EEPROM behaves like other memories, where bits are grouped into 8-bit bytes. When using EEPROM, it is important to remember that the lifetime of memory bytes is about 100000 write cycles. Therefore you should write only the minimum necessary data to EEPROM. ===== Practice ===== AVR microcontrollers have a certain amount of EEPROM built in. The HomeLab III controller ATxmega128A1U has 2 KB of EEPROM. To work with EEPROM, it is recommended to use the library already built into AVR GCC. The library defines the main functions for EEPROM access: * uint8_t eeprom_read_byte (const uint8_t *addr) * uint16_t eeprom_read_word (const uint16_t *addr) * void eeprom_read_block (void *pointer_ram, const void *pointer_eeprom, size_t n) * void eeprom_write_byte (uint8_t *addr, uint8_t value) * void eeprom_write_word (uint16_t *addr, uint16_t value) * void eeprom_write_block (const void *pointer_eeprom, void *pointer_ram, size_t n) * void eeprom_update_byte (uint8_t *addr, uint8_t value) * void eeprom_update_word (uint16_t *addr, uint16_t value) * void eeprom_update_block (const void *pointer_ram, void *pointer_eeprom, size_t n) Simple example code for EEPROM storage. It reads a byte from address 46 and a word from address 50. Writing uses the //update// function, which reads the EEPROM location before writing and does not overwrite when the value is already correct. This saves memory cells from wear, but writing takes a bit longer. // AVR EEPROM byte and word save/read example #include // Main program int main(void) { uint8_t dataByte; uint8_t dataWord; // Write value 86 to EEPROM address 46 eeprom_update_byte((uint8_t*)46, 86); // Write value 860 to EEPROM address 50 eeprom_update_word((uint16_t*)50, 860); // Read byte from address 46 (should be 86) dataByte = eeprom_read_byte((uint8_t*)46); // Read word from address 50 (should be 860) dataWord = eeprom_read_word((uint16_t*)50); } To move more data at once, use block read/write. First define a data block in RAM: // AVR EEPROM block save/read example #include // Main program int main(void) { uint8_t dataArray1[10] = "TestLause."; uint8_t dataArray2[10]; // First parameter is pointer to EEPROM block, // second parameter is pointer to RAM block // third parameter is dataArray length eeprom_update_block((const void*)&dataArray1, (void*)12, 10); // First parameter is pointer to RAM block, // second parameter is pointer to EEPROM block // third parameter is dataArray length eeprom_read_block((void*)&dataArray2, (const void*)12, 10); } It is not always practical to remember exact EEPROM addresses. For that there is a variable attribute called EEMEM. It frees the user from managing addresses and lets the compiler do it. Note that you still must use library functions to move data in EEPROM. // AVR EEPROM EEMEM usage example #include uint8_t EEMEM NonVolatileChar; uint16_t EEMEM NonVolatileInt; uint8_t EEMEM NonVolatileString[10]; // Main program int main(void) { uint8_t SRAMchar; uint16_t SRAMint; uint8_t SRAMstring[10]; SRAMchar = eeprom_read_byte(&NonVolatileChar); SRAMint = eeprom_read_word(&NonVolatileInt); eeprom_read_block((void*)&SRAMstring, (const void*)&NonVolatileString, 10); }