Revamp variable names and update code documentation for wear levelling component

wear levelling code cleanup
This commit is contained in:
Sonika Rathi 2023-03-30 19:45:43 +05:30 committed by sonika.rathi
parent ff0135448b
commit 4585ff806a
17 changed files with 398 additions and 339 deletions

View File

@ -12,7 +12,7 @@ Partition::Partition(const esp_partition_t *partition)
this->partition = partition;
}
size_t Partition::chip_size()
size_t Partition::get_flash_size()
{
return this->partition->size;
}
@ -49,7 +49,7 @@ esp_err_t Partition::read(size_t src_addr, void *dest, size_t size)
return result;
}
size_t Partition::sector_size()
size_t Partition::get_sector_size()
{
return SPI_FLASH_SEC_SIZE;
}

View File

@ -15,7 +15,7 @@ SPI_Flash::SPI_Flash()
{
}
size_t SPI_Flash::chip_size()
size_t SPI_Flash::get_flash_size()
{
uint32_t chip_size;
esp_flash_get_size(NULL, &chip_size);
@ -67,7 +67,7 @@ esp_err_t SPI_Flash::read(size_t src_addr, void *dest, size_t size)
return result;
}
size_t SPI_Flash::sector_size()
size_t SPI_Flash::get_sector_size()
{
return SPI_FLASH_SEC_SIZE;
}

View File

@ -27,19 +27,21 @@ WL_Ext_Perf::~WL_Ext_Perf()
esp_err_t WL_Ext_Perf::config(WL_Config_s *cfg, Flash_Access *flash_drv)
{
wl_ext_cfg_t *config = (wl_ext_cfg_t *)cfg;
wl_ext_cfg_t *ext_cfg = (wl_ext_cfg_t *)cfg;
this->fat_sector_size = config->fat_sector_size;
this->flash_sector_size = cfg->sector_size;
this->flash_sector_size = ext_cfg->flash_sector_size;
this->fat_sector_size = ext_cfg->fat_sector_size;
this->sector_buffer = (uint32_t *)malloc(cfg->sector_size);
if (this->sector_buffer == NULL) {
return ESP_ERR_NO_MEM;
/*when flash and fat sector sizes are not equal, (where flash_sector_size >= fat_sector_size)
this flash_fat_sector_size_factor will be used while flash sector erase or read-write operation */
this->flash_fat_sector_size_factor = this->flash_sector_size / this->fat_sector_size;
if (this->flash_fat_sector_size_factor < 1) {
return ESP_ERR_INVALID_ARG;
}
this->size_factor = this->flash_sector_size / this->fat_sector_size;
if (this->size_factor < 1) {
return ESP_ERR_INVALID_ARG;
this->sector_buffer = (uint32_t *)malloc(ext_cfg->flash_sector_size);
if (this->sector_buffer == NULL) {
return ESP_ERR_NO_MEM;
}
return WL_Flash::config(cfg, flash_drv);
@ -50,42 +52,55 @@ esp_err_t WL_Ext_Perf::init()
return WL_Flash::init();
}
size_t WL_Ext_Perf::chip_size()
size_t WL_Ext_Perf::get_flash_size()
{
return WL_Flash::chip_size();
return WL_Flash::get_flash_size();
}
size_t WL_Ext_Perf::sector_size()
size_t WL_Ext_Perf::get_sector_size()
{
return this->fat_sector_size;
}
esp_err_t WL_Ext_Perf::erase_sector(size_t sector)
{
return this->erase_sector_fit(sector, 1);
return WL_Flash::erase_sector(sector);
}
esp_err_t WL_Ext_Perf::erase_sector_fit(uint32_t start_sector, uint32_t count)
/*
erase_sector_fit function is needed in case flash_sector_size != fat_sector_size and
sector to be erased is not multiple of flash_fat_sector_size_factor
*/
esp_err_t WL_Ext_Perf::erase_sector_fit(uint32_t first_erase_sector, uint32_t count)
{
ESP_LOGV(TAG, "%s begin, start_sector = 0x%08x, count = %i", __func__, start_sector, count);
// This method works with one flash device sector and able to erase "count" of fatfs sectors from this sector
// This method works with one flash device sector and able to erase "count" of fatfs sectors from this first_erase_sector
esp_err_t result = ESP_OK;
ESP_LOGV(TAG, "%s begin, first_erase_sector = 0x%08x, count = %i", __func__, first_erase_sector, count);
uint32_t pre_check_start = start_sector % this->size_factor;
uint32_t flash_sector_base_addr = first_erase_sector / this->flash_fat_sector_size_factor;
uint32_t pre_check_start = first_erase_sector % this->flash_fat_sector_size_factor;
for (int i = 0; i < this->size_factor; i++) {
// Except pre check and post check data area, read and store all other data to sector_buffer
for (int i = 0; i < this->flash_fat_sector_size_factor; i++) {
if ((i < pre_check_start) || (i >= count + pre_check_start)) {
result = this->read(start_sector / this->size_factor * this->flash_sector_size + i * this->fat_sector_size, &this->sector_buffer[i * this->fat_sector_size / sizeof(uint32_t)], this->fat_sector_size);
result = this->read(flash_sector_base_addr * this->flash_sector_size + i * this->fat_sector_size,
&this->sector_buffer[i * this->fat_sector_size / sizeof(uint32_t)],
this->fat_sector_size);
WL_EXT_RESULT_CHECK(result);
}
}
result = WL_Flash::erase_sector(start_sector / this->size_factor); // erase comlete flash sector
//erase complete flash sector which includes pre and post check data area
result = WL_Flash::erase_sector(flash_sector_base_addr);
WL_EXT_RESULT_CHECK(result);
// And write back only data that should not be erased...
for (int i = 0; i < this->size_factor; i++) {
/* Restore data which was previously stored to sector_buffer
back to data area which was not part of pre and post check data */
for (int i = 0; i < this->flash_fat_sector_size_factor; i++) {
if ((i < pre_check_start) || (i >= count + pre_check_start)) {
result = this->write(start_sector / this->size_factor * this->flash_sector_size + i * this->fat_sector_size, &this->sector_buffer[i * this->fat_sector_size / sizeof(uint32_t)], this->fat_sector_size);
result = this->write(flash_sector_base_addr * this->flash_sector_size + i * this->fat_sector_size,
&this->sector_buffer[i * this->fat_sector_size / sizeof(uint32_t)],
this->fat_sector_size);
WL_EXT_RESULT_CHECK(result);
}
}
@ -95,11 +110,13 @@ esp_err_t WL_Ext_Perf::erase_sector_fit(uint32_t start_sector, uint32_t count)
esp_err_t WL_Ext_Perf::erase_range(size_t start_address, size_t size)
{
esp_err_t result = ESP_OK;
//start_address as well as size should be aligned to fat_sector_size
if ((start_address % this->fat_sector_size) != 0) {
result = ESP_ERR_INVALID_ARG;
}
if (((size % this->fat_sector_size) != 0) || (size == 0)) {
result = ESP_ERR_INVALID_ARG;
result = ESP_ERR_INVALID_SIZE;
}
WL_EXT_RESULT_CHECK(result);
@ -109,49 +126,56 @@ esp_err_t WL_Ext_Perf::erase_range(size_t start_address, size_t size)
// |0|0|x|x|x|x|x|x|x|x|x|x|x|x|0|0|
// | pre | rest | rest | post | <- check ranges
//
// Pre check - the data that is not fit to the full sector at the begining of the erased block
// Post check - the data that are not fit to the full sector at the end of the erased block
// rest - data that are fit to the flash device sector at the middle of the erased block
// Pre check - the data that does not fit in the full sector at the begining of the erased block
// Post check - the data that does not fit in the full sector at the end of the erased block
// rest check - the data that fits in the full sector at the middle of the erased block
//
// In case of pre and post check situations the data of the non erased area have to be readed first and then
// stored back.
// For the rest area this operation not needed because complete flash device sector will be erased.
// In case of pre and post check situations, the data of the area which should not be erased
// as part of pre and post check data area have to read first, store at other location,
// erase complete sector and restore data of area which should not be erased.
// For the rest check area, this operation not needed because complete flash device sector will be erased.
ESP_LOGV(TAG, "%s begin, addr = 0x%08x, size = %i", __func__, start_address, size);
// Calculate pre check values
uint32_t pre_check_start = (start_address / this->fat_sector_size) % this->size_factor;
uint32_t sectors_count = size / this->fat_sector_size;
uint32_t pre_check_count = (this->size_factor - pre_check_start);
// Calculate pre check values
uint32_t pre_check_start = (start_address / this->fat_sector_size) % this->flash_fat_sector_size_factor;
uint32_t pre_check_count = (this->flash_fat_sector_size_factor - pre_check_start);
//maximum sectors count that need to be erased is sectors_count
if (pre_check_count > sectors_count) {
pre_check_count = sectors_count;
}
// Calculate post ckeck
uint32_t post_check_count = (sectors_count - pre_check_count) % this->size_factor;
// Calculate post check values
uint32_t post_check_count = (sectors_count - pre_check_count) % this->flash_fat_sector_size_factor;
uint32_t post_check_start = ((start_address + size - post_check_count * this->fat_sector_size) / this->fat_sector_size);
// Calculate rest
// Calculate rest check values
uint32_t rest_check_count = sectors_count - pre_check_count - post_check_count;
if ((pre_check_count == this->size_factor) && (0 == pre_check_start)) {
rest_check_count+=this->size_factor;
if ((pre_check_count == this->flash_fat_sector_size_factor) && (0 == pre_check_start)) {
rest_check_count+=this->flash_fat_sector_size_factor;
pre_check_count = 0;
}
uint32_t rest_check_start = start_address + pre_check_count * this->fat_sector_size;
// Here we will clear pre_check_count amount of sectors
// Clear pre_check_count sectors
if (pre_check_count != 0) {
result = this->erase_sector_fit(start_address / this->fat_sector_size, pre_check_count);
WL_EXT_RESULT_CHECK(result);
}
ESP_LOGV(TAG, "%s rest_check_start = %i, pre_check_count=%i, rest_check_count=%i, post_check_count=%i", __func__, rest_check_start, pre_check_count, rest_check_count, post_check_count);
// Clear rest_check_count sectors
if (rest_check_count > 0) {
rest_check_count = rest_check_count / this->size_factor;
rest_check_count = rest_check_count / this->flash_fat_sector_size_factor;
size_t start_sector = rest_check_start / this->flash_sector_size;
for (size_t i = 0; i < rest_check_count; i++) {
result = WL_Flash::erase_sector(start_sector + i);
WL_EXT_RESULT_CHECK(result);
}
}
// Clear post_check_count sectors
if (post_check_count != 0) {
result = this->erase_sector_fit(post_check_start, post_check_count);
WL_EXT_RESULT_CHECK(result);

View File

@ -24,16 +24,20 @@ static const char *TAG = "wl_ext_safe";
#define WL_EXT_SAFE_OK 0x12345678
#endif // WL_EXT_SAFE_OK
#ifndef WL_EXT_SAFE_OFFSET
#define WL_EXT_SAFE_OFFSET 16
#endif // WL_EXT_SAFE_OFFSET
/*
WL_Ext_Safe_State stores the buffer transaction state in between erase and write operation of the sector.
This is mainly for safety purpose, in case of power outage in between erase and write operation,
data will be recovered after power outage as temporary data is also stored on flash memory (dump_addr).
- sector_restore_sign : if any transaction was pending before power outage, then on power up,
this should be WL_EXT_SAFE_OK which indicates that data recovery from dump buffer is needed, else it should be zero.
- sector_base_addr : sector base address where data from dump buffer will be restored.
- sector_base_addr_offset : sector base address offset at which data will be restored
*/
struct WL_Ext_Safe_State {
public:
uint32_t erase_begin;
uint32_t local_addr_base;
uint32_t local_addr_shift;
uint32_t sector_restore_sign;
uint32_t sector_base_addr;
uint32_t sector_base_addr_offset;
uint32_t count;
};
@ -51,8 +55,10 @@ esp_err_t WL_Ext_Safe::config(WL_Config_s *cfg, Flash_Access *flash_drv)
result = WL_Ext_Perf::config(cfg, flash_drv);
WL_EXT_RESULT_CHECK(result);
this->state_addr = WL_Flash::chip_size() - 2 * WL_Flash::sector_size();
this->dump_addr = WL_Flash::chip_size() - 1 * WL_Flash::sector_size();
/* two extra sectors will be reserved to store buffer transaction state WL_Ext_Safe_State
and temporary storage of the actual sector data from the sector which is to be erased*/
this->buff_trans_state_addr = WL_Ext_Perf::get_flash_size() - 2 * this->flash_sector_size;
this->dump_addr = WL_Ext_Perf::get_flash_size() - 1 * this->flash_sector_size;
return ESP_OK;
}
@ -64,89 +70,110 @@ esp_err_t WL_Ext_Safe::init()
result = WL_Ext_Perf::init();
WL_EXT_RESULT_CHECK(result);
//check if any buffer write operation was pending and recover data if needed
result = this->recover();
return result;
}
size_t WL_Ext_Safe::chip_size()
size_t WL_Ext_Safe::get_flash_size()
{
ESP_LOGV(TAG, "%s size = %i", __func__, WL_Flash::chip_size() - 2 * this->flash_sector_size);
return WL_Flash::chip_size() - 2 * this->flash_sector_size;
ESP_LOGV(TAG, "%s size = %i", __func__, WL_Ext_Perf::get_flash_size() - 2 * this->flash_sector_size);
return WL_Ext_Perf::get_flash_size() - 2 * this->flash_sector_size;
}
esp_err_t WL_Ext_Safe::recover()
{
esp_err_t result = ESP_OK;
// read WL_Ext_Safe_State from flash memory at buff_trans_state_addr
WL_Ext_Safe_State state;
result = WL_Flash::read(this->state_addr, &state, sizeof(WL_Ext_Safe_State));
result = this->read(this->buff_trans_state_addr, &state, sizeof(WL_Ext_Safe_State));
WL_EXT_RESULT_CHECK(result);
ESP_LOGV(TAG, "%s recover, start_addr = 0x%08x, local_addr_base = 0x%08x, local_addr_shift = %i, count=%i", __func__, state.erase_begin, state.local_addr_base, state.local_addr_shift, state.count);
ESP_LOGV(TAG, "%s recover, start_addr = 0x%08x, sector_base_addr = 0x%08x, sector_base_addr_offset= %i, count=%i", __func__, state.sector_restore_sign, state.sector_base_addr, state.sector_base_addr_offset, state.count);
// check if we have transaction
if (state.erase_begin == WL_EXT_SAFE_OK) {
// check if we have any incomplete transaction pending.
if (state.sector_restore_sign == WL_EXT_SAFE_OK) {
// recover data from dump_addr and store it to temporary storage sector_buffer.
result = this->read(this->dump_addr, this->sector_buffer, this->flash_sector_size);
WL_EXT_RESULT_CHECK(result);
result = WL_Flash::erase_sector(state.local_addr_base); // erase comlete flash sector
//erase complete flash sector
result = this->erase_sector(state.sector_base_addr);
WL_EXT_RESULT_CHECK(result);
// And write back...
for (int i = 0; i < this->size_factor; i++) {
if ((i < state.local_addr_shift) || (i >= state.count + state.local_addr_shift)) {
result = this->write(state.local_addr_base * this->flash_sector_size + i * this->fat_sector_size, &this->sector_buffer[i * this->fat_sector_size / sizeof(uint32_t)], this->fat_sector_size);
/* Restore data which was previously stored to sector_buffer
back to data area provided by WL_Ext_Safe_State state */
for (int i = 0; i < this->flash_fat_sector_size_factor; i++) {
if ((i < state.sector_base_addr_offset) || (i >= state.count + state.sector_base_addr_offset)) {
result = this->write(state.sector_base_addr * this->flash_sector_size + i * this->fat_sector_size, &this->sector_buffer[i * this->fat_sector_size / sizeof(uint32_t)], this->fat_sector_size);
WL_EXT_RESULT_CHECK(result);
}
}
// clear transaction
result = WL_Flash::erase_range(this->state_addr, this->flash_sector_size);
// clear the buffer transaction state after the data recovery.
result = this->erase_range(this->buff_trans_state_addr, this->flash_sector_size);
}
return result;
}
esp_err_t WL_Ext_Safe::erase_sector_fit(uint32_t start_sector, uint32_t count)
/*
erase_sector_fit function is needed in case flash_sector_size != fat_sector_size and
sector to be erased is not multiple of flash_fat_sector_size_factor
*/
esp_err_t WL_Ext_Safe::erase_sector_fit(uint32_t first_erase_sector, uint32_t count)
{
esp_err_t result = ESP_OK;
uint32_t local_addr_base = start_sector / this->size_factor;
uint32_t pre_check_start = start_sector % this->size_factor;
ESP_LOGV(TAG, "%s start_sector=0x%08x, count = %i", __func__, start_sector, count);
for (int i = 0; i < this->size_factor; i++) {
uint32_t flash_sector_base_addr = first_erase_sector / this->flash_fat_sector_size_factor;
uint32_t pre_check_start = first_erase_sector % this->flash_fat_sector_size_factor;
// Except pre check and post check data area, read and store all other data to sector_buffer
ESP_LOGV(TAG, "%s first_erase_sector=0x%08x, count = %i", __func__, first_erase_sector, count);
for (int i = 0; i < this->flash_fat_sector_size_factor; i++) {
if ((i < pre_check_start) || (i >= count + pre_check_start)) {
result = this->read(start_sector / this->size_factor * this->flash_sector_size + i * this->fat_sector_size, &this->sector_buffer[i * this->fat_sector_size / sizeof(uint32_t)], this->fat_sector_size);
result = this->read(flash_sector_base_addr * this->flash_sector_size + i * this->fat_sector_size,
&this->sector_buffer[i * this->fat_sector_size / sizeof(uint32_t)],
this->fat_sector_size);
WL_EXT_RESULT_CHECK(result);
}
}
result = WL_Flash::erase_sector(this->dump_addr / this->flash_sector_size);
// For safety purpose store temporary stored data sector_buffer to flash memory at dump_addr
result = this->erase_sector(this->dump_addr / this->flash_sector_size);
WL_EXT_RESULT_CHECK(result);
result = WL_Flash::write(this->dump_addr, this->sector_buffer, this->flash_sector_size);
result = this->write(this->dump_addr, this->sector_buffer, this->flash_sector_size);
WL_EXT_RESULT_CHECK(result);
//store transaction buffer state to flash memory at buff_trans_state_addr
WL_Ext_Safe_State state;
state.erase_begin = WL_EXT_SAFE_OK;
state.local_addr_base = local_addr_base;
state.local_addr_shift = pre_check_start;
state.sector_restore_sign = WL_EXT_SAFE_OK;
state.sector_base_addr = flash_sector_base_addr;
state.sector_base_addr_offset = pre_check_start;
state.count = count;
result = WL_Flash::erase_sector(this->state_addr / this->flash_sector_size);
result = this->erase_sector(this->buff_trans_state_addr / this->flash_sector_size);
WL_EXT_RESULT_CHECK(result);
result = WL_Flash::write(this->state_addr + 0, &state, sizeof(WL_Ext_Safe_State));
result = this->write(this->buff_trans_state_addr + 0, &state, sizeof(WL_Ext_Safe_State));
WL_EXT_RESULT_CHECK(result);
// Erase
result = WL_Flash::erase_sector(local_addr_base); // erase comlete flash sector
//erase complete flash sector which includes pre and post check data area
result = this->erase_sector(flash_sector_base_addr);
WL_EXT_RESULT_CHECK(result);
// And write back...
for (int i = 0; i < this->size_factor; i++) {
/* Restore data which was previously stored to sector_buffer
back to data area which was not part of pre and post check data */
for (int i = 0; i < this->flash_fat_sector_size_factor; i++) {
if ((i < pre_check_start) || (i >= count + pre_check_start)) {
result = this->write(local_addr_base * this->flash_sector_size + i * this->fat_sector_size, &this->sector_buffer[i * this->fat_sector_size / sizeof(uint32_t)], this->fat_sector_size);
result = this->write(flash_sector_base_addr * this->flash_sector_size + i * this->fat_sector_size,
&this->sector_buffer[i * this->fat_sector_size / sizeof(uint32_t)],
this->fat_sector_size);
WL_EXT_RESULT_CHECK(result);
}
}
result = WL_Flash::erase_sector(this->state_addr / this->flash_sector_size);
// clear the buffer transaction state after data is restored properly.
result = this->erase_sector(this->buff_trans_state_addr / this->flash_sector_size);
WL_EXT_RESULT_CHECK(result);
return ESP_OK;

View File

@ -39,21 +39,21 @@ WL_Flash::~WL_Flash()
esp_err_t WL_Flash::config(wl_config_t *cfg, Flash_Access *flash_drv)
{
ESP_LOGV(TAG, "%s start_addr=0x%08x, full_mem_size=0x%08x, page_size=0x%08x, sector_size=0x%08x, updaterate=0x%08x, wr_size=0x%08x, version=0x%08x, temp_buff_size=0x%08x", __func__,
(uint32_t) cfg->start_addr,
cfg->full_mem_size,
cfg->page_size,
cfg->sector_size,
cfg->updaterate,
cfg->wr_size,
ESP_LOGV(TAG, "%s partition_start_addr=0x%08x, wl_partition_size=0x%08x, flash_sector_size=0x%08x, wl_update_rate=0x%08x, wl_pos_update_record_size=0x%08x, version=0x%08x, wl_temp_buff_size=0x%08x", __func__,
(uint32_t) cfg->wl_partition_start_addr,
cfg->wl_partition_size,
cfg->wl_page_size,
cfg->flash_sector_size,
cfg->wl_update_rate,
cfg->wl_pos_update_record_size,
cfg->version,
(uint32_t) cfg->temp_buff_size);
(uint32_t) cfg->wl_temp_buff_size);
cfg->crc = crc32::crc32_le(WL_CFG_CRC_CONST, (const unsigned char *)cfg, offsetof(wl_config_t, crc));
cfg->crc32 = crc32::crc32_le(WL_CFG_CRC_CONST, (const unsigned char *)cfg, offsetof(wl_config_t, crc32));
esp_err_t result = ESP_OK;
memcpy(&this->cfg, cfg, sizeof(wl_config_t));
if (this->cfg.temp_buff_size < this->cfg.wr_size) {
this->cfg.temp_buff_size = this->cfg.wr_size;
if (this->cfg.wl_temp_buff_size < this->cfg.wl_pos_update_record_size) {
this->cfg.wl_temp_buff_size = this->cfg.wl_pos_update_record_size;
}
this->configured = false;
if (cfg == NULL) {
@ -63,28 +63,28 @@ esp_err_t WL_Flash::config(wl_config_t *cfg, Flash_Access *flash_drv)
if (flash_drv == NULL) {
result = ESP_ERR_INVALID_ARG;
}
if ((this->cfg.sector_size % this->cfg.temp_buff_size) != 0) {
if ((this->cfg.flash_sector_size % this->cfg.wl_temp_buff_size) != 0) {
result = ESP_ERR_INVALID_ARG;
}
if (this->cfg.page_size < this->cfg.sector_size) {
if (this->cfg.wl_page_size < this->cfg.flash_sector_size) {
result = ESP_ERR_INVALID_ARG;
}
WL_RESULT_CHECK(result);
this->state_size = this->cfg.sector_size;
if (this->state_size < (sizeof(wl_state_t) + (this->cfg.full_mem_size / this->cfg.sector_size)*this->cfg.wr_size)) {
this->state_size = ((sizeof(wl_state_t) + (this->cfg.full_mem_size / this->cfg.sector_size) * this->cfg.wr_size) + this->cfg.sector_size - 1) / this->cfg.sector_size;
this->state_size = this->state_size * this->cfg.sector_size;
this->state_size = this->cfg.flash_sector_size;
if (this->state_size < (sizeof(wl_state_t) + (this->cfg.wl_partition_size / this->cfg.flash_sector_size)*this->cfg.wl_pos_update_record_size)) {
this->state_size = ((sizeof(wl_state_t) + (this->cfg.wl_partition_size / this->cfg.flash_sector_size) * this->cfg.wl_pos_update_record_size) + this->cfg.flash_sector_size - 1) / this->cfg.flash_sector_size;
this->state_size = this->state_size * this->cfg.flash_sector_size;
}
this->cfg_size = (sizeof(wl_config_t) + this->cfg.sector_size - 1) / this->cfg.sector_size;
this->cfg_size = cfg_size * this->cfg.sector_size;
this->cfg_size = (sizeof(wl_config_t) + this->cfg.flash_sector_size - 1) / this->cfg.flash_sector_size;
this->cfg_size = cfg_size * this->cfg.flash_sector_size;
this->addr_cfg = this->cfg.start_addr + this->cfg.full_mem_size - this->cfg_size;
this->addr_state1 = this->cfg.start_addr + this->cfg.full_mem_size - this->state_size * 2 - this->cfg_size; // allocate data at the end of memory
this->addr_state2 = this->cfg.start_addr + this->cfg.full_mem_size - this->state_size * 1 - this->cfg_size; // allocate data at the end of memory
this->addr_cfg = this->cfg.wl_partition_start_addr + this->cfg.wl_partition_size - this->cfg_size;
this->addr_state1 = this->cfg.wl_partition_start_addr + this->cfg.wl_partition_size - this->state_size * 2 - this->cfg_size; // allocate data at the end of memory
this->addr_state2 = this->cfg.wl_partition_start_addr + this->cfg.wl_partition_size - this->state_size * 1 - this->cfg_size; // allocate data at the end of memory
ptrdiff_t flash_sz = ((this->cfg.full_mem_size - this->state_size * 2 - this->cfg_size) / this->cfg.page_size - 1) * this->cfg.page_size; // -1 remove dummy block
this->flash_size = ((this->cfg.full_mem_size - this->state_size * 2 - this->cfg_size) / this->cfg.page_size - 1) * this->cfg.page_size; // -1 remove dummy block
ptrdiff_t flash_sz = ((this->cfg.wl_partition_size - this->state_size * 2 - this->cfg_size) / this->cfg.wl_page_size - 1) * this->cfg.wl_page_size; // -1 remove dummy block
this->flash_size = ((this->cfg.wl_partition_size - this->state_size * 2 - this->cfg_size) / this->cfg.wl_page_size - 1) * this->cfg.wl_page_size; // -1 remove dummy block
ESP_LOGD(TAG, "%s - config result: state_size=0x%08x, cfg_size=0x%08x, addr_cfg=0x%08x, addr_state1=0x%08x, addr_state2=0x%08x, flash_size=0x%08x", __func__,
(uint32_t) this->state_size,
@ -99,7 +99,7 @@ esp_err_t WL_Flash::config(wl_config_t *cfg, Flash_Access *flash_drv)
}
WL_RESULT_CHECK(result);
this->temp_buff = (uint8_t *)malloc(this->cfg.temp_buff_size);
this->temp_buff = (uint8_t *)malloc(this->cfg.wl_temp_buff_size);
if (this->temp_buff == NULL) {
result = ESP_ERR_NO_MEM;
}
@ -129,18 +129,18 @@ esp_err_t WL_Flash::init()
uint32_t crc1 = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, check_size);
uint32_t crc2 = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)state_copy, check_size);
ESP_LOGD(TAG, "%s - config ID=%i, stored ID=%i, access_count=%i, block_size=%i, max_count=%i, pos=%i, move_count=0x%8.8X",
ESP_LOGD(TAG, "%s - config ID=%i, stored ID=%i, wl_sec_erase_cycle_count=%i, wl_block_size=%i, wl_max_sec_erase_cycle_count=%i, wl_dummy_sec_pos=%i, wl_dummy_sec_move_count=0x%8.8X",
__func__,
this->cfg.version,
this->state.version,
this->state.access_count,
this->state.block_size,
this->state.max_count,
this->state.pos,
this->state.move_count);
this->state.wl_sec_erase_cycle_count,
this->state.wl_block_size,
this->state.wl_max_sec_erase_cycle_count,
this->state.wl_dummy_sec_pos,
this->state.wl_dummy_sec_move_count);
ESP_LOGD(TAG, "%s starts: crc1= 0x%08x, crc2 = 0x%08x, this->state.crc= 0x%08x, state_copy->crc= 0x%08x, version=%i, read_version=%i", __func__, crc1, crc2, this->state.crc, state_copy->crc, this->cfg.version, this->state.version);
if ((crc1 == this->state.crc) && (crc2 == state_copy->crc)) {
ESP_LOGD(TAG, "%s starts: crc1= 0x%08x, crc2 = 0x%08x, this->state.crc= 0x%08x, state_copy->crc= 0x%08x, version=%i, read_version=%i", __func__, crc1, crc2, this->state.crc32, state_copy->crc32, this->cfg.version, this->state.version);
if ((crc1 == this->state.crc32) && (crc2 == state_copy->crc32)) {
// The state is OK. Check the ID
if (this->state.version != this->cfg.version) {
result = this->initSections();
@ -153,14 +153,15 @@ esp_err_t WL_Flash::init()
WL_RESULT_CHECK(result);
result = this->flash_drv->write(this->addr_state2, &this->state, sizeof(wl_state_t));
WL_RESULT_CHECK(result);
for (size_t i = 0; i < ((this->cfg.full_mem_size / this->cfg.sector_size)); i++) {
for (size_t i = 0; i < ((this->cfg.wl_partition_size / this->cfg.flash_sector_size)); i++) {
bool pos_bits;
result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wl_pos_update_record_size, this->temp_buff, this->cfg.wl_pos_update_record_size);
WL_RESULT_CHECK(result);
pos_bits = this->OkBuffSet(i);
if (pos_bits == true) {
//this->fillOkBuff(i);
result = this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
result = this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + i * this->cfg.wl_pos_update_record_size, this->temp_buff, this->cfg.wl_pos_update_record_size);
WL_RESULT_CHECK(result);
}
}
@ -169,7 +170,7 @@ esp_err_t WL_Flash::init()
result = this->recoverPos();
WL_RESULT_CHECK(result);
}
} else if ((crc1 != this->state.crc) && (crc2 != state_copy->crc)) { // This is just new flash or new version
} else if ((crc1 != this->state.crc32) && (crc2 != state_copy->crc32)) { // This is just new flash or new version
// Check if this is new version or just new instance of WL
ESP_LOGD(TAG, "%s: try to update version - crc1= 0x%08x, crc2 = 0x%08x, result= 0x%08x", __func__, (uint32_t)crc1, (uint32_t)crc2, (uint32_t)result);
result = this->updateVersion();
@ -182,18 +183,19 @@ esp_err_t WL_Flash::init()
WL_RESULT_CHECK(result);
} else {
// recover broken state
if (crc1 == this->state.crc) {// we have to recover state 2
if (crc1 == this->state.crc32) {// we have to recover state 2
result = this->flash_drv->erase_range(this->addr_state2, this->state_size);
WL_RESULT_CHECK(result);
result = this->flash_drv->write(this->addr_state2, &this->state, sizeof(wl_state_t));
WL_RESULT_CHECK(result);
for (size_t i = 0; i < ((this->cfg.full_mem_size / this->cfg.sector_size)); i++) {
for (size_t i = 0; i < ((this->cfg.wl_partition_size / this->cfg.flash_sector_size)); i++) {
bool pos_bits;
result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wl_pos_update_record_size, this->temp_buff, this->cfg.wl_pos_update_record_size);
WL_RESULT_CHECK(result);
pos_bits = this->OkBuffSet(i);
if (pos_bits == true) {
result = this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
result = this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + i * this->cfg.wl_pos_update_record_size, this->temp_buff, this->cfg.wl_pos_update_record_size);
WL_RESULT_CHECK(result);
}
}
@ -204,20 +206,21 @@ esp_err_t WL_Flash::init()
WL_RESULT_CHECK(result);
result = this->flash_drv->write(this->addr_state1, state_copy, sizeof(wl_state_t));
WL_RESULT_CHECK(result);
for (size_t i = 0; i < ((this->cfg.full_mem_size / this->cfg.sector_size)); i++) {
for (size_t i = 0; i < ((this->cfg.wl_partition_size / this->cfg.flash_sector_size)); i++) {
bool pos_bits;
result = this->flash_drv->read(this->addr_state2 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
result = this->flash_drv->read(this->addr_state2 + sizeof(wl_state_t) + i * this->cfg.wl_pos_update_record_size, this->temp_buff, this->cfg.wl_pos_update_record_size);
WL_RESULT_CHECK(result);
pos_bits = this->OkBuffSet(i);
if (pos_bits == true) {
result = this->flash_drv->write(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
result = this->flash_drv->write(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wl_pos_update_record_size, this->temp_buff, this->cfg.wl_pos_update_record_size);
WL_RESULT_CHECK(result);
}
}
result = this->flash_drv->read(this->addr_state1, &this->state, sizeof(wl_state_t));
WL_RESULT_CHECK(result);
this->state.pos = this->state.max_pos - 1;
this->state.wl_dummy_sec_pos = this->state.wl_part_max_sec_pos - 1;
}
// done. We have recovered the state
// If we have a new configuration, we will overwrite it
@ -232,7 +235,7 @@ esp_err_t WL_Flash::init()
return result;
}
this->initialized = true;
ESP_LOGD(TAG, "%s - move_count= 0x%08x", __func__, (uint32_t)this->state.move_count);
ESP_LOGD(TAG, "%s - wl_dummy_sec_move_count= 0x%08x", __func__, (uint32_t)this->state.wl_dummy_sec_move_count);
return ESP_OK;
}
@ -241,10 +244,10 @@ esp_err_t WL_Flash::recoverPos()
esp_err_t result = ESP_OK;
size_t position = 0;
ESP_LOGV(TAG, "%s start", __func__);
for (size_t i = 0; i < this->state.max_pos; i++) {
for (size_t i = 0; i < this->state.wl_part_max_sec_pos; i++) {
bool pos_bits;
position = i;
result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wl_pos_update_record_size, this->temp_buff, this->cfg.wl_pos_update_record_size);
pos_bits = this->OkBuffSet(i);
WL_RESULT_CHECK(result);
ESP_LOGV(TAG, "%s - check pos: result=0x%08x, position= %i, pos_bits= 0x%08x", __func__, (uint32_t)result, (uint32_t)position, (uint32_t)pos_bits);
@ -253,11 +256,11 @@ esp_err_t WL_Flash::recoverPos()
}
}
this->state.pos = position;
if (this->state.pos == this->state.max_pos) {
this->state.pos--;
this->state.wl_dummy_sec_pos = position;
if (this->state.wl_dummy_sec_pos == this->state.wl_part_max_sec_pos) {
this->state.wl_dummy_sec_pos--;
}
ESP_LOGD(TAG, "%s - this->state.pos= 0x%08x, position= 0x%08x, result= 0x%08x, max_pos= 0x%08x", __func__, (uint32_t)this->state.pos, (uint32_t)position, (uint32_t)result, (uint32_t)this->state.max_pos);
ESP_LOGD(TAG, "%s - this->state.wl_dummy_sec_pos= 0x%08x, position= 0x%08x, result= 0x%08x, wl_part_max_sec_pos= 0x%08x", __func__, (uint32_t)this->state.wl_dummy_sec_pos, (uint32_t)position, (uint32_t)result, (uint32_t)this->state.wl_part_max_sec_pos);
ESP_LOGV(TAG, "%s done", __func__);
return result;
}
@ -265,22 +268,22 @@ esp_err_t WL_Flash::recoverPos()
esp_err_t WL_Flash::initSections()
{
esp_err_t result = ESP_OK;
this->state.pos = 0;
this->state.access_count = 0;
this->state.move_count = 0;
this->state.wl_dummy_sec_pos = 0;
this->state.wl_sec_erase_cycle_count = 0;
this->state.wl_dummy_sec_move_count = 0;
// max count
this->state.max_count = this->flash_size / this->state_size * this->cfg.updaterate;
if (this->cfg.updaterate != 0) {
this->state.max_count = this->cfg.updaterate;
this->state.wl_max_sec_erase_cycle_count = this->flash_size / this->state_size * this->cfg.wl_update_rate;
if (this->cfg.wl_update_rate != 0) {
this->state.wl_max_sec_erase_cycle_count = this->cfg.wl_update_rate;
}
this->state.version = this->cfg.version;
this->state.block_size = this->cfg.page_size;
this->state.device_id = esp_random();
this->state.wl_block_size = this->cfg.wl_page_size;
this->state.wl_device_id = esp_random();
memset(this->state.reserved, 0, sizeof(this->state.reserved));
this->state.max_pos = 1 + this->flash_size / this->cfg.page_size;
this->state.wl_part_max_sec_pos = 1 + this->flash_size / this->cfg.wl_page_size;
this->state.crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, WL_STATE_CRC_LEN_V2);
this->state.crc32 = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, WL_STATE_CRC_LEN_V2);
result = this->flash_drv->erase_range(this->addr_state1, this->state_size);
WL_RESULT_CHECK(result);
@ -297,7 +300,7 @@ esp_err_t WL_Flash::initSections()
result = this->flash_drv->write(this->addr_cfg, &this->cfg, sizeof(wl_config_t));
WL_RESULT_CHECK(result);
ESP_LOGD(TAG, "%s - this->state->max_count= 0x%08x, this->state->max_pos= 0x%08x", __func__, this->state.max_count, this->state.max_pos);
ESP_LOGD(TAG, "%s - this->state->wl_max_sec_erase_cycle_count= 0x%08x, this->state->wl_part_max_sec_pos= 0x%08x", __func__, this->state.wl_max_sec_erase_cycle_count, this->state.wl_part_max_sec_pos);
ESP_LOGD(TAG, "%s - result= 0x%08x", __func__, result);
return result;
}
@ -328,9 +331,9 @@ esp_err_t WL_Flash::updateV1_V2()
WL_RESULT_CHECK(result);
uint32_t crc2 = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)state_copy, check_size);
// For V1 crc in place of device_id and version
uint32_t v1_crc1 = this->state.device_id;
uint32_t v1_crc2 = state_copy->device_id;
// For V1 crc in place of wl_device_id and version
uint32_t v1_crc1 = this->state.wl_device_id;
uint32_t v1_crc2 = state_copy->wl_device_id;
ESP_LOGD(TAG, "%s - process crc1=0x%08x, crc2=0x%08x, v1_crc1=0x%08x, v1_crc2=0x%08x, version=%i", __func__, crc1, crc2, v1_crc1, v1_crc2, this->state.version);
@ -339,9 +342,9 @@ esp_err_t WL_Flash::updateV1_V2()
ESP_LOGI(TAG, "%s Update from V1 to V2, crc=0x%08x, ", __func__, crc1);
uint32_t pos = 0;
for (size_t i = 0; i < this->state.max_pos; i++) {
for (size_t i = 0; i < this->state.wl_part_max_sec_pos; i++) {
uint8_t pos_bits;
result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, &pos_bits, 1);
result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wl_pos_update_record_size, &pos_bits, 1);
WL_RESULT_CHECK(result);
ESP_LOGV(TAG, "%s- result= 0x%08x, pos= %i, pos_bits= 0x%08x", __func__, (uint32_t)result, (uint32_t)pos, (uint32_t)pos_bits);
pos = i;
@ -349,27 +352,27 @@ esp_err_t WL_Flash::updateV1_V2()
break; // we have found position
}
}
ESP_LOGI(TAG, "%s max_pos=%i, pos=%i, state.ver=%i, state2.ver=%i", __func__, (uint32_t)this->state.max_pos, (uint32_t)pos, (uint32_t)this->state.version, (uint32_t)state_copy->version);
if (pos == this->state.max_pos) {
ESP_LOGI(TAG, "%s wl_part_max_sec_pos=%i, pos=%i, state.ver=%i, state2.ver=%i", __func__, (uint32_t)this->state.wl_part_max_sec_pos, (uint32_t)pos, (uint32_t)this->state.version, (uint32_t)state_copy->version);
if (pos == this->state.wl_part_max_sec_pos) {
pos--;
}
WL_RESULT_CHECK(result);
this->state.version = 2;
this->state.pos = 0;
this->state.device_id = esp_random();
this->state.wl_dummy_sec_pos = 0;
this->state.wl_device_id = esp_random();
memset(this->state.reserved, 0, sizeof(this->state.reserved));
this->state.crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, WL_STATE_CRC_LEN_V2);
this->state.crc32 = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, WL_STATE_CRC_LEN_V2);
result = this->flash_drv->erase_range(this->addr_state1, this->state_size);
WL_RESULT_CHECK(result);
result = this->flash_drv->write(this->addr_state1, &this->state, sizeof(wl_state_t));
WL_RESULT_CHECK(result);
memset(this->temp_buff, 0, this->cfg.wr_size);
memset(this->temp_buff, 0, this->cfg.wl_pos_update_record_size);
for (uint32_t i = 0 ; i <= pos; i++) {
this->fillOkBuff(i);
result = this->flash_drv->write(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
result = this->flash_drv->write(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wl_pos_update_record_size, this->temp_buff, this->cfg.wl_pos_update_record_size);
WL_RESULT_CHECK(result);
}
@ -377,15 +380,15 @@ esp_err_t WL_Flash::updateV1_V2()
WL_RESULT_CHECK(result);
result = this->flash_drv->write(this->addr_state2, &this->state, sizeof(wl_state_t));
WL_RESULT_CHECK(result);
ESP_LOGD(TAG, "%s - move_count= 0x%08x, pos= 0x%08x", __func__, this->state.move_count, this->state.pos);
ESP_LOGD(TAG, "%s - wl_dummy_sec_move_count= 0x%08x, pos= 0x%08x", __func__, this->state.wl_dummy_sec_move_count, this->state.wl_dummy_sec_pos);
memset(this->temp_buff, 0, this->cfg.wr_size);
memset(this->temp_buff, 0, this->cfg.wl_pos_update_record_size);
for (uint32_t i = 0 ; i <= pos; i++) {
this->fillOkBuff(i);
result = this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
result = this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + i * this->cfg.wl_pos_update_record_size, this->temp_buff, this->cfg.wl_pos_update_record_size);
WL_RESULT_CHECK(result);
}
this->state.pos = pos;
this->state.wl_dummy_sec_pos = pos;
return result;
}
@ -397,7 +400,7 @@ void WL_Flash::fillOkBuff(int n)
uint32_t *buff = (uint32_t *)this->temp_buff;
for (int i = 0 ; i < 4 ; i++) {
buff[i] = this->state.device_id + n * 4 + i;
buff[i] = this->state.wl_device_id + n * 4 + i;
buff[i] = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&buff[i], sizeof(uint32_t));
}
}
@ -407,7 +410,7 @@ bool WL_Flash::OkBuffSet(int n)
bool result = true;
uint32_t *data_buff = (uint32_t *)this->temp_buff;
for (int i = 0 ; i < 4 ; i++) {
uint32_t data = this->state.device_id + n * 4 + i;
uint32_t data = this->state.wl_device_id + n * 4 + i;
uint32_t crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&data, sizeof(uint32_t));
if (crc != data_buff[i]) {
result = false;
@ -420,72 +423,72 @@ bool WL_Flash::OkBuffSet(int n)
esp_err_t WL_Flash::updateWL()
{
esp_err_t result = ESP_OK;
this->state.access_count++;
if (this->state.access_count < this->state.max_count) {
this->state.wl_sec_erase_cycle_count++;
if (this->state.wl_sec_erase_cycle_count < this->state.wl_max_sec_erase_cycle_count) {
return result;
}
// Here we have to move the block and increase the state
this->state.access_count = 0;
ESP_LOGV(TAG, "%s - access_count= 0x%08x, pos= 0x%08x", __func__, this->state.access_count, this->state.pos);
this->state.wl_sec_erase_cycle_count = 0;
ESP_LOGV(TAG, "%s - wl_sec_erase_cycle_count= 0x%08x, pos= 0x%08x", __func__, this->state.wl_sec_erase_cycle_count, this->state.wl_dummy_sec_pos);
// copy data to dummy block
size_t data_addr = this->state.pos + 1; // next block, [pos+1] copy to [pos]
if (data_addr >= this->state.max_pos) {
size_t data_addr = this->state.wl_dummy_sec_pos + 1; // next block, [pos+1] copy to [pos]
if (data_addr >= this->state.wl_part_max_sec_pos) {
data_addr = 0;
}
data_addr = this->cfg.start_addr + data_addr * this->cfg.page_size;
this->dummy_addr = this->cfg.start_addr + this->state.pos * this->cfg.page_size;
result = this->flash_drv->erase_range(this->dummy_addr, this->cfg.page_size);
data_addr = this->cfg.wl_partition_start_addr + data_addr * this->cfg.wl_page_size;
this->dummy_addr = this->cfg.wl_partition_start_addr + this->state.wl_dummy_sec_pos * this->cfg.wl_page_size;
result = this->flash_drv->erase_range(this->dummy_addr, this->cfg.wl_page_size);
if (result != ESP_OK) {
ESP_LOGE(TAG, "%s - erase wl dummy sector result= 0x%08x", __func__, result);
this->state.access_count = this->state.max_count - 1; // we will update next time
this->state.wl_sec_erase_cycle_count = this->state.wl_max_sec_erase_cycle_count - 1; // we will update next time
return result;
}
size_t copy_count = this->cfg.page_size / this->cfg.temp_buff_size;
size_t copy_count = this->cfg.wl_page_size / this->cfg.wl_temp_buff_size;
for (size_t i = 0; i < copy_count; i++) {
result = this->flash_drv->read(data_addr + i * this->cfg.temp_buff_size, this->temp_buff, this->cfg.temp_buff_size);
result = this->flash_drv->read(data_addr + i * this->cfg.wl_temp_buff_size, this->temp_buff, this->cfg.wl_temp_buff_size);
if (result != ESP_OK) {
ESP_LOGE(TAG, "%s - not possible to read buffer, will try next time, result= 0x%08x", __func__, result);
this->state.access_count = this->state.max_count - 1; // we will update next time
this->state.wl_sec_erase_cycle_count = this->state.wl_max_sec_erase_cycle_count - 1; // we will update next time
return result;
}
result = this->flash_drv->write(this->dummy_addr + i * this->cfg.temp_buff_size, this->temp_buff, this->cfg.temp_buff_size);
result = this->flash_drv->write(this->dummy_addr + i * this->cfg.wl_temp_buff_size, this->temp_buff, this->cfg.wl_temp_buff_size);
if (result != ESP_OK) {
ESP_LOGE(TAG, "%s - not possible to write buffer, will try next time, result= 0x%08x", __func__, result);
this->state.access_count = this->state.max_count - 1; // we will update next time
this->state.wl_sec_erase_cycle_count = this->state.wl_max_sec_erase_cycle_count - 1; // we will update next time
return result;
}
}
// done... block moved.
// Here we will update structures...
// Update bits and save to flash:
uint32_t byte_pos = this->state.pos * this->cfg.wr_size;
this->fillOkBuff(this->state.pos);
uint32_t byte_pos = this->state.wl_dummy_sec_pos * this->cfg.wl_pos_update_record_size;
this->fillOkBuff(this->state.wl_dummy_sec_pos);
// write state to mem. We updating only affected bits
result |= this->flash_drv->write(this->addr_state1 + sizeof(wl_state_t) + byte_pos, this->temp_buff, this->cfg.wr_size);
result |= this->flash_drv->write(this->addr_state1 + sizeof(wl_state_t) + byte_pos, this->temp_buff, this->cfg.wl_pos_update_record_size);
if (result != ESP_OK) {
ESP_LOGE(TAG, "%s - update position 1 result= 0x%08x", __func__, result);
this->state.access_count = this->state.max_count - 1; // we will update next time
this->state.wl_sec_erase_cycle_count = this->state.wl_max_sec_erase_cycle_count - 1; // we will update next time
return result;
}
this->fillOkBuff(this->state.pos);
result |= this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + byte_pos, this->temp_buff, this->cfg.wr_size);
this->fillOkBuff(this->state.wl_dummy_sec_pos);
result |= this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + byte_pos, this->temp_buff, this->cfg.wl_pos_update_record_size);
if (result != ESP_OK) {
ESP_LOGE(TAG, "%s - update position 2 result= 0x%08x", __func__, result);
this->state.access_count = this->state.max_count - 1; // we will update next time
this->state.wl_sec_erase_cycle_count = this->state.wl_max_sec_erase_cycle_count - 1; // we will update next time
return result;
}
this->state.pos++;
if (this->state.pos >= this->state.max_pos) {
this->state.pos = 0;
this->state.wl_dummy_sec_pos++;
if (this->state.wl_dummy_sec_pos >= this->state.wl_part_max_sec_pos) {
this->state.wl_dummy_sec_pos = 0;
// one loop more
this->state.move_count++;
if (this->state.move_count >= (this->state.max_pos - 1)) {
this->state.move_count = 0;
this->state.wl_dummy_sec_move_count++;
if (this->state.wl_dummy_sec_move_count >= (this->state.wl_part_max_sec_pos - 1)) {
this->state.wl_dummy_sec_move_count = 0;
}
// write main state
this->state.crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, WL_STATE_CRC_LEN_V2);
this->state.crc32 = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, WL_STATE_CRC_LEN_V2);
result = this->flash_drv->erase_range(this->addr_state1, this->state_size);
WL_RESULT_CHECK(result);
@ -495,7 +498,7 @@ esp_err_t WL_Flash::updateWL()
WL_RESULT_CHECK(result);
result = this->flash_drv->write(this->addr_state2, &this->state, sizeof(wl_state_t));
WL_RESULT_CHECK(result);
ESP_LOGD(TAG, "%s - move_count= 0x%08x, pos= 0x%08x, ", __func__, this->state.move_count, this->state.pos);
ESP_LOGD(TAG, "%s - wl_dummy_sec_move_count= 0x%08x, wl_dummy_sec_pos= 0x%08x, ", __func__, this->state.wl_dummy_sec_move_count, this->state.wl_dummy_sec_pos);
}
// Save structures to the flash... and check result
if (result == ESP_OK) {
@ -508,33 +511,33 @@ esp_err_t WL_Flash::updateWL()
size_t WL_Flash::calcAddr(size_t addr)
{
size_t result = (this->flash_size - this->state.move_count * this->cfg.page_size + addr) % this->flash_size;
size_t dummy_addr = this->state.pos * this->cfg.page_size;
size_t result = (this->flash_size - this->state.wl_dummy_sec_move_count * this->cfg.wl_page_size + addr) % this->flash_size;
size_t dummy_addr = this->state.wl_dummy_sec_pos * this->cfg.wl_page_size;
if (result < dummy_addr) {
} else {
result += this->cfg.page_size;
result += this->cfg.wl_page_size;
}
ESP_LOGV(TAG, "%s - addr= 0x%08x -> result= 0x%08x, dummy_addr= 0x%08x", __func__, (uint32_t) addr, (uint32_t) result, (uint32_t)dummy_addr);
return result;
}
size_t WL_Flash::chip_size()
size_t WL_Flash::get_flash_size()
{
if (!this->configured) {
return 0;
}
return this->flash_size;
}
size_t WL_Flash::sector_size()
size_t WL_Flash::get_sector_size()
{
if (!this->configured) {
return 0;
}
return this->cfg.sector_size;
return this->cfg.flash_sector_size;
}
esp_err_t WL_Flash::erase_sector(size_t sector)
{
esp_err_t result = ESP_OK;
@ -544,11 +547,12 @@ esp_err_t WL_Flash::erase_sector(size_t sector)
ESP_LOGD(TAG, "%s - sector= 0x%08x", __func__, (uint32_t) sector);
result = this->updateWL();
WL_RESULT_CHECK(result);
size_t virt_addr = this->calcAddr(sector * this->cfg.sector_size);
result = this->flash_drv->erase_sector((this->cfg.start_addr + virt_addr) / this->cfg.sector_size);
size_t virt_addr = this->calcAddr(sector * this->cfg.flash_sector_size);
result = this->flash_drv->erase_sector((this->cfg.wl_partition_start_addr + virt_addr) / this->cfg.flash_sector_size);
WL_RESULT_CHECK(result);
return result;
}
esp_err_t WL_Flash::erase_range(size_t start_address, size_t size)
{
esp_err_t result = ESP_OK;
@ -556,8 +560,8 @@ esp_err_t WL_Flash::erase_range(size_t start_address, size_t size)
return ESP_ERR_INVALID_STATE;
}
ESP_LOGD(TAG, "%s - start_address= 0x%08x, size= 0x%08x", __func__, (uint32_t) start_address, (uint32_t) size);
size_t erase_count = (size + this->cfg.sector_size - 1) / this->cfg.sector_size;
size_t start_sector = start_address / this->cfg.sector_size;
size_t erase_count = (size + this->cfg.flash_sector_size - 1) / this->cfg.flash_sector_size;
size_t start_sector = start_address / this->cfg.flash_sector_size;
for (size_t i = 0; i < erase_count; i++) {
result = this->erase_sector(start_sector + i);
WL_RESULT_CHECK(result);
@ -573,14 +577,14 @@ esp_err_t WL_Flash::write(size_t dest_addr, const void *src, size_t size)
return ESP_ERR_INVALID_STATE;
}
ESP_LOGD(TAG, "%s - dest_addr= 0x%08x, size= 0x%08x", __func__, (uint32_t) dest_addr, (uint32_t) size);
uint32_t count = (size - 1) / this->cfg.page_size;
uint32_t count = (size - 1) / this->cfg.wl_page_size;
for (size_t i = 0; i < count; i++) {
size_t virt_addr = this->calcAddr(dest_addr + i * this->cfg.page_size);
result = this->flash_drv->write(this->cfg.start_addr + virt_addr, &((uint8_t *)src)[i * this->cfg.page_size], this->cfg.page_size);
size_t virt_addr = this->calcAddr(dest_addr + i * this->cfg.wl_page_size);
result = this->flash_drv->write(this->cfg.wl_partition_start_addr + virt_addr, &((uint8_t *)src)[i * this->cfg.wl_page_size], this->cfg.wl_page_size);
WL_RESULT_CHECK(result);
}
size_t virt_addr_last = this->calcAddr(dest_addr + count * this->cfg.page_size);
result = this->flash_drv->write(this->cfg.start_addr + virt_addr_last, &((uint8_t *)src)[count * this->cfg.page_size], size - count * this->cfg.page_size);
size_t virt_addr_last = this->calcAddr(dest_addr + count * this->cfg.wl_page_size);
result = this->flash_drv->write(this->cfg.wl_partition_start_addr + virt_addr_last, &((uint8_t *)src)[count * this->cfg.wl_page_size], size - count * this->cfg.wl_page_size);
WL_RESULT_CHECK(result);
return result;
}
@ -592,15 +596,15 @@ esp_err_t WL_Flash::read(size_t src_addr, void *dest, size_t size)
return ESP_ERR_INVALID_STATE;
}
ESP_LOGD(TAG, "%s - src_addr= 0x%08x, size= 0x%08x", __func__, (uint32_t) src_addr, (uint32_t) size);
uint32_t count = (size - 1) / this->cfg.page_size;
uint32_t count = (size - 1) / this->cfg.wl_page_size;
for (size_t i = 0; i < count; i++) {
size_t virt_addr = this->calcAddr(src_addr + i * this->cfg.page_size);
ESP_LOGV(TAG, "%s - real_addr= 0x%08x, size= 0x%08x", __func__, (uint32_t) (this->cfg.start_addr + virt_addr), (uint32_t) size);
result = this->flash_drv->read(this->cfg.start_addr + virt_addr, &((uint8_t *)dest)[i * this->cfg.page_size], this->cfg.page_size);
size_t virt_addr = this->calcAddr(src_addr + i * this->cfg.wl_page_size);
ESP_LOGV(TAG, "%s - real_addr= 0x%08x, size= 0x%08x", __func__, (uint32_t) (this->cfg.wl_partition_start_addr + virt_addr), (uint32_t) size);
result = this->flash_drv->read(this->cfg.wl_partition_start_addr + virt_addr, &((uint8_t *)dest)[i * this->cfg.wl_page_size], this->cfg.wl_page_size);
WL_RESULT_CHECK(result);
}
size_t virt_addr_last = this->calcAddr(src_addr + count * this->cfg.page_size);
result = this->flash_drv->read(this->cfg.start_addr + virt_addr_last, &((uint8_t *)dest)[count * this->cfg.page_size], size - count * this->cfg.page_size);
size_t virt_addr_last = this->calcAddr(src_addr + count * this->cfg.wl_page_size);
result = this->flash_drv->read(this->cfg.wl_partition_start_addr + virt_addr_last, &((uint8_t *)dest)[count * this->cfg.wl_page_size], size - count * this->cfg.wl_page_size);
WL_RESULT_CHECK(result);
return result;
}
@ -617,8 +621,8 @@ wl_config_t *WL_Flash::get_cfg()
esp_err_t WL_Flash::flush()
{
esp_err_t result = ESP_OK;
this->state.access_count = this->state.max_count - 1;
this->state.wl_sec_erase_cycle_count = this->state.wl_max_sec_erase_cycle_count - 1;
result = this->updateWL();
ESP_LOGD(TAG, "%s - result= 0x%08x, move_count= 0x%08x", __func__, result, this->state.move_count);
ESP_LOGD(TAG, "%s - result= 0x%08x, wl_dummy_sec_move_count= 0x%08x", __func__, result, this->state.wl_dummy_sec_move_count);
return result;
}

View File

@ -1,78 +1,73 @@
Wear Levelling Component
========================
Wear Levelling Component (WLC) it is a software component that is implemented to prevent situation when some sectors in flash memory used by erase operations more then others. The component shares access attempts between all avalible sectors.
Wear Levelling Component (WLC) is a software component, implemented to prolong the service life of a storage media. This is done by preventing frequent erase operations at specific locations of the storage media memory space, which cause wear out of that particular memory while other locations are possibly not used at all. The WLC controls access attempts to all the media sectors available.
The WLC do not have internal cache. When write operation is finished, that means that data was really stored to the flash.
As a parameter the WLC requires the driver to access the flash device. The driver has to implement Flash_Access interface.
The component requires the storage media access driver as its parameter, in order to manipulate target sectors. As the WLC implements wear-levelling for the SPI Flash device, the driver is controlled through the Flash_Access interface.
The WLC Versioning and Compatibility
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The WLC accept data formats from older version. Latest version of the WLC will update data format from older versions to the current one.
The WLC accepts data formats from older version. Latest version of the WLC will update data format from older versions to the current one.
Current implementation of WLC has version 2. The data format from current version incompatible with data format from previous versions, and could not be
used with previous versions.
The WLC Files
^^^^^^^^^^^^^^^
The WLC consist of few components that are implemented in different files. The list and brief description of these components written below.
The WLC consists of several components that are implemented in various files. The list and brief description of these components follows:
- Flash_Access - memory access interface. Used to access the memory. A classes WL_Flash, Partition, SPI_Flash are implements this interface.
- Flash_Access - SPI Flash memory access interface. Implemented in classes WL_Flash, Partition and SPI_Flash.
- SPI_Flash - class implements the Flash_Access interface to provide access to the flash memory.
- Partition - class implements the Flash_Access interface to provide access to the partition.
- WL_Flash - the main class that implements wear levelling functionality.
- WL_State - contains state structure of the WLC.
- WL_Config - contains structure to configure the WLC component at startup.
- WL_Config - contains structure to configure the WLC at startup.
- wear_levelling - wrapper API class that provides "C" interface to access the memory through the WLC
Flash_Access Interface
^^^^^^^^^^^^^^^^^^^^^^
In the component exist virtual interface Flash_Access. This interface implement main basic functions:
- read - read memory to the buffer.
- write - writes buffer to the memory.
- erase - erase one sector.
- erase_range - erase range of memory. The address of rage must be rounded to the sector size.
- chip_size - returns the equivalent amount of memory.
- sector_size - returns the sector size.
Virtual interface Flash_Access defines the following basic functions:
- read - reads from the flash memory to a data buffer.
- write - writes to the flash memory from a data buffer.
- erase - erases a sector of the flash memory.
- erase_range - erases a range of sectors of the flash memory. The range length must be rounded to a multile of the sector size.
- flash_size - returns the available flash memory (in bytes).
- sector_size - returns the flash sector size.
- flush - stores current state to the flash, if needed.
The WLC implements this interface for the user, and requires this interface to access the memory.
Structure wl_config_t to Configure the WLC at startup
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
WLC startup configuration (wl_config_t structure)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The wl_config_t contains configuration parameters for the WLC component.
- start_addr - offset in the flash memory. The WLC will place all data after this address.
- full_mem_size - amount of memory that was allocated and can be used by WLC
- sector_size - flash memory sector size
- page_size - size of memory for relocation at once. Must be N*sector_size, where N > 0.
- updaterate - amount of erase cycles to execute the relocation procedure.
- wr_size - smalest possible write access size without erasing of sector.
- wl_partition_start_addr - wear levelled partition starting address (in the flash memory)
- wl_partition_size - size of the wear-levelled partition
- flash_sector_size - flash memory sector size
- wl_page_size - one WLC page size (in bytes). wl_page_size >= (N * sector_size), where N > 0
- wl_update_rate - erase operation count after which the physical sector and the WLC dummy sector swap their addresses
- wl_pos_update_record_size - number of bytes for storing position-update record, appended to the WLC state sector data after each expiration of wl_update_rate.
- version - version of the WLC component.
- temp_buff_size - amount of memory that the WLC will allocate internally. Must be > 0.
- temp_buff_size - size of a temporary buffer to copy data from one flash memory area to another. This value should be equal to the flash sector size.
Internal Memory Organization
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The WLC divide the memory that are define by start_addr and full_mem_size to three regions:
- Data
- States
The WLC divides the memory given by wl_partition_start_addr and wl_partition_size to three regions:
- Configuration
- States
- Data
The Configuration region used to store configuration information. The user can use it to recover the WLC from memory dump.
The Data - is a region where user data stored.
The States - is a region where the WLC stores internal information about the WLC state. The States region contains two copies of the WLC states. It is implemented to prevent situation when the device is shut down
during operation when the device stores the states. If one of copies is wrong, the WLC can recover the state from another. The broken copy will be overwritten by another.
The Configuration - a region used to store the WLC configuration information. User can use this information to restore the WL partition from a memory dump.
The States - a region to store internal WLC status information. The States region contains two copies of the WLC status record - this is to help safely recover last-known WLC status in case of power outage.
The Data - a region where the user data is stored.
Main Idea
^^^^^^^^^
The WLC has two access addresses: virtual address and real address. The virtual address used by user to access the WLC, the real address used by the WLC to access the real memory.
The WLC makes the conversion between virtual and real addresses.
The Data region divided to N pages (page could be equal to the sector size). One page defined as dummy page. For user will be available only N-1 pages.
The WLC has two internal counters to calculate virtual and real addresses: erase counter and move counter.
Every erase operation will be counted by erase counter. When this counter reached the *updaterate* number the page after Dummy page will be moved to the Dummy page, and Dummy page will be changed to this one. The erase counter will
be cleared and move counter will be incremented. This procedure will be repeated again and again.
When the Dummy page will be at last page in the memory and erase counter will reach the updaterate, the move counter will be cleared and the state will be stored to the State memory.
Bellow shown the example with 4 available memory pages. Every state after updaterate erases. The X is a Dummy page.
The WLC uses two types of flash memory-access addresses: virtual (logical) address and real (physical) address. The virtual address is used by users as a common target address, while the real address is used internally by the WLC to access the actual memory block.
The Data region is divided into N pages (page could be equal to the sector size, see above). One WLC page is defined as a "dummy" page, which implies the users can use only N-1 pages to store the data.
The WLC has two internal counters to calculate virtual and real addresses: erase counter (access_count) and move counter (move_count).
Every erase operation increments the erase counter. When the counter reaches the *wl_update_rate* number, the contents of the page next after the actual "dummy" page is copied to the dummy page and the next page itself becomes a new WLC dummy page (the last partition page swaps its position with the first one). This way, the WLC dummy page will traverses across whole partition, ensuring the wear burden is distributed evenly. After a completion of one cycle, the move counter is incremented too.
On the increment of the move counter, the WLC status record is stored to the State sector in the flash memory.
The example below shows 4 available memory pages and their corresponding states after each wl_update_rate change. The 'X' is the WLC dummy page.
- X 0 1 2 - start position
- 0 X 1 2 - first move, the page 0 and Dummy page change the places
@ -88,6 +83,5 @@ Bellow shown the example with 4 available memory pages. Every state after update
- 2 0 1 X -
- X 0 1 2 - state stored to the memory, the memory made full cycle.
As we see, if user will write data only to one address, amount of erase cycles will be shared between the full memory. The price for that is a one memory page that will not be used by user.
As can be seen, erase cycles of the sectors get distributed across the entire flash at the cost of small memory part used by the WLC, which is thus not available to the users.

View File

@ -282,7 +282,7 @@ void calculate_wl_state_crc(WL_State_s *state_ptr)
{
int check_size = WL_STATE_CRC_LEN_V2;
// Chech CRC and recover state
state_ptr->crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)state_ptr, check_size);
state_ptr->crc32 = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)state_ptr, check_size);
}
TEST_CASE("power down during WL status 1 update", "[wear_levelling]")
@ -403,7 +403,7 @@ TEST_CASE("power down between WL status 1 and WL status 2 update", "[wear_levell
// change move count and recalc crc
WL_State_s *state_ptr = (WL_State_s *) tmp_state;
state_ptr->move_count++;
state_ptr->wl_dummy_sec_move_count++;
calculate_wl_state_crc(state_ptr);
// write back modified status2

View File

@ -28,9 +28,9 @@ typedef int32_t wl_handle_t;
* @param out_handle handle of the WL instance
*
* @return
* - ESP_OK, if the allocation was successfully;
* - ESP_ERR_INVALID_ARG, if WL allocation was unsuccessful;
* - ESP_ERR_NO_MEM, if there was no memory to allocate WL components;
* - ESP_OK, if the WL allocation is successful;
* - ESP_ERR_INVALID_ARG, if the arguments for WL configuration are not valid;
* - ESP_ERR_NO_MEM, if the WL allocation fails because of insufficient memory;
*/
esp_err_t wl_mount(const esp_partition_t *partition, wl_handle_t *out_handle);
@ -40,7 +40,7 @@ esp_err_t wl_mount(const esp_partition_t *partition, wl_handle_t *out_handle);
* @param handle WL partition handle
*
* @return
* - ESP_OK, if the operation completed successfully;
* - ESP_OK, if the operation is successful;
* - or one of error codes from lower-level flash driver.
*/
esp_err_t wl_unmount(wl_handle_t handle);
@ -49,13 +49,13 @@ esp_err_t wl_unmount(wl_handle_t handle);
* @brief Erase part of the WL storage
*
* @param handle WL handle that are related to the partition
* @param start_addr Address where erase operation should start. Must be aligned
* @param start_addr Address from where erase operation should start. Must be aligned
* to the result of function wl_sector_size(...).
* @param size Size of the range which should be erased, in bytes.
* Must be divisible by result of function wl_sector_size(...)..
* Must be divisible by the result of function wl_sector_size(...)..
*
* @return
* - ESP_OK, if the range was erased successfully;
* - ESP_OK, if the given range was erased successfully;
* - ESP_ERR_INVALID_ARG, if iterator or dst are NULL;
* - ESP_ERR_INVALID_SIZE, if erase would go out of bounds of the partition;
* - or one of error codes from lower-level flash driver.
@ -68,7 +68,7 @@ esp_err_t wl_erase_range(wl_handle_t handle, size_t start_addr, size_t size);
* Before writing data to flash, corresponding region of flash needs to be erased.
* This can be done using wl_erase_range function.
*
* @param handle WL handle that are related to the partition
* @param handle WL handle corresponding to the WL partition
* @param dest_addr Address where the data should be written, relative to the
* beginning of the partition.
* @param src Pointer to the source buffer. Pointer must be non-NULL and
@ -91,7 +91,7 @@ esp_err_t wl_write(wl_handle_t handle, size_t dest_addr, const void *src, size_t
*
* @param handle WL module instance that was initialized before
* @param dest Pointer to the buffer where data should be stored.
* Pointer must be non-NULL and buffer must be at least 'size' bytes long.
* The Pointer must be non-NULL and the buffer must be at least 'size' bytes long.
* @param src_addr Address of the data to be read, relative to the
* beginning of the partition.
* @param size Size of data to be read, in bytes.
@ -105,7 +105,7 @@ esp_err_t wl_write(wl_handle_t handle, size_t dest_addr, const void *src, size_t
esp_err_t wl_read(wl_handle_t handle, size_t src_addr, void *dest, size_t size);
/**
* @brief Get size of the WL storage
* @brief Get the actual flash size in use for the WL storage partition
*
* @param handle WL module handle that was initialized before
* @return usable size, in bytes

View File

@ -15,7 +15,7 @@
class Flash_Access
{
public:
virtual size_t chip_size() = 0;
virtual size_t get_flash_size() = 0;
virtual esp_err_t erase_sector(size_t sector) = 0;
virtual esp_err_t erase_range(size_t start_address, size_t size) = 0;
@ -23,7 +23,7 @@ public:
virtual esp_err_t write(size_t dest_addr, const void *src, size_t size) = 0;
virtual esp_err_t read(size_t src_addr, void *dest, size_t size) = 0;
virtual size_t sector_size() = 0;
virtual size_t get_sector_size() = 0;
virtual esp_err_t flush()
{

View File

@ -23,7 +23,7 @@ class Partition : public Flash_Access
public:
Partition(const esp_partition_t *partition);
virtual size_t chip_size();
virtual size_t get_flash_size();
virtual esp_err_t erase_sector(size_t sector);
virtual esp_err_t erase_range(size_t start_address, size_t size);
@ -31,7 +31,7 @@ public:
virtual esp_err_t write(size_t dest_addr, const void *src, size_t size);
virtual esp_err_t read(size_t src_addr, void *dest, size_t size);
virtual size_t sector_size();
virtual size_t get_sector_size();
virtual ~Partition();
protected:

View File

@ -20,12 +20,12 @@ class SPI_Flash : public Flash_Access
public:
SPI_Flash();
size_t chip_size() override;
size_t get_flash_size() override;
esp_err_t erase_sector(size_t sector) override;
esp_err_t erase_range(size_t start_address, size_t size) override;
esp_err_t write(size_t dest_addr, const void *src, size_t size) override;
esp_err_t read(size_t src_addr, void *dest, size_t size) override;
size_t sector_size() override;
size_t get_sector_size() override;
~SPI_Flash() override;
};

View File

@ -22,15 +22,15 @@
#endif
typedef struct ALIGNED_(16) WL_Config_s {/*!< Size of wl_config_t structure should be divided by 16 for encryption*/
size_t start_addr; /*!< start address in the flash*/
uint32_t full_mem_size; /*!< Amount of memory used to store data in bytes*/
uint32_t page_size; /*!< One page size in bytes. Page could be more then memory block. This parameter must be page_size >= N*block_size.*/
uint32_t sector_size; /*!< size of flash memory sector that will be erased and stored at once (erase)*/
uint32_t updaterate; /*!< Amount of accesses before block will be moved*/
uint32_t wr_size; /*!< Minimum amount of bytes per one block at write operation: 1...*/
size_t wl_partition_start_addr; /*!< Partition start address in the flash*/
uint32_t wl_partition_size; /*!< Size of partition used to store data in bytes*/
uint32_t wl_page_size; /*!< One page size in bytes. Page size can be more than memory block. Here, wl_page_size >= N*flash_sector_size, where N > 0.*/
uint32_t flash_sector_size; /*!< Size of flash memory sector that will be erased and stored at once (erase)*/
uint32_t wl_update_rate; /*!< Memory erase count after which physical sector and dummy sector swaps its address.*/
uint32_t wl_pos_update_record_size; /*!< Number of bytes for storing pos update record appended on the state sector data after every wl_update_rate*/
uint32_t version; /*!< A version of current implementation. To erase and reallocate complete memory this ID must be different from id before.*/
size_t temp_buff_size; /*!< Size of temporary allocated buffer to copy from one flash area to another. The best way, if this value will be equal to sector size.*/
uint32_t crc; /*!< CRC for this config*/
size_t wl_temp_buff_size; /*!< Size of temporary allocated buffer to copy from one flash area to another. The best way, if this value will be equal to sector size.*/
uint32_t crc32; /*!< CRC for this config*/
} wl_config_t;
#ifndef _MSC_VER // MSVS has different format for this define

View File

@ -18,9 +18,8 @@ public:
esp_err_t config(WL_Config_s *cfg, Flash_Access *flash_drv) override;
esp_err_t init() override;
size_t chip_size() override;
size_t sector_size() override;
size_t get_flash_size() override;
size_t get_sector_size() override;
esp_err_t erase_sector(size_t sector) override;
esp_err_t erase_range(size_t start_address, size_t size) override;
@ -28,8 +27,12 @@ public:
protected:
uint32_t flash_sector_size;
uint32_t fat_sector_size;
uint32_t size_factor;
uint32_t *sector_buffer;
/*when flash and fat sector sizes are not equal (where flash_sector_size >= fat_sector_size),
this flash_fat_sector_size_factor will be used while flash sector erase or read-write operation.
This factor is the ratio of flash_sector_size to fat_sector_size*/
uint32_t flash_fat_sector_size_factor;
uint32_t *sector_buffer; /*Ptr to sector buffer allocated in heap memory for temporary
storage of flash sector during erase operation*/
virtual esp_err_t erase_sector_fit(uint32_t start_sector, uint32_t count);

View File

@ -19,14 +19,14 @@ public:
esp_err_t config(WL_Config_s *cfg, Flash_Access *flash_drv) override;
esp_err_t init() override;
size_t chip_size() override;
size_t get_flash_size() override;
protected:
esp_err_t erase_sector_fit(uint32_t start_sector, uint32_t count) override;
// Dump Sector
uint32_t dump_addr; // dump buffer address
uint32_t state_addr;// sectore where state of transaction will be stored
uint32_t buff_trans_state_addr;// sector address where state of buffer transaction will be stored
esp_err_t recover();
};

View File

@ -24,9 +24,8 @@ public :
virtual esp_err_t config(wl_config_t *cfg, Flash_Access *flash_drv);
virtual esp_err_t init();
size_t chip_size() override;
size_t sector_size() override;
size_t get_flash_size() override;
size_t get_sector_size() override;
esp_err_t erase_sector(size_t sector) override;
esp_err_t erase_range(size_t start_address, size_t size) override;

View File

@ -21,23 +21,23 @@
typedef struct ALIGNED_(32) WL_State_s {
public:
uint32_t pos; /*!< current dummy block position*/
uint32_t max_pos; /*!< maximum amount of positions*/
uint32_t move_count; /*!< total amount of move counts. Used to calculate the address*/
uint32_t access_count; /*!< current access count*/
uint32_t max_count; /*!< max access count when block will be moved*/
uint32_t block_size; /*!< size of move block*/
uint32_t version; /*!< state id used to identify the version of current library implementation*/
uint32_t device_id; /*!< ID of current WL instance*/
uint32_t wl_dummy_sec_pos; /*!< Current dummy sector position*/
uint32_t wl_part_max_sec_pos; /*!< Number of sectors in the partition (excluding config and state sectors) for dummy sector movement*/
uint32_t wl_dummy_sec_move_count; /*!< When dummy sector completes one cycle through the entire flash, wl_dummy_sector_move_count will be incremented by 1*/
uint32_t wl_sec_erase_cycle_count; /*!< After every 'sector erase cycle', this count will be incremented by 1*/
uint32_t wl_max_sec_erase_cycle_count; /*!< Max wl_sector_erase_cycle_count after which block will be moved and dummy sector position record will be updated in state sector*/
uint32_t wl_block_size; /*!< WL partition block size*/
uint32_t version; /*!< State id used to identify the version of current library implementation*/
uint32_t wl_device_id; /*!< ID of current WL instance. Generated randomly when the state is first initialized*/
uint32_t reserved[7]; /*!< Reserved space for future use*/
uint32_t crc; /*!< CRC of structure*/
uint32_t crc32; /*!< CRC of structure*/
} wl_state_t;
#ifndef _MSC_VER // MSVS has different format for this define
static_assert(sizeof(wl_state_t) % 16 == 0, "Size of wl_state_t structure should be compatible with flash encryption");
#endif // _MSC_VER
#define WL_STATE_CRC_LEN_V1 offsetof(wl_state_t, device_id)
#define WL_STATE_CRC_LEN_V2 offsetof(wl_state_t, crc)
#define WL_STATE_CRC_LEN_V1 offsetof(wl_state_t, wl_device_id)
#define WL_STATE_CRC_LEN_V2 offsetof(wl_state_t, crc32)
#endif // _WL_State_H_

View File

@ -58,10 +58,12 @@ esp_err_t wl_mount(const esp_partition_t *partition, wl_handle_t *out_handle)
WL_Flash *wl_flash = NULL;
void *part_ptr = NULL;
Partition *part = NULL;
_lock_acquire(&s_instances_lock);
esp_err_t result = ESP_OK;
*out_handle = WL_INVALID_HANDLE;
_lock_acquire(&s_instances_lock);
// Get first available WL handle
for (size_t i = 0; i < MAX_WL_HANDLES; i++) {
if (s_instances[i].instance == NULL) {
*out_handle = i;
@ -69,24 +71,24 @@ esp_err_t wl_mount(const esp_partition_t *partition, wl_handle_t *out_handle)
}
}
wl_ext_cfg_t cfg;
cfg.full_mem_size = partition->size;
cfg.start_addr = WL_DEFAULT_START_ADDR;
cfg.version = WL_CURRENT_VERSION;
cfg.sector_size = SPI_FLASH_SEC_SIZE;
cfg.page_size = SPI_FLASH_SEC_SIZE;
cfg.updaterate = WL_DEFAULT_UPDATERATE;
cfg.temp_buff_size = WL_DEFAULT_TEMP_BUFF_SIZE;
cfg.wr_size = WL_DEFAULT_WRITE_SIZE;
// FAT sector size by default will be 512
cfg.fat_sector_size = CONFIG_WL_SECTOR_SIZE;
if (*out_handle == WL_INVALID_HANDLE) {
ESP_LOGE(TAG, "MAX_WL_HANDLES=%d instances already allocated", MAX_WL_HANDLES);
result = ESP_ERR_NO_MEM;
goto out;
}
wl_ext_cfg_t cfg;
cfg.wl_partition_start_addr = WL_DEFAULT_START_ADDR;
cfg.wl_partition_size = partition->size;
cfg.wl_page_size = SPI_FLASH_SEC_SIZE;
cfg.flash_sector_size = SPI_FLASH_SEC_SIZE; //default size is 4096
cfg.wl_update_rate = WL_DEFAULT_UPDATERATE;
cfg.wl_pos_update_record_size = WL_DEFAULT_WRITE_SIZE; //16 bytes per pos update will be stored
cfg.version = WL_CURRENT_VERSION;
cfg.wl_temp_buff_size = WL_DEFAULT_TEMP_BUFF_SIZE;
cfg.fat_sector_size = CONFIG_WL_SECTOR_SIZE; //default size is 4096
// Allocate memory for a Partition object, and then initialize the object
// using placement new operator. This way we can recover from out of
// memory condition.
@ -98,9 +100,9 @@ esp_err_t wl_mount(const esp_partition_t *partition, wl_handle_t *out_handle)
}
part = new (part_ptr) Partition(partition);
// Same for WL_Flash: allocate memory, use placement new
// Same for WL_Flash: allocate memory first and then use placement new operator
#if CONFIG_WL_SECTOR_SIZE == 512
#if CONFIG_WL_SECTOR_MODE == 1
#if CONFIG_WL_SECTOR_MODE == 1 //Safety mode
wl_flash_ptr = malloc(sizeof(WL_Ext_Safe));
if (wl_flash_ptr == NULL) {
@ -109,7 +111,7 @@ esp_err_t wl_mount(const esp_partition_t *partition, wl_handle_t *out_handle)
goto out;
}
wl_flash = new (wl_flash_ptr) WL_Ext_Safe();
#else
#else //Performance mode
wl_flash_ptr = malloc(sizeof(WL_Ext_Perf));
if (wl_flash_ptr == NULL) {
@ -118,7 +120,7 @@ esp_err_t wl_mount(const esp_partition_t *partition, wl_handle_t *out_handle)
goto out;
}
wl_flash = new (wl_flash_ptr) WL_Ext_Perf();
#endif // CONFIG_WL_SECTOR_MODE
#endif // CONFIG_WL_SECTOR_MODE (Safety or performance mode)
#endif // CONFIG_WL_SECTOR_SIZE
#if CONFIG_WL_SECTOR_SIZE == 4096
wl_flash_ptr = malloc(sizeof(WL_Flash));
@ -131,18 +133,24 @@ esp_err_t wl_mount(const esp_partition_t *partition, wl_handle_t *out_handle)
wl_flash = new (wl_flash_ptr) WL_Flash();
#endif // CONFIG_WL_SECTOR_SIZE
// Configure data needed by WL layer for respective flash driver
result = wl_flash->config(&cfg, part);
if (ESP_OK != result) {
ESP_LOGE(TAG, "%s: config instance=0x%08x, result=0x%x", __func__, *out_handle, result);
goto out;
}
// Initialise sectors used by WL layer for respective flash driver
result = wl_flash->init();
if (ESP_OK != result) {
ESP_LOGE(TAG, "%s: init instance=0x%08x, result=0x%x", __func__, *out_handle, result);
goto out;
}
s_instances[*out_handle].instance = wl_flash;
// Initialise the lock for respective WL handle
_lock_init(&s_instances[*out_handle].lock);
_lock_release(&s_instances_lock);
return ESP_OK;
@ -224,7 +232,7 @@ size_t wl_size(wl_handle_t handle)
return 0;
}
_lock_acquire(&s_instances[handle].lock);
size_t result = s_instances[handle].instance->chip_size();
size_t result = s_instances[handle].instance->get_flash_size();
_lock_release(&s_instances[handle].lock);
return result;
}
@ -236,7 +244,7 @@ size_t wl_sector_size(wl_handle_t handle)
return 0;
}
_lock_acquire(&s_instances[handle].lock);
size_t result = s_instances[handle].instance->sector_size();
size_t result = s_instances[handle].instance->get_sector_size();
_lock_release(&s_instances[handle].lock);
return result;
}