Большой апгрейд:

- исправлены баги библиотеки memspi
- добавлены модули для сохранения настреок в eeprom и flash (с равномерным износом)
- надо тестить, проверять и рефакторить
This commit is contained in:
2026-02-17 18:34:50 +03:00
parent e9d2214953
commit 643391038e
8 changed files with 2534 additions and 193 deletions

380
Src/set_to_mem.c Normal file
View File

@@ -0,0 +1,380 @@
/**
**************************************************************************
* @file set_to_mem.c
* @brief Модуль для записи в память настроек.
*************************************************************************/
#include "set_to_mem.h"
/**
* @brief Инициализация одного массива настроек для хранения в памяти.
*
* @param array Указатель на структуру для записи настроек.
* @param pRealArray Указатель на реальные массива настроек.
* @param startadr Указатель на начальный адрес в памяти.
* @param sizeofarray Размер массива.
* @details Функция используется при @ref SETTINGS_USE_SETTINGS_FROM_POINTER
*/
HAL_StatusTypeDef Settings_AddArray(SettingsTypeDef *settings, uint8_t *pRealArray, uint32_t *startadr, uint32_t sizeofarray)
{
if(!settings || !pRealArray || !startadr || !sizeofarray)
return HAL_ERROR;
if(settings->setarr_count >= SETTINGS_MAX_ARRAYS)
return HAL_ERROR;
SettingArrayTypeDef *array = &settings->setarr[settings->setarr_count];
array->adr = *startadr; // Устанавливаем адрес начала массива настроек
array->length = sizeofarray; // Устанавливаем размер массива настроек
array->real_ptr = pRealArray;
#ifdef SETTINGS_USE_SETTINGS_FROM_POINTER
array->mem_ptr = pRealArray;
#else
if(settings->buffer == NULL)
{
settings->buffer = malloc(sizeofarray);
if(!settings->buffer)
return HAL_ERROR;
array->mem_ptr = settings->buffer;
settings->settings_size = sizeofarray;
}
else
{
// расширяем буфер под новый массив
uint8_t *newbuf = realloc(settings->buffer, settings->settings_size + sizeofarray);
if(!newbuf)
return HAL_ERROR;
settings->buffer = newbuf;
array->mem_ptr = settings->buffer + settings->settings_size;
settings->settings_size += sizeofarray;
}
#endif
*startadr += array->length; // Смещаем начальный адрес настроек
settings->setarr_count++;
return HAL_OK;
}
HAL_StatusTypeDef Settings_Init(SettingsTypeDef *settings, SPI_HandleTypeDef *hspi, uint32_t adr)
{
if(!settings)
return HAL_ERROR;
settings->start_adr = adr;
// settings->setarr_count = 0;
settings->settings_error = 0;
settings->hmemspi = &memory_spi;
MEMSPI_Base_Init(settings->hmemspi, hspi);
#ifdef SETTINGS_USE_WEAR_LEVELING_FLASH
if(MEMSPI_FLASH_Protection(&memory_spi, 0, 0x11000, 1000, 1) != HAL_OK)
{
return HAL_ERROR;
}
ParamsFlash_HandleInit(&settings->flash_handle, 0, 1, settings->settings_size);
if(MEMSPI_FLASH_Protection(&memory_spi, 0, 0x11000, 1000, 1) != HAL_OK)
{
return HAL_ERROR;
}
#endif
return HAL_OK;
}
/**
* @brief Запись настроек в память.
*
* @param settings Указатель на хендл для настроек.
* @details Записывает настройки в память, если установлен флаг обновления.
* Можно включить защиту @ref SETTINGS_MEMORY_PROTECT_ENABLE : добавляет защиту памяти перед записью и снимает её после.
*/
void Settings_WriteSettings(SettingsTypeDef *settings)
{
if(!settings)
return;
static int update_start = 0;
static uint32_t update_request_tick = 0;
HAL_StatusTypeDef res = HAL_OK;
#ifdef SETTINGS_USE_SETTINGS_FROM_BUFFER
// Сравниваем текущие настройки с буфером
for(int i = 0; i < settings->setarr_count; i++)
{
if(memcmp(settings->setarr[i].mem_ptr,
settings->setarr[i].real_ptr,
settings->setarr[i].length) != 0)
{
settings->update_settings_flag = 1;
break;
}
}
#endif
if(settings->update_settings_flag)
{
// if(GPIO_Read_Switch(&MZKT_DISCIN.err_24V))
// {
// printf_memspi_err("Power Err, cancel writing");
// settings->update_settings_flag = 0;
// update_start = 0;
// return;
// }
if(msDelayDone(1000, &update_request_tick))
{
update_start = 1;
}
}
else
{
msDelayStart(&update_request_tick);
update_start = 0;
}
if(update_start)
{
// Сбрасываем флаг обновления
settings->update_settings_flag = 0;
update_start = 0;
#ifdef SETTINGS_USE_SETTINGS_FROM_BUFFER
// Обновляем буфер новыми настройками
for(uint8_t i = 0; i < settings->setarr_count; i++)
{
memcpy( settings->setarr[i].mem_ptr,
settings->setarr[i].real_ptr,
settings->setarr[i].length);
}
#endif
// Записываем настройки в память
WriteSettingsToMem(settings);
Settings_CheckSettings(settings);
__enable_irq();
}
}
/**
* @brief Чтение настроек из памяти.
*
* @param settings Указатель на хендл для настроек.
* @details Включает:
* - Чтение настроек из памяти (`ReadSettingsFromMem`).
* - Обновление буфера, если используется @ref SETTINGS_USE_SETTINGS_FROM_BUFFER.
*/
void Settings_ReadSettings(SettingsTypeDef *settings)
{
if(!settings)
return;
__disable_irq();
ReadSettingsFromMem(settings);
#ifdef SETTINGS_USE_SETTINGS_FROM_BUFFER
for(uint8_t i = 0; i < settings->setarr_count; i++)
{
memcpy(settings->setarr[i].real_ptr,
settings->setarr[i].mem_ptr,
settings->setarr[i].length);
}
#endif
__enable_irq();
Settings_CheckSettings(settings);
}
/**
* @brief Проверить настройки на валидность.
*
* @param settings Указатель на хендл для настроек.
* @details Проверяет не пустые ли настройки. Если пустые - выставялет флаг ошибки.
*/
void Settings_CheckSettings(SettingsTypeDef *settings)
{
if(!settings)
return;
uint32_t total_size = 0;
uint32_t ff_cnt = 0;
for(uint8_t i = 0; i < settings->setarr_count; i++)
{
uint8_t *ptr = settings->setarr[i].mem_ptr;
uint32_t size = settings->setarr[i].length;
total_size += size;
for(uint32_t j = 0; j < size; j++)
{
if(ptr[j] == 0xFF)
ff_cnt++;
}
}
if(total_size && ff_cnt > total_size * 0.8)
settings->settings_error |= MEMORY_ERROR_EMPTY;
else
settings->settings_error &= ~MEMORY_ERROR_EMPTY;
printf_memspi("Zero Bytes: %u/%u", ff_cnt, total_size);
}
/**
* @brief Записи настроек в память в зависимости от конфигурации.
*
* @param settings Указатель на хендл для настроек.
* @details Реализация зависит от конфигурации:
* - @ref SETTINGS_USE_SETTINGS_FROM_POINTER : запись по отдельным указателям на различные массивы настроек.
* - @ref SETTINGS_USE_SETTINGS_FROM_BUFFER : запись всего буфера настроек целиком.
*/
void WriteSettingsToMem(SettingsTypeDef *settings)
{
HAL_StatusTypeDef res = HAL_OK;
#ifdef SETTINGS_USE_WEAR_LEVELING_FLASH
if(MEMSPI_FLASH_Protection(settings->hmemspi, 0, 0x11000, DISABLE, 1000) != HAL_OK)
{
settings->settings_error |= MEMORY_ERROR_WRITE;
return;
}
if(ParamsFlash_WriteBlock(&settings->flash_handle, PARAMS_LAST_BLOCK,
(uint16_t *)settings->buffer,
settings->settings_size) < 0)
{
res = HAL_ERROR;
}
if(MEMSPI_FLASH_Protection(settings->hmemspi, 0, 0x11000, ENABLE, 1000) != HAL_OK)
{
settings->settings_error |= MEMORY_ERROR_WRITE;
}
#else //SETTINGS_USE_WEAR_LEVELING_FLASH
if(MEMSPI_FLASH_Protection(settings->hmemspi, settings->start_adr, settings->settings_size, DISABLE, 1000) != HAL_OK)
{
settings->settings_error |= MEMORY_ERROR_WRITE;
return;
}
for(uint8_t i = 0; i < settings->setarr_count; i++)
{
WriteSettingsArrayToMem(settings, &settings->setarr[i]);
}
if(MEMSPI_FLASH_Protection(settings->hmemspi, settings->start_adr, settings->settings_size, DISABLE, 1000) != HAL_OK)
{
settings->settings_error |= MEMORY_ERROR_WRITE;
return;
}
#endif //SETTINGS_USE_WEAR_LEVELING_FLASH
if(res != HAL_OK)
{
printf_memspi_err("Write Error: %u", res);
settings->settings_error |= MEMORY_ERROR_WRITE;
}
else
{
printf_memspi("Write Ok");
settings->settings_error &= ~MEMORY_ERROR_WRITE;
}
}
/**
* @brief Читает настройки из памяти в зависимости от конфигурации.
*
* @param settings Указатель на хендл для настроек.
* @details Реализация зависит от конфигурации:
* - @ref SETTINGS_USE_SETTINGS_FROM_POINTER : чтение по отдельным указателям на различные массивы настроек.
* - @ref SETTINGS_USE_SETTINGS_FROM_BUFFER : чтение всего буфера настроек целиком.
*/
void ReadSettingsFromMem(SettingsTypeDef *settings)
{
HAL_StatusTypeDef res = HAL_OK;
#ifdef SETTINGS_USE_WEAR_LEVELING_FLASH
if(ParamsFlash_ReadBlock(&settings->flash_handle, PARAMS_LAST_BLOCK,
(uint16_t *)settings->buffer,
settings->settings_size, NULL) < 0)
{
res = HAL_ERROR;
}
#else //SETTINGS_USE_WEAR_LEVELING_FLASH
for(uint8_t i = 0; i < settings->setarr_count; i++)
{
ReadSettingsArrayFromMem(settings, &settings->setarr[i]);
}
#endif //SETTINGS_USE_WEAR_LEVELING_FLASH
if(res != HAL_OK)
{
printf_memspi_err("Read Error: %u", res);
}
else
{
printf_memspi("Read Ok");
}
}
/**
* @brief Записывает массив настроек через указатель в память.
*
* @param settings Указатель на хендл для настроек.
* @param settingarr Указатель на структуру для записи массива настроек.
* @details Функция используется при @ref SETTINGS_USE_SETTINGS_FROM_POINTER
*/
void WriteSettingsArrayToMem(SettingsTypeDef *settings, SettingArrayTypeDef *settingarr)
{
#ifndef SETTINGS_USE_MEMORY_EEPROM
MEMSPI_WriteInitTypeDef writeinit;
writeinit.Data_Address = settingarr->adr;
writeinit.Data_Size = settingarr->length;
writeinit.Sector_Address = settings->start_adr;
writeinit.Sector_Size = settings->settings_size;
writeinit.fSavePrevoisData = 1;
writeinit.pDataPtr = settingarr->mem_ptr;
if(MEMSPI_FLASH_Write(settings->hmemspi, &writeinit, 1000, 1) != HAL_OK)
{
settings->settings_error |= MEMORY_ERROR_WRITE;
return;
}
#else
if(MEMSPI_EEPROM_Write(settings->hmemspi, settingarr->adr, settingarr->mem_ptr, settingarr->length, 1000, 1) != HAL_OK)
{
settings->settings_error |= MEMORY_ERROR_WRITE;
return;
}
#endif
}
/**
* @brief Читает массив настроек через указатель в память.
*
* @param settings Указатель на хендл для настроек.
* @param settingarr Указатель на структуру для записи массива настроек.
* @details Функция используется при @ref SETTINGS_USE_SETTINGS_FROM_POINTER
*/
void ReadSettingsArrayFromMem(SettingsTypeDef *settings, SettingArrayTypeDef *settingarr)
{
MEMSPI_Read_Memory(settings->hmemspi, settingarr->adr, settingarr->mem_ptr, settingarr->length, 1000);
}