Большой апгрейд:
- исправлены баги библиотеки memspi - добавлены модули для сохранения настреок в eeprom и flash (с равномерным износом) - надо тестить, проверять и рефакторить
This commit is contained in:
18
Inc/memspi.h
18
Inc/memspi.h
@@ -39,31 +39,35 @@
|
||||
#define __SPI_MEMORY_H_
|
||||
|
||||
#include "memspi_core.h"
|
||||
|
||||
extern MEMSPI_HandleTypeDef memory_spi;
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
///////////////////////---FUNCTIONS FOR USER---//////////////////////
|
||||
/* Initialize SPI and GPIO for MEMSPI FLASH */
|
||||
void MEMSPI_Base_Init(MEMSPI_HandleTypeDef *hmemspi, SPI_HandleTypeDef *hspi);
|
||||
/* Read external FLASH */
|
||||
HAL_StatusTypeDef MEMSPI_Read_Memory(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pBuff, uint16_t Size, uint32_t Timeout);
|
||||
HAL_StatusTypeDef MEMSPI_Read_Memory(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pBuff, uint32_t Size, uint32_t Timeout);
|
||||
/* Write external EEPROM */
|
||||
HAL_StatusTypeDef MEMSPI_EEPROM_Write(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout, uint8_t WaitForEnd);
|
||||
HAL_StatusTypeDef MEMSPI_EEPROM_Write(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint32_t Size, uint32_t Timeout, uint8_t WaitForEnd);
|
||||
/* Write external FLASH */
|
||||
HAL_StatusTypeDef MEMSPI_FLASH_Write(MEMSPI_HandleTypeDef *hmemspi, MEMSPI_WriteInitTypeDef *WriteInit, uint32_t Timeout, uint8_t WaitForEnd);
|
||||
/* Program external FLASH */
|
||||
HAL_StatusTypeDef MEMSPI_FLASH_Program(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout, uint8_t WaitForEnd);
|
||||
HAL_StatusTypeDef MEMSPI_FLASH_Program(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint32_t Size, uint32_t Timeout, uint8_t WaitForEnd);
|
||||
/* Erase external FLASH */
|
||||
HAL_StatusTypeDef MEMSPI_FLASH_Erase(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint16_t Size, uint32_t Timeout, uint8_t WaitForEnd);
|
||||
HAL_StatusTypeDef MEMSPI_FLASH_Erase(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint32_t Size, uint32_t Timeout, uint8_t WaitForEnd);
|
||||
/* @brief Set protection for FLASH sectors */
|
||||
HAL_StatusTypeDef MEMSPI_FLASH_Protection(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint32_t Size, uint32_t ProtectState, uint32_t Timeout);
|
||||
///////////////////////---FUNCTIONS FOR USER---//////////////////////
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
////////////////////////---SERVICE FUNCTIONS---//////////////////////
|
||||
/* Write page in external EEPROM */
|
||||
HAL_StatusTypeDef MEMSPI_EEPROM_Write_Page(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t *Timeout, uint32_t *tickstart, uint8_t WaitForEnd);
|
||||
HAL_StatusTypeDef MEMSPI_EEPROM_Write_Page(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint32_t Size, uint32_t *Timeout, uint32_t *tickstart, uint8_t WaitForEnd);
|
||||
/* Erase external FLASH Sector */
|
||||
HAL_StatusTypeDef MEMSPI_FLASH_Erase_Sector(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint32_t *Timeout, uint32_t *tickstart, uint8_t WaitForEnd);
|
||||
/* Program page in external FLASH */
|
||||
HAL_StatusTypeDef MEMSPI_FLASH_Program_Page(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t *Timeout, uint32_t *tickstart, uint8_t WaitForEnd);
|
||||
HAL_StatusTypeDef MEMSPI_FLASH_Program_Page(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint32_t Size, uint32_t *Timeout, uint32_t *tickstart, uint8_t WaitForEnd);
|
||||
/* Program data in external FLASH */
|
||||
HAL_StatusTypeDef MEMSPI_FLASH_Program_Bytes(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint32_t Size, uint32_t *Timeout, uint32_t *tickstart, uint8_t WaitForEnd);
|
||||
/* Setting WEL bit until it setted or until timeout */
|
||||
HAL_StatusTypeDef MEMSPI_WriteEnablingUntilTimeout(MEMSPI_HandleTypeDef *hmemspi, uint32_t *Timeout, uint32_t *tickstart);
|
||||
/* Wait for flag until timeout */
|
||||
|
||||
@@ -26,30 +26,61 @@
|
||||
|
||||
#include "memspi_config.h"
|
||||
|
||||
#ifndef local_time
|
||||
#define local_time() HAL_GetTick() ///< Локальное время
|
||||
#endif
|
||||
|
||||
/** @defgroup MEMSPI_Commands Memory SPI Commands
|
||||
* @brief Определения команд SPI-памяти
|
||||
* @{
|
||||
*/
|
||||
#define MEMSPI_READ_JEDEC_ID 0x9F ///< Команда чтения JEDEC ID
|
||||
#define MEMSPI_READ_UNIQUE_ID 0x4B ///< Команда чтения уникального идентификатора
|
||||
|
||||
#ifdef RUFLASH
|
||||
|
||||
#define MEMSPI_READ_DATA (0x03)
|
||||
|
||||
#define MEMSPI_ERASE_SECTOR (0xD8)
|
||||
#define MEMSPI_ERASE_CHIP (0x60)
|
||||
|
||||
#define MEMSPI_WRITE_ENABLE (0x06)
|
||||
#define MEMSPI_WRITE_DISABLE (0x04)
|
||||
|
||||
#define MEMSPI_PAGE_PROGRAM (0x02)
|
||||
#define MEMSPI_BYTE_PROGRAM (0x02)
|
||||
#define MEMSPI_WRITE_EEPROM (MEMSPI_PAGE_PROGRAM)
|
||||
|
||||
#define MEMSPI_PROTECT_SECTOR (0x36)
|
||||
#define MEMSPI_UNPROTECT_SECTOR (0x39)
|
||||
#define MEMSPI_READ_PROTECT_REG (0x3C)
|
||||
|
||||
|
||||
#define MEMSPI_READ_STATUS_REG (0x05)
|
||||
#if defined(SEPARATED_STATUS_REGISTER)
|
||||
#define MEMSPI_READ_STATUS_REG_2 (0x35)
|
||||
#endif
|
||||
#define MEMSPI_WRITE_STATUS_REG (0x01)
|
||||
|
||||
|
||||
#define MEMSPI_READ_JEDEC_ID (0x9F)
|
||||
#define MEMSPI_READ_UNIQUE_ID (0x4B)
|
||||
|
||||
#else
|
||||
#define MEMSPI_READ_DATA 0x03 ///< Чтение данных из памяти
|
||||
|
||||
#define MEMSPI_ERASE_SECTOR 0x20 ///< Стирание одного сектора
|
||||
|
||||
#define MEMSPI_WRITE_ENABLE 0x06 ///< Разрешение записи
|
||||
#define MEMSPI_WRITE_DISABLE 0x04 ///< Запрещение записи
|
||||
#define MEMSPI_WRITE_STATUS_REG 0x01 ///< Запись в регистр состояния
|
||||
#define MEMSPI_ERASE_SECTOR 0x20 ///< Стирание одного сектора
|
||||
|
||||
#define MEMSPI_PAGE_PROGRAM 0x02 ///< Программирование одной страницы
|
||||
#define MEMSPI_WRITE_EEPROM MEMSPI_PAGE_PROGRAM ///< Псевдоним для программирования EEPROM
|
||||
#define MEMSPI_READ_STATUS_REG 0x05 ///< Чтение регистра состояния
|
||||
|
||||
#define MEMSPI_READ_STATUS_REG 0x05 ///< Чтение регистра состояния
|
||||
#if defined(MEMSPI_SEPARATED_STATUS_REGISTER)
|
||||
#define MEMSPI_READ_STATUS_REG_2 0x35 ///< Чтение второго регистра состояния (если поддерживается)
|
||||
#endif
|
||||
#define MEMSPI_WRITE_STATUS_REG 0x01 ///< Запись в регистр состояния
|
||||
|
||||
#define MEMSPI_READ_DATA 0x03 ///< Чтение данных из памяти
|
||||
|
||||
#define MEMSPI_READ_JEDEC_ID 0x9F ///< Команда чтения JEDEC ID
|
||||
#define MEMSPI_READ_UNIQUE_ID 0x4B ///< Команда чтения уникального идентификатора
|
||||
#endif
|
||||
/** //MEMSPI_Commands
|
||||
* @}
|
||||
*/
|
||||
@@ -82,6 +113,8 @@
|
||||
#define MEMSPI_SR_SRWD MEMSPI_SR_SRP0 ///< Status Register Write Disable (аналог SRP0)
|
||||
#define MEMSPI_SR_WIP MEMSPI_SR_WEL ///< Write-In-Progress (используется в некоторых EEPROM)
|
||||
|
||||
// Exclusive (by name) RUFLASH SR bits
|
||||
#define MEMSPI_SR_EPE (1<<5) ///< Ошибка/стирания записи
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@@ -144,8 +177,16 @@ HAL_StatusTypeDef MEMSPI_CMD_Read_Data(MEMSPI_HandleTypeDef *hmemspi, uint32_t F
|
||||
HAL_StatusTypeDef MEMSPI_CMD_EEPROM_Write(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout);
|
||||
/* Send command to page program in FLASH */
|
||||
HAL_StatusTypeDef MEMSPI_CMD_FLASH_Page_Program(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout);
|
||||
/* Send command to byte program in FLASH */
|
||||
HAL_StatusTypeDef MEMSPI_CMD_FLASH_Byte_Program(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t Byte, uint32_t Timeout);
|
||||
/* Send command to erase sector of FLASH */
|
||||
HAL_StatusTypeDef MEMSPI_CMD_FLASH_Erase_Sector(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint32_t Timeout);
|
||||
/* Send command to Unprotect Sector */
|
||||
HAL_StatusTypeDef MEMSPI_CMD_Unprotect_Sector(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint32_t Timeout);
|
||||
/* Send command to Protect sector */
|
||||
HAL_StatusTypeDef MEMSPI_CMD_Protect_Sector(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint32_t Timeout);
|
||||
/* Send command to read Sector Protection Register */
|
||||
HAL_StatusTypeDef MEMSPI_CMD_Read_Sector_Protection(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pStatus, uint32_t Timeout);
|
||||
/* Send command to read JEDEC ID */
|
||||
uint32_t MEMSPI_CMD_Read_JEDEC_ID(MEMSPI_HandleTypeDef *hmemspi, uint32_t Timeout);
|
||||
/* Send command to read JEDEC ID */
|
||||
@@ -158,6 +199,17 @@ HAL_StatusTypeDef MEMSPI_CMD_Fast_Read(MEMSPI_HandleTypeDef *hmemspi, uint32_t F
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifndef local_time
|
||||
#define local_time() HAL_GetTick() ///< Локальное время
|
||||
#endif
|
||||
|
||||
#ifndef printf_memspi
|
||||
#define printf_memspi(...)
|
||||
#endif
|
||||
#ifndef printf_memspi_err
|
||||
#define printf_memspi_err(...)
|
||||
#endif
|
||||
|
||||
#endif // __SPI_MEMORY_CORE_H_
|
||||
|
||||
/** //MEMSPI_CORE
|
||||
|
||||
275
Inc/params_flash.h
Normal file
275
Inc/params_flash.h
Normal file
@@ -0,0 +1,275 @@
|
||||
/**
|
||||
**************************************************************************
|
||||
* @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
|
||||
136
Inc/set_to_mem.h
Normal file
136
Inc/set_to_mem.h
Normal file
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
**************************************************************************
|
||||
* @file set_to_mem.h
|
||||
* @brief Заголовочный файл для записи в память настроек.
|
||||
**************************************************************************
|
||||
* @defgroup SETMEM_TOOLS Settings to Memory Tools
|
||||
* @brief Модуль для записи/считывания настроек в память
|
||||
**************************************************************************
|
||||
@details Есть следующие настройки:
|
||||
|
||||
- @ref SETTINGS_USE_SETTINGS_FROM_BUFFER : выкидывать в память данные по указателю на разные настройки
|
||||
- Для работы надо объявить в структуре данные которые будут записываться (@ref SettingsInMemTypeDef)
|
||||
и указатели на эти данные (@ref SettingsSourceTypeDef)
|
||||
- Добавить @ref CompareSettings на каждый массив настроек, для отслеживания изменений.
|
||||
При отличии - выставляется флаг для записи настроек в память
|
||||
- Добавить @ref WriteSettingToBuffer и @ref ReadSettingFromBuffer для синхронизации
|
||||
каждого элемента структуры буфера и реальных настроек.
|
||||
|
||||
(_CompareSettings`, WriteSettingToBuffer` и ReadSettingFromBuffer` это дефайны которые принимают название элемента структуры и уже вызывают нужные функции_)
|
||||
|
||||
|
||||
- @ref SETTINGS_USE_SETTINGS_FROM_POINTER : заполнять необходимыми настройками буфер и полностью выкидывать его в память
|
||||
- Для работы надо объявить в структуре данные которые будут записываться (@ref SettingsInMemTypeDef)
|
||||
- Инициализировать каждый элемент структуры функцией @ref InitSettingsToMem
|
||||
- Добавить @ref WriteSettingsArrayToMem и @ref ReadSettingsArrayFromMem для записи/считывания
|
||||
каждого элемента структуры в память
|
||||
- Выставлять флаг @ref update_settings_flag для записи настроек в память,
|
||||
когда необходимо это сделать (само по себе оно не может определить когда надо записать,
|
||||
т.к. нет буфера для отслеживания изменений)
|
||||
|
||||
- @ref SETTINGS_MEMORY_PROTECT_ENABLE : включение защиты на память.
|
||||
Перед записью защита снимается, и после записи ставится обратно.
|
||||
* @{
|
||||
*************************************************************************/
|
||||
#ifndef _SET_TO_MEM_H_
|
||||
#define _SET_TO_MEM_H_
|
||||
|
||||
#include "mylibs_include.h"
|
||||
#include "params_flash.h"
|
||||
#include "memspi.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief Структура для записи одного массива настроек по указателю.
|
||||
* @details Используется при @ref SETTINGS_USE_SETTINGS_FROM_POINTER
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t adr; ///< Адрес в памяти
|
||||
uint32_t length; ///< Размер блока
|
||||
|
||||
uint8_t *real_ptr; ///< Указатель на реальные рабочие данные
|
||||
uint8_t *mem_ptr; ///< Указатель на данные, которые пишутся в память
|
||||
}SettingArrayTypeDef;
|
||||
|
||||
|
||||
#define MEMORY_ERROR_EMPTY ((uint32_t)(1<<0)) ///< Бит ошибки - память пустая
|
||||
#define MEMORY_ERROR_WRITE ((uint32_t)(1<<1)) ///< Бит ошибки - запись
|
||||
#define MEMORY_ERROR_READ ((uint32_t)(1<<2)) ///< Бит ошибки - чтение
|
||||
|
||||
/**
|
||||
* @brief Структура для хранения настроек устройства.
|
||||
* @details Содержит указатели на настройки и другие параметры для их обработки.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
MEMSPI_HandleTypeDef *hmemspi; ///< Указатель на хендл для работы с памятью
|
||||
|
||||
#ifdef SETTINGS_USE_WEAR_LEVELING_FLASH
|
||||
ParamsFlashHandle_t flash_handle; ///< Хендл для равномерного использования флеш памяти
|
||||
#endif
|
||||
|
||||
#ifdef SETTINGS_USE_SETTINGS_FROM_BUFFER
|
||||
uint8_t *buffer;
|
||||
#endif
|
||||
|
||||
SettingArrayTypeDef setarr[32]; ///< Структура настроек для хранения в памяти
|
||||
uint8_t setarr_count;
|
||||
|
||||
uint32_t start_adr; ///< Начальный адрес в памяти для записи настроек
|
||||
uint32_t settings_size; ///< Размер всего массива настроек
|
||||
|
||||
uint8_t update_settings_flag; ///< Флаг для обновления настроек в памяти
|
||||
uint32_t settings_error; ///< Флаг ошибки настроек
|
||||
}SettingsTypeDef;
|
||||
extern SettingsTypeDef Settings;
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup SETMEM_GENERAL_FUNC General functions for writing/reading settings
|
||||
* @ingroup SETMEM_TOOLS
|
||||
* @brief Общие функции для работы с настройками в памяти.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Инициализаия обзего хендла для работы с настройками */
|
||||
HAL_StatusTypeDef Settings_Init(SettingsTypeDef *settings, SPI_HandleTypeDef *hspi, uint32_t adr);
|
||||
/* Добавление массива настроек для хранения в памяти */
|
||||
HAL_StatusTypeDef Settings_AddArray(SettingsTypeDef *settings, uint8_t *pRealArray, uint32_t *startadr, uint32_t sizeofarray);
|
||||
/* Запись настроек в память */
|
||||
void Settings_WriteSettings(SettingsTypeDef *settings);
|
||||
/* Чтение настроек из памяти */
|
||||
void Settings_ReadSettings(SettingsTypeDef *settings);
|
||||
/* Проверить настройки на валидность. */
|
||||
void Settings_CheckSettings(SettingsTypeDef *settings);
|
||||
|
||||
/** SETMEM_GENERAL_FUNC
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup SETMEM_SUPPORT_FUNC Support functions for writing/reading
|
||||
* @ingroup SETMEM_TOOLS
|
||||
* @brief Служебные функции для работы с настройками в памяти
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Запись настроек в память в зависимости от конфигурации */
|
||||
void WriteSettingsToMem(SettingsTypeDef *settings);
|
||||
/* Чтение настроек из памяти в зависимости от конфигурации */
|
||||
void ReadSettingsFromMem(SettingsTypeDef *settings);
|
||||
|
||||
/* Записывает массив настроек через указатель в память */
|
||||
void WriteSettingsArrayToMem(SettingsTypeDef *settings, SettingArrayTypeDef *settingarr);
|
||||
/* итает массив настроек через указатель в память */
|
||||
void ReadSettingsArrayFromMem(SettingsTypeDef *settings, SettingArrayTypeDef *settingarr);
|
||||
|
||||
/** SETMEM_SUPPORT_FUNC
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** SETMEM_TOOLS
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif //_SET_TO_MEM_H_
|
||||
312
Src/memspi.c
312
Src/memspi.c
@@ -21,6 +21,7 @@
|
||||
#include "memspi.h"
|
||||
uint8_t sector_buff[MEMSPI_SECTOR_SIZE];
|
||||
|
||||
MEMSPI_HandleTypeDef memory_spi;
|
||||
//-------------------------------------------------------------
|
||||
//--------------------------FOR USER---------------------------
|
||||
/**
|
||||
@@ -63,7 +64,7 @@ void MEMSPI_Base_Init(MEMSPI_HandleTypeDef *hmemspi, SPI_HandleTypeDef *hspi)
|
||||
* @return HAL status.
|
||||
* @note Включает в себя проверку на доступность памяти (флаг BUSY)
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_Read_Memory(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pBuff, uint16_t Size, uint32_t Timeout)
|
||||
HAL_StatusTypeDef MEMSPI_Read_Memory(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pBuff, uint32_t Size, uint32_t Timeout)
|
||||
{
|
||||
HAL_StatusTypeDef MEMSPI_Status;
|
||||
uint32_t tickstart = local_time();
|
||||
@@ -90,7 +91,7 @@ HAL_StatusTypeDef MEMSPI_Read_Memory(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLA
|
||||
* @return HAL status.
|
||||
* @note Позволяет записать участок памяти. Можно записывать несколько страниц.
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_EEPROM_Write(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout, uint8_t WaitForEnd)
|
||||
HAL_StatusTypeDef MEMSPI_EEPROM_Write(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint32_t Size, uint32_t Timeout, uint8_t WaitForEnd)
|
||||
{
|
||||
uint32_t tickstart = local_time();
|
||||
HAL_StatusTypeDef MEMSPI_Status;
|
||||
@@ -180,7 +181,7 @@ HAL_StatusTypeDef MEMSPI_FLASH_Write(MEMSPI_HandleTypeDef *hmemspi, MEMSPI_Write
|
||||
uint32_t addr_shift = WriteInit->Data_Address - WriteInit->Sector_Address;
|
||||
for(int i = 0; i < WriteInit->Data_Size; i++)
|
||||
{
|
||||
sector_buff[addr_shift+i] = WriteInit->pDataPtr[addr_shift+i];
|
||||
sector_buff[addr_shift+i] = WriteInit->pDataPtr[i];
|
||||
}
|
||||
|
||||
// CALC AREA TO REPROGRAM
|
||||
@@ -243,54 +244,57 @@ HAL_StatusTypeDef MEMSPI_FLASH_Write(MEMSPI_HandleTypeDef *hmemspi, MEMSPI_Write
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Program external FLASH.
|
||||
* @param hmemspi Указатель на хендл внешней памяти.
|
||||
* @param FLASH_Address Адресс куда начинать записывать.
|
||||
* @param pData Откуда брать данные для записи в FLASH.
|
||||
* @param Size Вколько байтов записать.
|
||||
* @param Timeout Время, за которое должно быть осуществлено чтение.
|
||||
* @param WaitForEnd Ожидание, пока память не выполненит операцию.
|
||||
* @return HAL status.
|
||||
* @note Программирование участка памяти, без ограничений на кол-во байт
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_FLASH_Program(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout, uint8_t WaitForEnd)
|
||||
* @brief Program external FLASH.
|
||||
* @param hmemspi - указатель на хендл внешней памяти.
|
||||
* @param FLASH_Address - адресс куда начинать записывать.
|
||||
* @param pData - откуда брать данные для записи в FLASH.
|
||||
* @param Size - сколько байтов записать.
|
||||
* @param Timeout - время, за которое должно быть осуществлено чтение.
|
||||
* @param WaitForEnd - ожидание, пока память не выполненит операцию.
|
||||
* @return HAL status.
|
||||
* @note Программирование участка памяти, без ограничений на кол-во байт
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_FLASH_Program(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint32_t Size, uint32_t Timeout, uint8_t WaitForEnd)
|
||||
{
|
||||
uint32_t tickstart = local_time();
|
||||
HAL_StatusTypeDef MEMSPI_Status;
|
||||
|
||||
// CALC AREA TO PROGRAM
|
||||
uint16_t lastpage_size = Size;
|
||||
uint16_t firstpage = (FLASH_Address/MEMSPI_PAGE_SIZE);
|
||||
uint16_t lastpage = ((FLASH_Address+Size-1)/MEMSPI_PAGE_SIZE);
|
||||
if(firstpage != lastpage) // if area is on several pages
|
||||
{
|
||||
lastpage_size = (FLASH_Address+Size) - lastpage*MEMSPI_PAGE_SIZE; // set size of data on last page
|
||||
}
|
||||
|
||||
// PROGRAM PAGES: FROM FIRST NO THE PREVIOUS TO THE LAST
|
||||
hmemspi->hNextAddr = FLASH_Address; // address would automatically increase in this variable
|
||||
hmemspi->hNextPage = firstpage+1; // address would automatically increase in this variable
|
||||
uint16_t bytecnt = 0;
|
||||
uint16_t bytes_to_next_page = 0;
|
||||
for(int i = 0; i < lastpage - firstpage; i++)
|
||||
{
|
||||
// calc bytes to next sector
|
||||
bytes_to_next_page = hmemspi->hNextPage*MEMSPI_PAGE_SIZE - hmemspi->hNextAddr;
|
||||
|
||||
MEMSPI_Status = MEMSPI_FLASH_Program_Page(hmemspi, hmemspi->hNextAddr, &pData[bytecnt], bytes_to_next_page, &Timeout, &tickstart, 0); // programm page
|
||||
if(MEMSPI_Status != HAL_OK) // note: no need waiting for end: the next call will wait for unbusy
|
||||
return MEMSPI_Status;
|
||||
|
||||
// then we shift byte count to data, that shoud be on the next page
|
||||
bytecnt += bytes_to_next_page;
|
||||
}
|
||||
|
||||
// PROGRAM LAST PAGE
|
||||
MEMSPI_Status = MEMSPI_FLASH_Program_Page(hmemspi, hmemspi->hNextAddr, &pData[bytecnt], lastpage_size, &Timeout, &tickstart, WaitForEnd); // programm page
|
||||
if(MEMSPI_Status != HAL_OK)
|
||||
return MEMSPI_Status;
|
||||
|
||||
return HAL_OK; // if all ok return HAL_OK
|
||||
uint32_t tickstart = HAL_GetTick();
|
||||
HAL_StatusTypeDef MEMSPI_Status;
|
||||
|
||||
#ifdef FLASHTYPE_BYTE_PROGRAMM
|
||||
// PROGRAM DATA: FROM FIRST BYTE TO THE LAST
|
||||
MEMSPI_Status = MEMSPI_FLASH_Program_Bytes(hmemspi, FLASH_Address, pData, Size, &Timeout, &tickstart, WaitForEnd); // programm data
|
||||
if(MEMSPI_Status != HAL_OK)
|
||||
return MEMSPI_Status;
|
||||
#else
|
||||
// CALC AREA TO PROGRAM
|
||||
uint16_t lastpage_size = Size;
|
||||
uint16_t firstpage = (FLASH_Address/MEMSPI_PAGE_SIZE);
|
||||
uint16_t lastpage = ((FLASH_Address+Size-1)/MEMSPI_PAGE_SIZE);
|
||||
if(firstpage != lastpage) // if area is on several pages
|
||||
{
|
||||
lastpage_size = (FLASH_Address+Size) - lastpage*MEMSPI_PAGE_SIZE; // set size of data on last page
|
||||
}
|
||||
|
||||
// PROGRAM PAGES: FROM FIRST PAGE TO THE PREVIOUS TO THE LAST
|
||||
hmemspi->hNextAddr = FLASH_Address; // address would automatically increase in this variable
|
||||
hmemspi->hNextPage = firstpage+1; // address would automatically increase in this variable
|
||||
uint16_t bytecnt = 0;
|
||||
for(int i = 0; i < lastpage - firstpage; i++)
|
||||
{
|
||||
// calc bytes to next sector
|
||||
hmemspi->TxSize = hmemspi->hNextPage*MEMSPI_PAGE_SIZE - hmemspi->hNextAddr;
|
||||
|
||||
MEMSPI_Status = MEMSPI_FLASH_Program_Page(hmemspi, hmemspi->hNextAddr, &pData[bytecnt], hmemspi->TxSize, &Timeout, &tickstart, 0); // programm page
|
||||
if(MEMSPI_Status != HAL_OK) // note: no need waiting for end: the next call will wait for unbusy
|
||||
return MEMSPI_Status;
|
||||
// then we shift byte count to data, that shoud be on the next page
|
||||
bytecnt += hmemspi->TxSize;
|
||||
}
|
||||
// PROGRAM LAST PAGE
|
||||
MEMSPI_Status = MEMSPI_FLASH_Program_Page(hmemspi, hmemspi->hNextAddr, &pData[bytecnt], lastpage_size, &Timeout, &tickstart, WaitForEnd); // programm page
|
||||
if(MEMSPI_Status != HAL_OK)
|
||||
return MEMSPI_Status;
|
||||
#endif
|
||||
return HAL_OK; // if all ok return HAL_OK
|
||||
}
|
||||
|
||||
|
||||
@@ -305,7 +309,7 @@ HAL_StatusTypeDef MEMSPI_FLASH_Program(MEMSPI_HandleTypeDef *hmemspi, uint32_t F
|
||||
* @note Т.к. очитска происходит по секторам, Size нужен, чтобы определить сколько секторов очистить
|
||||
* И если начальны адресс будет на Sector 0, а последний байт на Sector 1, то произойдет очистка Sector 0 и Sector 1
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_FLASH_Erase(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint16_t Size, uint32_t Timeout, uint8_t WaitForEnd)
|
||||
HAL_StatusTypeDef MEMSPI_FLASH_Erase(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint32_t Size, uint32_t Timeout, uint8_t WaitForEnd)
|
||||
{
|
||||
uint32_t tickstart = local_time();
|
||||
HAL_StatusTypeDef MEMSPI_Status;
|
||||
@@ -325,7 +329,70 @@ HAL_StatusTypeDef MEMSPI_FLASH_Erase(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLA
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set protection for FLASH sectors.
|
||||
* @param hmemspi Указатель на хендл внешней памяти.
|
||||
* @param FLASH_Address Адресс сектора для выставления защиты.
|
||||
* @param Size Сколько байтов защитить.
|
||||
* @param ProtectState Состояние защиты: ENABLE / DISABLE.
|
||||
* @param Timeout Время, за которое должно быть осуществлено выставление защиты.
|
||||
* @return HAL status.
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_FLASH_Protection(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint32_t Size, uint32_t ProtectState, uint32_t Timeout)
|
||||
{
|
||||
#ifdef MEMSPI_PROTECT_SECTOR
|
||||
uint32_t tickstart = local_time();
|
||||
HAL_StatusTypeDef MEMSPI_Status;
|
||||
|
||||
// CALC AREA TO PROTECT
|
||||
uint16_t bytecnt = 0;
|
||||
uint16_t firstsector = (FLASH_Address/MEMSPI_SECTOR_SIZE);
|
||||
uint16_t lastsector = ((FLASH_Address+Size-1)/MEMSPI_SECTOR_SIZE);
|
||||
|
||||
for(int i = 0; i <= (lastsector - firstsector); i++)
|
||||
{
|
||||
|
||||
if(MEMSPI_WriteEnablingUntilTimeout(hmemspi, &Timeout, &tickstart) != HAL_OK) // if writting isnt enable
|
||||
return HAL_TIMEOUT; // return timeout
|
||||
|
||||
if(ProtectState == ENABLE)
|
||||
{
|
||||
MEMSPI_Status = MEMSPI_CMD_Protect_Sector(hmemspi, FLASH_Address, Timeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
MEMSPI_Status = MEMSPI_CMD_Unprotect_Sector(hmemspi, FLASH_Address, Timeout);
|
||||
}
|
||||
|
||||
if(MEMSPI_WaitOnFlagsUntilTimeout(hmemspi, MEMSPI_SR_WEL|MEMSPI_SR_BUSY, 0, &Timeout, &tickstart) != HAL_OK) // if operation isnt done (MEMSPI busy and WEL bit isnt in reset state)
|
||||
return HAL_TIMEOUT; // return timeout because erasing instruction accepted, but arent done
|
||||
|
||||
uint8_t ProtectStateCheck;
|
||||
if(MEMSPI_CMD_Read_Sector_Protection(hmemspi, FLASH_Address, &ProtectStateCheck, Timeout) == HAL_OK)
|
||||
{
|
||||
uint8_t expectedState = (ProtectState == ENABLE) ? 0xFF : 0x00;
|
||||
if(ProtectStateCheck == expectedState)
|
||||
{
|
||||
// return HAL_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
FLASH_Address += MEMSPI_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
|
||||
return MEMSPI_Status;
|
||||
#else
|
||||
return HAL_ERROR;
|
||||
#endif
|
||||
}
|
||||
//-------------------------------------------------------------
|
||||
//----------------------SERVICE FUNCTIONS----------------------
|
||||
/**
|
||||
@@ -341,7 +408,7 @@ HAL_StatusTypeDef MEMSPI_FLASH_Erase(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLA
|
||||
* @note Позволяет записывать только байты в пределах одной страницы.
|
||||
Для более гибкой записи есть функция MEMSPI_EEPROM_Write, которая программирует участки любой длины (в теории).
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_EEPROM_Write_Page(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t *Timeout, uint32_t *tickstart, uint8_t WaitForEnd)
|
||||
HAL_StatusTypeDef MEMSPI_EEPROM_Write_Page(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint32_t Size, uint32_t *Timeout, uint32_t *tickstart, uint8_t WaitForEnd)
|
||||
{
|
||||
HAL_StatusTypeDef MEMSPI_Status;
|
||||
// enable writting and waiting for unbusy
|
||||
@@ -397,45 +464,114 @@ HAL_StatusTypeDef MEMSPI_FLASH_Erase_Sector(MEMSPI_HandleTypeDef *hmemspi, uint3
|
||||
|
||||
/**
|
||||
* @brief Program page in external FLASH.
|
||||
* @param hmemspi Указатель на хендл внешней памяти.
|
||||
* @param FLASH_Address Адресс куда начинать записывать.
|
||||
* @param pData Откуда брать данные для записи в FLASH.
|
||||
* @param Size Вколько байтов записать.
|
||||
* @param Timeout Время, за которое должно быть осуществлено чтение.
|
||||
* @param tickstart Время, относительно которого надо отсчитывать таймаут.
|
||||
* @param WaitForEnd Ожидание, пока память не выполненит операцию.
|
||||
* @return HAL status.
|
||||
* @note Позволяет перепрограммировать только байты в прелелах одной страницы.
|
||||
Для более гибкого программирования есть функция MEMSPI_FLASH_Program, которая программирует участки любой длины (в теории).
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_FLASH_Program_Page(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t *Timeout, uint32_t *tickstart, uint8_t WaitForEnd)
|
||||
* @param hmemspi - указатель на хендл внешней памяти.
|
||||
* @param FLASH_Address - адресс куда начинать записывать.
|
||||
* @param pData - откуда брать данные для записи в FLASH.
|
||||
* @param Size - сколько байтов записать.
|
||||
* @param Timeout - время, за которое должно быть осуществлено чтение.
|
||||
* @param tickstart - время, относительно которого надо отсчитывать таймаут.
|
||||
* @param WaitForEnd - ожидание, пока память не выполненит операцию.
|
||||
* @return HAL status.
|
||||
* @note Позволяет перепрограммировать только байты в прелелах одной страницы.
|
||||
Для более гибкого программирования есть функция MEMSPI_FLASH_Program, которая программирует участки любой длины (в теории).
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_FLASH_Program_Page(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint32_t Size, uint32_t *Timeout, uint32_t *tickstart, uint8_t WaitForEnd)
|
||||
{
|
||||
HAL_StatusTypeDef MEMSPI_Status;
|
||||
// enable writting and waiting for unbusy
|
||||
if(MEMSPI_WriteEnablingUntilTimeout(hmemspi, Timeout, tickstart) != HAL_OK) // if writting isnt enable
|
||||
return HAL_TIMEOUT; // return timeout
|
||||
HAL_StatusTypeDef MEMSPI_Status;
|
||||
|
||||
// check if flash range is placed at one page
|
||||
if((FLASH_Address/MEMSPI_PAGE_SIZE) != ((FLASH_Address+Size-1)/MEMSPI_PAGE_SIZE)) // if page of first byte isnt equal page of last byte
|
||||
return HAL_ERROR; // return error
|
||||
#ifndef FLASHTYPE_BYTE_PROGRAMM
|
||||
// PROGRAM WHOLE PAGE
|
||||
// enable writting and waiting for unbusy
|
||||
if(MEMSPI_WriteEnablingUntilTimeout(hmemspi, &Timeout, &tickstart) != HAL_OK) // if writting isnt enable
|
||||
return HAL_TIMEOUT; // return timeout
|
||||
|
||||
// check if flash range is placed at one page
|
||||
if((FLASH_Address/MEMSPI_PAGE_SIZE) != ((FLASH_Address+Size-1)/MEMSPI_PAGE_SIZE)) // if page of first byte isnt equal page of last byte
|
||||
return HAL_ERROR; // return error
|
||||
|
||||
// programm page (instruction)
|
||||
MEMSPI_Status = MEMSPI_CMD_FLASH_Page_Program(hmemspi, FLASH_Address, pData, Size, Timeout);
|
||||
if(MEMSPI_Status != HAL_OK)
|
||||
return MEMSPI_Status;
|
||||
|
||||
// waiting for ending of writting if need
|
||||
if(WaitForEnd)
|
||||
if(MEMSPI_WaitOnFlagsUntilTimeout(hmemspi, MEMSPI_SR_WEL|MEMSPI_SR_BUSY, 0, &Timeout, &tickstart) != HAL_OK) // if writting isnt done (MEMSPI busy and WEL bit isnt in reset state)
|
||||
return HAL_TIMEOUT;
|
||||
#else
|
||||
// PROGRAM PAGE BY BYTES
|
||||
|
||||
// programm page (instruction)
|
||||
MEMSPI_Status = MEMSPI_CMD_FLASH_Page_Program(hmemspi, FLASH_Address, pData, Size, *Timeout);
|
||||
if(MEMSPI_Status != HAL_OK)
|
||||
return MEMSPI_Status;
|
||||
|
||||
// waiting for ending of writting if need
|
||||
if(WaitForEnd)
|
||||
if(MEMSPI_WaitOnFlagsUntilTimeout(hmemspi, MEMSPI_SR_WEL|MEMSPI_SR_BUSY, 0, Timeout, tickstart) != HAL_OK) // if writting isnt done (MEMSPI busy and WEL bit isnt in reset state)
|
||||
return HAL_TIMEOUT;
|
||||
|
||||
// update handle variables
|
||||
hmemspi->hNextAddr = (FLASH_Address+Size);
|
||||
hmemspi->hNextPage = (hmemspi->hNextAddr+Size)/MEMSPI_PAGE_SIZE;
|
||||
hmemspi->hNextSector = (hmemspi->hNextAddr+Size)/MEMSPI_SECTOR_SIZE;
|
||||
|
||||
return HAL_OK;
|
||||
for(int j = 0; j < MEMSPI_PAGE_SIZE; j++)
|
||||
{
|
||||
// enable writting and waiting for unbusy
|
||||
if(MEMSPI_WriteEnablingUntilTimeout(hmemspi, Timeout, tickstart) != HAL_OK) // if writting isnt enable
|
||||
return HAL_TIMEOUT; // return timeout
|
||||
|
||||
// check if flash range is placed at one page
|
||||
if((FLASH_Address/MEMSPI_PAGE_SIZE) != ((FLASH_Address+Size-1)/MEMSPI_PAGE_SIZE)) // if page of first byte isnt equal page of last byte
|
||||
return HAL_ERROR; // return error
|
||||
|
||||
// programm page (instruction)
|
||||
MEMSPI_Status = MEMSPI_CMD_FLASH_Byte_Program(hmemspi, FLASH_Address, pData[j], *Timeout);
|
||||
if(MEMSPI_Status != HAL_OK)
|
||||
return MEMSPI_Status;
|
||||
|
||||
// waiting for ending of writting if need
|
||||
if(WaitForEnd)
|
||||
if(MEMSPI_WaitOnFlagsUntilTimeout(hmemspi, MEMSPI_SR_WEL|MEMSPI_SR_BUSY, 0, Timeout, tickstart) != HAL_OK) // if writting isnt done (MEMSPI busy and WEL bit isnt in reset state)
|
||||
return HAL_TIMEOUT;
|
||||
}
|
||||
#endif
|
||||
|
||||
// update handle variables
|
||||
hmemspi->hNextAddr = (FLASH_Address+Size);
|
||||
hmemspi->hNextPage = (hmemspi->hNextAddr+Size)/MEMSPI_PAGE_SIZE;
|
||||
hmemspi->hNextSector = (hmemspi->hNextAddr+Size)/MEMSPI_SECTOR_SIZE;
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Program data in external FLASH in blocking mode.
|
||||
* @param hmemspi - указатель на хендл внешней памяти.
|
||||
* @param FLASH_Address - адресс куда начинать записывать.
|
||||
* @param pData - откуда брать данные для записи в FLASH.
|
||||
* @param Size - сколько байтов записать.
|
||||
* @param Timeout - время, за которое должно быть осуществлено чтение.
|
||||
* @param tickstart - время, относительно которого надо отсчитывать таймаут.
|
||||
* @param WaitForEnd - ожидание, пока память не выполненит операцию.
|
||||
* @return HAL status.
|
||||
* @note Позволяет перепрограммировать любое количество байт (без ограничений на количество страниц)
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_FLASH_Program_Bytes(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint32_t Size, uint32_t *Timeout, uint32_t *tickstart, uint8_t WaitForEnd)
|
||||
{
|
||||
HAL_StatusTypeDef MEMSPI_Status;
|
||||
|
||||
for(int j = 0; j < Size; j++)
|
||||
{
|
||||
// enable writting and waiting for unbusy
|
||||
if(MEMSPI_WriteEnablingUntilTimeout(hmemspi, Timeout, tickstart) != HAL_OK) // if writting isnt enable
|
||||
return HAL_TIMEOUT; // return timeout
|
||||
|
||||
// programm page (instruction)
|
||||
MEMSPI_Status = MEMSPI_CMD_FLASH_Byte_Program(hmemspi, FLASH_Address+j, pData[j], *Timeout);
|
||||
if(MEMSPI_Status != HAL_OK)
|
||||
return MEMSPI_Status;
|
||||
|
||||
// waiting for ending of writting if need
|
||||
if(WaitForEnd)
|
||||
if(MEMSPI_WaitOnFlagsUntilTimeout(hmemspi, MEMSPI_SR_WEL|MEMSPI_SR_BUSY, 0, Timeout, tickstart) != HAL_OK) // if writting isnt done (MEMSPI busy and WEL bit isnt in reset state)
|
||||
return HAL_TIMEOUT;
|
||||
}
|
||||
|
||||
// update handle variables
|
||||
hmemspi->hNextAddr = (FLASH_Address+Size);
|
||||
hmemspi->hNextPage = (hmemspi->hNextAddr+Size)/MEMSPI_PAGE_SIZE;
|
||||
hmemspi->hNextSector = (hmemspi->hNextAddr+Size)/MEMSPI_SECTOR_SIZE;
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Setting WEL bit until it setted or until timeout.
|
||||
* @param hmemspi Указатель на хендл внешней памяти.
|
||||
|
||||
@@ -32,44 +32,44 @@
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_CMD_Read_Status_Register(MEMSPI_HandleTypeDef *hmemspi, uint16_t RequestedBits, uint8_t EndCMD, uint32_t Timeout)
|
||||
{
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
uint8_t command[2];
|
||||
uint8_t *pSRPtr = 0;
|
||||
uint8_t size = 1;
|
||||
|
||||
if(RequestedBits >> 8) // if its high byte of status register
|
||||
{
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
uint8_t command[2];
|
||||
uint8_t *pSRPtr = 0;
|
||||
uint8_t size = 1;
|
||||
|
||||
if(RequestedBits >> 8) // if its high byte of status register
|
||||
{
|
||||
#ifdef MEMSPI_READ_STATUS_REG_2
|
||||
command[0] = MEMSPI_READ_STATUS_REG_2;
|
||||
pSRPtr = (uint8_t *)(&hmemspi->SR) + 1; // set pointer to HI byte of SR register
|
||||
size = 1;
|
||||
if(RequestedBits & 0xFF) // if low byte also requester
|
||||
{
|
||||
size = 2; // set size to 2 bytes
|
||||
command[1] = MEMSPI_READ_STATUS_REG;
|
||||
}
|
||||
#endif // MEMSPI_READ_STATUS_REG_2
|
||||
}
|
||||
else // of its low byte of status register
|
||||
command[0] = MEMSPI_READ_STATUS_REG_2;
|
||||
pSRPtr = (uint8_t *)(&hmemspi->SR) + 1; // set pointer to HI byte of SR register
|
||||
size = 1;
|
||||
if(RequestedBits & 0xFF) // if low byte also requester
|
||||
{
|
||||
command[0] = MEMSPI_READ_STATUS_REG;
|
||||
pSRPtr = (uint8_t *)(&hmemspi->SR); // set pointer to LO byte of SR register
|
||||
size = 1;
|
||||
}
|
||||
MEMSPI_Select(hmemspi);
|
||||
size = 2; // set size to 2 bytes
|
||||
command[1] = MEMSPI_READ_STATUS_REG;
|
||||
}
|
||||
#endif // MEMSPI_READ_STATUS_REG_2
|
||||
}
|
||||
else // of its low byte of status register
|
||||
{
|
||||
command[0] = MEMSPI_READ_STATUS_REG;
|
||||
pSRPtr = (uint8_t *)(&hmemspi->SR); // set pointer to LO byte of SR register
|
||||
size = 1;
|
||||
}
|
||||
MEMSPI_Select(hmemspi);
|
||||
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 1, Timeout); // send insctruction to read SR
|
||||
SPI_RES = MEMSPI_SPI_Receive(hmemspi, pSRPtr, 1, Timeout); // receive response
|
||||
if(size > 1) // if 2 bytes are requested
|
||||
{
|
||||
MEMSPI_Deselect(hmemspi);
|
||||
MEMSPI_Select(hmemspi);
|
||||
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command+1, 1, Timeout); // send insctruction to read SR
|
||||
SPI_RES = MEMSPI_SPI_Receive(hmemspi, pSRPtr-1, 1, Timeout); // receive response
|
||||
MEMSPI_Deselect(hmemspi);
|
||||
}
|
||||
if(EndCMD)
|
||||
MEMSPI_Deselect(hmemspi);
|
||||
return SPI_RES;
|
||||
if(size > 1) // if 2 bytes are requested
|
||||
{
|
||||
MEMSPI_Deselect(hmemspi);
|
||||
MEMSPI_Select(hmemspi);
|
||||
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command+1, 1, Timeout); // send insctruction to read SR
|
||||
SPI_RES = MEMSPI_SPI_Receive(hmemspi, pSRPtr-1, 1, Timeout); // receive response
|
||||
MEMSPI_Deselect(hmemspi);
|
||||
}
|
||||
if(EndCMD)
|
||||
MEMSPI_Deselect(hmemspi);
|
||||
return SPI_RES;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,21 +82,21 @@ HAL_StatusTypeDef MEMSPI_CMD_Read_Status_Register(MEMSPI_HandleTypeDef *hmemspi,
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_CMD_Write_Status_Register(MEMSPI_HandleTypeDef *hmemspi, uint16_t WrittenBits, uint32_t Timeout)
|
||||
{
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
uint8_t command[3];
|
||||
uint8_t size;
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
uint8_t command[3];
|
||||
uint8_t size;
|
||||
|
||||
command[0] = MEMSPI_WRITE_STATUS_REG;
|
||||
command[1] = WrittenBits;
|
||||
command[2] = WrittenBits >> 8;
|
||||
|
||||
size = 3;
|
||||
command[1] = WrittenBits;
|
||||
command[2] = WrittenBits >> 8;
|
||||
|
||||
size = 3;
|
||||
|
||||
MEMSPI_Select(hmemspi);
|
||||
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, size, Timeout);
|
||||
MEMSPI_Deselect(hmemspi);
|
||||
|
||||
return SPI_RES;
|
||||
return SPI_RES;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,7 +107,7 @@ HAL_StatusTypeDef MEMSPI_CMD_Write_Status_Register(MEMSPI_HandleTypeDef *hmemspi
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_CMD_Write_Enable(MEMSPI_HandleTypeDef *hmemspi, uint32_t Timeout)
|
||||
{
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
uint8_t command[1];
|
||||
command[0] = MEMSPI_WRITE_ENABLE;
|
||||
|
||||
@@ -115,7 +115,7 @@ HAL_StatusTypeDef MEMSPI_CMD_Write_Enable(MEMSPI_HandleTypeDef *hmemspi, uint32_
|
||||
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 1, Timeout);
|
||||
MEMSPI_Deselect(hmemspi);
|
||||
|
||||
return SPI_RES;
|
||||
return SPI_RES;
|
||||
}
|
||||
|
||||
|
||||
@@ -130,9 +130,9 @@ HAL_StatusTypeDef MEMSPI_CMD_Write_Enable(MEMSPI_HandleTypeDef *hmemspi, uint32_
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_CMD_Read_Data(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pBuff, uint16_t Size, uint32_t Timeout)
|
||||
{
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
uint8_t command[4];
|
||||
uint8_t response[2] = {0};
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
uint8_t command[4];
|
||||
uint8_t response[2] = {0};
|
||||
|
||||
command[0] = MEMSPI_READ_DATA;
|
||||
command[1] = FLASH_Address >> 16 & 0xFF;
|
||||
@@ -144,7 +144,7 @@ HAL_StatusTypeDef MEMSPI_CMD_Read_Data(MEMSPI_HandleTypeDef *hmemspi, uint32_t F
|
||||
SPI_RES = MEMSPI_SPI_Receive(hmemspi, pBuff, Size, Timeout);
|
||||
MEMSPI_Deselect(hmemspi);
|
||||
|
||||
return SPI_RES;
|
||||
return SPI_RES;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,22 +158,22 @@ HAL_StatusTypeDef MEMSPI_CMD_Read_Data(MEMSPI_HandleTypeDef *hmemspi, uint32_t F
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_CMD_EEPROM_Write(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout)
|
||||
{
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
// 1 command byte + 3 address bytes + 256 data bytes
|
||||
uint8_t command[1+3+MEMSPI_PAGE_SIZE];
|
||||
FLASH_Address = FLASH_Address & 0xFFFFFF;
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
// 1 command byte + 3 address bytes + 256 data bytes
|
||||
uint8_t command[1+3+MEMSPI_PAGE_SIZE];
|
||||
FLASH_Address = FLASH_Address & 0xFFFFFF;
|
||||
|
||||
command[0] = MEMSPI_WRITE_EEPROM;
|
||||
command[1] = FLASH_Address >> 16 & 0xFF;
|
||||
command[2] = FLASH_Address >> 8 & 0xFF;
|
||||
command[3] = FLASH_Address & 0xFF;
|
||||
command[1] = FLASH_Address >> 16 & 0xFF;
|
||||
command[2] = FLASH_Address >> 8 & 0xFF;
|
||||
command[3] = FLASH_Address & 0xFF;
|
||||
|
||||
MEMSPI_Select(hmemspi);
|
||||
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 4, Timeout); // send insctruction to write
|
||||
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, pData, Size, Timeout); // send data to write
|
||||
MEMSPI_Deselect(hmemspi);
|
||||
|
||||
return SPI_RES;
|
||||
return SPI_RES;
|
||||
}
|
||||
/**
|
||||
* @brief Send command to page program in FLASH.
|
||||
@@ -187,26 +187,57 @@ HAL_StatusTypeDef MEMSPI_CMD_EEPROM_Write(MEMSPI_HandleTypeDef *hmemspi, uint32_
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_CMD_FLASH_Page_Program(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout)
|
||||
{
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
// 1 command byte + 3 address bytes + 256 data bytes
|
||||
uint8_t command[1+3+MEMSPI_PAGE_SIZE];
|
||||
FLASH_Address = FLASH_Address & 0xFFFFFF;
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
// 1 command byte + 3 address bytes + 256 data bytes
|
||||
uint8_t command[1+3+MEMSPI_PAGE_SIZE];
|
||||
FLASH_Address = FLASH_Address & 0xFFFFFF;
|
||||
|
||||
command[0] = MEMSPI_PAGE_PROGRAM;
|
||||
command[1] = FLASH_Address >> 16 & 0xFF;
|
||||
command[2] = FLASH_Address >> 8 & 0xFF;
|
||||
command[3] = FLASH_Address & 0xFF;
|
||||
|
||||
// check if flash range is placed at one page
|
||||
if((FLASH_Address/MEMSPI_PAGE_SIZE) != ((FLASH_Address+Size-1)/MEMSPI_PAGE_SIZE)) // if page of first byte isnt equal page of last byte
|
||||
return HAL_ERROR; // return error
|
||||
command[1] = FLASH_Address >> 16 & 0xFF;
|
||||
command[2] = FLASH_Address >> 8 & 0xFF;
|
||||
command[3] = FLASH_Address & 0xFF;
|
||||
|
||||
// check if flash range is placed at one page
|
||||
if((FLASH_Address/MEMSPI_PAGE_SIZE) != ((FLASH_Address+Size-1)/MEMSPI_PAGE_SIZE)) // if page of first byte isnt equal page of last byte
|
||||
return HAL_ERROR; // return error
|
||||
|
||||
MEMSPI_Select(hmemspi);
|
||||
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 4, Timeout); // send insctruction to write
|
||||
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, pData, Size, Timeout); // send data to write
|
||||
MEMSPI_Deselect(hmemspi);
|
||||
|
||||
return SPI_RES;
|
||||
return SPI_RES;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send command to byte program in FLASH.
|
||||
* @param hmemspi - указатель на хендл внешней памяти.
|
||||
* @param FLASH_Address - адресс куда начинать записывать.
|
||||
* @param Byte - байт для записи в FLASH.
|
||||
* @param Timeout - время, за которое должна быть осуществлена запись.
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_CMD_FLASH_Byte_Program(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t Byte, uint32_t Timeout)
|
||||
{
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
// 1 command byte + 3 address bytes + 256 data bytes
|
||||
uint8_t command[1+3+MEMSPI_PAGE_SIZE];
|
||||
FLASH_Address = FLASH_Address & 0xFFFFFF;
|
||||
|
||||
command[0] = MEMSPI_BYTE_PROGRAM;
|
||||
command[1] = FLASH_Address >> 16 & 0xFF;
|
||||
command[2] = FLASH_Address >> 8 & 0xFF;
|
||||
command[3] = FLASH_Address & 0xFF;
|
||||
|
||||
MEMSPI_Select(hmemspi);
|
||||
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 4, Timeout); // send insctruction to write
|
||||
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, &Byte, 1, Timeout); // send byte to write
|
||||
MEMSPI_Deselect(hmemspi);
|
||||
|
||||
if(SPI_RES != HAL_OK)
|
||||
{
|
||||
printf_memspi_err("Error Program Byte: 0x%08lX", (unsigned long)FLASH_Address);
|
||||
}
|
||||
return SPI_RES;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -218,23 +249,118 @@ HAL_StatusTypeDef MEMSPI_CMD_FLASH_Page_Program(MEMSPI_HandleTypeDef *hmemspi, u
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_CMD_FLASH_Erase_Sector(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint32_t Timeout)
|
||||
{
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
uint8_t command[4];
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
uint8_t command[4];
|
||||
uint8_t response[8];
|
||||
FLASH_Address = FLASH_Address & 0xFFFFFF;
|
||||
FLASH_Address = FLASH_Address & 0xFFFFFF;
|
||||
|
||||
command[0] = MEMSPI_ERASE_SECTOR;
|
||||
command[1] = FLASH_Address >> 16;
|
||||
command[2] = FLASH_Address >> 8;
|
||||
command[3] = FLASH_Address;
|
||||
command[1] = FLASH_Address >> 16;
|
||||
command[2] = FLASH_Address >> 8;
|
||||
command[3] = FLASH_Address;
|
||||
|
||||
MEMSPI_Select(hmemspi);
|
||||
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 4, Timeout);
|
||||
MEMSPI_Deselect(hmemspi);
|
||||
|
||||
return SPI_RES;
|
||||
|
||||
return SPI_RES;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send command to unprotect sector.
|
||||
* @param hmemspi - указатель на хендл внешней памяти.
|
||||
* @param FLASH_Address - адресс сектора, с которого надо снять защиту.
|
||||
* @param Timeout - время, за которое должна быть осуществлена операция.
|
||||
* @note Микросхема вроде сама высчитывает какой сектор ерейзнуть, в соответствии с заданным адресом.
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_CMD_Unprotect_Sector(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint32_t Timeout)
|
||||
{
|
||||
#ifdef MEMSPI_PROTECT_SECTOR
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
uint8_t command[4];
|
||||
FLASH_Address = FLASH_Address & 0xFFFFFF;
|
||||
|
||||
command[0] = MEMSPI_UNPROTECT_SECTOR;
|
||||
command[1] = FLASH_Address >> 16;
|
||||
command[2] = FLASH_Address >> 8;
|
||||
command[3] = FLASH_Address;
|
||||
|
||||
MEMSPI_Select(hmemspi);
|
||||
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 4, Timeout);
|
||||
MEMSPI_Deselect(hmemspi);
|
||||
|
||||
return SPI_RES;
|
||||
#else
|
||||
return HAL_ERROR;
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
* @brief Send command to protect sector.
|
||||
* @param hmemspi - указатель на хендл внешней памяти.
|
||||
* @param FLASH_Address - адресс сектора, на который надо поставить защиту.
|
||||
* @param Timeout - время, за которое должна быть осуществлена операция.
|
||||
* @note Микросхема вроде сама высчитывает какой сектор ерейзнуть, в соответствии с заданным адресом.
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_CMD_Protect_Sector(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint32_t Timeout)
|
||||
{
|
||||
#ifdef MEMSPI_PROTECT_SECTOR
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
uint8_t command[4];
|
||||
FLASH_Address = FLASH_Address & 0xFFFFFF;
|
||||
|
||||
command[0] = MEMSPI_PROTECT_SECTOR;
|
||||
command[1] = FLASH_Address >> 16;
|
||||
command[2] = FLASH_Address >> 8;
|
||||
command[3] = FLASH_Address;
|
||||
|
||||
MEMSPI_Select(hmemspi);
|
||||
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 4, Timeout);
|
||||
MEMSPI_Deselect(hmemspi);
|
||||
|
||||
return SPI_RES;
|
||||
#else
|
||||
return HAL_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send command to read Sector Protection Register.
|
||||
* @param hmemspi Указатель на хендл внешней памяти.
|
||||
* @param FLASH_Address Адрес в пределах интересующего сектора (A16-A0).
|
||||
* @param pStatus Указатель для сохранения статуса защиты (0x00 - не защищен, 0xFF - защищен).
|
||||
* @param Timeout Время, за которое должно быть осуществлено чтение.
|
||||
* @return HAL_StatusTypeDef.
|
||||
* @note Команда 0x3C. После адреса микросхема начинает выдавать байты FFh или 00h.
|
||||
* Рекомендуется читать минимум 2 байта для корректного определения статуса на высокой частоте.
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_CMD_Read_Sector_Protection(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pStatus, uint32_t Timeout)
|
||||
{
|
||||
#ifdef MEMSPI_PROTECT_SECTOR
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
uint8_t command[4];
|
||||
uint8_t receive[2] = {0}; // читаем 2 байта для надежности
|
||||
FLASH_Address = FLASH_Address & 0xFFFFFF;
|
||||
|
||||
command[0] = MEMSPI_READ_PROTECT_REG;
|
||||
command[1] = FLASH_Address >> 16;
|
||||
command[2] = FLASH_Address >> 8;
|
||||
command[3] = FLASH_Address;
|
||||
|
||||
MEMSPI_Select(hmemspi);
|
||||
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 4, Timeout);
|
||||
SPI_RES = MEMSPI_SPI_Receive(hmemspi, receive, 2, Timeout); // Читаем данные защиты (рекомендуется минимум 2 байта для корректного определения на высокой частоте SCK)
|
||||
MEMSPI_Deselect(hmemspi);
|
||||
|
||||
if(SPI_RES == HAL_OK) {
|
||||
*pStatus = receive[1]; // Второй байт более надежен на высокой частоте
|
||||
// Согласно документации: 0x00 - сектор не защищен, 0xFF - сектор защищен
|
||||
}
|
||||
|
||||
return SPI_RES;
|
||||
#else
|
||||
return HAL_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send command to read JEDEC ID.
|
||||
@@ -244,10 +370,10 @@ HAL_StatusTypeDef MEMSPI_CMD_FLASH_Erase_Sector(MEMSPI_HandleTypeDef *hmemspi, u
|
||||
*/
|
||||
uint32_t MEMSPI_CMD_Read_JEDEC_ID(MEMSPI_HandleTypeDef *hmemspi, uint32_t Timeout)
|
||||
{
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
uint8_t command[1] = {0};
|
||||
uint8_t receive[4] = {0};
|
||||
uint32_t return_val;
|
||||
uint32_t return_val;
|
||||
|
||||
command[0] = MEMSPI_READ_JEDEC_ID;
|
||||
MEMSPI_Select(hmemspi);
|
||||
@@ -267,19 +393,19 @@ uint32_t MEMSPI_CMD_Read_JEDEC_ID(MEMSPI_HandleTypeDef *hmemspi, uint32_t Timeou
|
||||
*/
|
||||
uint64_t MEMSPI_CMD_Read_Device_ID(MEMSPI_HandleTypeDef *hmemspi, uint32_t Timeout)
|
||||
{
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
uint8_t command[1] = {0};
|
||||
uint8_t receive[8] = {0};
|
||||
uint64_t return_val_LO;
|
||||
uint64_t return_val_HI;
|
||||
uint64_t return_val_LO;
|
||||
uint64_t return_val_HI;
|
||||
command[0] = MEMSPI_READ_UNIQUE_ID;
|
||||
MEMSPI_Select(hmemspi);
|
||||
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 1, Timeout);
|
||||
SPI_RES = MEMSPI_SPI_Receive(hmemspi, receive, 8, Timeout);
|
||||
MEMSPI_Deselect(hmemspi);
|
||||
|
||||
return_val_LO = (*(uint64_t *)receive) >> 32;
|
||||
return_val_HI = (*(uint64_t *)receive) & 0xFFFFFFFF;
|
||||
return_val_LO = (*(uint64_t *)receive) >> 32;
|
||||
return_val_HI = (*(uint64_t *)receive) & 0xFFFFFFFF;
|
||||
return ((uint64_t)__REV(return_val_HI) << 32) | __REV(return_val_LO);
|
||||
}
|
||||
/**
|
||||
@@ -293,9 +419,9 @@ uint64_t MEMSPI_CMD_Read_Device_ID(MEMSPI_HandleTypeDef *hmemspi, uint32_t Timeo
|
||||
*/
|
||||
HAL_StatusTypeDef MEMSPI_CMD_Fast_Read(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pBuff, uint16_t Size, uint32_t Timeout)
|
||||
{
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
uint8_t command[5] = {0};
|
||||
uint8_t response[2] = {0};
|
||||
HAL_StatusTypeDef SPI_RES;
|
||||
uint8_t command[5] = {0};
|
||||
uint8_t response[2] = {0};
|
||||
|
||||
command[0] = MEMSPI_READ_DATA;
|
||||
command[1] = FLASH_Address >> 16 & 0xFF;
|
||||
@@ -307,8 +433,8 @@ HAL_StatusTypeDef MEMSPI_CMD_Fast_Read(MEMSPI_HandleTypeDef *hmemspi, uint32_t F
|
||||
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 5, Timeout);
|
||||
SPI_RES = MEMSPI_SPI_Receive(hmemspi, pBuff, Size, Timeout);
|
||||
MEMSPI_Deselect(hmemspi);
|
||||
|
||||
return SPI_RES;
|
||||
|
||||
return SPI_RES;
|
||||
}
|
||||
//-------------------------------------------------------------
|
||||
|
||||
|
||||
1232
Src/params_flash.c
Normal file
1232
Src/params_flash.c
Normal file
@@ -0,0 +1,1232 @@
|
||||
/**
|
||||
**************************************************************************
|
||||
* @file params_flash.c
|
||||
* @brief Модуль записи параметров в Flash
|
||||
*************************************************************************/
|
||||
#include "params_flash.h"
|
||||
#include "__crc_algs.h"
|
||||
|
||||
|
||||
extern uint32_t ParamsFlash_GetSectorInfo(uint32_t SectorNum, uint32_t *pSectorSize); // return SectorAddr
|
||||
|
||||
/* Внутренние штуки */
|
||||
static volatile int flash_working = 0; ///< общий флаг занятости флеш
|
||||
static volatile int flash_block_size = sizeof(ParamsFlash_t); ///< размер структуры которая будет положена в флеш
|
||||
static int __ParamsFlash_CheckHandle(ParamsFlashHandle_t *h, int check_busy);
|
||||
static int __ParamsFlash_SwitchSector(ParamsFlashHandle_t *h, int force_ind);
|
||||
static FlashBlockStatus_t __ParamsFlash_FindBlock(ParamsFlashHandle_t *h, uint16_t block_num, uint32_t *found_addr, volatile ParamsFlash_t **found_blk);
|
||||
static FlashBlockStatus_t __ParamsFlash_FindFreeSpace(ParamsFlashHandle_t *h, uint16_t block_num, uint32_t *free_addr, uint16_t *free_numb);
|
||||
static FlashBlockStatus_t __ParamsFlash_VerifyBlock(volatile ParamsFlash_t *blk);
|
||||
#if defined(FLASH_WORKING_NONBLOCKING)
|
||||
static int __ParamsFlash_WriteHandle(ParamsFlashHandle_t *h);
|
||||
static int __ParamsFlash_EraseHandle(ParamsFlashHandle_t *h);
|
||||
#endif
|
||||
|
||||
ParamsFlash_t __buff;
|
||||
|
||||
/* === Публичные функции ============================================ */
|
||||
|
||||
/**
|
||||
* @brief Проверка свободности флеш
|
||||
* @param h Указатель на handle параметров в Flash
|
||||
* @return 1 — свободна, 0 — занята
|
||||
*/
|
||||
int ParamsFlash_IsFlashFree(ParamsFlashHandle_t *h)
|
||||
{
|
||||
return flash_working || h->write_pending || h->sector[!h->sect_curr_ind].erase_pending;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализация handle
|
||||
* @param h Указатель на handle параметров в Flash
|
||||
* @param sector_1 Номер первого сектора
|
||||
* @param sector_2 Номер второго сектора
|
||||
* @param buf_size Размер буфера данных, который будет сохранятся в Flash
|
||||
* (размер структуры будет все равно @ref PARAMS_FLASH_MAX_BUFFER_SIZE,
|
||||
* этот buf_size определяет сколько данных будет считано и упаковывано)
|
||||
* @return 0 — успех, <0 — ошибка
|
||||
*/
|
||||
int ParamsFlash_HandleInit(ParamsFlashHandle_t *h, int sector_1, int sector_2, int buf_size)
|
||||
{
|
||||
// переменные для инициалиазции секторов
|
||||
unsigned int sector_size;
|
||||
FlashBlockStatus_t sector_status = FLASH_BLOCK_UNKNOWN_ERR;
|
||||
int sector_1_empty = 0;
|
||||
int sector_2_empty = 0;
|
||||
int long sector_1_max_block = 0;
|
||||
int long sector_2_max_block = 0;
|
||||
int sector_erase_flag = 0;
|
||||
// переменные для поиска блока
|
||||
volatile ParamsFlash_t *found_blk = NULL;
|
||||
int i = 0; unsigned long j = 0;
|
||||
|
||||
if(h == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
memset(h, 0, sizeof(ParamsFlashHandle_t));
|
||||
h->status = FLASH_BLOCK_UNKNOWN_ERR;
|
||||
|
||||
|
||||
if(buf_size > PARAMS_FLASH_MAX_BUFFER_SIZE)
|
||||
{
|
||||
h->status = FLASH_BLOCK_INIT_ERR;
|
||||
h->buffer_size = 0xFFFF;
|
||||
return -1;
|
||||
}
|
||||
h->buffer_size = buf_size;
|
||||
|
||||
|
||||
h->sector[0].sector_num = sector_1;
|
||||
h->sector[1].sector_num = sector_2;
|
||||
|
||||
for(i = 0; i < 2; i++)
|
||||
{
|
||||
h->sector[i].addr_start = ParamsFlash_GetSectorInfo(h->sector[i].sector_num, §or_size);
|
||||
h->sector[i].addr_end = h->sector[i].addr_start + sector_size;
|
||||
|
||||
if( (h->sector[i].addr_start < PARAMS_FLASH_ADDR_START) ||
|
||||
(h->sector[i].addr_start > PARAMS_FLASH_ADDR_END))
|
||||
{
|
||||
h->status = FLASH_BLOCK_INIT_ERR;
|
||||
h->sector[i].addr_start = 0xFFFFFFFF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( (h->sector[i].addr_end < PARAMS_FLASH_ADDR_START) ||
|
||||
(h->sector[i].addr_end > PARAMS_FLASH_ADDR_END) ||
|
||||
(h->sector[i].addr_end <= h->sector[i].addr_start))
|
||||
{
|
||||
h->status = FLASH_BLOCK_INIT_ERR;
|
||||
h->sector[i].addr_end = 0xFFFFFFFF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
h->sector[i].capacity = (h->sector[i].addr_end-h->sector[i].addr_start)/flash_block_size;
|
||||
|
||||
__ParamsFlash_SwitchSector(h, i+1); // переключится на 1 или 2 сектор
|
||||
if(__ParamsFlash_FindFreeSpace(h, PARAMS_LAST_BLOCK, &h->next_block_adr, NULL) == FLASH_BLOCK_FLASH_FULL) // инициализация h->next_block_adr
|
||||
{
|
||||
h->next_block_adr = h->sector[i].addr_end - 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// проверка ерейзнутости секторов
|
||||
uint8_t tmp_data = (uint16_t)(~EMPTY_MEMORY & 0xFF);
|
||||
__ParamsFlash_SwitchSector(h, 1); // переключится на 1 сектор
|
||||
for(j = h->addr_start; j < h->addr_end; j++)
|
||||
{
|
||||
__READ_BYTE(j, &tmp_data, 1);
|
||||
if(tmp_data != (EMPTY_MEMORY & 0xFF))
|
||||
{
|
||||
// если сектор не пустой - начинаем проверяеть другой сектор
|
||||
sector_1_empty = 0;
|
||||
break;
|
||||
}
|
||||
sector_1_empty = 1;
|
||||
}
|
||||
__ParamsFlash_SwitchSector(h, 2); // переключится на 2 сектор
|
||||
for(j = h->addr_start; j < h->addr_end; j++)
|
||||
{
|
||||
__READ_BYTE(j, &tmp_data, 1);
|
||||
if(tmp_data != (EMPTY_MEMORY & 0xFF))
|
||||
{
|
||||
// если сектор не пустой - сразу идем дальше
|
||||
sector_2_empty = 0;
|
||||
break;
|
||||
}
|
||||
sector_2_empty = 1;
|
||||
}
|
||||
|
||||
|
||||
// Если сектор 1 не пуст, а 2 пуст
|
||||
if(!sector_1_empty && sector_2_empty)
|
||||
{
|
||||
__ParamsFlash_SwitchSector(h, 1); // переключится на 1 сектор
|
||||
}
|
||||
// Если сектор 2 не пуст, а 1 пуст
|
||||
else if(sector_1_empty && !sector_2_empty)
|
||||
{
|
||||
__ParamsFlash_SwitchSector(h, 2); // переключится на 2 сектор
|
||||
}
|
||||
// Если оба сектора не пустые - смотрим в каком более свежие данные
|
||||
else if(!sector_1_empty && !sector_2_empty)
|
||||
{
|
||||
sector_erase_flag = 1; // один из секторов будет стерт
|
||||
// нет учета переполнения... типа старые данные 65535, а 1 - новые данные
|
||||
// хз что пока делать
|
||||
__ParamsFlash_SwitchSector(h, 1); // переключится на 1 сектор
|
||||
sector_status = __ParamsFlash_FindBlock(h, PARAMS_LAST_BLOCK, NULL, &found_blk);
|
||||
if(sector_status == FLASH_BLOCK_OK && found_blk != NULL) {
|
||||
sector_1_max_block = found_blk->numb;
|
||||
}
|
||||
|
||||
__ParamsFlash_SwitchSector(h, 2); // переключится на 2 сектор
|
||||
sector_status = __ParamsFlash_FindBlock(h, PARAMS_LAST_BLOCK, NULL, &found_blk);
|
||||
if(sector_status == FLASH_BLOCK_OK && found_blk != NULL) {
|
||||
sector_2_max_block = found_blk->numb;
|
||||
}
|
||||
// если максимальный номер блока больше в втором сектора - он актуальнее
|
||||
if(sector_2_max_block > sector_1_max_block)
|
||||
{
|
||||
__ParamsFlash_SwitchSector(h, 2); // переключится на 2 сектор
|
||||
}
|
||||
// если оба сектора нулевые - сбрасываем оба
|
||||
else if ((sector_2_max_block == sector_1_max_block) && (sector_1_max_block == 0))
|
||||
{
|
||||
sector_erase_flag = 2; // оба сектора будут стерты
|
||||
}
|
||||
// если нет - первый сектор актуальнее
|
||||
else
|
||||
{
|
||||
__ParamsFlash_SwitchSector(h, 1); // переключится на 1 сектор
|
||||
}
|
||||
}
|
||||
// Если оба сектора пустые - берем первый
|
||||
else if(sector_1_empty && sector_2_empty)
|
||||
{
|
||||
__ParamsFlash_SwitchSector(h, 1); // переключится на 1 сектор
|
||||
}
|
||||
|
||||
|
||||
h->status = FLASH_BLOCK_OK;
|
||||
h->initialized = 1;
|
||||
|
||||
if(sector_erase_flag)
|
||||
{
|
||||
sector_erase_flag--;
|
||||
ParamsFlash_Init(h); // стирание другого сектора
|
||||
}
|
||||
|
||||
|
||||
if(sector_erase_flag)
|
||||
{
|
||||
__ParamsFlash_SwitchSector(h, 0); // переключится на другой сектор
|
||||
ParamsFlash_Init(h); // стирание другого сектора
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Запись блока во Flash
|
||||
* @param h Указатель на handle параметров в Flash
|
||||
* @param block_num Номер блока для записи, @ref PARAMS_LAST_BLOCK — записать в следующий после последнего
|
||||
* @param Buffer Буфер данных для записи
|
||||
* @param size Размер данных
|
||||
* @return >=0 — номер записанного блока, <0 — ошибка
|
||||
*/
|
||||
int ParamsFlash_WriteBlock(ParamsFlashHandle_t *h, int block_num, const uint16_t *Buffer, int size)
|
||||
{
|
||||
FlashBlockStatus_t local_status = FLASH_BLOCK_UNKNOWN_ERR;
|
||||
// переменные для поиска блока
|
||||
uint32_t free_addr = 0;
|
||||
uint16_t free_numb = 0;
|
||||
uint16_t switch_to_new_sector = 0;
|
||||
|
||||
if(__ParamsFlash_CheckHandle(h, 1))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if(h->write_pending)
|
||||
{
|
||||
h->status = FLASH_BLOCK_BUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!Buffer || size==0 || size>PARAMS_FLASH_MAX_BUFFER_SIZE)
|
||||
{
|
||||
h->status = FLASH_BLOCK_INIT_ERR;
|
||||
return -1;
|
||||
}
|
||||
#if defined(TRACE_WRITE_READ)
|
||||
LED1_TRACE_ENTER();
|
||||
#endif
|
||||
local_status = __ParamsFlash_FindFreeSpace(h, block_num, &free_addr, &free_numb);
|
||||
|
||||
// если сектор заполнен - переходим на другой
|
||||
if(local_status == FLASH_BLOCK_FLASH_FULL)
|
||||
{
|
||||
switch_to_new_sector = 1;
|
||||
__ParamsFlash_SwitchSector(h, 0);
|
||||
local_status = __ParamsFlash_FindFreeSpace(h, free_numb, &free_addr, &free_numb);
|
||||
}
|
||||
|
||||
if(local_status != FLASH_BLOCK_OK)
|
||||
{
|
||||
h->status = local_status;
|
||||
return -1;
|
||||
}
|
||||
//LED1_TRACE_ENTER();
|
||||
// Подготавливаем блок для записи
|
||||
memset(&h->blk_tmp, 0, sizeof(h->blk_tmp));
|
||||
h->blk_tmp.numb = free_numb;
|
||||
h->blk_tmp.size = size;
|
||||
memcpy(h->blk_tmp.data, Buffer, size);
|
||||
h->blk_tmp.crc16 = 0; // Обнуляем навсякий
|
||||
h->blk_tmp.crc16 = crc16((uint8_t*)&h->blk_tmp, flash_block_size-2);
|
||||
|
||||
__ParamsFlash_VerifyBlock(&h->blk_tmp);
|
||||
h->write_pending = 1;
|
||||
|
||||
#if !defined(FLASH_WORKING_NONBLOCKING)
|
||||
if(FLASH_WORKING_CHECK(h))
|
||||
{
|
||||
h->status = FLASH_BLOCK_BUSY;
|
||||
return -1;
|
||||
}
|
||||
FLASH_WORKING_ENTER(h);
|
||||
// Записываем блок во Flash
|
||||
|
||||
if(__WRITE_CURR_BLOCK(&h->blk_tmp, free_addr, flash_block_size) != HAL_OK)
|
||||
{
|
||||
h->status = FLASH_BLOCK_WRITE_ERR;
|
||||
FLASH_WORKING_EXIT(h);
|
||||
return -1;
|
||||
}
|
||||
FLASH_WORKING_EXIT(h);
|
||||
|
||||
h->next_block_adr = free_addr + flash_block_size;
|
||||
h->write_pending = 0;
|
||||
#endif
|
||||
|
||||
// Если перешли на новый сектор - старый стираем
|
||||
if(switch_to_new_sector)
|
||||
{
|
||||
if(ParamsFlash_Init(h))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(TRACE_WRITE_READ)
|
||||
LED1_TRACE_EXIT();
|
||||
#endif
|
||||
|
||||
|
||||
h->status = FLASH_BLOCK_OK;
|
||||
return h->blk_tmp.numb;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Чтение блока из Flash
|
||||
* @param h Указатель на handle параметров в Flash
|
||||
* @param block_num Номер блока для считывания, @ref PARAMS_LAST_BLOCK - считать последний.
|
||||
* @param Buffer Буфер куда сохранить считанные данные.
|
||||
* @param size Максимальный размер буфера в словах.
|
||||
* @param read_size Указатель на переменную для сохранения кол-ва считанных слов (опционально).
|
||||
* @return >=0 — номер считанного блока, <0 — ошибка
|
||||
*
|
||||
* @details
|
||||
* - Если block_num == PARAMS_LAST_BLOCK, читается последний валидный блок в памяти.
|
||||
* - Если block_num != PARAMS_LAST_BLOCK, читается именно этот блок.
|
||||
* - CRC проверяется перед копированием, при ошибке возвращается <0.
|
||||
*/
|
||||
int ParamsFlash_ReadBlock(ParamsFlashHandle_t *h, int block_num, uint16_t *Buffer, int size, int *read_size)
|
||||
{
|
||||
FlashBlockStatus_t local_status = FLASH_BLOCK_UNKNOWN_ERR;
|
||||
// переменные для поиска блока
|
||||
uint32_t found_addr = 0;
|
||||
volatile ParamsFlash_t *found_blk = NULL;
|
||||
// сколько данных копировать
|
||||
uint16_t to_copy = 0;
|
||||
|
||||
|
||||
if(__ParamsFlash_CheckHandle(h, 1))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((Buffer == NULL) || (size == 0) || (size>PARAMS_FLASH_MAX_BUFFER_SIZE))
|
||||
{
|
||||
h->status = FLASH_BLOCK_INIT_ERR;
|
||||
return -1;
|
||||
}
|
||||
#if defined(TRACE_WRITE_READ)
|
||||
LED1_TRACE_ENTER();
|
||||
#endif
|
||||
|
||||
local_status = __ParamsFlash_FindBlock(h, block_num, &found_addr, &found_blk);
|
||||
|
||||
if (local_status != FLASH_BLOCK_OK)
|
||||
{
|
||||
h->status = local_status;
|
||||
#if defined(TRACE_WRITE_READ)
|
||||
LED1_TRACE_EXIT();
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
//LED1_TRACE_ENTER();
|
||||
to_copy = (found_blk->size < (uint16_t)size) ? found_blk->size : size;
|
||||
memcpy((void*)Buffer, (uint16_t*)found_blk->data, to_copy);
|
||||
|
||||
if (read_size)
|
||||
*read_size = to_copy;
|
||||
|
||||
#if defined(TRACE_WRITE_READ)
|
||||
LED1_TRACE_EXIT();
|
||||
#endif
|
||||
h->status = FLASH_BLOCK_OK;
|
||||
return found_blk->numb;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Упаковка Flash: запись последнего блока в второй сектор и стирание первого сектора
|
||||
* @param h Указатель на handle параметров в Flash
|
||||
* @param force Принудительно очистить Flash, даже если не удалось считать блок
|
||||
* @return 0 — успех, <0 — ошибка
|
||||
*/
|
||||
int ParamsFlash_Pack(ParamsFlashHandle_t *h, int force)
|
||||
{
|
||||
// номер записанного блока / если <0 ошибка
|
||||
int pack_numb = 0; // Номер блока для упаковки
|
||||
int pack_size = 0; // Размер блока для упаковки
|
||||
int recheck_sector = 0; // Номер блока для упаковки
|
||||
|
||||
int numb_rewrite = 0;
|
||||
|
||||
if(__ParamsFlash_CheckHandle(h, 1))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
pack_numb = ParamsFlash_ReadBlock(h, PARAMS_LAST_BLOCK, h->blk_tmp.data, h->buffer_size, &pack_size);
|
||||
|
||||
if(force == 0)
|
||||
{
|
||||
if(pack_numb < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
__ParamsFlash_SwitchSector(h, 0); // переходим на новый сектор
|
||||
|
||||
recheck_sector = h->sect_curr_ind;
|
||||
if(pack_numb >= 0)
|
||||
{
|
||||
numb_rewrite = ParamsFlash_WriteBlock(h, pack_numb, h->blk_tmp.data, pack_size);
|
||||
if(numb_rewrite < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(recheck_sector == h->sect_curr_ind) // стираем сектор, если он НЕ поменялся в ParamsFlash_WriteBlock
|
||||
{
|
||||
if(ParamsFlash_Init(h)) // стирание старого сектора
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
h->status = FLASH_BLOCK_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализация сектора Flash (стирание)
|
||||
* @param h Указатель на handle параметров в Flash
|
||||
* @return 0 — успех, <0 — ошибка
|
||||
* @details Инициирует стирание сектора Flash, который сейчас не используется
|
||||
*/
|
||||
int ParamsFlash_Init(ParamsFlashHandle_t *h)
|
||||
{
|
||||
// переменные для определения что ерейзить
|
||||
#if !defined(FLASH_WORKING_NONBLOCKING)
|
||||
uint32_t current_addr = 0;
|
||||
if(__ParamsFlash_CheckHandle(h, 1))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
if(__ParamsFlash_CheckHandle(h, 0))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
h->sector[!h->sect_curr_ind].erase_pending = 1;
|
||||
#ifndef SETTINGS_USE_MEMORY_EEPROM
|
||||
if(h->sector[!h->sect_curr_ind].erase_pending)
|
||||
{
|
||||
if(MEMSPI_FLASH_Erase(&memory_spi, h->sector[!h->sect_curr_ind].addr_start, 1, 5000, 1) != HAL_OK)
|
||||
{
|
||||
h->status = FLASH_BLOCK_WRITE_ERR;
|
||||
FLASH_WORKING_EXIT(h);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
h->sector[!h->sect_curr_ind].erase_pending = 0;
|
||||
#endif
|
||||
h->status = FLASH_BLOCK_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Проверка блока на корректность
|
||||
* @param h Указатель на handle параметров в Flash
|
||||
* @param block_num Номер блока для проверки, @ref PARAMS_LAST_BLOCK — последний инициализированный блок (с записанным numb)
|
||||
* @param last_valid_num Указатель на переменную куда сохранится номер последнего корректного блока
|
||||
* @return Статус блока Flash @ref FlashBlockStatus_t
|
||||
*/
|
||||
FlashBlockStatus_t ParamsFlash_VerifyBlock(ParamsFlashHandle_t *h, int block_num, int *last_valid_num)
|
||||
{
|
||||
FlashBlockStatus_t local_status = FLASH_BLOCK_UNKNOWN_ERR;
|
||||
// переменные для поиска блока
|
||||
uint32_t addr = 0;
|
||||
uint16_t last_correct_num = 0;
|
||||
uint32_t found_addr = 0;
|
||||
volatile ParamsFlash_t *found_blk = NULL;
|
||||
// переменная для цикла while
|
||||
volatile ParamsFlash_t *cur = NULL;
|
||||
|
||||
|
||||
if(__ParamsFlash_CheckHandle(h, 1))
|
||||
{
|
||||
if(h)
|
||||
return h->status;
|
||||
else
|
||||
return FLASH_BLOCK_INIT_ERR;
|
||||
}
|
||||
|
||||
local_status = __ParamsFlash_FindBlock(h, block_num, &found_addr, &found_blk);
|
||||
h->status = local_status;
|
||||
|
||||
// Если не требуется возвращать last_valid_num - выходим сразу
|
||||
if (last_valid_num == NULL) {
|
||||
return local_status;
|
||||
}
|
||||
|
||||
if(local_status == FLASH_BLOCK_OK)
|
||||
{
|
||||
// Запрошенный блок корректен - возвращаем его номер
|
||||
if(found_blk != NULL)
|
||||
*last_valid_num = found_blk->numb;
|
||||
}
|
||||
else // блок некорректен
|
||||
{
|
||||
if(block_num == PARAMS_LAST_BLOCK) // Запросили последний, но он некорректен - ищем предыдущий корректный
|
||||
{
|
||||
addr = h->addr_start;
|
||||
last_correct_num = 0;
|
||||
|
||||
while(addr + flash_block_size <= h->addr_end)
|
||||
{
|
||||
__SET_CURR_BLOCK(cur, addr);
|
||||
local_status = __ParamsFlash_VerifyBlock(cur);
|
||||
|
||||
if(local_status == FLASH_BLOCK_OK && cur->numb > last_correct_num)
|
||||
{
|
||||
last_correct_num = cur->numb;
|
||||
}
|
||||
|
||||
addr += flash_block_size;
|
||||
}
|
||||
|
||||
*last_valid_num = last_correct_num;
|
||||
}
|
||||
else // Запросили конкретный блок и он некорректен
|
||||
{
|
||||
// последний корректный не ищем - просто устанавливаем в 0xFFFF
|
||||
*last_valid_num = 0xFFFF;
|
||||
}
|
||||
|
||||
}
|
||||
return local_status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Сравнение данных с блоком из Flash
|
||||
* @param h Указатель на handle параметров в Flash
|
||||
* @param block_num Номер блока для сравнения, @ref PARAMS_LAST_BLOCK - сравнить последний.
|
||||
* @param data Указатель на данные
|
||||
* @param size Размер данных
|
||||
* @return 0 — совпадает, 1 — отличается, <0 - ошибка
|
||||
*/
|
||||
int ParamsFlash_Compare(ParamsFlashHandle_t *h, int block_num, const uint16_t *data, int size)
|
||||
{
|
||||
// параметры блока
|
||||
int real_size = 0;
|
||||
int numb = 0;
|
||||
// результат сравнения
|
||||
int result = 0;
|
||||
|
||||
if(__ParamsFlash_CheckHandle(h, 1))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data == NULL || size == 0 || size > PARAMS_FLASH_MAX_BUFFER_SIZE || (uint16_t)size > h->buffer_size) {
|
||||
h->status = FLASH_BLOCK_INIT_ERR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
numb = ParamsFlash_ReadBlock(h, block_num, h->blk_tmp.data, h->buffer_size, &real_size);
|
||||
|
||||
if((numb < 0) || (real_size <= 0) || (real_size < size))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = memcmp(h->blk_tmp.data, data, size);
|
||||
h->status = FLASH_BLOCK_OK;
|
||||
return (result != 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Получение статистики по блокам
|
||||
* @param h Указатель на handle параметров в Flash
|
||||
* @param totalBlocks Общее число блоков
|
||||
* @param validBlocks Количество блоков с корректным CRC
|
||||
* @param invalidBlocks Количество блоков с некорректным CRC
|
||||
* @return 0 — успех, <0 — ошибка
|
||||
*/
|
||||
int ParamsFlash_GetInfo(ParamsFlashHandle_t *h, int *total, int *valid, int *invalid)
|
||||
{
|
||||
FlashBlockStatus_t local_status = FLASH_BLOCK_UNKNOWN_ERR;
|
||||
// переменные для просмотра блоков
|
||||
uint32_t addr = 0;
|
||||
volatile ParamsFlash_t *blk = NULL;
|
||||
// счетчики для статистики
|
||||
uint16_t t=0, v=0, i=0;
|
||||
|
||||
if(__ParamsFlash_CheckHandle(h, 1))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr = h->addr_start;
|
||||
|
||||
while(addr + flash_block_size <= h->addr_end)
|
||||
{
|
||||
__SET_CURR_BLOCK(blk, addr);
|
||||
if(blk->numb == EMPTY_MEMORY && blk->size == EMPTY_MEMORY) break;
|
||||
|
||||
t++;
|
||||
local_status = __ParamsFlash_VerifyBlock(blk);
|
||||
if(local_status == FLASH_BLOCK_OK)
|
||||
v++;
|
||||
else
|
||||
i++;
|
||||
addr += flash_block_size;
|
||||
}
|
||||
|
||||
if(total)
|
||||
*total = t;
|
||||
if(valid)
|
||||
*valid = v;
|
||||
if(invalid)
|
||||
*invalid = i;
|
||||
|
||||
h->status = FLASH_BLOCK_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* === Асинхронные функции ============================================ */
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Обработчик неблокирующей работы модуля
|
||||
* @param h Указатель на handle параметров в Flash
|
||||
* @details Должен вызываться периодически, в main while(1) или по таймеру
|
||||
*/
|
||||
int ParamsFlash_AsynchHandle(ParamsFlashHandle_t *h)
|
||||
{
|
||||
int write_status = 0;
|
||||
int erase_status = 0;
|
||||
|
||||
#if defined(TRACE_ASYNCH)
|
||||
LED1_TRACE_ENTER();
|
||||
#endif
|
||||
|
||||
#if defined(FLASH_WORKING_NONBLOCKING)
|
||||
write_status = __ParamsFlash_WriteHandle(h);
|
||||
erase_status = __ParamsFlash_EraseHandle(h);
|
||||
|
||||
#endif //FLASH_WORKING_NONBLOCKING
|
||||
|
||||
|
||||
#if defined(TRACE_ASYNCH)
|
||||
LED1_TRACE_EXIT();
|
||||
#endif
|
||||
|
||||
if(!write_status && !erase_status) // все по нулям
|
||||
return 0;
|
||||
else if((write_status < 0) || (erase_status < 0)) // если у кого-то ошибка
|
||||
return -1;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* === Внутренние функции ============================================ */
|
||||
|
||||
/**
|
||||
* @brief Проверка структуры @ref ParamsFlashHandle_t
|
||||
* @param h Указатель на handle параметров в Flash
|
||||
* @param check_busy Проверять занятость флеш
|
||||
* @return 0 — успех, <0 — ошибка
|
||||
*/
|
||||
static int __ParamsFlash_CheckHandle(ParamsFlashHandle_t *h, int check_busy)
|
||||
{
|
||||
if(h == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
h->status = FLASH_BLOCK_UNKNOWN_ERR;
|
||||
if(!h->initialized) // неинициализировная структура
|
||||
{
|
||||
h->status = FLASH_BLOCK_INIT_ERR;
|
||||
return -1;
|
||||
}
|
||||
if(check_busy)
|
||||
{
|
||||
if(FLASH_WORKING_CHECK(h)) // флеш занята
|
||||
{
|
||||
h->status = FLASH_BLOCK_BUSY;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if( (h->addr_start != h->sector[h->sect_curr_ind].addr_start) || // поехали адреса сектора
|
||||
(h->addr_end != h->sector[h->sect_curr_ind].addr_end) )
|
||||
{
|
||||
if(__ParamsFlash_SwitchSector(h, h->sect_curr_ind+1)) // обновляем их
|
||||
{
|
||||
h->status = FLASH_BLOCK_INIT_ERR; // не получилось обновить
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Переключение на следующий сектор
|
||||
* @param h Указатель на handle параметров в Flash
|
||||
* @param force_ind Принудительно переключить на 1 или 2 сектор. 0 для автоматического выбора
|
||||
* @return 0 — успех, <0 — ошибка
|
||||
*/
|
||||
static int __ParamsFlash_SwitchSector(ParamsFlashHandle_t *h, int force_ind)
|
||||
{
|
||||
int next_sector_idx = 0;
|
||||
if(h == NULL)
|
||||
return -1;
|
||||
if((force_ind > 2) || (force_ind < 0))
|
||||
return -1;
|
||||
|
||||
|
||||
// Автоматическое переключение
|
||||
if(force_ind == 0)
|
||||
{
|
||||
// Определяем индекс следующего сектора инверсией текущего сектора
|
||||
next_sector_idx = !h->sect_curr_ind;
|
||||
}
|
||||
// Принудительное переключение по номеру (1 или 2)
|
||||
else
|
||||
{
|
||||
// Определяем индекс следующего сектора по переданному индексу
|
||||
next_sector_idx = force_ind - 1;
|
||||
}
|
||||
|
||||
// Обновляем сектор из основной структуры
|
||||
h->sector[h->sect_curr_ind].next_block_adr = h->next_block_adr;
|
||||
|
||||
// Обновляем основную структуру из сектора
|
||||
h->addr_start = h->sector[next_sector_idx].addr_start;
|
||||
h->addr_end = h->sector[next_sector_idx].addr_end;
|
||||
h->next_block_adr = h->sector[next_sector_idx].next_block_adr;
|
||||
|
||||
h->sect_curr_ind = next_sector_idx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Внутренняя функция поиска блока по номеру
|
||||
* @param h Указатель на handle параметров в Flash
|
||||
* @param block_num Номер блока для поиска, @ref PARAMS_LAST_BLOCK — последний инициализированный блок (numb != EMPTY_MEMORY)
|
||||
* @param found_addr Возвращаемый адрес найденного блока
|
||||
* @param found_blk Возвращаемый указатель на найденный блок
|
||||
* @return Статус поиска блока
|
||||
* @code Алгоритм
|
||||
* 1. Если next_block_adr корректен - начинаем поиск с предыдущего блока и идем назад
|
||||
* 2. Иначе - начинаем с начала сектора и идем вперед
|
||||
* 4. Для PARAMS_LAST_BLOCK ищется последний валидный блок (который дальше всего от adr_start)
|
||||
* 5. Для конкретного номера - ищется блок с этим номером
|
||||
* @endcode
|
||||
*/
|
||||
static FlashBlockStatus_t __ParamsFlash_FindBlock(ParamsFlashHandle_t *h, uint16_t block_num,
|
||||
uint32_t *found_addr, volatile ParamsFlash_t **found_blk)
|
||||
{
|
||||
// переменные для последнего найденного блока
|
||||
volatile uint32_t last_init_addr = 0;
|
||||
volatile ParamsFlash_t *last_init_blk = NULL;
|
||||
volatile FlashBlockStatus_t last_init_status = FLASH_BLOCK_NOT_FOUND;
|
||||
// переменные для поиска блока
|
||||
int block_finded_flag = 0;
|
||||
uint32_t addr = 0;
|
||||
int search_from_start = 0;
|
||||
volatile ParamsFlash_t *cur = NULL;
|
||||
FlashBlockStatus_t st = FLASH_BLOCK_NOT_FOUND;
|
||||
|
||||
|
||||
if(h == NULL)
|
||||
{
|
||||
return FLASH_BLOCK_INIT_ERR;
|
||||
}
|
||||
#if defined(TRACE_FIND_BLOCK)
|
||||
LED1_TRACE_ENTER();
|
||||
#endif
|
||||
|
||||
// Если next_block_adr корректен
|
||||
if((h->next_block_adr > h->addr_start) && // в диапаоне сектора, но не равен addr_start
|
||||
(h->next_block_adr <= h->addr_end) &&
|
||||
(((h->next_block_adr - h->addr_start) % flash_block_size) == 0)) // выравивание на начале блока
|
||||
{
|
||||
addr = h->next_block_adr - flash_block_size;
|
||||
search_from_start = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = h->addr_start;
|
||||
search_from_start = 1;
|
||||
}
|
||||
|
||||
if(found_addr)
|
||||
*found_addr = 0;
|
||||
if(found_blk)
|
||||
*found_blk = NULL;
|
||||
|
||||
while( (addr >= h->addr_start) &&
|
||||
(addr + flash_block_size <= h->addr_end) )
|
||||
{
|
||||
__SET_CURR_BLOCK(cur, addr);
|
||||
st = __ParamsFlash_VerifyBlock(cur);
|
||||
|
||||
if(st != FLASH_BLOCK_EMPTY)
|
||||
{
|
||||
// Если ищем последний
|
||||
if(block_num == PARAMS_LAST_BLOCK)
|
||||
{
|
||||
// запоминаем валидный блок
|
||||
if(st == FLASH_BLOCK_OK)
|
||||
{
|
||||
last_init_addr = addr;
|
||||
last_init_blk = cur;
|
||||
last_init_status = st;
|
||||
if(!search_from_start) // если ищем с конца
|
||||
break; // сразу выходим, т.к. мы начали с конца - и первый найденый будет последним от adr_start
|
||||
}
|
||||
}
|
||||
// Если ищем кокнретный - запоминаем конкретный инициализировнный (он может быть невалидным)
|
||||
else if(cur->numb == block_num)
|
||||
{
|
||||
// запоминаем любой блок
|
||||
last_init_addr = addr;
|
||||
last_init_blk = cur;
|
||||
last_init_status = st;
|
||||
// если блок валидный - возвращаем сразу
|
||||
if(last_init_status == FLASH_BLOCK_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(search_from_start)
|
||||
addr += flash_block_size;
|
||||
else
|
||||
addr -= flash_block_size;
|
||||
}
|
||||
|
||||
#if defined(TRACE_FIND_BLOCK)
|
||||
LED1_TRACE_EXIT();
|
||||
#endif
|
||||
|
||||
// если ищем последний блок и нашли валидный - возвращаем его
|
||||
if((block_num == PARAMS_LAST_BLOCK) && (last_init_status == FLASH_BLOCK_OK))
|
||||
{
|
||||
block_finded_flag = 1;
|
||||
}
|
||||
// если ищем конкретный блок и нашли ЛЮБОЙ - возвращаем его
|
||||
else if((block_num != PARAMS_LAST_BLOCK) && (last_init_status != FLASH_BLOCK_NOT_FOUND))
|
||||
{
|
||||
block_finded_flag = 1;
|
||||
}
|
||||
|
||||
|
||||
if(block_finded_flag)
|
||||
{ // заполняем внешние переменные для блока
|
||||
__SET_CURR_BLOCK(cur, last_init_addr);
|
||||
if(found_addr)
|
||||
*found_addr = last_init_addr;
|
||||
if(found_blk)
|
||||
*found_blk = last_init_blk;
|
||||
return last_init_status;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FLASH_BLOCK_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Внутренняя функция поиска свободного места для записи
|
||||
* @param h Указатель на handle параметров в Flash
|
||||
* @param block_num Номер блока для записи, @ref PARAMS_LAST_BLOCK — следующий после последнего
|
||||
* @param free_addr Возвращаемый адрес свободного места
|
||||
* @param free_numb Возвращаемый номер для нового блока
|
||||
* @return Статус поиска
|
||||
* @code Алгоритм
|
||||
* 1. Если next_block_adr корректен - начинаем поиск с него и идем вперед
|
||||
* 2. Иначе - начинаем с начала сектора и идем вперед
|
||||
* 4. Поиск идет до тех пор, пока не будет найден пустой блок
|
||||
* @endcode
|
||||
*/
|
||||
static FlashBlockStatus_t __ParamsFlash_FindFreeSpace(ParamsFlashHandle_t *h, uint16_t block_num,
|
||||
uint32_t *free_addr, uint16_t *free_numb)
|
||||
{
|
||||
// переменные для последнего найденного блока
|
||||
int64_t first_free_addr = -1;
|
||||
uint16_t found_free_numb = block_num;
|
||||
// переменные для поиска блока
|
||||
uint32_t addr = 0;
|
||||
uint16_t last_numb = 0;
|
||||
volatile ParamsFlash_t *cur = NULL;
|
||||
FlashBlockStatus_t st = FLASH_BLOCK_NOT_FOUND;
|
||||
|
||||
if(h == NULL)
|
||||
{
|
||||
return FLASH_BLOCK_INIT_ERR;
|
||||
}
|
||||
if(block_num == 0)
|
||||
return FLASH_BLOCK_INIT_ERR;
|
||||
|
||||
#if defined(TRACE_FIND_BLOCK)
|
||||
LED1_TRACE_ENTER();
|
||||
#endif
|
||||
|
||||
// Если next_block_adr корректен
|
||||
if((h->next_block_adr > h->addr_start) && // в диапаоне сектора, но не равен addr_start
|
||||
(h->next_block_adr <= h->addr_end) &&
|
||||
(((h->next_block_adr - h->addr_start) % flash_block_size) == 0)) // выравивание на начале блока
|
||||
{
|
||||
addr = h->next_block_adr - flash_block_size; // захватываем предыдущий блок чтобы узнать его номер и инкрементировать
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = h->addr_start;
|
||||
}
|
||||
|
||||
|
||||
if(free_addr)
|
||||
*free_addr = 0;
|
||||
if(free_numb)
|
||||
*free_numb = PARAMS_LAST_BLOCK;
|
||||
|
||||
while(addr + flash_block_size < h->addr_end)
|
||||
{
|
||||
__SET_CURR_BLOCK(cur, addr);
|
||||
st = __ParamsFlash_VerifyBlock(cur);
|
||||
|
||||
if(st == FLASH_BLOCK_EMPTY)
|
||||
{
|
||||
if(first_free_addr == -1)
|
||||
{
|
||||
first_free_addr = addr;
|
||||
if(block_num == PARAMS_LAST_BLOCK)
|
||||
{
|
||||
found_free_numb = last_numb + 1;
|
||||
if(found_free_numb >= INT16_MAX) // если номер переполнен
|
||||
{
|
||||
found_free_numb = 1; // зацикливаем
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Проверяем, не существует ли уже блок с таким номером
|
||||
// Проверка устарела, т.к. оно не просматривает весь блок. Поэтмоу по сути
|
||||
// при валидном next_block_adr оно всегда будет верно. Т.к. все блоки после next_block_adr - пустые
|
||||
if(block_num != PARAMS_LAST_BLOCK && cur->numb == block_num)
|
||||
{
|
||||
return FLASH_BLOCK_ALREADY_EXIST;
|
||||
}
|
||||
last_numb = cur->numb;
|
||||
}
|
||||
|
||||
addr += flash_block_size;
|
||||
}
|
||||
|
||||
#if defined(TRACE_FIND_BLOCK)
|
||||
LED1_TRACE_EXIT();
|
||||
#endif
|
||||
|
||||
if(first_free_addr == -1)
|
||||
{
|
||||
if(free_numb)
|
||||
{
|
||||
*free_numb = last_numb = cur->numb;
|
||||
}
|
||||
return FLASH_BLOCK_FLASH_FULL;
|
||||
}
|
||||
|
||||
if(free_addr)
|
||||
*free_addr = (uint32_t)first_free_addr;
|
||||
if(free_numb)
|
||||
*free_numb = found_free_numb;
|
||||
return FLASH_BLOCK_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Внутренняя проверка блока на корректность
|
||||
* @param blk Указатель на блок ParamsFlash_t
|
||||
* @return
|
||||
* - @ref FLASH_BLOCK_OK — блок корректен
|
||||
* - @ref FLASH_BLOCK_EMPTY — блок не инициализирован
|
||||
* - @ref FLASH_BLOCK_CRC_ERROR — CRC не совпадает
|
||||
*/
|
||||
static FlashBlockStatus_t __ParamsFlash_VerifyBlock(volatile ParamsFlash_t *blk)
|
||||
{
|
||||
uint16_t crc = 0;
|
||||
uint16_t empty_cnt = 0;
|
||||
uint16_t *blk_uintptr = NULL;
|
||||
int i = 0;
|
||||
|
||||
if(blk == NULL)
|
||||
return FLASH_BLOCK_INIT_ERR;
|
||||
|
||||
blk_uintptr = (uint16_t*)blk;
|
||||
for(i = 0; i < flash_block_size/2; i++)
|
||||
{
|
||||
if(blk_uintptr[i] == EMPTY_MEMORY)
|
||||
empty_cnt++;
|
||||
}
|
||||
if(empty_cnt == flash_block_size/2)
|
||||
return FLASH_BLOCK_EMPTY;
|
||||
|
||||
// if(blk->numb == EMPTY_MEMORY && blk->size == EMPTY_MEMORY)
|
||||
// return FLASH_BLOCK_EMPTY;
|
||||
|
||||
crc = crc16((uint8_t*)blk, flash_block_size-2);
|
||||
if(crc != blk->crc16)
|
||||
return FLASH_BLOCK_CRC_ERROR;
|
||||
|
||||
return FLASH_BLOCK_OK;
|
||||
}
|
||||
|
||||
|
||||
/* === Внутренние асинхронные функции ==================================== */
|
||||
|
||||
#if defined(FLASH_WORKING_NONBLOCKING)
|
||||
|
||||
/**
|
||||
* @brief Обработчик неблокирующей записи в Flash
|
||||
* @param h Указатель на handle параметров в Flash
|
||||
* @return 0 — запись завершена, 1 — запись в процессе, <0 — ошибка
|
||||
* @code Алгоритм
|
||||
* 1. Проверяется что флеш свободна
|
||||
* 2. Если выставлен флаг для записи write_pending - инициализируется её начало
|
||||
* 3. При каждом вызове записывается блок размером PARAMS_FLASH_ASYNCH_BUFFER_SIZE
|
||||
* 4. Когда будет записан весь блок - сбрасывается флаги
|
||||
* @endcode
|
||||
*/
|
||||
static int __ParamsFlash_WriteHandle(ParamsFlashHandle_t *h)
|
||||
{
|
||||
static ParamsFlashHandle_t* current_handle = NULL; // текущий обратаываемый handle
|
||||
// размер подблока для записи. Каждый вызов __ParamsFlash_WriteHandle будет записывать это количество слов
|
||||
static uint16_t sub_block_size = PARAMS_FLASH_ASYNCH_BUFFER_SIZE;
|
||||
// переменные для контроля записи
|
||||
uint16_t *blk_ptr = NULL; // вспомогательный указатель на блок для записи
|
||||
static uint32_t current_addr = 0;
|
||||
static uint32_t current_block_size = 0;
|
||||
static int write_in_progress = 0;
|
||||
|
||||
if(h == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if(!h->initialized) // неинициализировная структура
|
||||
{
|
||||
h->status = FLASH_BLOCK_INIT_ERR;
|
||||
return -1;
|
||||
}
|
||||
/* Если нет активного write - выходим */
|
||||
if(!h->write_pending)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/* Если есть write_in_progress у другого handle - выходим*/
|
||||
if(write_in_progress && current_handle != h) {
|
||||
h->status = FLASH_BLOCK_BUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Проверяем статус аппаратной занятости флеш */
|
||||
if(flash_toggle_bit_check(current_addr))
|
||||
{
|
||||
h->status = FLASH_BLOCK_BUSY;
|
||||
return 1; // операция еще не завершена
|
||||
}
|
||||
|
||||
/* Если операция только начинается - инициализируем */
|
||||
if(!write_in_progress)
|
||||
{
|
||||
if(FLASH_WORKING_CHECK(h)) // программная занятость флеш
|
||||
{
|
||||
h->status = FLASH_BLOCK_BUSY;
|
||||
return -1;
|
||||
}
|
||||
FLASH_WORKING_ENTER(h);
|
||||
|
||||
/* Запуск WRITE */
|
||||
current_handle = h;
|
||||
current_addr = h->next_block_adr;
|
||||
write_in_progress = 1;
|
||||
h->write_word_cnt = 0;
|
||||
}
|
||||
|
||||
// Записываем блок во Flash
|
||||
// определяем размер блока на иттерации
|
||||
if((flash_block_size - h->write_word_cnt) > sub_block_size)
|
||||
{
|
||||
current_block_size = sub_block_size; // записываем подблок целиком
|
||||
}
|
||||
else
|
||||
{
|
||||
current_block_size = flash_block_size - h->write_word_cnt; // записываем оставшиется слова (меньше подблока)
|
||||
}
|
||||
|
||||
// записываем подблок
|
||||
blk_ptr = (uint16_t*)&h->blk_tmp;
|
||||
if(RunFlashData((unsigned long)&blk_ptr[h->write_word_cnt], current_addr, current_block_size, 0))
|
||||
{
|
||||
h->status = FLASH_BLOCK_WRITE_ERR;
|
||||
FLASH_WORKING_EXIT(h);
|
||||
write_in_progress = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
h->write_word_cnt += current_block_size;
|
||||
current_addr += current_block_size;
|
||||
|
||||
if(h->write_word_cnt < flash_block_size)
|
||||
{
|
||||
return 1; // записываем до тех пор пока не запишем весь блок
|
||||
}
|
||||
|
||||
FLASH_WORKING_EXIT(h);
|
||||
current_handle = NULL;
|
||||
h->next_block_adr = current_addr;
|
||||
h->write_pending = 0;
|
||||
write_in_progress = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Обработчик неблокирующего стирания Flash
|
||||
* @param h Указатель на handle параметров в Flash
|
||||
* @return 0 — стирание завершено, 1 — стирание в процессе, <0 — ошибка
|
||||
* @details Стирается неактивный сектор
|
||||
* @code Алгоритм
|
||||
* 1. Проверяется что флеш свободна
|
||||
* 2. Если выставлен флаг для ерейза неактивного сектора erase_pending - инициализируется начало ерейза
|
||||
* 3. При каждом вызове проверяется состояние флеш (toggle bit)
|
||||
* 4. Когда ерейз завершен - сбрасываются флаги
|
||||
* @endcode
|
||||
*/
|
||||
static int __ParamsFlash_EraseHandle(ParamsFlashHandle_t *h)
|
||||
{
|
||||
static ParamsFlashHandle_t* current_handle = NULL; // текущий обратаываемый handle
|
||||
static uint32_t current_addr = 0;
|
||||
static int erase_in_progress = 0;
|
||||
|
||||
if(h == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if(!h->initialized) // неинициализировная структура
|
||||
{
|
||||
h->status = FLASH_BLOCK_INIT_ERR;
|
||||
return -1;
|
||||
}
|
||||
/* Если нет активного erase - выходим */
|
||||
if(!h->sector[!h->sect_curr_ind].erase_pending)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/* Если есть erase_in_progress у другого handle - выходим*/
|
||||
if(erase_in_progress && current_handle != h) {
|
||||
h->status = FLASH_BLOCK_BUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Если операция только начинается - инициализируем */
|
||||
if(!erase_in_progress)
|
||||
{
|
||||
/* Проверяем статус занятости флеш */
|
||||
if(flash_toggle_bit_check(h->sector[!h->sect_curr_ind].addr_start))
|
||||
{
|
||||
h->status = FLASH_BLOCK_BUSY;
|
||||
return 1; // операция еще не завершена
|
||||
}
|
||||
|
||||
if(FLASH_WORKING_CHECK(h)) // программная занятость флеш
|
||||
{
|
||||
h->status = FLASH_BLOCK_BUSY;
|
||||
return -1;
|
||||
}
|
||||
FLASH_WORKING_ENTER(h);
|
||||
|
||||
/* Запуск ERASE */
|
||||
current_handle = h;
|
||||
current_addr = h->sector[!h->sect_curr_ind].addr_start;
|
||||
erase_in_progress = 1;
|
||||
if(flash_erase_start_abs_address(current_addr))
|
||||
{
|
||||
h->status = FLASH_BLOCK_WRITE_ERR;
|
||||
FLASH_WORKING_EXIT(h);
|
||||
erase_in_progress = 0;
|
||||
current_addr = 0;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Проверяем статус текущей операции стирания */
|
||||
if(flash_toggle_bit_check(current_addr))
|
||||
{
|
||||
return 1; // операция еще не завершена
|
||||
}
|
||||
|
||||
|
||||
/* Если дошли до конца - завершаем операцию */
|
||||
FLASH_WORKING_EXIT(h);
|
||||
current_handle = NULL;
|
||||
erase_in_progress = 0;
|
||||
h->sector[!h->sect_curr_ind].erase_pending = 0;
|
||||
h->sector[!h->sect_curr_ind].next_block_adr = h->sector[!h->sect_curr_ind].addr_start;
|
||||
h->status = FLASH_BLOCK_OK;
|
||||
return 0; // операция завершена
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
380
Src/set_to_mem.c
Normal file
380
Src/set_to_mem.c
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user