elbear_arduino_bsp/libraries/EEPROM/src/EEPROM.h

255 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#ifndef EEPROM_h
#define EEPROM_h
#include <inttypes.h>
#include "string.h"
#define EEPROM_OP_TIMEOUT 100000
#define EEPROM_PAGE_WORDS 32 // Количество слов на странице
#define EEPROM_PAGE_COUNT 8 // КОличество страниц пользовательской EEPROM
#define EEPROM_START_ADDR 0x1C00 // Адрес начала пользовательской EEPROM
#define EEPROM_WORD_SIZE 4 // Слово занимает 4 байта
#define EEPROM_PAGE_SIZE ( EEPROM_PAGE_WORDS * EEPROM_WORD_SIZE ) // Страница занимает 32*4 = 128 байт
#define EEPROM_END 0x1FFF
#define EEPROM_LENGHT (EEPROM_PAGE_SIZE * EEPROM_PAGE_COUNT)
void HAL_read(uint16_t addr, uint32_t * data);
void HAL_write(uint16_t addr, uint32_t * data);
void HAL_erase(uint16_t addr);
uint8_t read_byte( int idx );
void write_byte( int idx, uint8_t val );
void update_byte( int idx, uint8_t val );
extern void ErrorMsgHandler(const char * msg);
struct EERef{
EERef( const int index )
: index( index ) {}
uint8_t operator*() const { return read_byte( index ); }
operator uint8_t() const { return **this; }
EERef &operator=( const EERef &ref ) { return *this = *ref; }
EERef &operator=( uint8_t in ) { return write_byte( index, in ), *this; }
EERef &operator +=( uint8_t in ) { return *this = **this + in; }
EERef &operator -=( uint8_t in ) { return *this = **this - in; }
EERef &operator *=( uint8_t in ) { return *this = **this * in; }
EERef &operator /=( uint8_t in ) { return *this = **this / in; }
EERef &operator ^=( uint8_t in ) { return *this = **this ^ in; }
EERef &operator %=( uint8_t in ) { return *this = **this % in; }
EERef &operator &=( uint8_t in ) { return *this = **this & in; }
EERef &operator |=( uint8_t in ) { return *this = **this | in; }
EERef &operator <<=( uint8_t in ) { return *this = **this << in; }
EERef &operator >>=( uint8_t in ) { return *this = **this >> in; }
EERef &update( uint8_t in ) { return in != *this ? *this = in : *this; }
/** Prefix increment/decrement **/
EERef& operator++() { return *this += 1; }
EERef& operator--() { return *this -= 1; }
/** Postfix increment/decrement **/
uint8_t operator++ (int){
uint8_t ret = **this;
return ++(*this), ret;
}
uint8_t operator-- (int){
uint8_t ret = **this;
return --(*this), ret;
}
int index;
};
struct EEPtr{
EEPtr( const int index )
: index( index ) {}
operator int() const { return index; }
EEPtr &operator=( int in ) { return index = in, *this; }
bool operator!=( const EEPtr &ptr ) { return index != ptr.index; }
EERef operator*() { return index; }
EEPtr& operator++() { return ++index, *this; }
EEPtr& operator--() { return --index, *this; }
EEPtr operator++ (int) { return index++; }
EEPtr operator-- (int) { return index--; }
int index;
};
struct EEPROMClass{
//Basic user access methods.
EERef operator[]( const int idx ) { return idx; }
uint8_t read( int idx ) { return EERef( idx ); }
void write( int idx, uint8_t val ) { (EERef( idx )) = val; }
void update( int idx, uint8_t val ) { update_byte(idx, val); }
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; }
template< typename T >
T &put(int idx, T &data)
{
void* dataPointer = (void*)&data;
// Проверка адекватности адреса idx
if (idx < 0)
{
idx = -idx;
ErrorMsgHandler("EEPROM.put(): The eeprom cell address must be non-negative");
}
if ((uint32_t)idx >= (uint32_t)EEPROM_LENGHT)
{
idx = (int)((uint32_t)idx % EEPROM_LENGHT);
ErrorMsgHandler("EEPROM.put(): The address of the eeprom cell goes beyond the eeprom");
}
uint32_t write_data_buf[EEPROM_PAGE_WORDS] = {};
// Размер данных под запись
uint32_t dataSize = sizeof(data);
// Сдвиг начала записи данных
uint32_t dataShift = 0;
uint32_t writeSize = dataSize;
// Вычисление адреса начала нужной страницы
uint32_t addr = EEPROM_START_ADDR + (((uint32_t)idx) / EEPROM_PAGE_SIZE) * EEPROM_PAGE_SIZE;
// Адрес искомого слова в eeprom: EEPROM_START_ADDR + (uint32_t)idx
uint32_t word_addr = EEPROM_START_ADDR + (((uint32_t)idx) / EEPROM_WORD_SIZE) * EEPROM_WORD_SIZE;
// Индекс искомого слова в массиве write_data_buf: адрес слова в eeprom за вычетом адреса начала страницы
uint32_t word_idx = (word_addr - addr) / EEPROM_WORD_SIZE;
// Адрес начала данных на странице
uint32_t byte_addr = (uint32_t)idx % EEPROM_PAGE_SIZE;
// Номер байта в составе слова
uint32_t byte_idx = ((uint32_t)idx) % EEPROM_WORD_SIZE;
// Чтение первой страницы
HAL_read((uint16_t)addr, write_data_buf);
// Если данные не влезут на первую страницу, то записываем только то, что влезло
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;
// Запись данных постранично, сначала записываем первую страницу - отдельно
memcpy((void *)((uint8_t *)write_data_buf + byte_addr), (void*)dataPointer, writeSize);
// Разворачиваем слова
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);
}
HAL_erase((uint16_t)addr);
HAL_write((uint16_t)addr, write_data_buf);
// Если данные остались после записи первой страницы, то пишем их постранично, пока не закончатся
while (dataSize > 0)
{
addr += EEPROM_PAGE_SIZE;
// При достижении крайнего адреса eeprom возвращаемся к начальному адресу
if (addr == EEPROM_START_ADDR + EEPROM_LENGHT)
addr = EEPROM_START_ADDR;
HAL_read((uint16_t)addr, write_data_buf);
dataShift += writeSize;
writeSize = dataSize;
if (EEPROM_PAGE_SIZE < dataSize)
writeSize = EEPROM_PAGE_SIZE;
lastWord = (writeSize - 1) / EEPROM_WORD_SIZE;
memcpy((void *)(write_data_buf), (void*)((uint8_t *)dataPointer + dataShift), writeSize);
// Разворачиваем слова
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[0] = writeSize;
HAL_erase((uint16_t)addr);
HAL_write((uint16_t)addr, write_data_buf);
dataSize -= writeSize;
}
return data;
}
template< typename T >
T &get(int idx, T &data)
{
void* dataPointer = (void*)&data;
// Проверка адекватности адреса idx
if (idx < 0)
{
idx = -idx;
ErrorMsgHandler("EEPROM.get(): The eeprom cell address must be non-negative");
}
if ((uint32_t)idx >= (uint32_t)EEPROM_LENGHT)
{
idx = (int)((uint32_t)idx % EEPROM_LENGHT);
ErrorMsgHandler("EEPROM.get(): The address of the eeprom cell goes beyond the eeprom");
}
uint32_t read_data_buf[EEPROM_PAGE_WORDS] = {};
// Размер данных
uint32_t dataSize = sizeof(data);
// Сдвиг начала чтения данных
uint32_t dataShift = 0;
uint32_t readSize = dataSize;
// Вычисление адреса начала нужной страницы
uint32_t addr = EEPROM_START_ADDR + (((uint32_t)idx) / EEPROM_PAGE_SIZE) * EEPROM_PAGE_SIZE;
// Адрес искомого слова в eeprom: EEPROM_START_ADDR + (uint32_t)idx
uint32_t word_addr = EEPROM_START_ADDR + (((uint32_t)idx) / EEPROM_WORD_SIZE) * EEPROM_WORD_SIZE;
// Индекс искомого слова в массиве write_data_buf: адрес слова в eeprom за вычетом адреса начала страницы
uint32_t word_idx = (word_addr - addr) / EEPROM_WORD_SIZE;
// Адрес начала данных на странице
uint32_t byte_addr = (uint32_t)idx % EEPROM_PAGE_SIZE;
// Номер байта в составе слова
uint32_t byte_idx = ((uint32_t)idx) % EEPROM_WORD_SIZE;
// Чтение первой страницы
HAL_read((uint16_t)addr, read_data_buf);
if (EEPROM_PAGE_SIZE - byte_addr < dataSize)
readSize = EEPROM_PAGE_SIZE - byte_addr;
uint32_t lastWord = (readSize + byte_idx - 1) / EEPROM_WORD_SIZE + word_idx;
dataSize -= readSize;
// Разворачиваем слова
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);
}
// Чтение данных постранично, сначала читаем первую страницу - отдельно
memcpy((void *)dataPointer, (void*)((uint8_t *)read_data_buf + byte_addr), readSize);
// Если данные остались после записи первой страницы, то пишем их постранично, пока не закончатся
while (dataSize > 0)
{
addr += EEPROM_PAGE_SIZE;
// При достижении крайнего адреса eeprom возвращаемся к начальному адресу
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;
// Разворачиваем слова
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);
}
memcpy((void *)((uint8_t *)dataPointer + dataShift), (void*)(read_data_buf), readSize);
dataSize -= readSize;
}
return data; // Возвращаем ссылку на переданный объект с прочитанными данными
}
};
static EEPROMClass EEPROM;
#endif