Files
STM32_MemorySPI/Inc/params_flash.h
Razvalyaev 643391038e Большой апгрейд:
- исправлены баги библиотеки memspi
- добавлены модули для сохранения настреок в eeprom и flash (с равномерным износом)
- надо тестить, проверять и рефакторить
2026-02-17 18:34:50 +03:00

276 lines
15 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.
/**
**************************************************************************
* @file params_flash.h
* @brief Заголовочный файл модуля записи параметров в Flash
**************************************************************************
* @details
Модуль позволяет сохранять данные в Flash и читать их обратно по номерам блоков.
@par Параметры
- @ref PARAMS_FLASH_MAX_BUFFER_SIZE - Максимальный размер блока данных
- @ref PARAMS_FLASH_ASYNCH_BUFFER_SIZE - Размер блока для записи в асинхронном режиме.
Заданное количество слов будет записыватся при каждом вызове @ref ParamsFlash_AsynchHandle
пока весь блок не будет записан
- @ref PARAMS_FLASH_ADDR_START - Начало области Flash для хранения параметров
- @ref PARAMS_FLASH_ADDR_END - Конец области Flash для хранения параметров
@par Пример использования
@code
#include "params_flash.h"
ParamsFlash_HandleInit(&flash_handle, 9, 10, 16); // Инициализация 9 и 10 секторов для записи, размер блока 16 слов
read_block_numb = ParamsFlash_ReadBlock(&flash_handle, PARAMS_LAST_BLOCK, read_data, size, read_size); // читаем последний блок
// ...
if(flag_to_write)
{
if(ParamsFlash_IsFlashFree(&flash_handle)) // првеоряем свободность флеш
{
ParamsFlash_WriteBlock(&flash_handle, PARAMS_LAST_BLOCK, data, size); // записываем новый блок
if(flash_handle.status == FLASH_BLOCK_FLASH_FULL) // если по какой-то причине не получилось
{
if(ParamsFlash_Pack(&flash_handle, 0)) // пробуем упаковку
{
// ошибка при ините упаковке, мб не удалось найти валидный блок
ParamsFlash_Pack(&flash_handle, 1); // erase без копирования блока
}
}
else // получилось
{
flag_to_write = 0; // успешно записали, сбрасываем флаг
}
}
}
// уходим и возврашаемся к этому коду позже...
@endcode
@par Возможности
- Каждый блок имеет уникальный номер (numb) и хранится в фиксированной
структуре @ref ParamsFlash_t
@code
[numb][size][data_start.......data_end][crc]
@endcode
- Блоки располагаются последовательно в выделенной области Flash.
В процессе работы хранится адрес куда будет записан следующий блок.
@code
[ParamsFlash_t #1][ParamsFlash_t #2][ParamsFlash_t #3]...
^
|
next_block_adr
@endcode
От next_block_adr вправо идет поиск свободного места. А влево идет поиск уже записанных блоков
@ref __ParamsFlash_FindBlock и @ref __ParamsFlash_FindFreeSpace для подробностей
- Можно создать несколько хендлов @ref ParamsFlashHandle_t, каждый из которых
будет работать с своими параметрами и своей областью Flash памяти.
Для работы с несколькими handle необходимо использовать разные сектора Flash памяти
@code
ParamsFlash_HandleInit(&flash_handle1, 9, 10, 16); // 9,10 сектора
ParamsFlash_HandleInit(&flash_handle2, 11, 12, 32); // 11,12 сектора
@endcode
- Запись и стирание происходит асихнронно @ref __ParamsFlash_WriteHandle и @ref __ParamsFlash_EraseHandle.
Поэтому надо удостоверится что функции @ref ParamsFlash_WriteBlock и @ref ParamsFlash_Pack вызываются корректно
и не накладываются друг на друга. Иначе может произойти игнорирование команд для записи/стирания. **См. Пример использования**
- При записи c @ref PARAMS_LAST_BLOCK номер нового блока вычисляется
автоматически (последний_номер + 1)
При записи конкретного блока он запишется только в том случае, если его номер не равен последнему номер
@code
writen_block_numb = ParamsFlash_WriteBlock(&flash_handle, PARAMS_LAST_BLOCK, data, size); // пишем с инкрементом
// ждем пока асихнронно запишется...
writen_block_numb = ParamsFlash_WriteBlock(&flash_handle, writen_block_numb, data, size); // ошибка
// ждем пока асихнронно запишется...
writen_block_numb = ParamsFlash_WriteBlock(&flash_handle, 1, data, size); // норм
@endcode
- При чтении c @ref PARAMS_LAST_BLOCK читается последний инициализированный блок
@code
read_block_numb = ParamsFlash_ReadBlock(&flash_handle, PARAMS_LAST_BLOCK, read_data, size, NULL);
@endcode
При чтении конкретного блока он считается только в том случае, если он валидный (CRC correct)
- При переполнении сектора Flash будет выполнено стирание текщуего сектора и переход на другой
Erase будет пытаться выполнится до тех пор пока не будет успеха.
Если вдруг будет ошибка FLASH_BLOCK_FLASH_FULL (нет места в flash, оба сектора заполнены и не стерты по какой-то причине).
Можно попытаться сделать упаковку. **См. Пример использования**.
- Поддерживается проверка целостности и корректности блоков
@code
if(ParamsFlash_VerifyBlock(&flash_handle, PARAMS_LAST_BLOCK, &last_valid_block_numb))
{
// crc неправильный или еще что-то
}
if(ParamsFlash_Compare(&flash_handle, block_numb, data, size))
{
// данные НЕ совпадают
}
@endcode
- При вызове каждой функции в структуре заполняется status по которому можно
отследить разные ошибки @ref FlashBlockStatus_t
*************************************************************************/
#ifndef PARAMS_FLASH_H
#define PARAMS_FLASH_H
#include "mylibs_include.h"
#include "memspi.h"
#include <string.h>
//#define TRACE_WRITE_READ //led1 трейс ParamsFlash_WriteBlock и ParamsFlash_ReadBlock
//#define TRACE_FIND_BLOCK //led1 трейс внутренниъх функцйи по поиску блоков/свобождных мест
//#define TRACE_FLASH_BUSY //led2 трейс заняносит флеш FLASH_WORKING_ENTER и FLASH_WORKING_EXIT
//#define TRACE_ASYNCH //led1 трейс работы asynch
//#define FLASH_WORKING_NONBLOCKING ///< Режим неблокирующей работы с Flash
#if !defined(PARAMS_FLASH_MAX_BUFFER_SIZE)
#define PARAMS_FLASH_MAX_BUFFER_SIZE 1096 ///< Максимальный размер блока данных
#endif
#if !defined(PARAMS_FLASH_ASYNCH_BUFFER_SIZE)
#define PARAMS_FLASH_ASYNCH_BUFFER_SIZE 100 ///< Размер блока для записи в асинхронном режиме. Заданное количество слов будет записыватся при каждом вызове @ref ParamsFlash_AsynchHandle
#endif
#if !defined(PARAMS_FLASH_ADDR_START)
#define PARAMS_FLASH_ADDR_START 0x0 ///< Начало допустимой адресации Flash
#endif
#if !defined(PARAMS_FLASH_ADDR_END)
#define PARAMS_FLASH_ADDR_END 0x1FFFF+1 ///< Конец допустимой адресации Flash
#endif
#define PARAMS_LAST_BLOCK 0xFFFF ///< Команда считать последний блок
#define FLASH_WORKING_CHECK(_h_) (flash_working == 1) ///< Проверка занятности Flash
#define FLASH_WORKING_ENTER(_h_) do{flash_working = 1; LED2_TRACE_ENTER(); /*DINT;flash_reset();*/ }while(0) ///< Начало работы с Flash
#define FLASH_WORKING_EXIT(_h_) do{flash_working = 0; LED2_TRACE_EXIT(); /*EnableInterrupts();*/ }while(0) ///< Конец работы с Flash
#ifndef SETTINGS_USE_MEMORY_EEPROM
#define EMPTY_MEMORY 0xFFFF
#else
#define EMPTY_MEMORY 0x0000
#endif
#define __SET_CURR_BLOCK(pcur, adr) do{ pcur = &__buff; MEMSPI_Read_Memory(&memory_spi, adr, (uint8_t *)pcur, sizeof(ParamsFlash_t), 1000); }while(0);
#define __WRITE_CURR_BLOCK(pcur, adr, size) MEMSPI_FLASH_Program(&memory_spi, adr, (uint8_t *)pcur, size, 1000, 1)
#define __READ_BYTE(adr, data, size) MEMSPI_Read_Memory(&memory_spi, adr, (uint8_t *)data, size, 1000)
//#define __SET_CURR_BLOCK(pcur) do{ cur = (volatile ParamsFlash_t*)addr }while(0);
/**
* @brief Варианты ошибок блока
*/
typedef enum {
FLASH_BLOCK_OK = 0, ///< Блок корректен
FLASH_BLOCK_EMPTY , ///< Блок не инициализирован
FLASH_BLOCK_CRC_ERROR , ///< CRC блока не совпадает
FLASH_BLOCK_ALREADY_EXIST , ///< Блок уже существует
FLASH_BLOCK_NOT_FOUND , ///< Блок не найден
FLASH_BLOCK_FLASH_FULL , ///< Нет места в Flash для блока
FLASH_BLOCK_INIT_ERR , ///< Ошибка инициализации блока (неадекватные параметры)
FLASH_BLOCK_WRITE_ERR , ///< Ошибка записи
FLASH_BLOCK_BUSY , ///< Работа с флеш уже идет
FLASH_BLOCK_UNKNOWN_ERR ///< Неизвестная ошибка
} FlashBlockStatus_t;
/**
* @brief Структура данных, которая будет положена в Flash
*/
typedef struct {
uint16_t numb; ///< Номер блока
uint16_t size; ///< Размер данных
uint16_t data[PARAMS_FLASH_MAX_BUFFER_SIZE]; ///< Буфер данных
uint16_t crc16; ///< CRC блока
} ParamsFlash_t;
/**
* @brief Handle конкретного сектора
*/
typedef struct {
// общая инфа о секторе
uint16_t sector_num; ///< Номер сектора
uint32_t addr_start; ///< Абсолютный адрес начала сектора
uint32_t addr_end; ///< Абсолютный адрес конца сектора
uint16_t size; ///< Размер сектора словах
uint16_t capacity; ///< Вместимость - сколько блоков можно положить
// всякие служебные штуки
uint32_t next_block_adr; ///< Адрес следующего блока в секторе
uint16_t erase_pending; ///< Флаг, что нужен erase сектора
} FlashSector_t;
/**
* @brief Handle для работы с конкретной областью Flash
*/
typedef struct {
int initialized; ///< Флаг что модуль успешно инициализирован
FlashSector_t sector[2]; ///< Два сектора для записи
int sect_curr_ind; ///< Номер текущего сектора (0 или 1)
uint16_t buffer_size; ///< Размер буфера в словах (1 слово = 16 бит)
ParamsFlash_t blk_tmp; ///< Временная структура для операций
uint32_t addr_start; ///< Начало текущей области Flash
uint32_t addr_end; ///< Конец текущей области Flash
uint32_t next_block_adr; ///< Адрес следующего блока
uint16_t write_pending; ///< Флаг для записи @ref blk_tmp в Flash
uint16_t write_word_cnt; ///< Количество записанных байт
FlashBlockStatus_t status; ///< Статус хендла
} ParamsFlashHandle_t;
/* ======= Инициализация модуля ======================================= */
/* Инициализация handle */
int ParamsFlash_HandleInit(ParamsFlashHandle_t *h, int sector_1, int sector_2, int buf_size);
/* Обработчик неблокирующей работы модуля */
int ParamsFlash_AsynchHandle(ParamsFlashHandle_t *h);
/* ======= Функции управления ======================================= */
/* Проверка свободности флеш */
int ParamsFlash_IsFlashFree(ParamsFlashHandle_t *h);
/* Запись блока во Flash */
int ParamsFlash_WriteBlock(ParamsFlashHandle_t *h, int block_num, const uint16_t *Buffer, int size);
/* Чтение блока из Flash */
int ParamsFlash_ReadBlock(ParamsFlashHandle_t *h, int block_num, uint16_t *Buffer, int size, int *read_size);
/* Упаковка Flash: стирание всей области и запись последнего блока в начало */
int ParamsFlash_Pack(ParamsFlashHandle_t *h, int force);
/* Полная инициализация Flash (стирание всей области) */
int ParamsFlash_Init(ParamsFlashHandle_t *h);
/* Проверка блока на корректность */
FlashBlockStatus_t ParamsFlash_VerifyBlock(ParamsFlashHandle_t *h, int block_num, int *last_valid_num);
/* Сравнение данных с блоком из Flash */
int ParamsFlash_Compare(ParamsFlashHandle_t *h, int block_num, const uint16_t *data, int size);
/* Получение статистики по блокам */
int ParamsFlash_GetInfo(ParamsFlashHandle_t *h, int *totalBlocks, int *validBlocks, int *invalidBlocks);
#if defined(TRACE_FLASH_BUSY)
#define LED2_TRACE_ENTER() i_led2_on_off(1);
#define LED2_TRACE_EXIT() i_led2_on_off(0);
#else
#define LED2_TRACE_ENTER()
#define LED2_TRACE_EXIT()
#endif
#define LED1_TRACE_ENTER() i_led1_on_off(1);
#define LED1_TRACE_EXIT() i_led1_on_off(0);
#endif //PARAMS_FLASH_H