diff --git a/libraries/EEPROM/README.md b/libraries/EEPROM/README.md index 9ca761d..30a2043 100644 --- a/libraries/EEPROM/README.md +++ b/libraries/EEPROM/README.md @@ -134,6 +134,5 @@ This is useful for STL objects, custom iteration and C++11 style ranged for loop #### **`EEPROM.end()`** This function returns an `EEPtr` pointing at the location after the last EEPROM cell. -Used with `begin()` to provide custom iteration. -**Note:** The `EEPtr` returned is invalid as it is out of range. In fact the hardware causes wrapping of the address (overflow) and `EEPROM.end()` actually references the first EEPROM cell. +**Note:** The `EEPtr` returned is invalid as it is out of range and must not be dereferenced. diff --git a/libraries/EEPROM/src/EEPROM.cpp b/libraries/EEPROM/src/EEPROM.cpp index 10f5a89..4a7b6af 100644 --- a/libraries/EEPROM/src/EEPROM.cpp +++ b/libraries/EEPROM/src/EEPROM.cpp @@ -20,13 +20,13 @@ uint8_t read_byte( int idx ) // check if idx is valid if (idx < 0) { - idx = -idx; ErrorMsgHandler("EEPROM.read(): The eeprom cell address must be non-negative"); + return 0xFF; } - if ((uint32_t)idx >= (uint32_t)EEPROM_LENGHT) + if ((uint32_t)idx >= (uint32_t)EEPROM_LENGTH) { - idx = (int)((uint32_t)idx % EEPROM_LENGHT); ErrorMsgHandler("EEPROM.read(): The address of the eeprom cell goes beyond the eeprom"); + return 0xFF; } uint32_t read_data_buf[EEPROM_PAGE_WORDS] = {}; @@ -50,13 +50,13 @@ void write_byte( int idx, uint8_t val ) // check if idx is valid if (idx < 0) { - idx = -idx; ErrorMsgHandler("EEPROM.write(): The eeprom cell address must be non-negative"); + return; } - if ((uint32_t)idx >= (uint32_t)EEPROM_LENGHT) + if ((uint32_t)idx >= (uint32_t)EEPROM_LENGTH) { - idx = (int)((uint32_t)idx % EEPROM_LENGHT); ErrorMsgHandler("EEPROM.write(): The address of the eeprom cell goes beyond the eeprom"); + return; } update_byte(idx, val); } @@ -66,13 +66,13 @@ void update_byte( int idx, uint8_t val ) // check if idx is valid if (idx < 0) { - idx = -idx; ErrorMsgHandler("EEPROM.update(): The eeprom cell address must be non-negative"); + return; } - if ((uint32_t)idx >= (uint32_t)EEPROM_LENGHT) + if ((uint32_t)idx >= (uint32_t)EEPROM_LENGTH) { - idx = (int)((uint32_t)idx % EEPROM_LENGHT); ErrorMsgHandler("EEPROM.update(): The address of the eeprom cell goes beyond the eeprom"); + return; } uint32_t write_data_buf[EEPROM_PAGE_WORDS] = {}; @@ -88,15 +88,16 @@ void update_byte( int idx, uint8_t val ) // byte number in a word uint32_t byte_idx = ((uint32_t)idx) % EEPROM_WORD_SIZE; // get desired byte - uint32_t byte = ((uint32_t)val) << ((EEPROM_WORD_SIZE - byte_idx - 1) * 8); - uint8_t oldVal = (uint8_t)(*((uint8_t*)write_data_buf + word_idx * EEPROM_WORD_SIZE + (EEPROM_WORD_SIZE - byte_idx - 1))); + uint32_t shift = (EEPROM_WORD_SIZE - byte_idx - 1) * 8; + uint32_t byte = ((uint32_t)val) << shift; + uint8_t oldVal = (uint8_t)((write_data_buf[word_idx] >> shift) & 0xFF); // checking if written byte is different from the new one if(oldVal != val) { // clear page HAL_EEPROM_Erase(&heeprom, (uint16_t)addr, EEPROM_PAGE_WORDS, HAL_EEPROM_WRITE_SINGLE, EEPROM_OP_TIMEOUT); // get and replace the desired byte - write_data_buf[word_idx] = (write_data_buf[word_idx] & (~((uint32_t)(0xFF) << ((EEPROM_WORD_SIZE - byte_idx - 1) * 8)))) | byte; + write_data_buf[word_idx] = (write_data_buf[word_idx] & (~((uint32_t)(0xFF) << shift))) | byte; HAL_EEPROM_Write(&heeprom, (uint16_t)addr, write_data_buf, EEPROM_PAGE_WORDS, HAL_EEPROM_WRITE_SINGLE, EEPROM_OP_TIMEOUT); } diff --git a/libraries/EEPROM/src/EEPROM.h b/libraries/EEPROM/src/EEPROM.h index 780a89e..fa1875d 100644 --- a/libraries/EEPROM/src/EEPROM.h +++ b/libraries/EEPROM/src/EEPROM.h @@ -12,7 +12,7 @@ #define EEPROM_WORD_SIZE 4 // word takes 4 bytes #define EEPROM_PAGE_SIZE ( EEPROM_PAGE_WORDS * EEPROM_WORD_SIZE ) // page takes 32*4 = 128 bytes #define EEPROM_END 0x1FFF -#define EEPROM_LENGHT (EEPROM_PAGE_SIZE * EEPROM_PAGE_COUNT) +#define EEPROM_LENGTH (EEPROM_PAGE_SIZE * EEPROM_PAGE_COUNT) void HAL_read(uint16_t addr, uint32_t * data); void HAL_write(uint16_t addr, uint32_t * data); @@ -81,6 +81,14 @@ struct EEPtr{ int index; }; +static inline uint32_t eeprom_reverse_word(uint32_t word) +{ + return ((word & 0x000000FFUL) << 24) | + ((word & 0x0000FF00UL) << 8) | + ((word & 0x00FF0000UL) >> 8) | + ((word & 0xFF000000UL) >> 24); +} + struct EEPROMClass{ //Basic user access methods. @@ -91,7 +99,7 @@ struct EEPROMClass{ void begin(); EEPtr end() { return length(); } // Standards requires this to be the item after the last valid entry. The returned pointer is invalid. - uint16_t length() { return (uint16_t)EEPROM_LENGHT; } + uint16_t length() { return (uint16_t)EEPROM_LENGTH; } template< typename T > const T &put(int idx, const T &data) @@ -100,20 +108,26 @@ struct EEPROMClass{ // check if idx is valid if (idx < 0) { - idx = -idx; ErrorMsgHandler("EEPROM.put(): The eeprom cell address must be non-negative"); + return data; } - if ((uint32_t)idx >= (uint32_t)EEPROM_LENGHT) + if ((uint32_t)idx >= (uint32_t)EEPROM_LENGTH) { - idx = (int)((uint32_t)idx % EEPROM_LENGHT); ErrorMsgHandler("EEPROM.put(): The address of the eeprom cell goes beyond the eeprom"); + return data; + } + if (sizeof(data) > ((uint32_t)EEPROM_LENGTH - (uint32_t)idx)) + { + ErrorMsgHandler("EEPROM.put(): The data goes beyond the eeprom"); + return data; } uint32_t write_data_buf[EEPROM_PAGE_WORDS] = {}; + uint32_t old_data_buf[EEPROM_PAGE_WORDS]; uint32_t dataSize = sizeof(data); // writing data size uint32_t dataShift = 0; // shift of the data writing start address uint32_t writeSize = dataSize; - + // calc start address of the desired page uint32_t addr = EEPROM_START_ADDR + (((uint32_t)idx) / EEPROM_PAGE_SIZE) * EEPROM_PAGE_SIZE; // address of the searched word in eeprom: EEPROM_START_ADDR + (uint32_t)idx @@ -126,45 +140,56 @@ struct EEPROMClass{ uint32_t byte_idx = ((uint32_t)idx) % EEPROM_WORD_SIZE; // read first page HAL_read((uint16_t)addr, write_data_buf); + memcpy(old_data_buf, write_data_buf, sizeof(write_data_buf)); // if data does not fit on the first page, then write down only what fits if (EEPROM_PAGE_SIZE - byte_addr < dataSize) writeSize = EEPROM_PAGE_SIZE - byte_addr; uint32_t lastWord = (writeSize + byte_idx - 1) / EEPROM_WORD_SIZE + word_idx; dataSize -= writeSize; + // Convert affected words to byte order suitable for memcpy() + for(uint8_t i = word_idx; i <= lastWord; i++) + { + write_data_buf[i] = eeprom_reverse_word(write_data_buf[i]); + } // write data page by page, first separately write the first page memcpy((void *)((uint8_t *)write_data_buf + byte_addr), (void*)dataPointer, writeSize); // prepare words for writing for(uint8_t i = word_idx; i <= lastWord; i++) { - uint32_t word = write_data_buf[i]; - write_data_buf[i] = 0; - write_data_buf[i] = ((word & 0xFF)<<24) | ((word & (0xFF<<8))<<8) | ((word & (0xFF<<16))>>8) | ((word & (0xFF<<24))>>24); + write_data_buf[i] = eeprom_reverse_word(write_data_buf[i]); + } + if (memcmp(old_data_buf, write_data_buf, sizeof(write_data_buf)) != 0) + { + HAL_erase((uint16_t)addr); + HAL_write((uint16_t)addr, write_data_buf); } - HAL_erase((uint16_t)addr); - HAL_write((uint16_t)addr, write_data_buf); // if there is data left after writing the first page, then write it page by page until it runs out while (dataSize > 0) { addr += EEPROM_PAGE_SIZE; - // if reaching the eeprom end address, return to the initial address - if (addr == EEPROM_START_ADDR + EEPROM_LENGHT) - addr = EEPROM_START_ADDR; HAL_read((uint16_t)addr, write_data_buf); + memcpy(old_data_buf, write_data_buf, sizeof(write_data_buf)); dataShift += writeSize; writeSize = dataSize; if (EEPROM_PAGE_SIZE < dataSize) writeSize = EEPROM_PAGE_SIZE; lastWord = (writeSize - 1) / EEPROM_WORD_SIZE; + // Convert affected words to byte order suitable for memcpy() + for(uint8_t i = 0; i <= lastWord; i++) + { + write_data_buf[i] = eeprom_reverse_word(write_data_buf[i]); + } memcpy((void *)(write_data_buf), (void*)((uint8_t *)dataPointer + dataShift), writeSize); // prepare words for writing for(uint8_t i = 0; i <= lastWord; i++) { - uint32_t word = write_data_buf[i]; - write_data_buf[i] = 0; - write_data_buf[i] = ((word & 0xFF)<<24) | ((word & (0xFF<<8))<<8) | ((word & (0xFF<<16))>>8) | ((word & (0xFF<<24))>>24); + write_data_buf[i] = eeprom_reverse_word(write_data_buf[i]); + } + if (memcmp(old_data_buf, write_data_buf, sizeof(write_data_buf)) != 0) + { + HAL_erase((uint16_t)addr); + HAL_write((uint16_t)addr, write_data_buf); } - HAL_erase((uint16_t)addr); - HAL_write((uint16_t)addr, write_data_buf); dataSize -= writeSize; } return data; @@ -177,13 +202,18 @@ struct EEPROMClass{ // check if idx is valid if (idx < 0) { - idx = -idx; ErrorMsgHandler("EEPROM.get(): The eeprom cell address must be non-negative"); + return data; } - if ((uint32_t)idx >= (uint32_t)EEPROM_LENGHT) + if ((uint32_t)idx >= (uint32_t)EEPROM_LENGTH) { - idx = (int)((uint32_t)idx % EEPROM_LENGHT); ErrorMsgHandler("EEPROM.get(): The address of the eeprom cell goes beyond the eeprom"); + return data; + } + if (sizeof(data) > ((uint32_t)EEPROM_LENGTH - (uint32_t)idx)) + { + ErrorMsgHandler("EEPROM.get(): The data goes beyond the eeprom"); + return data; } uint32_t read_data_buf[EEPROM_PAGE_WORDS] = {}; @@ -210,9 +240,7 @@ struct EEPROMClass{ // prepare words for(uint8_t i = word_idx; i <= lastWord; i++) { - uint32_t word = read_data_buf[i]; - read_data_buf[i] = 0; - read_data_buf[i] = ((word & 0xFF)<<24) | ((word & (0xFF<<8))<<8) | ((word & (0xFF<<16))>>8) | ((word & (0xFF<<24))>>24); + read_data_buf[i] = eeprom_reverse_word(read_data_buf[i]); } // read data page by page, first separately read the first page memcpy((void *)dataPointer, (void*)((uint8_t *)read_data_buf + byte_addr), readSize); @@ -221,21 +249,16 @@ struct EEPROMClass{ while (dataSize > 0) { addr += EEPROM_PAGE_SIZE; - // if reaching the eeprom end address, return to the initial address - if (addr == EEPROM_START_ADDR + EEPROM_LENGHT) - addr = EEPROM_START_ADDR; HAL_read((uint16_t)addr, read_data_buf); dataShift += readSize; readSize = dataSize; if (EEPROM_PAGE_SIZE < dataSize) readSize = EEPROM_PAGE_SIZE; - lastWord = (dataSize - 1) / EEPROM_WORD_SIZE; + lastWord = (readSize - 1) / EEPROM_WORD_SIZE; // prepare words for(uint8_t i = 0; i <= lastWord; i++) { - uint32_t word = read_data_buf[i]; - read_data_buf[i] = 0; - read_data_buf[i] = ((word & 0xFF)<<24) | ((word & (0xFF<<8))<<8) | ((word & (0xFF<<16))>>8) | ((word & (0xFF<<24))>>24); + read_data_buf[i] = eeprom_reverse_word(read_data_buf[i]); } memcpy((void *)((uint8_t *)dataPointer + dataShift), (void*)(read_data_buf), readSize); dataSize -= readSize; @@ -244,7 +267,9 @@ struct EEPROMClass{ } }; -#pragma GCC diagnostic ignored "-Wunused-variable" // for GCC and Clang - +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" static EEPROMClass EEPROM; -#endif +#pragma GCC diagnostic pop + +#endif \ No newline at end of file