bs_bcu_app/bsp/bsp_eeprom.c

565 lines
20 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "kit_data.h"
#include "kit_debug.h"
//#include "bsp_head.h"
//#include "bsp_flash.h"
#include "bsp_eeprom.h"
#define BSP_EEPROM_HEAD_LEN 0x0C
#define BSP_EEPROM_DATA_EMPTY 0xFFFFFFFF
EEpromItem *_eeprom_item;
static bool eeprom_format(EEpromItem * item, AreaItem * area);
static bool eeprom_transfer(EEpromItem * item, AreaItem * area);
static bool eeprom_load_area(EEpromItem * item, AreaItem * area);
static bool eeprom_load_def_data(EEpromItem * item, AreaItem * area);
static bool eeprom_check_data(uint16_t idx, uint16_t value, EepromDataType type);
static bool eeprom_write_static_data(EEpromItem * item, uint16_t idx, uint32_t value);
static bool eeprom_is_remain_enough(AreaItem * area, uint32_t need_space);
static uint8_t eeprom_get_area_type(EEpromItem * item, uint16_t idx);
static uint8_t eeprom_get_area_type(EEpromItem * item, uint16_t idx)
{
return (item->format[idx].property & BSP_EEPROM_AREA_BIT_MASK);
}
static bool eeprom_is_remain_enough(AreaItem * area, uint32_t need_space)
{
KIT_ASSERT_PARAM(area != NULL);
return ((area->write_addr + need_space) <= (area->main_addr + area->area_size));
}
static bool eeprom_format(EEpromItem * item, AreaItem * area)
{
bool res = false;
KIT_ASSERT_PARAM((item != NULL) && (area != NULL));
if((flash_series_erase_page(item->flash, area->main_addr, area->erase_page_num) == kKitResult_Ok)
&& (flash_series_erase_page(item->flash, area->sub_addr, area->erase_page_num) == kKitResult_Ok)
&& (bsp_head_set_status(item->flash, area->main_addr, kHeadStatus_Start) == kKitResult_Ok)
&& (bsp_head_set_status(item->flash, area->main_addr, kHeadStatus_Finsih) == kKitResult_Ok))
{
area->write_addr = area->main_addr + BSP_EEPROM_HEAD_LEN;
res = true;
}
return res;
}
/***********************************************************************************
*Case full move read = write res
* 1 1 1 1 1
* 2 1 1 0 0
* 3 1 0 - 0
* 4 0 - 1 1
* 5 0 - 0 0
*************************************************************************************/
static bool eeprom_write_static_data(EEpromItem * item, uint16_t idx, uint32_t value)
{
bool res;
uint32_t write_cnt = 0;
KIT_ASSERT_PARAM(item != NULL);
value &= 0x0000FFFF;
value |= ((uint32_t)idx << 16);
while (write_cnt++ <= BSP_EEPROM_REWRITE_CNT)
{
res = flash_write_u32_with_check_in(item->flash, &item->static_area.write_addr, value);
res &= flash_checken_write_u32(item->flash, item->static_area.write_addr + item->check_addr_offset - 4, ~value); //写校验值
if(res == true)
item->data_buf[idx] = value;
if ((eeprom_is_remain_enough(&item->static_area, 4) == false) && (eeprom_transfer(item, &item->static_area) == false))
return false;
if (res == true)
return true;
}
return false;
}
/***************************搬运时意外情况************************
1.写完head1后掉电或者未搬完掉电(valid receive)
*****************************************************************/
static bool eeprom_transfer(EEpromItem * item, AreaItem * area)
{
uint32_t idx, tmp, addr, write_cnt = 0;
KIT_ASSERT_PARAM((item != NULL) && (area != NULL));
if (bsp_head_get_status(item->flash, area->sub_addr) != kHeadStatus_None)
{
if (flash_series_erase_page(item->flash, area->sub_addr, area->erase_page_num) != kKitResult_Ok)
return false;
}
if (bsp_head_set_status(item->flash, area->sub_addr, kHeadStatus_Start) != kKitResult_Ok)
return false;
addr = area->sub_addr + BSP_EEPROM_HEAD_LEN;
for (idx = 0; idx < item->total_data_cnt; idx++)
{
write_cnt = 0;
if (eeprom_get_area_type(item, idx) == area->type)
{
tmp = ((uint32_t)idx << 16) | item->data_buf[idx];
while (write_cnt++ < BSP_EEPROM_REWRITE_CNT)
{
if (flash_write_u32_with_check_in(item->flash, &addr, tmp) == true)
{
if((area->type == BSP_EEPROM_AREA_STATIC)
&& (flash_checken_write_u32(item->flash, addr + item->check_addr_offset - 4, ~tmp) == false))
{
continue;
}
break;
}
}
if(write_cnt >= BSP_EEPROM_REWRITE_CNT)
return false;
}
}
//搬完数据后立即写标志后再擦除
if ((flash_series_erase_page(item->flash, area->main_addr, area->erase_page_num) == kKitResult_Ok)
&& (bsp_head_set_status(item->flash, area->sub_addr, kHeadStatus_Finsih) == kKitResult_Ok))
{
tmp = area->main_addr;
area->main_addr = area->sub_addr;
area->sub_addr = tmp;
area->write_addr = addr;
}
return true;
}
//Tan 20230909 优化eeprom 初始化标志位
#define EEPROM_INIT_FLAG_NUM 40
static bool eeprom_load_data(EEpromItem * item, AreaItem * area)
{
bool res = true;
uint32_t is_data_load[EEPROM_INIT_FLAG_NUM];
uint32_t tmp = 0, ntmp = 0, idx, read_addr, end_addr;
KIT_ASSERT_PARAM((item != NULL) && (area != NULL));
read_addr = area->main_addr + BSP_EEPROM_HEAD_LEN;
end_addr = area->main_addr + area->area_size;
kit_set_buf(is_data_load, EEPROM_INIT_FLAG_NUM * 4, 0);
while (read_addr < end_addr)
{
flash_read_u32(item->flash, read_addr, &tmp);
if(area->type == BSP_EEPROM_AREA_STATIC)
flash_read_u32(item->flash, read_addr + item->check_addr_offset, &ntmp);
else
ntmp = ~tmp;
if (tmp == BSP_EEPROM_DATA_EMPTY)
break;
read_addr += 4;
if(tmp + ntmp == 0xFFFFFFFF)
{
idx = (uint16_t)(tmp >> 16);
if ((idx < item->total_data_cnt) && (eeprom_get_area_type(item, idx) == area->type))
{
KIT_SET_32B_ARRAY_BIT(is_data_load, idx);
item->data_buf[idx] = (uint16_t)tmp;
}
}
}
area->write_addr = read_addr;
if(area->type == BSP_EEPROM_AREA_STATIC)
{
for (idx = 0; idx < item->total_data_cnt; idx++)
{
//TODO 初始化满,且正好新加了一个参数
if ((KIT_GET_32B_ARRAY_BIT(is_data_load, idx) == 0)
&& (eeprom_get_area_type(item, idx) == BSP_EEPROM_AREA_STATIC))
{
tmp = item->format[idx].config_default;
res &= eeprom_write_static_data(item, idx, tmp);
}
}
}
return res;
}
static bool eeprom_load_def_data(EEpromItem * item, AreaItem * area)
{
bool res = true;
uint32_t idx;
KIT_ASSERT_PARAM((item != NULL) && (area != NULL));
//只加载静态区默认值
if (area->type == BSP_EEPROM_AREA_STATIC)
{
for (idx = 0; idx < item->total_data_cnt; idx++)
{
if (eeprom_get_area_type(item, idx) == area->type)
{
item->data_buf[idx] = item->format[idx].config_default;
res &= eeprom_write_static_data(item, idx, item->data_buf[idx]);
}
}
}
return res;
}
/*******************************************************************************
B1 B2 MB 情况
1. V E B1 正常模式
2. V RI B1 换页中掉电
3. V RD B2 换完页后掉电
4. O RD B2 头部未擦除完全
4. E RD B2 擦除页时掉电
4. E V B2 完成换页
*******************************************************************************/
static bool eeprom_load_area(EEpromItem * item, AreaItem * area)
{
bool res = false;
HeadStatus head_part1_st, head_part2_st;
uint32_t tmp;
KIT_ASSERT_PARAM((item != NULL) && (area != NULL));
head_part1_st = bsp_head_get_status(item->flash, area->main_addr);
head_part2_st = bsp_head_get_status(item->flash, area->sub_addr);
if (head_part2_st == kHeadStatus_Finsih)
{
tmp = area->main_addr;
area->main_addr = area->sub_addr;
area->sub_addr = tmp;
}
/***********************************************************************************
*Case block1 block2 mark
* 1 empty(sub) valid(main) normal
* 2 valid(main) empty(sub) normal
***********************************************************************************/
if(((head_part1_st == kHeadStatus_Finsih) && (head_part2_st == kHeadStatus_None))
||((head_part1_st == kHeadStatus_None) && (head_part2_st == kHeadStatus_Finsih)))
{
if (eeprom_load_data(item, area) == true)
{
if (area->type == BSP_EEPROM_AREA_DYNAMIC)
{
tmp = area->data_cnt << 3;
}
else
{
//Tan 20230920 静态区预留40字节
tmp = 4 * 10;
}
//可能在需要换页擦除时掉电,上电需要检测是否需要换页
if((eeprom_is_remain_enough(area, tmp) == false)
&& (eeprom_transfer(item, area) == false))
return false;
res = true;
}
}
/*************************************************************************************
*Case block1 block2 mark
* 1 valid(main) receiving(sub) interrupt while transfer(should continue the transfer)
* 2 receiving(sub) valid(main) interrupt while transfer(should continue the transfer)
**************************************************************************************/
else if(((head_part1_st == kHeadStatus_Finsih) && (head_part2_st == kHeadStatus_Start))
||((head_part1_st == kHeadStatus_Start) && (head_part2_st == kHeadStatus_Finsih)))
{
if((flash_series_erase_page(item->flash, area->sub_addr, area->erase_page_num) == kKitResult_Ok)
&& (eeprom_load_data(item, area) == true)
&& (eeprom_transfer(item, area) == true))
res = true;
}
/***********************************************************************************
*Case Page0 Page1 mark
* 1 empty(sub) received(main) interrupt while modify the flag or interrupt while erase(transfer finish)
* 2 received(main) empty(sub) interrupt while modify the flag or interrupt while erase(transfer finish)
***********************************************************************************/
// else if((head_joint & kBspEepromHeadSt_Received) == kBspEepromHeadSt_Received)
// {
// if((flash_series_erase_page(item->flash, area->sub_addr, area->page_num * area->type) == kKitResult_Ok)
// && (eeprom_set_head_status(area->main_addr, BSP_EEPROM_HEAD_PART3) == true)
// && (eeprom_load_data(item, area) == true))
// res = true;
// }
/***********************************************************************************
*Case Page0 Page1 mark
* 1 empty empty maybe first to use or exception
* 2 valid valid exception
* 3 receive receive exception
* 4 other other page0 or page1 or both not the set state
************************************************************************************/
else
{
if((eeprom_format(item, area) == true)
&& (eeprom_load_def_data(item, area) == true))
res = true;
}
return res;
}
/*********************************************************************************************
1.eeprom数据结构备份区可选主区和校验区可放置在1个page中主区和副区会相互转换
+-------+-------+-------+-------+-------+-------+-------+-------+-------+
| | | | | | | | | |
| 备份区| S主区 |校验区 | S副区 | 校验 | D主区 | D副区 | | |
| | | | | 副区 | | | | |
| | | | | | | | | |
+-------+-------+-------+-------+-------+-------+-------+-------+-------+
**********************************************************************************************/
bool bsp_eeprom_init(EEpromItem *item, uint8_t backup_page_num, uint8_t static_page_num, uint8_t dynamic_page_num, uint32_t start_addr)
{
bool res = true;
uint32_t idx, tmp, static_num = 0, dynamic_num = 0;
KIT_ASSERT_PARAM(item != NULL);
if (item != NULL)
{
_eeprom_item = item;
item->backup_area_addr = start_addr;
item->backup_area_page_num = backup_page_num;
//计算静态区和动态区数据个数
for (idx = 0; idx < item->total_data_cnt; idx++)
{
if (eeprom_get_area_type(item, idx) == BSP_EEPROM_AREA_STATIC)
static_num++;
else if (eeprom_get_area_type(item, idx) == BSP_EEPROM_AREA_DYNAMIC)
dynamic_num++;
}
//407 小容量页较少,将主区和校验区放在一个页中,即将一个页分为两个区用
#if defined(STM32F40_41xxx) || defined(STM32F429_439xx)
tmp = flash_get_page_size(item->flash) >> 1;
#else
tmp = flash_get_page_size(item->flash);
#endif
if ((((static_num + 4) << 2) >= tmp * static_page_num)
|| (((dynamic_num + 4) << 2) >= tmp * dynamic_page_num))
return false;
item->check_addr_offset = tmp * static_page_num;
item->static_area.data_cnt = static_num;
item->dynamic_area.data_cnt = dynamic_num;
item->static_area.type = BSP_EEPROM_AREA_STATIC;
item->static_area.area_size = tmp * static_page_num;
item->static_area.main_addr = (start_addr + backup_page_num * tmp);
item->static_area.sub_addr = (item->static_area.main_addr + static_page_num * tmp *2);
item->dynamic_area.type = BSP_EEPROM_AREA_DYNAMIC;
item->dynamic_area.area_size = tmp * static_page_num;
item->dynamic_area.main_addr = (item->static_area.sub_addr + static_page_num * tmp * 2);
#if defined(STM32F40_41xxx) || defined(STM32F429_439xx)
item->dynamic_area.erase_page_num = item->static_area.erase_page_num = 1;
item->dynamic_area.sub_addr = (item->dynamic_area.main_addr + dynamic_page_num * tmp * 2);
#else
item->static_area.erase_page_num = static_page_num * BSP_EEPROM_AREA_STATIC;
item->dynamic_area.erase_page_num = dynamic_page_num * BSP_EEPROM_AREA_DYNAMIC;
item->dynamic_area.sub_addr = (item->dynamic_area.main_addr + dynamic_page_num * tmp);
#endif
#if defined(STM32F429_439xx) //20231005 by songman 防止配置恢复默认配置
if((item->static_area.main_addr == start_addr)
&& ((ARM_READ_INT32U(0x08006010) == 0xFFFFFFFF) && (ARM_READ_INT32U(0x08006014) == 0xFFFFFFFF)))
{
flash_series_write_u32(item->flash, 0x08006000, (uint8_t *)0x08008000, 0x2000);
flash_series_erase_page(item->flash, 0x08008000, 1);
}
#endif
if (static_num != 0)
res &= eeprom_load_area(item, &item->static_area);
if (dynamic_num != 0)
res &= eeprom_load_area(item, &item->dynamic_area);
}
return res;
}
static bool eeprom_check_data(uint16_t idx, uint16_t value, EepromDataType type)
{
bool res = false;
uint32_t max, min;
if (((_eeprom_item->format[idx].property) & BSP_EEPROM_CHECK_MAX_MIN_BIT_MASK) == BSP_EEPROM_CHECK_MAX_MIN_ON)
{
max = _eeprom_item->format[idx].config_max;
min = _eeprom_item->format[idx].config_min;
if (((type == kEepromDataType_Full) && (value >= min) && (value <= max ))
|| ((type == kEepromDataType_High) && (value >= (min >> 8)) && (value <= (max >> 8)))
|| ((type == kEepromDataType_Low) && (value >= (uint8_t)min) && (value <= (uint8_t)max)))
{
res = true;
}
}
else
{
res = true;
}
return res;
}
bool bsp_eeprom_set_data(uint16_t idx, uint32_t value, EepromDataType type)
{
bool res = false;
uint16_t write_value;
KIT_ASSERT_PARAM((idx < _eeprom_item->total_data_cnt) && (type < kEepromDataType_End));
if ((idx < _eeprom_item->total_data_cnt)
&& (type < kEepromDataType_End)
&& (eeprom_check_data(idx, value, type) == true))
{
res = true;
write_value = _eeprom_item->data_buf[idx];
if (type == kEepromDataType_High)
write_value = (write_value & 0x00FF) | (value << 8);
else if (type == kEepromDataType_Low)
write_value = (write_value & 0xFF00) | (value & 0x00FF);
else if (type == kEepromDataType_Full)
write_value = value;
else
{
//如果4字节先写低16位再写高16位
if(_eeprom_item->data_buf[idx] != (uint16_t)value)
{
_eeprom_item->data_buf[idx] = (uint16_t)value;
}
write_value = value >>16;
idx++;
}
if (_eeprom_item->data_buf[idx] != write_value)
{
_eeprom_item->data_buf[idx] = (uint16_t)write_value;
}
}
return res;
}
bool bsp_eeprom_save_data(uint16_t idx, uint32_t value, EepromDataType type)
{
bool res = false;
uint16_t write_value;
KIT_ASSERT_PARAM((idx < _eeprom_item->total_data_cnt) && (type < kEepromDataType_End));
if ((idx < _eeprom_item->total_data_cnt) && (type < kEepromDataType_End) && (eeprom_check_data(idx, value, type) == true))
{
res = true;
write_value = _eeprom_item->data_buf[idx];
if (type == kEepromDataType_High)
write_value = (write_value & 0x00FF) | (value << 8);
else if (type == kEepromDataType_Low)
write_value = (write_value & 0xFF00) | (value & 0x00FF);
else if (type == kEepromDataType_Full)
write_value = value;
else
{
if((_eeprom_item->data_buf[idx] != (uint16_t)value)
|| ((_eeprom_item->format[idx].property & BSP_EEPROM_CHECK_EQUAL_BIT_MASK) == false))
{
res &= eeprom_write_static_data(_eeprom_item, idx, (uint16_t)value);
}
write_value = value >>16;
idx++;
}
if((_eeprom_item->data_buf[idx] != (uint16_t)write_value)
|| ((_eeprom_item->format[idx].property & BSP_EEPROM_CHECK_EQUAL_BIT_MASK) == false))
{
res &= eeprom_write_static_data(_eeprom_item, idx, write_value);
}
}
return res;
}
uint32_t bsp_eeprom_get_data(uint16_t idx, EepromDataType type)
{
uint32_t value = 0;
KIT_ASSERT_PARAM((idx < _eeprom_item->total_data_cnt) && (type < kEepromDataType_End));
if ((idx < _eeprom_item->total_data_cnt) && (type < kEepromDataType_End))
{
value = _eeprom_item->data_buf[idx];
if (type == kEepromDataType_High)
value >>= 8;
else if (type == kEepromDataType_Low)
value &= 0x00FF;
else if (type == kEepromDataType_Double)
value |= (uint32_t)_eeprom_item->data_buf[idx + 1] << 16;
}
return value;
}
bool bsp_eeprom_backup_static_area(void)
{
uint32_t i, write, addr = _eeprom_item->backup_area_addr;
if ((_eeprom_item->backup_area_page_num != 0) && (flash_series_erase_page(_eeprom_item->flash, addr, _eeprom_item->static_area.erase_page_num) == kKitResult_Ok))
{
for (i = 0; i < _eeprom_item->total_data_cnt; i++)
{
write = (uint32_t)_eeprom_item->data_buf[i] | (i << 16);
if (flash_write_u32_with_check_in(_eeprom_item->flash, &addr, write) == false)
return false;
}
}
return true;
}
bool bsp_eeprom_recovery_static_area(EEpromItem *item, uint16_t except_idx)
{
bool res = false;
uint16_t data = bsp_eeprom_get_data(except_idx, kEepromDataType_Full);
if((eeprom_format(item, &item->static_area) == true)
&& (eeprom_load_def_data(item, &item->static_area) == true))
{
res = true;
bsp_eeprom_save_data(except_idx, data, kEepromDataType_Full);
}
return res;
}
void bsp_eeprom_power_off_save_data(EepromPoData *data, uint32_t len)
{
uint32_t i, idx, write_cnt;
//静态区页满情况:在上电换页时掉电,此时静态区数据不用存
if((data != NULL) && (_eeprom_item != NULL) && (len <= _eeprom_item->dynamic_area.data_cnt)
&& (eeprom_is_remain_enough(&_eeprom_item->dynamic_area, _eeprom_item->dynamic_area.data_cnt << 3) == true))
{
for (i = 0; i < len; i++)
{
write_cnt = 0;
idx = data[i].item.idx;
if ((idx < _eeprom_item->total_data_cnt) && (_eeprom_item->data_buf[idx] != data[i].item.value)
&& (eeprom_get_area_type(_eeprom_item, idx) == BSP_EEPROM_AREA_DYNAMIC))
{
while ((flash_write_u32_with_check_in(_eeprom_item->flash, &_eeprom_item->dynamic_area.write_addr, data[i].value) == false)
&& (write_cnt++ < BSP_EEPROM_REWRITE_CNT))
{
}
}
}
}
}