#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; } #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 { 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)) { } } } } }