From 1554fd3d8a0c8093551e21afa8978a5f04873011 Mon Sep 17 00:00:00 2001 From: KonstantinKondrashov Date: Thu, 2 Apr 2020 14:27:33 +0800 Subject: [PATCH 1/5] spi_flash(LEGACY_IMPL): Add vTaskDelay while a long erasing Added Kconfig options to enable yield operation during flash erase Closes: https://github.com/espressif/esp-idf/issues/2083 Closes: https://github.com/espressif/esp-idf/issues/4916 Closes: IDFGH-261 --- components/spi_flash/Kconfig | 22 ++++++++++++++++++++++ components/spi_flash/flash_ops.c | 14 ++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/components/spi_flash/Kconfig b/components/spi_flash/Kconfig index 046146e00..18b60978f 100644 --- a/components/spi_flash/Kconfig +++ b/components/spi_flash/Kconfig @@ -84,6 +84,28 @@ menu "SPI Flash driver" The implementation of SPI flash has been greatly changed in IDF v4.0. Enable this option to use the legacy implementation. + config SPI_FLASH_YIELD_DURING_ERASE + bool "Enables yield operation during flash erase" + default y + 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. + menu "Auto-detect flash chips" config SPI_FLASH_SUPPORT_ISSI_CHIP diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index a8ffc7810..105d2b4c0 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -42,6 +42,7 @@ #include "cache_utils.h" #include "esp_flash.h" #include "esp_attr.h" +#include "esp_timer.h" /* bytes erased by SPIEraseBlock() ROM function */ @@ -235,7 +236,13 @@ esp_err_t IRAM_ATTR spi_flash_erase_range(size_t start_addr, size_t size) esp_rom_spiflash_result_t rc; rc = spi_flash_unlock(); if (rc == ESP_ROM_SPIFLASH_RESULT_OK) { +#ifdef CONFIG_SPI_FLASH_YIELD_DURING_ERASE + int64_t no_yield_time_us = 0; +#endif 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); @@ -247,6 +254,13 @@ esp_err_t IRAM_ATTR spi_flash_erase_range(size_t start_addr, size_t size) COUNTER_ADD_BYTES(erase, SPI_FLASH_SEC_SIZE); } spi_flash_guard_end(); +#ifdef CONFIG_SPI_FLASH_YIELD_DURING_ERASE + no_yield_time_us += (esp_timer_get_time() - start_time_us); + if (no_yield_time_us / 1000 >= CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS) { + no_yield_time_us = 0; + vTaskDelay(CONFIG_SPI_FLASH_ERASE_YIELD_TICKS); + } +#endif } } COUNTER_STOP(erase); From d67e764ef6b7c080d420032accbfe67cdb84dd96 Mon Sep 17 00:00:00 2001 From: KonstantinKondrashov Date: Thu, 2 Apr 2020 17:29:21 +0800 Subject: [PATCH 2/5] spi_flash(new driver): Add vTaskDelay while a long erasing --- components/spi_flash/esp_flash_api.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/components/spi_flash/esp_flash_api.c b/components/spi_flash/esp_flash_api.c index 7073ab62e..734bb3508 100644 --- a/components/spi_flash/esp_flash_api.c +++ b/components/spi_flash/esp_flash_api.c @@ -23,6 +23,9 @@ #include "sdkconfig.h" #include "esp_heap_caps.h" #include "esp_flash_internal.h" +#include +#include +#include "esp_timer.h" static const char TAG[] = "spi_flash"; @@ -337,8 +340,13 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui err = spiflash_end(chip, err); } - +#ifdef CONFIG_SPI_FLASH_YIELD_DURING_ERASE + int64_t no_yield_time_us = 0; +#endif while (err == ESP_OK && len >= sector_size) { +#ifdef CONFIG_SPI_FLASH_YIELD_DURING_ERASE + int64_t start_time_us = esp_timer_get_time(); +#endif err = spiflash_start(chip); if (err != ESP_OK) { return err; @@ -358,6 +366,14 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui } err = spiflash_end(chip, err); + +#ifdef CONFIG_SPI_FLASH_YIELD_DURING_ERASE + no_yield_time_us += (esp_timer_get_time() - start_time_us); + if (no_yield_time_us / 1000 >= CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS) { + no_yield_time_us = 0; + vTaskDelay(CONFIG_SPI_FLASH_ERASE_YIELD_TICKS); + } +#endif } return err; } From b56c7d9066adc42a79a5689f87217ada72ec3f54 Mon Sep 17 00:00:00 2001 From: KonstantinKondrashov Date: Thu, 2 Apr 2020 17:54:43 +0800 Subject: [PATCH 3/5] spi_flash: Add into sim/stubs the esp_timer --- components/spi_flash/sim/Makefile.files | 2 ++ components/spi_flash/sim/stubs/Makefile.files | 3 +++ .../sim/stubs/esp_timer/include/esp_timer.h | 15 ++++++++++++++ .../sim/stubs/esp_timer/src/esp_timer.c | 20 +++++++++++++++++++ 4 files changed, 40 insertions(+) create mode 100644 components/spi_flash/sim/stubs/esp_timer/include/esp_timer.h create mode 100644 components/spi_flash/sim/stubs/esp_timer/src/esp_timer.c diff --git a/components/spi_flash/sim/Makefile.files b/components/spi_flash/sim/Makefile.files index f66a58c67..bc9db882c 100644 --- a/components/spi_flash/sim/Makefile.files +++ b/components/spi_flash/sim/Makefile.files @@ -17,6 +17,7 @@ INCLUDE_DIRS := \ app_update/include \ driver/include \ esp32/include \ + esp_timer/include \ freertos/include \ log/include \ newlib/include \ @@ -31,6 +32,7 @@ INCLUDE_DIRS := \ soc/esp32/include \ soc/include \ esp32/include \ + esp_timer/include \ bootloader_support/include \ app_update/include \ spi_flash/include \ diff --git a/components/spi_flash/sim/stubs/Makefile.files b/components/spi_flash/sim/stubs/Makefile.files index 91c034768..b8627aff4 100644 --- a/components/spi_flash/sim/stubs/Makefile.files +++ b/components/spi_flash/sim/stubs/Makefile.files @@ -4,6 +4,7 @@ SOURCE_FILES := \ newlib/lock.c \ esp32/crc.cpp \ esp32/esp_random.c \ + esp_timer/src/esp_timer.c \ bootloader_support/src/bootloader_common.c INCLUDE_DIRS := \ @@ -12,6 +13,7 @@ INCLUDE_DIRS := \ app_update/include \ driver/include \ esp32/include \ + esp_timer/include \ freertos/include \ log/include \ newlib/include \ @@ -24,6 +26,7 @@ INCLUDE_DIRS := \ xtensa/include \ xtensa/esp32/include \ esp32/include \ + esp_timer/include \ bootloader_support/include \ app_update/include \ spi_flash/include \ diff --git a/components/spi_flash/sim/stubs/esp_timer/include/esp_timer.h b/components/spi_flash/sim/stubs/esp_timer/include/esp_timer.h new file mode 100644 index 000000000..954448b0d --- /dev/null +++ b/components/spi_flash/sim/stubs/esp_timer/include/esp_timer.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int64_t esp_timer_get_time(void); + +#ifdef __cplusplus +} +#endif + diff --git a/components/spi_flash/sim/stubs/esp_timer/src/esp_timer.c b/components/spi_flash/sim/stubs/esp_timer/src/esp_timer.c new file mode 100644 index 000000000..657873cad --- /dev/null +++ b/components/spi_flash/sim/stubs/esp_timer/src/esp_timer.c @@ -0,0 +1,20 @@ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp_timer.h" + +int64_t esp_timer_get_time(void) +{ + return 0; +} From 5c98ff015ea4a9543b392d2b127b175956526ccc Mon Sep 17 00:00:00 2001 From: KonstantinKondrashov Date: Fri, 24 Apr 2020 02:09:15 +0800 Subject: [PATCH 4/5] spi_flash(LEGACY_IMPL): Add a Kconfig option - Bypass a block erase and always do sector erase Closes: IDF-1561 --- components/spi_flash/Kconfig | 8 ++++++++ components/spi_flash/flash_ops.c | 5 ++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/components/spi_flash/Kconfig b/components/spi_flash/Kconfig index 18b60978f..e884726c5 100644 --- a/components/spi_flash/Kconfig +++ b/components/spi_flash/Kconfig @@ -84,6 +84,14 @@ menu "SPI Flash driver" The implementation of SPI flash has been greatly changed in IDF v4.0. Enable this option to use the legacy implementation. + config SPI_FLASH_BYPASS_BLOCK_ERASE + bool "Bypass a block erase and always do sector erase" + default n + help + Some flash chips can have very high "max" erase times, especially for block erase (32KB or 64KB). + This option allows to bypass "block erase" and always do sector erase commands. + This will be much slower overall in most cases, but improves latency for other code to run. + config SPI_FLASH_YIELD_DURING_ERASE bool "Enables yield operation during flash erase" default y diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index 105d2b4c0..187c27c9b 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -244,11 +244,14 @@ esp_err_t IRAM_ATTR spi_flash_erase_range(size_t start_addr, size_t size) int64_t start_time_us = esp_timer_get_time(); #endif spi_flash_guard_start(); +#ifndef CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE if (sector % sectors_per_block == 0 && end - sector >= sectors_per_block) { rc = esp_rom_spiflash_erase_block(sector / sectors_per_block); sector += sectors_per_block; COUNTER_ADD_BYTES(erase, sectors_per_block * SPI_FLASH_SEC_SIZE); - } else { + } else +#endif + { rc = esp_rom_spiflash_erase_sector(sector); ++sector; COUNTER_ADD_BYTES(erase, SPI_FLASH_SEC_SIZE); From 4214179de1dbd24abad2c644143781e4701dd88c Mon Sep 17 00:00:00 2001 From: KonstantinKondrashov Date: Fri, 24 Apr 2020 02:13:17 +0800 Subject: [PATCH 5/5] spi_flash(new driver): Add a Kconfig option - Bypass a block erase and always do sector erase Closes: IDF-1561 --- components/spi_flash/esp_flash_api.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/spi_flash/esp_flash_api.c b/components/spi_flash/esp_flash_api.c index 734bb3508..340fba002 100644 --- a/components/spi_flash/esp_flash_api.c +++ b/components/spi_flash/esp_flash_api.c @@ -352,13 +352,15 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui return err; } +#ifndef CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE // If possible erase an entire multi-sector block if (block_erase_size > 0 && len >= block_erase_size && (start % block_erase_size) == 0) { err = chip->chip_drv->erase_block(chip, start); start += block_erase_size; len -= block_erase_size; - } - else { + } else +#endif + { // Otherwise erase individual sector only err = chip->chip_drv->erase_sector(chip, start); start += sector_size;