cfg->version,
(uint32_t) cfg->temp_buff_size);
- cfg->crc = crc32::crc32_le(WL_CFG_CRC_CONST, (const unsigned char *)cfg, sizeof(wl_config_t) - sizeof(cfg->crc));
+ cfg->crc = crc32::crc32_le(WL_CFG_CRC_CONST, (const unsigned char *)cfg, offsetof(wl_config_t, crc));
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;
this->configured = false;
if (cfg == NULL) {
result = ESP_ERR_INVALID_ARG;
}
WL_RESULT_CHECK(result);
- this->temp_buff = (uint8_t *)malloc(this->cfg.temp_buff_size);
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->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
+ 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
- ESP_LOGV(TAG, "%s - this->addr_state1=0x%08x", __func__, (uint32_t) this->addr_state1);
- ESP_LOGV(TAG, "%s - this->addr_state2=0x%08x", __func__, (uint32_t) this->addr_state2);
+ 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,
+ (uint32_t) this->cfg_size,
+ (uint32_t) this->addr_cfg,
+ (uint32_t) this->addr_state1,
+ (uint32_t) this->addr_state2,
+ (uint32_t) this->flash_size
+ );
+ if (flash_sz <= 0) {
+ result = ESP_ERR_INVALID_ARG;
+ }
+ WL_RESULT_CHECK(result);
+ this->temp_buff = (uint8_t *)malloc(this->cfg.temp_buff_size);
+ if (this->temp_buff == NULL) {
+ result = ESP_ERR_NO_MEM;
+ }
+ WL_RESULT_CHECK(result);
this->configured = true;
return ESP_OK;
}
result = this->flash_drv->read(this->addr_state2, state_copy, sizeof(wl_state_t));
WL_RESULT_CHECK(result);
- int check_size = sizeof(wl_state_t) - sizeof(uint32_t);
+ int check_size = offsetof(wl_state_t, crc);
// Chech CRC and recover state
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=%i",
+ 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",
__func__,
this->cfg.version,
this->state.version,
this->state.pos,
this->state.move_count);
-
- ESP_LOGD(TAG, "%s starts: crc1=%i, crc2 = %i, this->state.crc=%i, state_copy->crc=%i", __func__, crc1, crc2, this->state.crc, state_copy->crc);
+ ESP_LOGD(TAG, "%s starts: crc1=%i, crc2 = %i, this->state.crc=%i, state_copy->crc=%i, 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)) {
// The state is OK. Check the ID
if (this->state.version != this->cfg.version) {
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)*this->cfg.wr_size); i++) {
- uint8_t pos_bits = 0;
- result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i, &pos_bits, 1);
+ bool pos_bits = 0;
+ result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
WL_RESULT_CHECK(result);
- if (pos_bits != 0xff) {
- result = this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + i, &pos_bits, 1);
+ 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);
WL_RESULT_CHECK(result);
}
}
result = this->recoverPos();
WL_RESULT_CHECK(result);
}
- } else if ((crc1 != this->state.crc) && (crc2 != state_copy->crc)) { // This is just new flash
- result = this->initSections();
- WL_RESULT_CHECK(result);
+ } else if ((crc1 != this->state.crc) && (crc2 != state_copy->crc)) { // This is just new flash or new version
+ // Check if this is new version or just new instance of WL
+ result = this->updateVersion();
+ if (result == ESP_FAIL) {
+ result = this->initSections();
+ WL_RESULT_CHECK(result);
+ }
result = this->recoverPos();
WL_RESULT_CHECK(result);
} else {
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) * this->cfg.wr_size); i++) {
- uint8_t pos_bits = 0;
- result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i, &pos_bits, 1);
+ bool pos_bits = 0;
+ result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
WL_RESULT_CHECK(result);
- if (pos_bits != 0xff) {
- result = this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + i, &pos_bits, 1);
+ 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);
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) * this->cfg.wr_size); i++) {
- uint8_t pos_bits = 0;
- result = this->flash_drv->read(this->addr_state2 + sizeof(wl_state_t) + i, &pos_bits, 1);
+ bool pos_bits = 0;
+ result = this->flash_drv->read(this->addr_state2 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
+
WL_RESULT_CHECK(result);
- if (pos_bits != 0xff) {
- result = this->flash_drv->write(this->addr_state1 + sizeof(wl_state_t) + i, &pos_bits, 1);
+ 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);
WL_RESULT_CHECK(result);
}
}
}
if (result != ESP_OK) {
this->initialized = false;
- ESP_LOGE(TAG, "%s: returned 0x%x", __func__, result);
+ ESP_LOGE(TAG, "%s: returned 0x%x", __func__, (uint32_t)result);
return result;
}
this->initialized = true;
+ ESP_LOGD(TAG, "%s - move_count=%08x", __func__, (uint32_t)this->state.move_count);
return ESP_OK;
}
{
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++) {
- uint8_t pos_bits = 0;
- result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, &pos_bits, 1);
- WL_RESULT_CHECK(result);
+ bool pos_bits = false;
position = i;
- if (pos_bits == 0xff) {
+ result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
+ pos_bits = this->OkBuffSet(i);
+ WL_RESULT_CHECK(result);
+ ESP_LOGV(TAG, "%s - check pos: result=%i, position=%i, pos_bits=0x%08x", __func__, (uint32_t)result, (uint32_t)position, (uint32_t)pos_bits);
+ if (pos_bits == false) {
break; // we have found position
}
}
+
this->state.pos = position;
if (this->state.pos == this->state.max_pos) {
this->state.pos--;
}
- ESP_LOGD(TAG, "%s - this->state.pos=0x%08x, result=%08x", __func__, this->state.pos, result);
+ ESP_LOGD(TAG, "%s - this->state.pos=0x%08x, position=0x%08x, result=%08x, max_pos=%08x", __func__, (uint32_t)this->state.pos, (uint32_t)position, (uint32_t)result, (uint32_t)this->state.max_pos);
+ ESP_LOGV(TAG, "%s done", __func__);
return result;
}
this->state.version = this->cfg.version;
this->state.block_size = this->cfg.page_size;
this->used_bits = 0;
+ this->state.device_id = rand();
this->state.max_pos = 1 + this->flash_size / this->cfg.page_size;
- this->state.crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, sizeof(wl_state_t) - sizeof(uint32_t));
+ this->state.crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, offsetof(wl_state_t, crc));
result = this->flash_drv->erase_range(this->addr_state1, this->state_size);
WL_RESULT_CHECK(result);
return result;
}
+esp_err_t WL_Flash::updateVersion()
+{
+ esp_err_t result = ESP_OK;
+
+ result = this->updateV1_V2();
+ if (ESP_OK == result) return result;
+ // check next version
+ return result;
+}
+
+esp_err_t WL_Flash::updateV1_V2()
+{
+ esp_err_t result = ESP_OK;
+ // Check crc for old version and old version
+ ESP_LOGV(TAG, "%s start", __func__);
+ int check_size = offsetof(wl_state_t, crc) - sizeof(uint32_t);
+ // Chech CRC and recover state
+ uint32_t crc1 = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, check_size);
+ // For V1 crc in place of device_id and version
+ uint32_t v1_crc = this->state.device_id;
+
+ ESP_LOGD(TAG, "%s - process crc1=0x%08x v1_crc=0x%08x, version=%i", __func__, crc1, v1_crc, this->state.version);
+
+ if ((crc1 == v1_crc) && (this->state.version == 1)){
+ // Here we have to update all internal structures
+ ESP_LOGV(TAG, "%s Update from V1 to V2", __func__);
+ uint32_t pos = 0;
+
+ for (size_t i = 0; i < this->state.max_pos; i++) {
+ uint8_t pos_bits = 0;
+ result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, &pos_bits, 1);
+ WL_RESULT_CHECK(result);
+ ESP_LOGV(TAG, "%s- result=%i, pos=%i, pos_bits=0x%08x", __func__, (uint32_t)result, (uint32_t)pos, (uint32_t)pos_bits);
+ pos = i;
+ if (pos_bits == 0xff) {
+ break; // we have found position
+ }
+ }
+ if (pos == this->state.max_pos) {
+ pos--;
+ }
+ WL_RESULT_CHECK(result);
+
+ this->state.version = 2;
+ this->state.pos = 0;
+ this->state.crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, offsetof(wl_state_t, crc));
+ this->state.device_id = rand();
+
+ 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);
+ for (int 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);
+ WL_RESULT_CHECK(result);
+ }
+
+ 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);
+ ESP_LOGD(TAG, "%s - move_count=%08x, pos=%08x, ", __func__, this->state.move_count, this->state.pos);
+
+ memset(this->temp_buff, 0, this->cfg.wr_size);
+ for (int 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);
+ WL_RESULT_CHECK(result);
+ }
+ this->state.pos = pos;
+ return result;
+ }
+
+ return ESP_FAIL;
+}
+
+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] = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&buff[i], sizeof(uint32_t));
+ }
+}
+
+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 crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&data, sizeof(uint32_t));
+ if (crc != data_buff[i]) result = false;
+ }
+ return result;
+}
+
+
esp_err_t WL_Flash::updateWL()
{
esp_err_t result = ESP_OK;
// Here we will update structures...
// Update bits and save to flash:
uint32_t byte_pos = this->state.pos * this->cfg.wr_size;
- this->used_bits = 0;
+ this->fillOkBuff(this->state.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->used_bits, this->cfg.wr_size);
+ result |= this->flash_drv->write(this->addr_state1 + sizeof(wl_state_t) + byte_pos, this->temp_buff, this->cfg.wr_size);
if (result != ESP_OK) {
ESP_LOGE(TAG, "%s - update position 1 result=%08x", __func__, result);
this->state.access_count = this->state.max_count - 1; // we will update next time
return result;
}
- result |= this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + byte_pos, &this->used_bits, this->cfg.wr_size);
+ 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);
if (result != ESP_OK) {
ESP_LOGE(TAG, "%s - update position 2 result=%08x", __func__, result);
this->state.access_count = this->state.max_count - 1; // we will update next time
this->state.move_count = 0;
}
// write main state
- this->state.crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, sizeof(wl_state_t) - sizeof(uint32_t));
+ this->state.crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, offsetof(wl_state_t, crc));
result = this->flash_drv->erase_range(this->addr_state1, this->state_size);
WL_RESULT_CHECK(result);
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=%08x", __func__, this->state.move_count);
+ ESP_LOGD(TAG, "%s - move_count=%08x, pos=%08x, ", __func__, this->state.move_count, this->state.pos);
}
// Save structures to the flash... and check result
if (result == ESP_OK) {
} else {
result += this->cfg.page_size;
}
- ESP_LOGV(TAG, "%s - addr=0x%08x -> result=0x%08x", __func__, (uint32_t) addr, (uint32_t) result);
+ 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;
}
if (!this->initialized) {
return ESP_ERR_INVALID_STATE;
}
- ESP_LOGV(TAG, "%s - sector=0x%08x", __func__, (uint32_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);
if (!this->initialized) {
return ESP_ERR_INVALID_STATE;
}
- ESP_LOGV(TAG, "%s - start_address=0x%08x, size=0x%08x", __func__, (uint32_t) start_address, (uint32_t) size);
+ 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;
for (size_t i = 0; i < erase_count; i++) {
if (!this->initialized) {
return ESP_ERR_INVALID_STATE;
}
- ESP_LOGV(TAG, "%s - dest_addr=0x%08x, size=0x%08x", __func__, (uint32_t) dest_addr, (uint32_t) size);
+ 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;
for (size_t i = 0; i < count; i++) {
size_t virt_addr = this->calcAddr(dest_addr + i * this->cfg.page_size);
if (!this->initialized) {
return ESP_ERR_INVALID_STATE;
}
- ESP_LOGV(TAG, "%s - src_addr=0x%08x, size=0x%08x", __func__, (uint32_t) src_addr, (uint32_t) size);
+ 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;
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);
WL_RESULT_CHECK(result);
}
esp_err_t result = ESP_OK;
this->state.access_count = this->state.max_count - 1;
result = this->updateWL();
- ESP_LOGV(TAG, "%s - result=%08x", __func__, result);
+ ESP_LOGD(TAG, "%s - result=%08x, move_count=%08x", __func__, result, this->state.move_count);
return result;
}
#include "freertos/portable.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
+#include "esp_clk.h"
+#include "soc/cpu.h"
TEST_CASE("wl_unmount doesn't leak memory", "[wear_levelling]")
{
memcpy(&fake_partition, test_partition, sizeof(fake_partition));
wl_handle_t handle;
size_t size_before, size_after;
+ wl_unmount(WL_INVALID_HANDLE);
- // test small partition
- fake_partition.size = SPI_FLASH_SEC_SIZE;
- size_before = xPortGetFreeHeapSize();
- TEST_ESP_ERR(ESP_ERR_INVALID_ARG, wl_mount(&fake_partition, &handle));
- size_after = xPortGetFreeHeapSize();
- TEST_ASSERT_EQUAL_HEX32(size_before, size_after);
- // currently this test leaks memory
+ esp_partition_erase_range(test_partition, test_partition->address, test_partition->size);
+ // test small partition: result should be error
+ for (int i=0 ; i< 5 ; i++)
+ {
+ fake_partition.size = SPI_FLASH_SEC_SIZE*(i);
+ size_before = xPortGetFreeHeapSize();
+ TEST_ESP_ERR(ESP_ERR_INVALID_ARG, wl_mount(&fake_partition, &handle));
+ size_after = xPortGetFreeHeapSize();
+ TEST_ASSERT_EQUAL_HEX32(size_before, size_after);
+ printf("Test for size 0x%08x passed\n", fake_partition.size);
+ // currently this test leaks memory
+ }
- // test slightly bigger partition
- fake_partition.size = SPI_FLASH_SEC_SIZE * 3;
+ // test minimum size partition: result should be OK
+ fake_partition.size = SPI_FLASH_SEC_SIZE * 5;
size_before = xPortGetFreeHeapSize();
- TEST_ESP_ERR(ESP_ERR_INVALID_ARG, wl_mount(&fake_partition, &handle));
+ TEST_ESP_OK(wl_mount(&fake_partition, &handle));
+ wl_unmount(handle);
size_after = xPortGetFreeHeapSize();
TEST_ASSERT_EQUAL_HEX32(size_before, size_after);
// currently this test hangs
vSemaphoreDelete(args4.done);
wl_unmount(handle);
}
+
+#define TEST_SECTORS_COUNT 8
+
+static void check_mem_data(wl_handle_t handle, uint32_t init_val, uint32_t* buff)
+{
+ size_t sector_size = wl_sector_size(handle);
+
+ for (int m=0 ; m < TEST_SECTORS_COUNT ; m++) {
+ TEST_ESP_OK(wl_read(handle, sector_size * m, buff, sector_size));
+ for (int i=0 ; i< sector_size/sizeof(uint32_t) ; i++) {
+ uint32_t compare_val = init_val + i + m*sector_size;
+ TEST_ASSERT_EQUAL( buff[i], compare_val);
+ }
+ }
+}
+
+
+// We write complete memory with defined data
+// And then write one sector many times.
+// A data in other secors should be the same.
+// We do this also with unmount
+TEST_CASE("multiple write is correct", "[wear_levelling]")
+{
+ const esp_partition_t *partition = get_test_data_partition();
+ esp_partition_t fake_partition;
+ memcpy(&fake_partition, partition, sizeof(fake_partition));
+
+ fake_partition.size = SPI_FLASH_SEC_SIZE*(4 + TEST_SECTORS_COUNT);
+
+ wl_handle_t handle;
+ TEST_ESP_OK(wl_mount(&fake_partition, &handle));
+
+ size_t sector_size = wl_sector_size(handle);
+ // Erase 8 sectors
+ TEST_ESP_OK(wl_erase_range(handle, 0, sector_size * TEST_SECTORS_COUNT));
+ // Write data to all sectors
+ printf("Check 1 sector_size=0x%08x\n", sector_size);
+ // Set initial random value
+ uint32_t init_val = rand();
+
+ uint32_t* buff = (uint32_t*)malloc(sector_size);
+ for (int m=0 ; m < TEST_SECTORS_COUNT ; m++) {
+ for (int i=0 ; i< sector_size/sizeof(uint32_t) ; i++) {
+ buff[i] = init_val + i + m*sector_size;
+ }
+ TEST_ESP_OK(wl_erase_range(handle, sector_size*m, sector_size));
+ TEST_ESP_OK(wl_write(handle, sector_size*m, buff, sector_size));
+ }
+
+ check_mem_data(handle, init_val, buff);
+
+ uint32_t start;
+ RSR(CCOUNT, start);
+
+
+ for (int m=0 ; m< 100000 ; m++) {
+ uint32_t sector = m % TEST_SECTORS_COUNT;
+ for (int i=0 ; i< sector_size/sizeof(uint32_t) ; i++) {
+ buff[i] = init_val + i + sector*sector_size;
+ }
+ TEST_ESP_OK(wl_erase_range(handle, sector_size*sector, sector_size));
+ TEST_ESP_OK(wl_write(handle, sector_size*sector, buff, sector_size));
+ check_mem_data(handle, init_val, buff);
+
+ uint32_t end;
+ RSR(CCOUNT, end);
+ uint32_t ms = (end - start) / (esp_clk_cpu_freq() / 1000);
+ printf("loop %4i pass, time= %ims\n", m, ms);
+ if (ms > 10000) {
+ break;
+ }
+ }
+
+ free(buff);
+ wl_unmount(handle);
+}