notjob
This commit is contained in:
@@ -28,6 +28,13 @@ typedef struct {
|
||||
} EEPROM_Item;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct {
|
||||
uint8_t data[EEPROM_SIZE]; // Массив для хранения данных
|
||||
uint16_t head; // Указатель на место записи
|
||||
uint16_t tail; // Указатель на место чтения
|
||||
} RingBuffer_t;
|
||||
|
||||
|
||||
// Инициализация EEPROM
|
||||
EEPROM_Status EEPROM_Init(void);
|
||||
|
||||
|
||||
31
john103C6T6/EEPROM_Emul/lib/flash_ring.h
Normal file
31
john103C6T6/EEPROM_Emul/lib/flash_ring.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef FLASH_RING_H
|
||||
#define FLASH_RING_H
|
||||
#include "stm32f1xx_hal.h"
|
||||
|
||||
//#define FLASH_PAGE_SIZE 1024
|
||||
#define NUM_OF_PAGE_EEPROM 2
|
||||
#define FLASH_START_ADDR 0x08000000
|
||||
#define FLASH_SIZE (64 * 1024) // для STM32F103C8
|
||||
#define LAST_PAGE_ADDR (FLASH_START_ADDR + FLASH_SIZE - NUM_OF_PAGE_EEPROM*FLASH_PAGE_SIZE)
|
||||
#define RECORD_SIZE 255
|
||||
#define RECORDS_PER_PAGE NUM_OF_PAGE_EEPROM*(FLASH_PAGE_SIZE / RECORD_SIZE) // 10 записей
|
||||
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint32_t timestamp;
|
||||
uint8_t data[RECORD_SIZE-4]; // 200 - 4 байта timestamp
|
||||
} FlashRecord_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct {
|
||||
uint32_t write_index; // индекс следующей записи (0-9)
|
||||
uint8_t initialized; // флаг инициализации
|
||||
} BufferState_t;
|
||||
BufferState_t buffer_init(void);
|
||||
HAL_StatusTypeDef buffer_write_record(FlashRecord_t* record, BufferState_t* state);
|
||||
HAL_StatusTypeDef erase_flash_page(void) ;
|
||||
HAL_StatusTypeDef write_flash_record(uint32_t address, FlashRecord_t* record);
|
||||
FlashRecord_t* buffer_read_record(uint32_t index);
|
||||
void buffer_get_all_records(FlashRecord_t* records[], uint32_t* count);
|
||||
#endif // FLASH_RING_H
|
||||
@@ -14,243 +14,284 @@ static uint8_t EEPROM_IsPageErased(uint32_t address);
|
||||
static uint32_t EEPROM_CalculateCRC(EEPROM_Item* item);
|
||||
|
||||
// Инициализация EEPROM
|
||||
EEPROM_Status EEPROM_Init(void) {
|
||||
if (eeprom_initialized) {
|
||||
EEPROM_Status EEPROM_Init(void)
|
||||
{
|
||||
if (eeprom_initialized)
|
||||
{
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
|
||||
// Находим следующий адрес для записи
|
||||
eeprom_current_write_address = EEPROM_FindNextWriteAddress();
|
||||
|
||||
|
||||
// Если вся память заполнена, выполняем сборку мусора (форматирование)
|
||||
if (eeprom_current_write_address >= EEPROM_START_ADDRESS + EEPROM_SIZE) {
|
||||
if (eeprom_current_write_address >= EEPROM_START_ADDRESS + EEPROM_SIZE)
|
||||
{
|
||||
EEPROM_Format();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
eeprom_initialized = 1;
|
||||
}
|
||||
|
||||
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
// Чтение данных по виртуальному адресу
|
||||
EEPROM_Status EEPROM_Read(uint16_t virt_address, uint16_t* data) {
|
||||
if (!eeprom_initialized) {
|
||||
EEPROM_Status EEPROM_Read(uint16_t virt_address, uint16_t* data)
|
||||
{
|
||||
if (!eeprom_initialized)
|
||||
{
|
||||
return EEPROM_ERROR;
|
||||
}
|
||||
|
||||
if (virt_address >= EEPROM_MAX_VARIABLES || data == NULL) {
|
||||
|
||||
if (virt_address >= EEPROM_MAX_VARIABLES || data == NULL)
|
||||
{
|
||||
return EEPROM_INVALID;
|
||||
}
|
||||
|
||||
|
||||
return EEPROM_FindLatestData(virt_address, data);
|
||||
}
|
||||
|
||||
// Запись данных по виртуальному адресу
|
||||
EEPROM_Status EEPROM_Write(uint16_t virt_address, uint16_t data) {
|
||||
EEPROM_Status EEPROM_Write(uint16_t virt_address, uint16_t data)
|
||||
{
|
||||
EEPROM_Item item;
|
||||
|
||||
if (!eeprom_initialized) {
|
||||
|
||||
if (!eeprom_initialized)
|
||||
{
|
||||
return EEPROM_ERROR;
|
||||
}
|
||||
|
||||
if (virt_address >= EEPROM_MAX_VARIABLES) {
|
||||
|
||||
if (virt_address >= EEPROM_MAX_VARIABLES)
|
||||
{
|
||||
return EEPROM_INVALID;
|
||||
}
|
||||
|
||||
|
||||
// Подготавливаем элемент данных
|
||||
item.address = virt_address;
|
||||
item.data = data;
|
||||
item.timestamp = HAL_GetTick(); // Используем системный таймер
|
||||
|
||||
|
||||
// Записываем элемент
|
||||
return EEPROM_WriteItem(&item);
|
||||
}
|
||||
|
||||
// Поиск последних данных для виртуального адреса
|
||||
static EEPROM_Status EEPROM_FindLatestData(uint16_t virt_address, uint16_t* data) {
|
||||
static EEPROM_Status EEPROM_FindLatestData(uint16_t virt_address, uint16_t* data)
|
||||
{
|
||||
uint32_t address = EEPROM_START_ADDRESS;
|
||||
EEPROM_Item current_item;
|
||||
uint32_t latest_timestamp = 0;
|
||||
uint16_t latest_data = 0;
|
||||
uint8_t data_found = 0;
|
||||
|
||||
|
||||
// Сканируем всю область EEPROM
|
||||
while (address < EEPROM_START_ADDRESS + EEPROM_SIZE) {
|
||||
while (address < EEPROM_START_ADDRESS + EEPROM_SIZE)
|
||||
{
|
||||
// Читаем элемент
|
||||
memcpy(¤t_item, (void*)address, sizeof(EEPROM_Item));
|
||||
|
||||
|
||||
// Проверяем, является ли это валидными данными
|
||||
if (current_item.address == virt_address) {
|
||||
if (current_item.timestamp >= latest_timestamp) {
|
||||
if (current_item.address == virt_address)
|
||||
{
|
||||
if (current_item.timestamp >= latest_timestamp)
|
||||
{
|
||||
latest_timestamp = current_item.timestamp;
|
||||
latest_data = current_item.data;
|
||||
data_found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
address += sizeof(EEPROM_Item);
|
||||
|
||||
|
||||
// Проверяем конец страницы
|
||||
if ((address - EEPROM_START_ADDRESS) % EEPROM_PAGE_SIZE == 0) {
|
||||
if ((address - EEPROM_START_ADDRESS) % EEPROM_PAGE_SIZE == 0)
|
||||
{
|
||||
address += (EEPROM_PAGE_SIZE - (sizeof(EEPROM_Item) * 2));
|
||||
}
|
||||
}
|
||||
|
||||
if (data_found) {
|
||||
|
||||
if (data_found)
|
||||
{
|
||||
*data = latest_data;
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
|
||||
return EEPROM_INVALID;
|
||||
}
|
||||
|
||||
// Запись элемента в EEPROM
|
||||
static EEPROM_Status EEPROM_WriteItem(EEPROM_Item* item) {
|
||||
static EEPROM_Status EEPROM_WriteItem(EEPROM_Item* item)
|
||||
{
|
||||
HAL_StatusTypeDef hal_status;
|
||||
|
||||
|
||||
// Проверяем, нужно ли стирать страницу
|
||||
if ((eeprom_current_write_address - EEPROM_START_ADDRESS) % EEPROM_PAGE_SIZE == 0) {
|
||||
if (!EEPROM_IsPageErased(eeprom_current_write_address)) {
|
||||
if (EEPROM_ErasePage(eeprom_current_write_address) != EEPROM_OK) {
|
||||
if ((eeprom_current_write_address - EEPROM_START_ADDRESS) % EEPROM_PAGE_SIZE == 0)
|
||||
{
|
||||
if (!EEPROM_IsPageErased(eeprom_current_write_address))
|
||||
{
|
||||
if (EEPROM_ErasePage(eeprom_current_write_address) != EEPROM_OK)
|
||||
{
|
||||
return EEPROM_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Разблокируем Flash
|
||||
HAL_FLASH_Unlock();
|
||||
|
||||
|
||||
// Записываем данные по словам (32 бита)
|
||||
uint32_t* data_ptr = (uint32_t*)item;
|
||||
|
||||
for (uint8_t i = 0; i < sizeof(EEPROM_Item) / 4; i++) {
|
||||
hal_status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,
|
||||
eeprom_current_write_address + (i * 4),
|
||||
data_ptr[i]);
|
||||
|
||||
if (hal_status != HAL_OK) {
|
||||
|
||||
for (uint8_t i = 0; i < sizeof(EEPROM_Item) / 4; i++)
|
||||
{
|
||||
hal_status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,
|
||||
eeprom_current_write_address + (i * 4),
|
||||
data_ptr[i]);
|
||||
|
||||
if (hal_status != HAL_OK)
|
||||
{
|
||||
HAL_FLASH_Lock();
|
||||
return EEPROM_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Блокируем Flash
|
||||
HAL_FLASH_Lock();
|
||||
|
||||
|
||||
// Обновляем адрес для следующей записи
|
||||
eeprom_current_write_address += sizeof(EEPROM_Item);
|
||||
|
||||
|
||||
// Проверяем переполнение
|
||||
if (eeprom_current_write_address >= EEPROM_START_ADDRESS + EEPROM_SIZE) {
|
||||
if (eeprom_current_write_address >= EEPROM_START_ADDRESS + EEPROM_SIZE)
|
||||
{
|
||||
// Выполняем сборку мусора (в данном случае - форматирование)
|
||||
EEPROM_Format();
|
||||
}
|
||||
|
||||
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
// Стирание страницы Flash
|
||||
static EEPROM_Status EEPROM_ErasePage(uint32_t address) {
|
||||
static EEPROM_Status EEPROM_ErasePage(uint32_t address)
|
||||
{
|
||||
FLASH_EraseInitTypeDef erase;
|
||||
uint32_t page_error;
|
||||
|
||||
|
||||
// Определяем номер страницы
|
||||
uint32_t page = (address - FLASH_BASE) / EEPROM_PAGE_SIZE;
|
||||
|
||||
|
||||
HAL_FLASH_Unlock();
|
||||
|
||||
|
||||
erase.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
erase.PageAddress = address;
|
||||
erase.NbPages = 1;
|
||||
|
||||
if (HAL_FLASHEx_Erase(&erase, &page_error) != HAL_OK) {
|
||||
|
||||
if (HAL_FLASHEx_Erase(&erase, &page_error) != HAL_OK)
|
||||
{
|
||||
HAL_FLASH_Lock();
|
||||
return EEPROM_ERROR;
|
||||
}
|
||||
|
||||
|
||||
HAL_FLASH_Lock();
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
// Поиск следующего адреса для записи
|
||||
static uint32_t EEPROM_FindNextWriteAddress(void) {
|
||||
static uint32_t EEPROM_FindNextWriteAddress(void)
|
||||
{
|
||||
uint32_t address = EEPROM_START_ADDRESS;
|
||||
EEPROM_Item item;
|
||||
|
||||
|
||||
// Ищем первую свободную позицию
|
||||
while (address < EEPROM_START_ADDRESS + EEPROM_SIZE) {
|
||||
while (address < EEPROM_START_ADDRESS + EEPROM_SIZE)
|
||||
{
|
||||
memcpy(&item, (void*)address, sizeof(EEPROM_Item));
|
||||
|
||||
|
||||
// Если нашли пустой элемент (все FFFF), это свободная позиция
|
||||
if (item.address == 0xFFFF && item.data == 0xFFFF && item.timestamp == 0xFFFFFFFF) {
|
||||
if (item.address == 0xFFFF && item.data == 0xFFFF && item.timestamp == 0xFFFFFFFF)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
address += sizeof(EEPROM_Item);
|
||||
|
||||
|
||||
// Проверяем границу страницы
|
||||
if ((address - EEPROM_START_ADDRESS) % EEPROM_PAGE_SIZE == 0) {
|
||||
if ((address - EEPROM_START_ADDRESS) % EEPROM_PAGE_SIZE == 0)
|
||||
{
|
||||
address += (EEPROM_PAGE_SIZE - (sizeof(EEPROM_Item) * 2));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
// Проверка, стерта ли страница
|
||||
static uint8_t EEPROM_IsPageErased(uint32_t address) {
|
||||
static uint8_t EEPROM_IsPageErased(uint32_t address)
|
||||
{
|
||||
uint32_t* check_addr = (uint32_t*)address;
|
||||
|
||||
|
||||
// Проверяем первые несколько слов
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
if (check_addr[i] != 0xFFFFFFFF) {
|
||||
for (uint8_t i = 0; i < 8; i++)
|
||||
{
|
||||
if (check_addr[i] != 0xFFFFFFFF)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Полное форматирование EEPROM
|
||||
EEPROM_Status EEPROM_Format(void) {
|
||||
EEPROM_Status EEPROM_Format(void)
|
||||
{
|
||||
uint32_t address = EEPROM_START_ADDRESS;
|
||||
|
||||
|
||||
// Стираем все страницы, используемые для EEPROM
|
||||
while (address < EEPROM_START_ADDRESS + EEPROM_SIZE) {
|
||||
if (EEPROM_ErasePage(address) != EEPROM_OK) {
|
||||
while (address < EEPROM_START_ADDRESS + EEPROM_SIZE)
|
||||
{
|
||||
if (EEPROM_ErasePage(address) != EEPROM_OK)
|
||||
{
|
||||
return EEPROM_ERROR;
|
||||
}
|
||||
address += EEPROM_PAGE_SIZE;
|
||||
}
|
||||
|
||||
|
||||
eeprom_current_write_address = EEPROM_START_ADDRESS;
|
||||
eeprom_initialized = 1;
|
||||
|
||||
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
// Получение информации об использовании EEPROM
|
||||
void EEPROM_GetInfo(uint32_t* used, uint32_t* total) {
|
||||
void EEPROM_GetInfo(uint32_t* used, uint32_t* total)
|
||||
{
|
||||
uint32_t address = EEPROM_START_ADDRESS;
|
||||
uint32_t used_bytes = 0;
|
||||
|
||||
if (used) {
|
||||
|
||||
if (used)
|
||||
{
|
||||
// Подсчитываем использованные байты
|
||||
while (address < EEPROM_START_ADDRESS + EEPROM_SIZE) {
|
||||
while (address < EEPROM_START_ADDRESS + EEPROM_SIZE)
|
||||
{
|
||||
EEPROM_Item item;
|
||||
memcpy(&item, (void*)address, sizeof(EEPROM_Item));
|
||||
|
||||
if (item.address != 0xFFFF || item.data != 0xFFFF || item.timestamp != 0xFFFFFFFF) {
|
||||
|
||||
if (item.address != 0xFFFF || item.data != 0xFFFF || item.timestamp != 0xFFFFFFFF)
|
||||
{
|
||||
used_bytes += sizeof(EEPROM_Item);
|
||||
}
|
||||
|
||||
|
||||
address += sizeof(EEPROM_Item);
|
||||
}
|
||||
|
||||
|
||||
*used = used_bytes;
|
||||
}
|
||||
|
||||
if (total) {
|
||||
|
||||
if (total)
|
||||
{
|
||||
*total = EEPROM_SIZE;
|
||||
}
|
||||
}
|
||||
256
john103C6T6/EEPROM_Emul/src/EEPROM_Emul.c.orig
Normal file
256
john103C6T6/EEPROM_Emul/src/EEPROM_Emul.c.orig
Normal file
@@ -0,0 +1,256 @@
|
||||
#include "eeprom_emul.h"
|
||||
#include <string.h>
|
||||
|
||||
// Внутренние переменные
|
||||
static uint32_t eeprom_current_write_address = EEPROM_START_ADDRESS;
|
||||
static uint8_t eeprom_initialized = 0;
|
||||
|
||||
// Прототипы внутренних функций
|
||||
static EEPROM_Status EEPROM_FindLatestData(uint16_t virt_address, uint16_t* data);
|
||||
static EEPROM_Status EEPROM_WriteItem(EEPROM_Item* item);
|
||||
static EEPROM_Status EEPROM_ErasePage(uint32_t address);
|
||||
static uint32_t EEPROM_FindNextWriteAddress(void);
|
||||
static uint8_t EEPROM_IsPageErased(uint32_t address);
|
||||
static uint32_t EEPROM_CalculateCRC(EEPROM_Item* item);
|
||||
|
||||
// Инициализация EEPROM
|
||||
EEPROM_Status EEPROM_Init(void) {
|
||||
if (eeprom_initialized) {
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
// Находим следующий адрес для записи
|
||||
eeprom_current_write_address = EEPROM_FindNextWriteAddress();
|
||||
|
||||
// Если вся память заполнена, выполняем сборку мусора (форматирование)
|
||||
if (eeprom_current_write_address >= EEPROM_START_ADDRESS + EEPROM_SIZE) {
|
||||
EEPROM_Format();
|
||||
} else {
|
||||
eeprom_initialized = 1;
|
||||
}
|
||||
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
// Чтение данных по виртуальному адресу
|
||||
EEPROM_Status EEPROM_Read(uint16_t virt_address, uint16_t* data) {
|
||||
if (!eeprom_initialized) {
|
||||
return EEPROM_ERROR;
|
||||
}
|
||||
|
||||
if (virt_address >= EEPROM_MAX_VARIABLES || data == NULL) {
|
||||
return EEPROM_INVALID;
|
||||
}
|
||||
|
||||
return EEPROM_FindLatestData(virt_address, data);
|
||||
}
|
||||
|
||||
// Запись данных по виртуальному адресу
|
||||
EEPROM_Status EEPROM_Write(uint16_t virt_address, uint16_t data) {
|
||||
EEPROM_Item item;
|
||||
|
||||
if (!eeprom_initialized) {
|
||||
return EEPROM_ERROR;
|
||||
}
|
||||
|
||||
if (virt_address >= EEPROM_MAX_VARIABLES) {
|
||||
return EEPROM_INVALID;
|
||||
}
|
||||
|
||||
// Подготавливаем элемент данных
|
||||
item.address = virt_address;
|
||||
item.data = data;
|
||||
item.timestamp = HAL_GetTick(); // Используем системный таймер
|
||||
|
||||
// Записываем элемент
|
||||
return EEPROM_WriteItem(&item);
|
||||
}
|
||||
|
||||
// Поиск последних данных для виртуального адреса
|
||||
static EEPROM_Status EEPROM_FindLatestData(uint16_t virt_address, uint16_t* data) {
|
||||
uint32_t address = EEPROM_START_ADDRESS;
|
||||
EEPROM_Item current_item;
|
||||
uint32_t latest_timestamp = 0;
|
||||
uint16_t latest_data = 0;
|
||||
uint8_t data_found = 0;
|
||||
|
||||
// Сканируем всю область EEPROM
|
||||
while (address < EEPROM_START_ADDRESS + EEPROM_SIZE) {
|
||||
// Читаем элемент
|
||||
memcpy(¤t_item, (void*)address, sizeof(EEPROM_Item));
|
||||
|
||||
// Проверяем, является ли это валидными данными
|
||||
if (current_item.address == virt_address) {
|
||||
if (current_item.timestamp >= latest_timestamp) {
|
||||
latest_timestamp = current_item.timestamp;
|
||||
latest_data = current_item.data;
|
||||
data_found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
address += sizeof(EEPROM_Item);
|
||||
|
||||
// Проверяем конец страницы
|
||||
if ((address - EEPROM_START_ADDRESS) % EEPROM_PAGE_SIZE == 0) {
|
||||
address += (EEPROM_PAGE_SIZE - (sizeof(EEPROM_Item) * 2));
|
||||
}
|
||||
}
|
||||
|
||||
if (data_found) {
|
||||
*data = latest_data;
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
return EEPROM_INVALID;
|
||||
}
|
||||
|
||||
// Запись элемента в EEPROM
|
||||
static EEPROM_Status EEPROM_WriteItem(EEPROM_Item* item) {
|
||||
HAL_StatusTypeDef hal_status;
|
||||
|
||||
// Проверяем, нужно ли стирать страницу
|
||||
if ((eeprom_current_write_address - EEPROM_START_ADDRESS) % EEPROM_PAGE_SIZE == 0) {
|
||||
if (!EEPROM_IsPageErased(eeprom_current_write_address)) {
|
||||
if (EEPROM_ErasePage(eeprom_current_write_address) != EEPROM_OK) {
|
||||
return EEPROM_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Разблокируем Flash
|
||||
HAL_FLASH_Unlock();
|
||||
|
||||
// Записываем данные по словам (32 бита)
|
||||
uint32_t* data_ptr = (uint32_t*)item;
|
||||
|
||||
for (uint8_t i = 0; i < sizeof(EEPROM_Item) / 4; i++) {
|
||||
hal_status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,
|
||||
eeprom_current_write_address + (i * 4),
|
||||
data_ptr[i]);
|
||||
|
||||
if (hal_status != HAL_OK) {
|
||||
HAL_FLASH_Lock();
|
||||
return EEPROM_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// Блокируем Flash
|
||||
HAL_FLASH_Lock();
|
||||
|
||||
// Обновляем адрес для следующей записи
|
||||
eeprom_current_write_address += sizeof(EEPROM_Item);
|
||||
|
||||
// Проверяем переполнение
|
||||
if (eeprom_current_write_address >= EEPROM_START_ADDRESS + EEPROM_SIZE) {
|
||||
// Выполняем сборку мусора (в данном случае - форматирование)
|
||||
EEPROM_Format();
|
||||
}
|
||||
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
// Стирание страницы Flash
|
||||
static EEPROM_Status EEPROM_ErasePage(uint32_t address) {
|
||||
FLASH_EraseInitTypeDef erase;
|
||||
uint32_t page_error;
|
||||
|
||||
// Определяем номер страницы
|
||||
uint32_t page = (address - FLASH_BASE) / EEPROM_PAGE_SIZE;
|
||||
|
||||
HAL_FLASH_Unlock();
|
||||
|
||||
erase.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
erase.PageAddress = address;
|
||||
erase.NbPages = 1;
|
||||
|
||||
if (HAL_FLASHEx_Erase(&erase, &page_error) != HAL_OK) {
|
||||
HAL_FLASH_Lock();
|
||||
return EEPROM_ERROR;
|
||||
}
|
||||
|
||||
HAL_FLASH_Lock();
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
// Поиск следующего адреса для записи
|
||||
static uint32_t EEPROM_FindNextWriteAddress(void) {
|
||||
uint32_t address = EEPROM_START_ADDRESS;
|
||||
EEPROM_Item item;
|
||||
|
||||
// Ищем первую свободную позицию
|
||||
while (address < EEPROM_START_ADDRESS + EEPROM_SIZE) {
|
||||
memcpy(&item, (void*)address, sizeof(EEPROM_Item));
|
||||
|
||||
// Если нашли пустой элемент (все FFFF), это свободная позиция
|
||||
if (item.address == 0xFFFF && item.data == 0xFFFF && item.timestamp == 0xFFFFFFFF) {
|
||||
break;
|
||||
}
|
||||
|
||||
address += sizeof(EEPROM_Item);
|
||||
|
||||
// Проверяем границу страницы
|
||||
if ((address - EEPROM_START_ADDRESS) % EEPROM_PAGE_SIZE == 0) {
|
||||
address += (EEPROM_PAGE_SIZE - (sizeof(EEPROM_Item) * 2));
|
||||
}
|
||||
}
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
// Проверка, стерта ли страница
|
||||
static uint8_t EEPROM_IsPageErased(uint32_t address) {
|
||||
uint32_t* check_addr = (uint32_t*)address;
|
||||
|
||||
// Проверяем первые несколько слов
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
if (check_addr[i] != 0xFFFFFFFF) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Полное форматирование EEPROM
|
||||
EEPROM_Status EEPROM_Format(void) {
|
||||
uint32_t address = EEPROM_START_ADDRESS;
|
||||
|
||||
// Стираем все страницы, используемые для EEPROM
|
||||
while (address < EEPROM_START_ADDRESS + EEPROM_SIZE) {
|
||||
if (EEPROM_ErasePage(address) != EEPROM_OK) {
|
||||
return EEPROM_ERROR;
|
||||
}
|
||||
address += EEPROM_PAGE_SIZE;
|
||||
}
|
||||
|
||||
eeprom_current_write_address = EEPROM_START_ADDRESS;
|
||||
eeprom_initialized = 1;
|
||||
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
// Получение информации об использовании EEPROM
|
||||
void EEPROM_GetInfo(uint32_t* used, uint32_t* total) {
|
||||
uint32_t address = EEPROM_START_ADDRESS;
|
||||
uint32_t used_bytes = 0;
|
||||
|
||||
if (used) {
|
||||
// Подсчитываем использованные байты
|
||||
while (address < EEPROM_START_ADDRESS + EEPROM_SIZE) {
|
||||
EEPROM_Item item;
|
||||
memcpy(&item, (void*)address, sizeof(EEPROM_Item));
|
||||
|
||||
if (item.address != 0xFFFF || item.data != 0xFFFF || item.timestamp != 0xFFFFFFFF) {
|
||||
used_bytes += sizeof(EEPROM_Item);
|
||||
}
|
||||
|
||||
address += sizeof(EEPROM_Item);
|
||||
}
|
||||
|
||||
*used = used_bytes;
|
||||
}
|
||||
|
||||
if (total) {
|
||||
*total = EEPROM_SIZE;
|
||||
}
|
||||
}
|
||||
123
john103C6T6/EEPROM_Emul/src/flash_ring.c
Normal file
123
john103C6T6/EEPROM_Emul/src/flash_ring.c
Normal file
@@ -0,0 +1,123 @@
|
||||
#include "flash_ring.h"
|
||||
|
||||
extern int last_page_addr;
|
||||
|
||||
|
||||
|
||||
|
||||
BufferState_t buffer_init(void) {
|
||||
BufferState_t state = {0};
|
||||
|
||||
// Ищем последнюю записанную запись
|
||||
for (int i = 0; i < RECORDS_PER_PAGE; i++) {
|
||||
uint32_t record_addr = LAST_PAGE_ADDR + (i * RECORD_SIZE);
|
||||
FlashRecord_t* record = (FlashRecord_t*)record_addr;
|
||||
|
||||
// Проверяем валидность записи (не 0xFFFFFFFF)
|
||||
if (record->timestamp != 0xFFFFFFFF) {
|
||||
state.write_index = i + 1;
|
||||
state.initialized = 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Если буфер заполнен, начинаем с начала
|
||||
if (state.write_index >= RECORDS_PER_PAGE) {
|
||||
state.write_index = 0;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef buffer_write_record(FlashRecord_t* record, BufferState_t* state) {
|
||||
HAL_StatusTypeDef status;
|
||||
|
||||
// Если нужно стереть страницу (начало нового цикла)
|
||||
if (state->write_index == 0 && state->initialized) {
|
||||
status = erase_flash_page();
|
||||
if (status != HAL_OK) return status;
|
||||
}
|
||||
|
||||
// Записываем данные
|
||||
uint32_t record_addr = last_page_addr + (state->write_index * RECORD_SIZE);
|
||||
|
||||
status = write_flash_record(record_addr, record);
|
||||
if (status != HAL_OK) return status;
|
||||
|
||||
// Обновляем индекс
|
||||
state->write_index++;
|
||||
if (state->write_index >= RECORDS_PER_PAGE) {
|
||||
state->write_index = 0;
|
||||
}
|
||||
|
||||
state->initialized = 1;
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef erase_flash_page(void) {
|
||||
HAL_FLASH_Unlock();
|
||||
|
||||
FLASH_EraseInitTypeDef EraseInit = {
|
||||
.TypeErase = FLASH_TYPEERASE_PAGES,
|
||||
.PageAddress = LAST_PAGE_ADDR,
|
||||
.NbPages = 1
|
||||
};
|
||||
|
||||
uint32_t page_error;
|
||||
HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&EraseInit, &page_error);
|
||||
|
||||
HAL_FLASH_Lock();
|
||||
return status;
|
||||
}
|
||||
// Запись одной записи
|
||||
HAL_StatusTypeDef write_flash_record(uint32_t address, FlashRecord_t* record) {
|
||||
HAL_FLASH_Unlock();
|
||||
HAL_StatusTypeDef status = HAL_OK;
|
||||
|
||||
// Записываем данные по 4 байта (слово)
|
||||
uint32_t* data_ptr = (uint32_t*)record;
|
||||
uint32_t words_to_write = (RECORD_SIZE + 3) / 4; // округление вверх
|
||||
|
||||
for (uint32_t i = 0; i < words_to_write; i++) {
|
||||
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,
|
||||
address + (i * 4),
|
||||
data_ptr[i]);
|
||||
if (status != HAL_OK) break;
|
||||
}
|
||||
|
||||
HAL_FLASH_Lock();
|
||||
return status;
|
||||
}
|
||||
|
||||
// Чтение записи по индексу
|
||||
FlashRecord_t* buffer_read_record(uint32_t index) {
|
||||
if (index >= RECORDS_PER_PAGE) return NULL;
|
||||
|
||||
uint32_t record_addr = LAST_PAGE_ADDR + (index * RECORD_SIZE);
|
||||
FlashRecord_t* record = (FlashRecord_t*)record_addr;
|
||||
|
||||
// Проверяем что запись не пустая
|
||||
if (record->timestamp == 0xFFFFFFFF) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return record;
|
||||
}
|
||||
// Получение всех записей в порядке от старых к новым
|
||||
void buffer_get_all_records(FlashRecord_t* records[], uint32_t* count) {
|
||||
*count = 0;
|
||||
BufferState_t state = buffer_init();
|
||||
|
||||
if (!state.initialized) return;
|
||||
|
||||
// Начинаем с текущего write_index (самые старые данные)
|
||||
for (int i = 0; i < RECORDS_PER_PAGE; i++) {
|
||||
uint32_t idx = (state.write_index + i) % RECORDS_PER_PAGE;
|
||||
FlashRecord_t* record = buffer_read_record(idx);
|
||||
|
||||
if (record) {
|
||||
records[(*count)++] = record;
|
||||
}
|
||||
}
|
||||
}
|
||||
154
john103C6T6/EEPROM_Emul/src/flash_ring.c.orig
Normal file
154
john103C6T6/EEPROM_Emul/src/flash_ring.c.orig
Normal file
@@ -0,0 +1,154 @@
|
||||
#include "flash_ring.h"
|
||||
|
||||
|
||||
uint8_t current_page = 0; // текущая страница для записи
|
||||
|
||||
|
||||
// Вычисление CRC16 (полином 0x8005)
|
||||
static uint16_t calc_crc16(const uint8_t *data, uint32_t len)
|
||||
{
|
||||
uint16_t crc = 0xFFFF;
|
||||
for (uint32_t i = 0; i < len; i++)
|
||||
{
|
||||
crc ^= data[i];
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
if (crc & 1) crc = (crc >> 1) ^ 0xA001;
|
||||
else crc >>= 1;
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
// Проверка заголовка страницы
|
||||
static bool is_page_valid(uint32_t addr)
|
||||
{
|
||||
PageHeader_t *hdr = (PageHeader_t *)addr;
|
||||
return (hdr->valid_marker == 0xDEADBEEF);
|
||||
}
|
||||
|
||||
// Инициализация: поиск актуальной страницы или очистка
|
||||
bool FlashRing_Init(void)
|
||||
{
|
||||
for (uint8_t i = 0; i < PAGE_COUNT; i++)
|
||||
{
|
||||
uint32_t addr = FLASH_BASE_USER + i * FLASH_PAGE_SIZE_USER;
|
||||
if (is_page_valid(addr))
|
||||
{
|
||||
current_page = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Если ни одна страница не актуальна — стираем обе
|
||||
if (FlashRing_EraseAll()!= 1) {
|
||||
return false; // Ошибка стирания
|
||||
}
|
||||
|
||||
|
||||
|
||||
current_page = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t CalculateCRC16(const uint8_t *data, uint32_t len) {
|
||||
uint16_t crc = 0xFFFF; // Начальное значение
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
crc ^= data[i];
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if (crc & 1) {
|
||||
crc = (crc >> 1) ^ 0xA001; // 0xA001 = обратный полином 0x8005
|
||||
} else {
|
||||
crc >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
// Стирание всех страниц
|
||||
int FlashRing_EraseAll(void)
|
||||
{
|
||||
HAL_FLASH_Unlock();
|
||||
FLASH_EraseInitTypeDef EraseInit =
|
||||
{
|
||||
.TypeErase = FLASH_TYPEERASE_PAGES,
|
||||
.PageAddress = FLASH_BASE_USER,
|
||||
.NbPages = PAGE_COUNT
|
||||
};
|
||||
uint32_t page_error;
|
||||
HAL_FLASHEx_Erase(&EraseInit, &page_error);
|
||||
// HAL_FLASHLock();
|
||||
HAL_FLASH_Lock();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Запись уставки
|
||||
bool FlashRing_Write(const Setpoint_t *sp)
|
||||
{
|
||||
uint32_t page_addr = FLASH_BASE_USER + current_page * FLASH_PAGE_SIZE_USER;
|
||||
PageHeader_t *hdr = (PageHeader_t *)page_addr;
|
||||
|
||||
// Если страница не инициализирована или заполнена — переключаемся
|
||||
if (!is_page_valid(page_addr) || hdr->count >= (FLASH_PAGE_SIZE_USER - sizeof(PageHeader_t)) / sizeof(Setpoint_t))
|
||||
{
|
||||
// Стираем следующую страницу
|
||||
uint8_t next_page = (current_page + 1) % PAGE_COUNT;
|
||||
uint32_t next_addr = FLASH_BASE_USER + next_page * FLASH_PAGE_SIZE_USER;
|
||||
|
||||
HAL_FLASH_Unlock();
|
||||
FLASH_EraseInitTypeDef EraseInit =
|
||||
{
|
||||
.TypeErase = FLASH_TYPEERASE_PAGES,
|
||||
.PageAddress = next_addr,
|
||||
.NbPages = 1
|
||||
};
|
||||
uint32_t page_error;
|
||||
HAL_FLASHEx_Erase(&EraseInit, &page_error);
|
||||
|
||||
current_page = next_page;
|
||||
page_addr = next_addr;
|
||||
|
||||
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, (uint32_t)&hdr->valid_marker, 0xDEADBEEF);
|
||||
HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, (uint32_t)&hdr->count, 0);
|
||||
HAL_FLASH_Lock();
|
||||
|
||||
}
|
||||
|
||||
// Вычисляем смещение для новой уставки
|
||||
uint8_t *data_start = (uint8_t *)page_addr + sizeof(PageHeader_t);
|
||||
uint16_t idx = hdr->count;
|
||||
Setpoint_t *dst = (Setpoint_t *)(data_start + idx * sizeof(Setpoint_t));
|
||||
|
||||
*dst = *sp;
|
||||
hdr->count++;
|
||||
|
||||
// Обновляем CRC
|
||||
hdr->crc = calc_crc16(data_start, hdr->count * sizeof(Setpoint_t));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Чтение уставки по индексу
|
||||
bool FlashRing_Read(uint16_t index, Setpoint_t *sp)
|
||||
{
|
||||
uint32_t page_addr = FLASH_BASE_USER + current_page * FLASH_PAGE_SIZE_USER;
|
||||
if (!is_page_valid(page_addr)) return false;
|
||||
|
||||
|
||||
PageHeader_t *hdr = (PageHeader_t *)page_addr;
|
||||
if (index >= hdr->count) return false;
|
||||
|
||||
uint8_t *data_start = (uint8_t *)page_addr + sizeof(PageHeader_t);
|
||||
*sp = *(Setpoint_t *)(data_start + index * sizeof(Setpoint_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Получение числа записанных уставок
|
||||
uint16_t FlashRing_GetCount(void)
|
||||
{
|
||||
uint32_t page_addr = FLASH_BASE_USER + current_page * FLASH_PAGE_SIZE_USER;
|
||||
if (!is_page_valid(page_addr)) return 0;
|
||||
PageHeader_t *hdr = (PageHeader_t *)page_addr;
|
||||
return hdr->count;
|
||||
}
|
||||
Reference in New Issue
Block a user