/** ************************************************************************** * @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 //#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