- исправлены баги библиотеки memspi - добавлены модули для сохранения настреок в eeprom и flash (с равномерным износом) - надо тестить, проверять и рефакторить
1233 lines
43 KiB
C
1233 lines
43 KiB
C
/**
|
||
**************************************************************************
|
||
* @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
|