|
|
@@ -27,6 +27,8 @@
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
+#define DIV_AND_CEIL(x, y) ((x) / (y) + ((x) % (y) > 0))
|
|
|
+
|
|
|
SpiFlash::SpiFlash()
|
|
|
{
|
|
|
return;
|
|
|
@@ -37,16 +39,31 @@ SpiFlash::~SpiFlash()
|
|
|
deinit();
|
|
|
}
|
|
|
|
|
|
-void SpiFlash::init(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partitions_bin)
|
|
|
+void SpiFlash::init(uint32_t chip_size, uint32_t block_size, uint32_t sector_size, uint32_t page_size, const char* partitions_bin)
|
|
|
{
|
|
|
// De-initialize first
|
|
|
deinit();
|
|
|
|
|
|
+ // Initialize values and alloc memory
|
|
|
this->chip_size = chip_size;
|
|
|
this->block_size = block_size;
|
|
|
this->sector_size = sector_size;
|
|
|
this->page_size = page_size;
|
|
|
|
|
|
+ this->blocks = DIV_AND_CEIL(this->chip_size, this->block_size);
|
|
|
+ this->sectors = DIV_AND_CEIL(this->chip_size, this->sector_size);
|
|
|
+ this->pages = DIV_AND_CEIL(this->chip_size, this->page_size);
|
|
|
+
|
|
|
+ this->erase_cycles = (uint32_t*) calloc(this->sectors, sizeof(uint32_t));
|
|
|
+ this->erase_states = (bool*) calloc(this->sectors, sizeof(bool));
|
|
|
+ memset(this->erase_states, 0xFF, this->sectors * sizeof(bool));
|
|
|
+
|
|
|
+ this->total_erase_cycles_limit = 0;
|
|
|
+ this->erase_cycles_limit = 0;
|
|
|
+
|
|
|
+ this->total_erase_cycles = 0;
|
|
|
+
|
|
|
+ // Load partitions table bin
|
|
|
this->memory = (uint8_t *) malloc(this->chip_size);
|
|
|
memset(this->memory, 0xFF, this->chip_size);
|
|
|
|
|
|
@@ -65,31 +82,74 @@ void SpiFlash::init(size_t chip_size, size_t block_size, size_t sector_size, siz
|
|
|
|
|
|
void SpiFlash::deinit()
|
|
|
{
|
|
|
- if(inited)
|
|
|
- {
|
|
|
- free(this->memory);
|
|
|
- }
|
|
|
+ // Free all allocated memory
|
|
|
+ free(this->memory);
|
|
|
+
|
|
|
+ free(this->erase_cycles);
|
|
|
+ free(this->erase_states);
|
|
|
}
|
|
|
|
|
|
-size_t SpiFlash::get_chip_size()
|
|
|
+uint32_t SpiFlash::get_chip_size()
|
|
|
{
|
|
|
return this->chip_size;
|
|
|
}
|
|
|
|
|
|
-size_t SpiFlash::get_sector_size()
|
|
|
+uint32_t SpiFlash::get_block_size()
|
|
|
+{
|
|
|
+ return this->block_size;
|
|
|
+}
|
|
|
+
|
|
|
+uint32_t SpiFlash::get_sector_size()
|
|
|
{
|
|
|
return this->sector_size;
|
|
|
}
|
|
|
|
|
|
+uint32_t SpiFlash::get_page_size()
|
|
|
+{
|
|
|
+ return this->page_size;
|
|
|
+}
|
|
|
+
|
|
|
esp_rom_spiflash_result_t SpiFlash::erase_block(uint32_t block)
|
|
|
{
|
|
|
- memset(&this->memory[block * this->block_size], 0xFF, this->block_size);
|
|
|
+ uint32_t sectors_per_block = (this->block_size / this->sector_size);
|
|
|
+ uint32_t start_sector = block * sectors_per_block;
|
|
|
+
|
|
|
+ for (int i = start_sector; i < start_sector + sectors_per_block; i++) {
|
|
|
+ this->erase_sector(i);
|
|
|
+ }
|
|
|
+
|
|
|
return ESP_ROM_SPIFLASH_RESULT_OK;
|
|
|
}
|
|
|
|
|
|
-esp_rom_spiflash_result_t SpiFlash::erase_sector(size_t sector)
|
|
|
+esp_rom_spiflash_result_t SpiFlash::erase_sector(uint32_t sector)
|
|
|
{
|
|
|
- memset(&this->memory[sector * this->sector_size], 0xFF, this->sector_size);
|
|
|
+ if (this->total_erase_cycles_limit != 0 &&
|
|
|
+ this->total_erase_cycles >= this->total_erase_cycles_limit) {
|
|
|
+ return ESP_ROM_SPIFLASH_RESULT_ERR;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this->erase_cycles_limit != 0 &&
|
|
|
+ this->erase_cycles[sector] >= this->erase_cycles_limit) {
|
|
|
+ return ESP_ROM_SPIFLASH_RESULT_ERR;
|
|
|
+ }
|
|
|
+
|
|
|
+ uint32_t pages_per_sector = (this->sector_size / this->page_size);
|
|
|
+ uint32_t start_page = sector * pages_per_sector;
|
|
|
+
|
|
|
+ if (this->erase_states[sector]) {
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int i = start_page; i < start_page + pages_per_sector; i++) {
|
|
|
+ this->erase_page(i);
|
|
|
+ }
|
|
|
+
|
|
|
+ this->erase_cycles[sector]++;
|
|
|
+ this->total_erase_cycles++;
|
|
|
+
|
|
|
+ this->erase_states[sector] = true;
|
|
|
+
|
|
|
+out:
|
|
|
return ESP_ROM_SPIFLASH_RESULT_OK;
|
|
|
}
|
|
|
|
|
|
@@ -99,14 +159,36 @@ esp_rom_spiflash_result_t SpiFlash::erase_page(uint32_t page)
|
|
|
return ESP_ROM_SPIFLASH_RESULT_OK;
|
|
|
}
|
|
|
|
|
|
-esp_rom_spiflash_result_t SpiFlash::write(size_t dest_addr, const void *src, size_t size)
|
|
|
+esp_rom_spiflash_result_t SpiFlash::write(uint32_t dest_addr, const void *src, uint32_t size)
|
|
|
{
|
|
|
- // Emulate inability to set programmed bits without erasing
|
|
|
+ // Update reset states and check for failure
|
|
|
+ int start = 0;
|
|
|
+ int end = 0;
|
|
|
+
|
|
|
+ if (this->total_erase_cycles_limit != 0 &&
|
|
|
+ this->total_erase_cycles >= this->total_erase_cycles_limit) {
|
|
|
+ return ESP_ROM_SPIFLASH_RESULT_ERR;
|
|
|
+ }
|
|
|
+
|
|
|
+ start = dest_addr / this->get_sector_size();
|
|
|
+ end = size > 0 ? (dest_addr + size - 1) / this->get_sector_size() : start;
|
|
|
+
|
|
|
+ for (int i = start; i <= end; i++) {
|
|
|
+ if (this->erase_cycles_limit != 0 &&
|
|
|
+ this->erase_cycles[i] >= this->erase_cycles_limit) {
|
|
|
+ return ESP_ROM_SPIFLASH_RESULT_ERR;
|
|
|
+ }
|
|
|
+
|
|
|
+ this->erase_states[i] = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Do the write
|
|
|
for(uint32_t ctr = 0; ctr < size; ctr++)
|
|
|
{
|
|
|
uint8_t data = ((uint8_t*)src)[ctr];
|
|
|
uint8_t written = this->memory[dest_addr + ctr];
|
|
|
|
|
|
+ // Emulate inability to set programmed bits without erasing
|
|
|
data &= written;
|
|
|
|
|
|
this->memory[dest_addr + ctr] = data;
|
|
|
@@ -115,8 +197,28 @@ esp_rom_spiflash_result_t SpiFlash::write(size_t dest_addr, const void *src, siz
|
|
|
return ESP_ROM_SPIFLASH_RESULT_OK;
|
|
|
}
|
|
|
|
|
|
-esp_rom_spiflash_result_t SpiFlash::read(size_t src_addr, void *dest, size_t size)
|
|
|
+esp_rom_spiflash_result_t SpiFlash::read(uint32_t src_addr, void *dest, uint32_t size)
|
|
|
{
|
|
|
+ // Check for failure
|
|
|
+ int start = 0;
|
|
|
+ int end = 0;
|
|
|
+
|
|
|
+ if (this->total_erase_cycles_limit != 0 &&
|
|
|
+ this->total_erase_cycles >= this->total_erase_cycles_limit) {
|
|
|
+ return ESP_ROM_SPIFLASH_RESULT_ERR;
|
|
|
+ }
|
|
|
+
|
|
|
+ start = src_addr / this->get_sector_size();
|
|
|
+ end = size > 0 ? (src_addr + size - 1) / this->get_sector_size() : start;
|
|
|
+
|
|
|
+ for (int i = start; i <= end; i++) {
|
|
|
+ if (this->erase_cycles_limit != 0 &&
|
|
|
+ this->erase_cycles[i] >= this->erase_cycles_limit) {
|
|
|
+ return ESP_ROM_SPIFLASH_RESULT_ERR;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Do the read
|
|
|
memcpy(dest, &this->memory[src_addr], size);
|
|
|
return ESP_ROM_SPIFLASH_RESULT_OK;
|
|
|
}
|
|
|
@@ -124,4 +226,34 @@ esp_rom_spiflash_result_t SpiFlash::read(size_t src_addr, void *dest, size_t siz
|
|
|
uint8_t* SpiFlash::get_memory_ptr(uint32_t src_address)
|
|
|
{
|
|
|
return &this->memory[src_address];
|
|
|
+}
|
|
|
+
|
|
|
+uint32_t SpiFlash::get_erase_cycles(uint32_t sector)
|
|
|
+{
|
|
|
+ return this->erase_cycles[sector];
|
|
|
+}
|
|
|
+
|
|
|
+uint32_t SpiFlash::get_total_erase_cycles()
|
|
|
+{
|
|
|
+ return this->total_erase_cycles;
|
|
|
+}
|
|
|
+
|
|
|
+void SpiFlash::set_erase_cycles_limit(uint32_t limit)
|
|
|
+{
|
|
|
+ this->erase_cycles_limit = limit;
|
|
|
+}
|
|
|
+
|
|
|
+void SpiFlash::set_total_erase_cycles_limit(uint32_t limit)
|
|
|
+{
|
|
|
+ this->total_erase_cycles_limit = limit;
|
|
|
+}
|
|
|
+
|
|
|
+void SpiFlash::reset_erase_cycles()
|
|
|
+{
|
|
|
+ memset(this->erase_cycles, 0, sizeof(this->sectors * sizeof(uint32_t)));
|
|
|
+}
|
|
|
+
|
|
|
+void SpiFlash::reset_total_erase_cycles()
|
|
|
+{
|
|
|
+ this->total_erase_cycles = 0;
|
|
|
}
|