From 1bca6d0ffeac07114c22f83f97edd5ce569805bc Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Wed, 17 Apr 2019 09:18:11 +0800 Subject: [PATCH] spi_flash: Add vTaskDelay while a long erasing Added Kconfig options to enable yield operation during flash erase. By default disable. Closes: https://github.com/espressif/esp-idf/issues/2083 Closes: IDFGH-261 --- components/spi_flash/Kconfig | 22 ++++++++++++++++++++++ components/spi_flash/flash_ops.c | 15 +++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/components/spi_flash/Kconfig b/components/spi_flash/Kconfig index f5e3c7ecd..e22e13cea 100644 --- a/components/spi_flash/Kconfig +++ b/components/spi_flash/Kconfig @@ -77,6 +77,28 @@ config SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED bool "Allowed" endchoice + config SPI_FLASH_YIELD_DURING_ERASE + bool "Enables yield operation during flash erase" + default n + help + This allows to yield the CPUs between erase commands. + Prevents starvation of other tasks. + + config SPI_FLASH_ERASE_YIELD_DURATION_MS + int "Duration of erasing to yield CPUs (ms)" + depends on SPI_FLASH_YIELD_DURING_ERASE + default 20 + help + If a duration of one erase command is large + then it will yield CPUs after finishing a current command. + + config SPI_FLASH_ERASE_YIELD_TICKS + int "CPU release time (tick)" + depends on SPI_FLASH_YIELD_DURING_ERASE + default 1 + help + Defines how many ticks will be before returning to continue a erasing. + endmenu diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index aab0c1210..69e5e6305 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -34,6 +34,7 @@ #include "esp_flash_partitions.h" #include "esp_ota_ops.h" #include "cache_utils.h" +#include "esp_timer.h" /* bytes erased by SPIEraseBlock() ROM function */ #define BLOCK_ERASE_SIZE 65536 @@ -217,6 +218,9 @@ esp_err_t IRAM_ATTR spi_flash_erase_range(uint32_t start_addr, uint32_t size) rc = spi_flash_unlock(); if (rc == ESP_ROM_SPIFLASH_RESULT_OK) { for (size_t sector = start; sector != end && rc == ESP_ROM_SPIFLASH_RESULT_OK; ) { +#ifdef CONFIG_SPI_FLASH_YIELD_DURING_ERASE + int64_t start_time_us = esp_timer_get_time(); +#endif spi_flash_guard_start(); if (sector % sectors_per_block == 0 && end - sector > sectors_per_block) { rc = esp_rom_spiflash_erase_block(sector / sectors_per_block); @@ -228,6 +232,17 @@ esp_err_t IRAM_ATTR spi_flash_erase_range(uint32_t start_addr, uint32_t size) COUNTER_ADD_BYTES(erase, SPI_FLASH_SEC_SIZE); } spi_flash_guard_end(); +#ifdef CONFIG_SPI_FLASH_YIELD_DURING_ERASE + int dt_ms = (esp_timer_get_time() - start_time_us) / 1000; + if (dt_ms >= CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS || + dt_ms * 2 >= CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS) { + /* For example when dt_ms = 15 and CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS = 20. + * In this case we need to call vTaskDelay because + * the duration of this command + the next command probably will exceed more than 20. + */ + vTaskDelay(CONFIG_SPI_FLASH_ERASE_YIELD_TICKS); + } +#endif } } COUNTER_STOP(erase);