/** * Get log used flash total size. * * @return log used flash total size */ size_t ef_log_get_used_size(void) { EF_ASSERT(log_start_addr); EF_ASSERT(log_end_addr); /* must be call this function after initialize OK */ EF_ASSERT(init_ok); if (log_start_addr < log_end_addr) { return log_end_addr - log_start_addr + 4; } else if (log_start_addr > log_end_addr) { return LOG_AREA_SIZE - (log_start_addr - log_end_addr) + 4; } else { return 0; } }
/** * Flash port for hardware initialize. * * @param env_addr ENV start address * @param env_total_size ENV sector total bytes size (@note must be word alignment) * @param erase_min_size the minimum size of Flash erasure * @param default_env default ENV set for user * @param default_env_size default ENV size * @param log_total_size saved log area size * * @return result */ EfErrCode ef_port_init(uint32_t *env_addr, size_t *env_total_size, size_t *erase_min_size, ef_env const **default_env, size_t *default_env_size, size_t *log_size) { EfErrCode result = EF_NO_ERR; EF_ASSERT(EF_USER_SETTING_ENV_SIZE % 4 == 0); EF_ASSERT(ENV_SECTION_SIZE % 4 == 0); *env_addr = ENV_START_ADDR; *env_total_size = ENV_SECTION_SIZE; *erase_min_size = ERASE_MIN_SIZE; *default_env = default_env_set; *default_env_size = sizeof(default_env_set) / sizeof(default_env_set[0]); *log_size = LOG_AREA_SIZE; return result; }
/** * Erase data on flash. * @note This operation is irreversible. * @note This operation's units is different which on many chips. * * @param addr flash address * @param size erase bytes size * * @return result */ EfErrCode ef_port_erase(uint32_t addr, size_t size) { EfErrCode result = EF_NO_ERR; FLASH_Status flash_status; size_t erase_pages, i; /* make sure the start address is a multiple of FLASH_ERASE_MIN_SIZE */ EF_ASSERT(addr % ERASE_MIN_SIZE == 0); /* calculate pages */ erase_pages = size / PAGE_SIZE; if (size % PAGE_SIZE != 0) { erase_pages++; } /* start erase */ FLASH_Unlock(); FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR); for (i = 0; i < erase_pages; i++) { flash_status = FLASH_ErasePage(addr + (PAGE_SIZE * i)); if (flash_status != FLASH_COMPLETE) { result = EF_ERASE_ERR; break; } } FLASH_Lock(); return result; }
/** * Flash port for hardware initialize. * * @param env_addr ENV start address * @param env_total_size ENV sector total bytes size (@note must be word alignment) * @param erase_min_size the minimum size of Flash erasure * @param default_env default ENV set for user * @param default_env_size default ENV size * @param log_total_size saved log area size * * @return result */ EfErrCode ef_port_init(uint32_t *env_addr, size_t *env_total_size, size_t *erase_min_size, ef_env const **default_env, size_t *default_env_size, size_t *log_size) { EfErrCode result = EF_NO_ERR; EF_ASSERT(EF_USER_SETTING_ENV_SIZE % 4 == 0); EF_ASSERT(ENV_SECTION_SIZE % 4 == 0); *env_addr = ENV_START_ADDR; *env_total_size = ENV_SECTION_SIZE; *erase_min_size = ERASE_MIN_SIZE; *default_env = default_env_set; *default_env_size = sizeof(default_env_set) / sizeof(default_env_set[0]); rt_sem_init(&env_cache_lock, "env lock", 1, RT_IPC_FLAG_PRIO); return result; }
/** * Read data from flash. * @note This operation's units is word. * * @param addr flash address * @param buf buffer to store read data * @param size read bytes size * * @return result */ EfErrCode ef_port_read(uint32_t addr, uint32_t *buf, size_t size) { EfErrCode result = EF_NO_ERR; EF_ASSERT(size % 4 == 0); /* You can add your code under here. */ return result; }
/** * Erase data on flash. * @note This operation is irreversible. * @note This operation's units is different which on many chips. * * @param addr flash address * @param size erase bytes size * * @return result */ EfErrCode ef_port_erase(uint32_t addr, size_t size) { EfErrCode result = EF_NO_ERR; /* make sure the start address is a multiple of ERASE_MIN_SIZE */ EF_ASSERT(addr % ERASE_MIN_SIZE == 0); /* You can add your code under here. */ return result; }
/** * Read data from flash. * @note This operation's units is word. * * @param addr flash address * @param buf buffer to store read data * @param size read bytes size * * @return result */ EfErrCode ef_port_read(uint32_t addr, uint32_t *buf, size_t size) { EfErrCode result = EF_NO_ERR; const sfud_flash *flash = sfud_get_device_table() + SFUD_SST25_DEVICE_INDEX; EF_ASSERT(size % 4 == 0); sfud_read(flash, addr, size, (uint8_t *)buf); return result; }
/** * Read data from flash. * @note This operation's units is word. * * @param addr flash address * @param buf buffer to store read data * @param size read bytes size * * @return result */ EfErrCode ef_port_read(uint32_t addr, uint32_t *buf, size_t size) { EfErrCode result = EF_NO_ERR; EF_ASSERT(size % 4 == 0); /*copy from flash to ram */ for (; size > 0; size -= 4, addr += 4, buf++) { *buf = *(uint32_t *) addr; } return result; }
/** * Clean all log which in flash. * * @return result */ EfErrCode ef_log_clean(void) { EfErrCode result = EF_NO_ERR; EF_ASSERT(log_area_start_addr); /* clean address */ log_start_addr = log_end_addr = log_area_start_addr; /* erase log flash area */ result = ef_port_erase(log_area_start_addr, LOG_AREA_SIZE); return result; }
/** * The flash save log function initialize. * * @return result */ EfErrCode ef_log_init(void) { EfErrCode result = EF_NO_ERR; EF_ASSERT(LOG_AREA_SIZE); EF_ASSERT(EF_ERASE_MIN_SIZE); /* the log area size must be an integral multiple of erase minimum size. */ EF_ASSERT(LOG_AREA_SIZE % EF_ERASE_MIN_SIZE == 0); /* the log area size must be more than twice of EF_ERASE_MIN_SIZE */ EF_ASSERT(LOG_AREA_SIZE / EF_ERASE_MIN_SIZE >= 2); #ifdef EF_USING_ENV log_area_start_addr = EF_START_ADDR + ENV_AREA_SIZE; #else log_area_start_addr = EF_START_ADDR; #endif /* find the log store start address and end address */ find_start_and_end_addr(); /* initialize OK */ init_ok = true; return result; }
/** * Write data to flash. * @note This operation's units is word. * @note This operation must after erase. @see flash_erase. * * @param addr flash address * @param buf the write data buffer * @param size write bytes size * * @return result */ EfErrCode ef_port_write(uint32_t addr, const uint32_t *buf, size_t size) { EfErrCode result = EF_NO_ERR; sfud_err sfud_result = SFUD_SUCCESS; const sfud_flash *flash = sfud_get_device_table() + SFUD_SST25_DEVICE_INDEX; EF_ASSERT(size % 4 == 0); sfud_result = sfud_write(flash, addr, size, (const uint8_t *)buf); if(sfud_result != SFUD_SUCCESS) { result = EF_WRITE_ERR; } return result; }
/** * Erase data on flash. * @note This operation is irreversible. * @note This operation's units is different which on many chips. * * @param addr flash address * @param size erase bytes size * * @return result */ EfErrCode ef_port_erase(uint32_t addr, size_t size) { EfErrCode result = EF_NO_ERR; sfud_err sfud_result = SFUD_SUCCESS; const sfud_flash *flash = sfud_get_device_table() + SFUD_SST25_DEVICE_INDEX; /* make sure the start address is a multiple of FLASH_ERASE_MIN_SIZE */ EF_ASSERT(addr % EF_ERASE_MIN_SIZE == 0); sfud_result = sfud_erase(flash, addr, size); if(sfud_result != SFUD_SUCCESS) { result = EF_ERASE_ERR; } return result; }
/** * Write data to flash. * @note This operation's units is word. * @note This operation must after erase. @see flash_erase. * * @param addr flash address * @param buf the write data buffer * @param size write bytes size * * @return result */ EfErrCode ef_port_write(uint32_t addr, const uint32_t *buf, size_t size) { EfErrCode result = EF_NO_ERR; size_t i; uint32_t read_data; EF_ASSERT(size % 4 == 0); FLASH_Unlock(); FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR); for (i = 0; i < size; i += 4, buf++, addr += 4) { /* write data */ FLASH_ProgramWord(addr, *buf); read_data = *(uint32_t *)addr; /* check data */ if (read_data != *buf) { result = EF_WRITE_ERR; break; } } FLASH_Lock(); return result; }
/** * Write log to flash. * * @param log the log which will be write to flash * @param size write bytes size * * @return result */ EfErrCode ef_log_write(const uint32_t *log, size_t size) { EfErrCode result = EF_NO_ERR; size_t cur_using_size = ef_log_get_used_size(), write_size = 0, writable_size = 0; uint32_t write_addr, erase_addr; EF_ASSERT(size % 4 == 0); /* must be call this function after initialize OK */ EF_ASSERT(init_ok); /* write address is after log end address when LOG AREA isn't empty */ if (log_start_addr != log_end_addr) { write_addr = log_end_addr + 4; } else { write_addr = log_start_addr; } /* write the already erased but not used area */ writable_size = EF_ERASE_MIN_SIZE - ((write_addr - log_area_start_addr) % EF_ERASE_MIN_SIZE); if ((writable_size != EF_ERASE_MIN_SIZE) || (log_start_addr == log_end_addr)) { if (size > writable_size) { result = ef_port_write(write_addr, log, writable_size); if (result != EF_NO_ERR) { goto exit; } write_size += writable_size; } else { result = ef_port_write(write_addr, log, size); log_end_addr = write_addr + size - 4; goto exit; } } /* erase and write remain log */ while (true) { /* calculate next available sector address */ erase_addr = write_addr = get_next_flash_sec_addr(write_addr - 4); /* move the flash log start address to next available sector address */ if (log_start_addr == erase_addr) { log_start_addr = get_next_flash_sec_addr(log_start_addr); } /* erase sector */ result = ef_port_erase(erase_addr, EF_ERASE_MIN_SIZE); if (result == EF_NO_ERR) { if (size - write_size > EF_ERASE_MIN_SIZE) { result = ef_port_write(write_addr, log + write_size / 4, EF_ERASE_MIN_SIZE); if (result != EF_NO_ERR) { goto exit; } log_end_addr = write_addr + EF_ERASE_MIN_SIZE - 4; write_size += EF_ERASE_MIN_SIZE; write_addr += EF_ERASE_MIN_SIZE; } else { result = ef_port_write(write_addr, log + write_size / 4, size - write_size); if (result != EF_NO_ERR) { goto exit; } log_end_addr = write_addr + (size - write_size) - 4; break; } } else { goto exit; } } exit: return result; }
/** * Read log from flash. * * @param index index for saved log. * Minimum index is 0. * Maximum index is log used flash total size - 1. * @param log the log which will read from flash * @param size read bytes size * * @return result */ EfErrCode ef_log_read(size_t index, uint32_t *log, size_t size) { EfErrCode result = EF_NO_ERR; size_t cur_using_size = ef_log_get_used_size(); size_t read_size_temp = 0; EF_ASSERT(size % 4 == 0); EF_ASSERT(index + size <= cur_using_size); /* must be call this function after initialize OK */ EF_ASSERT(init_ok); if (!size) { return result; } if (log_start_addr < log_end_addr) { result = ef_port_read(log_area_start_addr + index, log, size); } else if (log_start_addr > log_end_addr) { if (log_start_addr + index + size <= log_area_start_addr + LOG_AREA_SIZE) { /* Flash log area * |--------------| * log_area_start_addr --> |##############| * |##############| * |##############| * |--------------| * |##############| * |##############| * |##############| <-- log_end_addr * |--------------| * log_start_addr --> |##############| * read start --> |**************| <-- read end * |##############| * |--------------| * * read from (log_start_addr + index) to (log_start_addr + index + size) */ result = ef_port_read(log_start_addr + index, log, size); } else if (log_start_addr + index < log_area_start_addr + LOG_AREA_SIZE) { /* Flash log area * |--------------| * log_area_start_addr --> |**************| <-- read end * |##############| * |##############| * |--------------| * |##############| * |##############| * |##############| <-- log_end_addr * |--------------| * log_start_addr --> |##############| * read start --> |**************| * |**************| * |--------------| * read will by 2 steps * step1: read from (log_start_addr + index) to flash log area end address * step2: read from flash log area start address to read size's end address */ read_size_temp = (log_area_start_addr + LOG_AREA_SIZE) - (log_start_addr + index); result = ef_port_read(log_start_addr + index, log, read_size_temp); if (result == EF_NO_ERR) { result = ef_port_read(log_area_start_addr, log + read_size_temp, size - read_size_temp); } } else { /* Flash log area * |--------------| * log_area_start_addr --> |##############| * read start --> |**************| * |**************| <-- read end * |--------------| * |##############| * |##############| * |##############| <-- log_end_addr * |--------------| * log_start_addr --> |##############| * |##############| * |##############| * |--------------| * read from (log_start_addr + index - LOG_AREA_SIZE) to read size's end address */ result = ef_port_read(log_start_addr + index - LOG_AREA_SIZE, log, size); } } return result; }