1、【增加】ENV功能的掉电保护模式,正在保存数据时意外掉电,下次上电后数据将会自动回滚。

Signed-off-by: armink <armink.ztl@gmail.com>
This commit is contained in:
armink 2015-07-10 15:11:21 +08:00
parent f65c5a7a60
commit 6326077976
5 changed files with 404 additions and 64 deletions

View File

@ -46,9 +46,11 @@ extern "C" {
/* #define EF_USING_LOG */
/* the user setting size of ENV, must be word alignment */
#define EF_USER_SETTING_ENV_SIZE (2 * 1024) /* default 2K */
/* using wear leveling mode or normal mode */
/* using wear leveling mode or normal mode for ENV */
/* #define EF_ENV_USING_WL_MODE */
#define EF_ENV_USING_NORMAL_MODE
/* using power fail safeguard mode for ENV */
/* #define EF_ENV_USING_PFS_MODE */
/* EasyFlash debug print function. Must be implement by user. */
#define EF_DEBUG(...) ef_log_debug(__FILE__, __LINE__, __VA_ARGS__)
@ -62,7 +64,7 @@ if (!(EXPR)) \
while (1); \
}
/* EasyFlash software version number */
#define EF_SW_VERSION "1.07.06"
#define EF_SW_VERSION "1.07.10"
typedef struct _eflash_env{
char *key;
@ -90,7 +92,7 @@ typedef enum {
EfErrCode easyflash_init(void);
#ifdef EF_USING_ENV
/* env.c env_wl.c */
/* ef_env.c ef_env_wl.c */
void ef_load_env(void);
void ef_print_env(void);
char *ef_get_env(const char *key);
@ -102,7 +104,7 @@ size_t ef_get_env_write_bytes(void);
#endif
#ifdef EF_USING_IAP
/* iap.c */
/* ef_iap.c */
EfErrCode ef_erase_bak_app(size_t app_size);
EfErrCode ef_erase_user_app(uint32_t user_app_addr, size_t user_app_size);
EfErrCode ef_erase_bl(uint32_t bl_addr, size_t bl_size);
@ -113,19 +115,19 @@ EfErrCode ef_copy_bl_from_bak(uint32_t bl_addr, size_t bl_size);
#endif
#ifdef EF_USING_LOG
/* log.c */
/* ef_log.c */
EfErrCode ef_log_read(size_t index, uint32_t *log, size_t size);
EfErrCode ef_log_write(const uint32_t *log, size_t size);
EfErrCode ef_log_clean(void);
size_t ef_log_get_used_size(void);
#endif
/* utils.c */
/* ef_utils.c */
uint32_t ef_calc_crc32(uint32_t crc, const void *buf, size_t size);
FlashSecrorStatus ef_get_sector_status(uint32_t addr, size_t sec_size);
uint32_t ef_find_sec_using_end_addr(uint32_t addr, size_t sec_size);
/* port.c */
/* ef_port.c */
EfErrCode ef_port_read(uint32_t addr, uint32_t *buf, size_t size);
EfErrCode ef_port_erase(uint32_t addr, size_t size);
EfErrCode ef_port_write(uint32_t addr, const uint32_t *buf, size_t size);

View File

@ -32,15 +32,10 @@
#define ENV_START_ADDR /* @note you must define it for a value */
/* the minimum size of flash erasure */
#define ERASE_MIN_SIZE /* @note you must define it for a value */
#ifdef EF_ENV_USING_WL_MODE
/* ENV section total bytes size in wear leveling mode. */
/* ENV section total bytes size. */
#define ENV_SECTION_SIZE /* @note you must define it for a value */
#else
/* ENV section total bytes size in normal mode. It's equal with FLASH_USER_SETTING_ENV_SIZE */
#define ENV_SECTION_SIZE (EF_USER_SETTING_ENV_SIZE)
#endif
/* saved log section size */
#define LOG_AREA_SIZE /* @note you must define it for a value */
#define LOG_AREA_SIZE /* @note you must define it for a value */
/* print debug information of flash */
#define PRINT_DEBUG

View File

@ -83,26 +83,13 @@ EfErrCode easyflash_init(void) {
#ifdef EF_USING_IAP
if (result == EF_NO_ERR) {
if (ef_get_env_total_size() < erase_min_size) {
result = ef_iap_init(env_start_addr + erase_min_size + log_size);
} else if (ef_get_env_total_size() % erase_min_size == 0) {
result = ef_iap_init(env_start_addr + ef_get_env_total_size() + log_size);
} else {
result = ef_iap_init((ef_get_env_total_size() / erase_min_size + 1) * erase_min_size + log_size);
}
result = ef_iap_init(env_start_addr + env_total_size + log_size);
}
#endif
#ifdef EF_USING_LOG
if (result == EF_NO_ERR) {
if (ef_get_env_total_size() < erase_min_size) {
result = ef_log_init(env_start_addr + erase_min_size, log_size, erase_min_size);
} else if (ef_get_env_total_size() % erase_min_size == 0) {
result = ef_log_init(env_start_addr + ef_get_env_total_size(), log_size, erase_min_size);
} else {
result = ef_log_init((ef_get_env_total_size() / erase_min_size + 1) * erase_min_size,
log_size, erase_min_size);
}
result = ef_log_init(env_start_addr + env_total_size, log_size, erase_min_size);
}
#endif

View File

@ -43,12 +43,19 @@
* All ENV must be 4 bytes alignment. The remaining part must fill '\0'.
*
* @note Word = 4 Bytes in this file
* @note It will has two ENV areas(Area0, Area1) when used power fail safeguard mode.
*/
/* flash ENV parameters index and size in system section */
enum {
/* data section ENV end address index in system section */
ENV_PARAM_INDEX_END_ADDR = 0,
#ifdef EF_ENV_USING_PFS_MODE
/* saved count for ENV area */
ENV_PARAM_INDEX_SAVED_COUNT,
#endif
/* data section CRC32 code index in system section */
ENV_PARAM_INDEX_DATA_CRC,
/* flash ENV parameters word size */
@ -61,11 +68,20 @@ enum {
static ef_env const *default_env_set = NULL;
/* default ENV set size, must be initialized by user */
static size_t default_env_set_size = NULL;
/* flash ENV all section total size */
static size_t env_total_size = NULL;
/* ENV RAM cache */
static uint32_t env_cache[EF_USER_SETTING_ENV_SIZE / 4] = { 0 };
/* ENV start address in flash */
static uint32_t env_start_addr = NULL;
#ifdef EF_ENV_USING_PFS_MODE
/* current load ENV area address */
static uint32_t cur_load_area_addr = NULL;
/* next save ENV area address */
static uint32_t next_save_area_addr = NULL;
#endif
static uint32_t get_env_system_addr(void);
static uint32_t get_env_data_addr(void);
static uint32_t get_env_end_addr(void);
@ -97,18 +113,35 @@ EfErrCode ef_env_init(uint32_t start_addr, size_t total_size, size_t erase_min_s
EF_ASSERT(start_addr);
EF_ASSERT(total_size);
/* user_size must equal with total_size in normal mode */
EF_ASSERT(EF_USER_SETTING_ENV_SIZE == total_size);
EF_ASSERT(default_env);
EF_ASSERT(default_env_size < total_size);
/* must be word alignment for ENV */
EF_ASSERT(total_size % 4 == 0);
#ifndef EF_ENV_USING_PFS_MODE
/* total_size must be aligned with erase_min_size */
if (EF_USER_SETTING_ENV_SIZE % erase_min_size == 0) {
EF_ASSERT(EF_USER_SETTING_ENV_SIZE == total_size);
} else {
EF_ASSERT((EF_USER_SETTING_ENV_SIZE/erase_min_size + 1)*erase_min_size == total_size);
}
#else
/* total_size must be aligned with erase_min_size */
if (EF_USER_SETTING_ENV_SIZE % erase_min_size == 0) {
/* it has double area when used power fail safeguard mode */
EF_ASSERT(2*EF_USER_SETTING_ENV_SIZE == total_size);
} else {
/* it has double area when used power fail safeguard mode */
EF_ASSERT(2*(EF_USER_SETTING_ENV_SIZE/erase_min_size + 1)*erase_min_size == total_size);
}
#endif
env_start_addr = start_addr;
env_total_size = total_size;
default_env_set = default_env;
default_env_set_size = default_env_size;
EF_DEBUG("Env start address is 0x%08X, size is %d bytes.\n", start_addr, total_size);
EF_DEBUG("ENV start address is 0x%08X, size is %d bytes.\n", start_addr, total_size);
ef_load_env();
@ -133,6 +166,11 @@ EfErrCode ef_env_set_default(void){
/* set environment end address is at data section start address */
set_env_end_addr(get_env_data_addr());
#ifdef EF_ENV_USING_PFS_MODE
/* set saved count to default 0 */
env_cache[ENV_PARAM_INDEX_SAVED_COUNT] = 0;
#endif
/* create default ENV */
for (i = 0; i < default_env_set_size; i++) {
create_env(default_env_set[i].key, default_env_set[i].value);
@ -152,8 +190,13 @@ EfErrCode ef_env_set_default(void){
* @return system section start address
*/
static uint32_t get_env_system_addr(void) {
#ifndef EF_ENV_USING_PFS_MODE
EF_ASSERT(env_start_addr);
return env_start_addr;
#else
EF_ASSERT(cur_load_area_addr);
return cur_load_area_addr;
#endif
}
/**
@ -162,8 +205,7 @@ static uint32_t get_env_system_addr(void) {
* @return data section start address
*/
static uint32_t get_env_data_addr(void) {
EF_ASSERT(env_start_addr);
return env_start_addr + ENV_PARAM_BYTE_SIZE;
return get_env_system_addr() + ENV_PARAM_BYTE_SIZE;
}
/**
@ -202,7 +244,7 @@ static size_t get_env_data_size(void) {
* @return size
*/
size_t ef_get_env_total_size(void) {
return EF_USER_SETTING_ENV_SIZE;
return env_total_size;
}
/**
@ -211,7 +253,12 @@ size_t ef_get_env_total_size(void) {
* @return write bytes
*/
size_t ef_get_env_write_bytes(void) {
#ifndef EF_ENV_USING_PFS_MODE
return get_env_end_addr() - env_start_addr;
#else
/* It has two ENV areas(Area0, Area1) on used power fail safeguard mode */
return 2 * (get_env_end_addr() - get_env_system_addr());
#endif
}
/**
@ -233,11 +280,13 @@ static EfErrCode write_env(const char *key, const char *value) {
env_str_len = (env_str_len / 4 + 1) * 4;
}
/* check capacity of ENV */
if (env_str_len + get_env_data_size() >= ef_get_env_total_size()) {
if (env_str_len + get_env_data_size() >= EF_USER_SETTING_ENV_SIZE) {
return EF_ENV_FULL;
}
/* calculate current ENV ram cache end address */
env_cache_bak += ef_get_env_write_bytes();
env_cache_bak += get_env_end_addr() - get_env_system_addr();
/* copy key name */
memcpy(env_cache_bak, key, ker_len);
env_cache_bak += ker_len;
@ -278,7 +327,7 @@ static uint32_t *find_env(const char *key) {
/* from data section start to data section end */
env_start = (char *) ((char *) env_cache + ENV_PARAM_BYTE_SIZE);
env_end = (char *) ((char *) env_cache + ef_get_env_write_bytes());
env_end = (char *) ((char *) env_cache + (get_env_end_addr() - get_env_system_addr()));
/* ENV is null */
if (env_start == env_end) {
@ -468,21 +517,29 @@ void ef_print_env(void) {
}
}
}
ef_print("\nENV size: %ld/%ld bytes, mode: normal.\n",
#ifndef EF_ENV_USING_PFS_MODE
ef_print("\nENV size: %ld/%ld bytes.\n",
ef_get_env_write_bytes(), ef_get_env_total_size());
#else
ef_print("\nENV size: %ld/%ld bytes, saved count: %ld, mode: power fail safeguard.\n",
ef_get_env_write_bytes(), ef_get_env_total_size(), env_cache[ENV_PARAM_INDEX_SAVED_COUNT]);
#endif
}
/**
* Load flash ENV to ram.
*/
#ifndef EF_ENV_USING_PFS_MODE
void ef_load_env(void) {
uint32_t *env_cache_bak, env_end_addr;
/* read ENV end address from flash */
ef_port_read(get_env_system_addr() + ENV_PARAM_INDEX_END_ADDR * 4, &env_end_addr, 4);
/* if ENV is not initialize or flash has dirty data, set default for it */
if ((env_end_addr == 0xFFFFFFFF)
|| (env_end_addr > env_start_addr + ef_get_env_total_size())) {
if ((env_end_addr == 0xFFFFFFFF) || (env_end_addr < env_start_addr)
|| (env_end_addr > env_start_addr + EF_USER_SETTING_ENV_SIZE)) {
ef_env_set_default();
} else {
/* set ENV end address */
@ -501,17 +558,110 @@ void ef_load_env(void) {
}
}
}
#else
void ef_load_env(void) {
uint32_t area0_start_address = env_start_addr, area1_start_address = env_start_addr
+ env_total_size / 2;
uint32_t area0_end_addr, area1_end_addr, area0_crc, area1_crc, area0_saved_count, area1_saved_count;
bool area0_is_valid = true, area1_is_valid = true;
/* read ENV area end address from flash */
ef_port_read(area0_start_address + ENV_PARAM_INDEX_END_ADDR * 4, &area0_end_addr, 4);
ef_port_read(area1_start_address + ENV_PARAM_INDEX_END_ADDR * 4, &area1_end_addr, 4);
if ((area0_end_addr == 0xFFFFFFFF) || (area0_end_addr < area0_start_address)
|| (area0_end_addr > area0_start_address + EF_USER_SETTING_ENV_SIZE)) {
area0_is_valid = false;
}
if ((area1_end_addr == 0xFFFFFFFF) || (area1_end_addr < area1_start_address)
|| (area1_end_addr > area1_start_address + EF_USER_SETTING_ENV_SIZE)) {
area1_is_valid = false;
}
/* check area0 CRC when it is valid */
if (area0_is_valid) {
/* read ENV area0 crc32 code from flash */
ef_port_read(area0_start_address + ENV_PARAM_INDEX_DATA_CRC * 4, &area0_crc, 4);
/* read ENV from ENV area0 */
ef_port_read(area0_start_address, env_cache, area0_end_addr - area0_start_address);
/* current load ENV area address is area0 start address */
cur_load_area_addr = area0_start_address;
if (!env_crc_is_ok()) {
area0_is_valid = false;
}
}
/* check area1 CRC when it is valid */
if (area1_is_valid) {
/* read ENV area1 crc32 code from flash */
ef_port_read(area1_start_address + ENV_PARAM_INDEX_DATA_CRC * 4, &area1_crc, 4);
/* read ENV from ENV area1 */
ef_port_read(area1_start_address, env_cache, area1_end_addr - area1_start_address);
/* current load ENV area address is area1 start address */
cur_load_area_addr = area1_start_address;
if (!env_crc_is_ok()) {
area1_is_valid = false;
}
}
/* all ENV area CRC is OK then compare saved count */
if (area0_is_valid && area1_is_valid) {
/* read ENV area saved count from flash */
ef_port_read(area0_start_address + ENV_PARAM_INDEX_SAVED_COUNT * 4,
&area0_saved_count, 4);
ef_port_read(area1_start_address + ENV_PARAM_INDEX_SAVED_COUNT * 4,
&area1_saved_count, 4);
/* the bigger saved count area is valid */
if ((area0_saved_count > area1_saved_count)||((area0_saved_count == 0)&&(area1_saved_count == 0xFFFFFFFF))) {
area1_is_valid = false;
} else {
area0_is_valid = false;
}
}
if (area0_is_valid) {
/* current load ENV area address is area0 start address */
cur_load_area_addr = area0_start_address;
/* next save ENV area address is area1 start address */
next_save_area_addr = area1_start_address;
/* read all ENV from area0 */
ef_port_read(area0_start_address, env_cache, area0_end_addr - area0_start_address);
} else if (area1_is_valid) {
/* next save ENV area address is area0 start address */
next_save_area_addr = area0_start_address;
} else {
/* current load ENV area address is area1 start address */
cur_load_area_addr = area1_start_address;
/* next save ENV area address is area0 start address */
next_save_area_addr = area0_start_address;
/* set the ENV to default */
ef_env_set_default();
}
}
#endif
/**
* Save ENV to flash.
*/
EfErrCode ef_save_env(void) {
EfErrCode result = EF_NO_ERR;
uint32_t write_addr, write_size;
#ifndef EF_ENV_USING_PFS_MODE
write_addr = get_env_system_addr();
write_size = get_env_end_addr() - get_env_system_addr();
/* calculate and cache CRC32 code */
env_cache[ENV_PARAM_INDEX_DATA_CRC] = calc_env_crc();
#else
write_addr = next_save_area_addr;
write_size = get_env_end_addr() - get_env_system_addr();
/* replace next_save_area_addr with cur_load_area_addr */
next_save_area_addr = cur_load_area_addr;
cur_load_area_addr = write_addr;
/* change the ENV end address to next save area address */
set_env_end_addr(write_addr + write_size);
/* ENV area saved count +1 */
env_cache[ENV_PARAM_INDEX_SAVED_COUNT]++;
/* calculate and cache CRC32 code */
env_cache[ENV_PARAM_INDEX_DATA_CRC] = calc_env_crc();
#endif
/* erase ENV */
result = ef_port_erase(get_env_system_addr(), ef_get_env_write_bytes());
result = ef_port_erase(write_addr, write_size);
switch (result) {
case EF_NO_ERR: {
EF_INFO("Erased ENV OK.\n");
@ -525,7 +675,7 @@ EfErrCode ef_save_env(void) {
}
/* write ENV to flash */
result = ef_port_write(get_env_system_addr(), env_cache, ef_get_env_write_bytes());
result = ef_port_write(write_addr, env_cache, write_size);
switch (result) {
case EF_NO_ERR: {
EF_INFO("Saved ENV OK.\n");
@ -548,11 +698,18 @@ EfErrCode ef_save_env(void) {
static uint32_t calc_env_crc(void) {
uint32_t crc32 = 0;
/* Calculate the ENV end address and all ENV data CRC32.
* The 4 is ENV end address bytes size. */
/* Calculate the ENV end address CRC32. The 4 is ENV end address bytes size. */
crc32 = ef_calc_crc32(crc32, &env_cache[ENV_PARAM_INDEX_END_ADDR], 4);
#ifdef EF_ENV_USING_PFS_MODE
/* Calculate the ENV area saved count CRC32. */
crc32 = ef_calc_crc32(crc32, &env_cache[ENV_PARAM_INDEX_SAVED_COUNT], 4);
#endif
/* Calculate the all ENV data CRC32. */
crc32 = ef_calc_crc32(crc32, &env_cache[ENV_PARAM_WORD_SIZE], get_env_data_size());
EF_DEBUG("Calculate Env CRC32 number is 0x%08X.\n", crc32);
EF_DEBUG("Calculate ENV CRC32 number is 0x%08X.\n", crc32);
return crc32;
}
@ -564,7 +721,7 @@ static uint32_t calc_env_crc(void) {
*/
static bool env_crc_is_ok(void) {
if (calc_env_crc() == env_cache[ENV_PARAM_INDEX_DATA_CRC]) {
EF_DEBUG("Verify Env CRC32 result is OK.\n");
EF_DEBUG("Verify ENV CRC32 result is OK.\n");
return true;
} else {
return false;

View File

@ -42,7 +42,7 @@
* 2. Data section
* The data section storage ENV's parameters and detail.
* When an exception has occurred on flash erase or write. The current using data section
* address will move to next available position. This position depends on FLASH_MIN_ERASE_SIZE.
* address will move to next available position. This position depends on flash_erase_min_size.
* 2.1 ENV parameters part
* It storage ENV's parameters.
* 2.2 ENV detail part
@ -50,12 +50,19 @@
* All ENV must be 4 bytes alignment. The remaining part must fill '\0'.
*
* @note Word = 4 Bytes in this file
* @note It will has two ENV areas(Area0, Area1) in data section when used power fail safeguard mode.
*/
/* flash ENV parameters part index and size */
enum {
/* data section ENV detail part end address index */
ENV_PARAM_PART_INDEX_END_ADDR = 0,
#ifdef EF_ENV_USING_PFS_MODE
/* saved count for ENV area */
ENV_PARAM_PART_INDEX_SAVED_COUNT,
#endif
/* data section CRC32 code index */
ENV_PARAM_PART_INDEX_DATA_CRC,
/* ENV parameters part word size */
@ -68,8 +75,10 @@ enum {
static ef_env const *default_env_set = NULL;
/* default ENV set size, must be initialized by user */
static size_t default_env_set_size = NULL;
/* flash ENV all section total size */
/* flash ENV all section(system section and data section) total size */
static size_t env_total_size = NULL;
/* flash ENV data section size */
static size_t env_data_section_size = NULL;
/* the minimum size of flash erasure */
static size_t flash_erase_min_size = NULL;
/* ENV RAM cache */
@ -79,6 +88,11 @@ static uint32_t env_start_addr = NULL;
/* current using data section address */
static uint32_t cur_using_data_addr = NULL;
#ifdef EF_ENV_USING_PFS_MODE
/* next save ENV area address */
static uint32_t next_save_area_addr = NULL;
#endif
static uint32_t get_env_start_addr(void);
static uint32_t get_cur_using_data_addr(void);
static uint32_t get_env_detail_addr(void);
@ -116,10 +130,21 @@ EfErrCode ef_env_init(uint32_t start_addr, size_t total_size, size_t erase_min_s
EF_ASSERT(default_env);
EF_ASSERT(default_env_size < EF_USER_SETTING_ENV_SIZE);
/* must be word alignment for ENV */
EF_ASSERT(EF_USER_SETTING_ENV_SIZE % 4 == 0);
EF_ASSERT(total_size % 4 == 0);
/* the ENV total size should be an integral multiple of erase minimum size. */
EF_ASSERT(total_size % erase_min_size == 0);
EF_ASSERT(EF_USER_SETTING_ENV_SIZE % 4 == 0);
/* system section size is erase_min_size, so last part is data section */
env_data_section_size = total_size - erase_min_size;
/* the ENV data section size should be an integral multiple of erase minimum size. */
EF_ASSERT(env_data_section_size % erase_min_size == 0);
#ifndef EF_ENV_USING_PFS_MODE
EF_ASSERT(env_data_section_size >= EF_USER_SETTING_ENV_SIZE);
#else
/* it has double area when used power fail safeguard mode */
EF_ASSERT(env_data_section_size >= 2*EF_USER_SETTING_ENV_SIZE);
EF_ASSERT((env_data_section_size / erase_min_size) % 2 == 0);
#endif
env_start_addr = start_addr;
env_total_size = total_size;
@ -127,7 +152,7 @@ EfErrCode ef_env_init(uint32_t start_addr, size_t total_size, size_t erase_min_s
default_env_set = default_env;
default_env_set_size = default_env_size;
EF_DEBUG("Env start address is 0x%08X, size is %d bytes.\n", start_addr, total_size);
EF_DEBUG("ENV start address is 0x%08X, size is %d bytes.\n", start_addr, total_size);
ef_load_env();
@ -152,6 +177,11 @@ EfErrCode ef_env_set_default(void){
/* set ENV detail part end address is at ENV detail part start address */
set_env_detail_end_addr(get_env_detail_addr());
#ifdef EF_ENV_USING_PFS_MODE
/* set saved count to default 0 */
env_cache[ENV_PARAM_PART_INDEX_SAVED_COUNT] = 0;
#endif
/* create default ENV */
for (i = 0; i < default_env_set_size; i++) {
create_env(default_env_set[i].key, default_env_set[i].value);
@ -242,7 +272,6 @@ static size_t get_env_detail_size(void) {
*/
/* must be initialized */
static size_t get_env_user_used_size(void) {
return get_env_detail_end_addr() - get_cur_using_data_addr();
}
@ -252,7 +281,20 @@ static size_t get_env_user_used_size(void) {
* @return write bytes
*/
size_t ef_get_env_write_bytes(void) {
#ifndef EF_ENV_USING_PFS_MODE
return get_env_detail_end_addr() - get_env_start_addr();
#else
if (get_cur_using_data_addr()
< get_env_start_addr() + flash_erase_min_size + env_data_section_size / 2) {
/* current using is ENV area0 */
return flash_erase_min_size + 2 * (get_env_detail_end_addr() - (get_env_start_addr()
+flash_erase_min_size));
} else {
/* current using is ENV area1 */
return flash_erase_min_size + 2 * (get_env_detail_end_addr() - (get_env_start_addr()
+ flash_erase_min_size + env_data_section_size / 2));
}
#endif
}
/**
@ -523,14 +565,22 @@ void ef_print_env(void) {
}
}
}
#ifndef EF_ENV_USING_PFS_MODE
ef_print("\nENV size: %ld/%ld bytes, write bytes %ld/%ld, mode: wear leveling.\n",
get_env_user_used_size(), EF_USER_SETTING_ENV_SIZE, ef_get_env_write_bytes(),
ef_get_env_total_size());
#else
ef_print("\nENV size: %ld/%ld bytes, write bytes %ld/%ld, saved count: %ld, mode: wear leveling and power fail safeguard.\n",
get_env_user_used_size(), EF_USER_SETTING_ENV_SIZE, ef_get_env_write_bytes(),
ef_get_env_total_size(), env_cache[ENV_PARAM_PART_INDEX_SAVED_COUNT]);
#endif
}
/**
* Load flash ENV to ram.
*/
#ifndef EF_ENV_USING_PFS_MODE
void ef_load_env(void) {
uint32_t *env_cache_bak, env_end_addr, using_data_addr;
@ -573,22 +623,138 @@ void ef_load_env(void) {
}
}
#else
void ef_load_env(void) {
/* ENV area0 current using address default value */
uint32_t area0_default_cur_using_addr = get_env_start_addr() + flash_erase_min_size;
/* ENV area1 current using address default value */
uint32_t area1_default_cur_using_addr = area0_default_cur_using_addr + env_data_section_size / 2;
uint32_t area0_cur_using_addr, area1_cur_using_addr, area0_end_addr, area1_end_addr;
uint32_t area0_crc, area1_crc, area0_saved_count, area1_saved_count;
bool area0_is_valid = true, area1_is_valid = true;
/* read ENV area0 and area1 current using address */
ef_port_read(get_env_start_addr(), &area0_cur_using_addr, 4);
ef_port_read(get_env_start_addr() + 4, &area1_cur_using_addr, 4);
/* if ENV is not initialize or flash has dirty data, set it isn't valid */
if ((area0_cur_using_addr == 0xFFFFFFFF)
|| (area0_cur_using_addr > get_env_start_addr() + ef_get_env_total_size())
|| (area0_cur_using_addr < get_env_start_addr() + flash_erase_min_size)) {
area0_is_valid = false;
}
if ((area1_cur_using_addr == 0xFFFFFFFF)
|| (area1_cur_using_addr > get_env_start_addr() + ef_get_env_total_size())
|| (area1_cur_using_addr < get_env_start_addr() + flash_erase_min_size)) {
area1_is_valid = false;
}
/* check area0 end address when it is valid */
if (area0_is_valid) {
/* read ENV area end address from flash */
ef_port_read(area0_cur_using_addr + ENV_PARAM_PART_INDEX_END_ADDR * 4, &area0_end_addr, 4);
if ((area0_end_addr == 0xFFFFFFFF) || (area0_end_addr < area0_cur_using_addr)
|| (area0_end_addr > area0_cur_using_addr + EF_USER_SETTING_ENV_SIZE)) {
area0_is_valid = false;
}
}
/* check area1 end address when it is valid */
if (area1_is_valid) {
/* read ENV area end address from flash */
ef_port_read(area1_cur_using_addr + ENV_PARAM_PART_INDEX_END_ADDR * 4, &area1_end_addr, 4);
if ((area1_end_addr == 0xFFFFFFFF) || (area1_end_addr < area1_cur_using_addr)
|| (area1_end_addr > area1_cur_using_addr + EF_USER_SETTING_ENV_SIZE)) {
area1_is_valid = false;
}
}
/* check area0 CRC when it is valid */
if (area0_is_valid) {
/* read ENV area0 crc32 code from flash */
ef_port_read(area0_cur_using_addr + ENV_PARAM_PART_INDEX_DATA_CRC * 4, &area0_crc, 4);
/* read ENV from ENV area0 */
ef_port_read(area0_cur_using_addr, env_cache, area0_end_addr - area0_cur_using_addr);
/* current using data section address is area0 current using data section address */
set_cur_using_data_addr(area0_cur_using_addr);
if (!env_crc_is_ok()) {
area0_is_valid = false;
}
}
/* check area1 CRC when it is valid */
if (area1_is_valid) {
/* read ENV area1 crc32 code from flash */
ef_port_read(area1_cur_using_addr + ENV_PARAM_PART_INDEX_DATA_CRC * 4, &area1_crc, 4);
/* read ENV from ENV area1 */
ef_port_read(area1_cur_using_addr, env_cache, area1_end_addr - area1_cur_using_addr);
/* current using data section address is area1 current using data section address */
set_cur_using_data_addr(area1_cur_using_addr);
if (!env_crc_is_ok()) {
area1_is_valid = false;
}
}
/* all ENV area CRC is OK then compare saved count */
if (area0_is_valid && area1_is_valid) {
/* read ENV area saved count from flash */
ef_port_read(area0_cur_using_addr + ENV_PARAM_PART_INDEX_SAVED_COUNT * 4,
&area0_saved_count, 4);
ef_port_read(area1_cur_using_addr + ENV_PARAM_PART_INDEX_SAVED_COUNT * 4,
&area1_saved_count, 4);
/* the bigger saved count area is valid */
if ((area0_saved_count > area1_saved_count)||((area0_saved_count == 0)&&(area1_saved_count == 0xFFFFFFFF))) {
area1_is_valid = false;
} else {
area0_is_valid = false;
}
}
if (area0_is_valid) {
/* current using data section address is area0 current using data section address */
set_cur_using_data_addr(area0_cur_using_addr);
/* next save ENV area address is area1 current using address default value */
next_save_area_addr = area1_default_cur_using_addr;
/* read all ENV from area0 */
ef_port_read(area0_cur_using_addr, env_cache, area0_end_addr - area0_cur_using_addr);
} else if (area1_is_valid) {
/* next save ENV area address is area0 current using address default value */
next_save_area_addr = area0_default_cur_using_addr;
} else {
/* current using data section address is area1 current using address default value */
set_cur_using_data_addr(area1_default_cur_using_addr);
/* next save ENV area address default is area0 current using address default value */
next_save_area_addr = area0_default_cur_using_addr;
/* save current using data section address to flash*/
save_cur_using_data_addr(area0_default_cur_using_addr);
save_cur_using_data_addr(area1_default_cur_using_addr);
/* set the ENV to default */
ef_env_set_default();
}
}
#endif
/**
* Save ENV to flash.
*/
EfErrCode ef_save_env(void) {
EfErrCode result = EF_NO_ERR;
uint32_t cur_data_addr_bak = get_cur_using_data_addr(), move_offset_addr;
size_t env_detail_size = get_env_detail_size();
uint32_t cur_using_addr_bak, move_offset_addr;
size_t env_used_size = get_env_user_used_size();
#ifndef EF_ENV_USING_PFS_MODE
cur_using_addr_bak = get_cur_using_data_addr();
#else
cur_using_addr_bak = next_save_area_addr;
/* replace next_save_area_addr with cur_using_data_addr */
next_save_area_addr = get_cur_using_data_addr();
set_cur_using_data_addr(cur_using_addr_bak);
/* change the ENV detail end address to next save area address */
set_env_detail_end_addr(get_cur_using_data_addr() + env_used_size);
/* ENV area saved count +1 */
env_cache[ENV_PARAM_PART_INDEX_SAVED_COUNT]++;
#endif
/* wear leveling process, automatic move ENV to next available position */
while (get_cur_using_data_addr() + env_detail_size
while (get_cur_using_data_addr() + env_used_size
< get_env_start_addr() + ef_get_env_total_size()) {
/* calculate and cache CRC32 code */
env_cache[ENV_PARAM_PART_INDEX_DATA_CRC] = calc_env_crc();
/* erase ENV */
result = ef_port_erase(get_cur_using_data_addr(), ENV_PARAM_PART_BYTE_SIZE + env_detail_size);
result = ef_port_erase(get_cur_using_data_addr(), env_used_size);
switch (result) {
case EF_NO_ERR: {
EF_INFO("Erased ENV OK.\n");
@ -609,8 +775,7 @@ EfErrCode ef_save_env(void) {
}
}
/* write ENV to flash */
result = ef_port_write(get_cur_using_data_addr(), env_cache,
ENV_PARAM_PART_BYTE_SIZE + env_detail_size);
result = ef_port_write(get_cur_using_data_addr(), env_cache, env_used_size);
switch (result) {
case EF_NO_ERR: {
EF_INFO("Saved ENV OK.\n");
@ -636,10 +801,10 @@ EfErrCode ef_save_env(void) {
}
}
if (get_cur_using_data_addr() + env_detail_size
if (get_cur_using_data_addr() + env_used_size
< get_env_start_addr() + ef_get_env_total_size()) {
/* current using data section address has changed, save it */
if (get_cur_using_data_addr() != cur_data_addr_bak) {
if (get_cur_using_data_addr() != cur_using_addr_bak) {
save_cur_using_data_addr(get_cur_using_data_addr());
}
} else {
@ -664,7 +829,7 @@ static uint32_t calc_env_crc(void) {
* The 4 is ENV end address bytes size. */
crc32 = ef_calc_crc32(crc32, &env_cache[ENV_PARAM_PART_INDEX_END_ADDR], 4);
crc32 = ef_calc_crc32(crc32, &env_cache[ENV_PARAM_PART_WORD_SIZE], get_env_detail_size());
EF_DEBUG("Calculate Env CRC32 number is 0x%08X.\n", crc32);
EF_DEBUG("Calculate ENV CRC32 number is 0x%08X.\n", crc32);
return crc32;
}
@ -676,7 +841,7 @@ static uint32_t calc_env_crc(void) {
*/
static bool env_crc_is_ok(void) {
if (calc_env_crc() == env_cache[ENV_PARAM_PART_INDEX_DATA_CRC]) {
EF_DEBUG("Verify Env CRC32 result is OK.\n");
EF_DEBUG("Verify ENV CRC32 result is OK.\n");
return true;
} else {
return false;
@ -690,8 +855,10 @@ static bool env_crc_is_ok(void) {
*
* @return result
*/
#ifndef EF_ENV_USING_PFS_MODE
static EfErrCode save_cur_using_data_addr(uint32_t cur_data_addr) {
EfErrCode result = EF_NO_ERR;
/* erase ENV system section */
result = ef_port_erase(get_env_start_addr(), 4);
if (result == EF_NO_ERR) {
@ -707,6 +874,38 @@ static EfErrCode save_cur_using_data_addr(uint32_t cur_data_addr) {
}
return result;
}
#else
static EfErrCode save_cur_using_data_addr(uint32_t cur_data_addr) {
EfErrCode result = EF_NO_ERR;
uint32_t cur_using_addr[2];
/* read area0 and area1 current using data section address for backup */
ef_port_read(get_env_start_addr(), &cur_using_addr[0], 4);
ef_port_read(get_env_start_addr() + 4, &cur_using_addr[1], 4);
if (cur_data_addr < get_env_start_addr() + flash_erase_min_size + env_data_section_size / 2){
/* current using data section is in ENV area0 */
cur_using_addr[0] = cur_data_addr;
} else {
/* current using data section is in ENV area1 */
cur_using_addr[1] = cur_data_addr;
}
/* erase ENV system section */
result = ef_port_erase(get_env_start_addr(), 8);
if (result == EF_NO_ERR) {
/* write area0 and area1 current using data section address to flash */
result = ef_port_write(get_env_start_addr(), cur_using_addr, 8);
if (result == EF_WRITE_ERR) {
EF_INFO("Error: Write system section fault!\n");
EF_INFO("Note: The ENV can not be used.\n");
}
} else {
EF_INFO("Error: Erased system section fault!\n");
EF_INFO("Note: The ENV can not be used\n");
}
return result;
}
#endif
#endif /* EF_ENV_USING_WL_MODE */