From 3cb655eaabd136700071c9225f33715ea4915917 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 7135d0767..c9dd305a1 100644 --- a/components/spi_flash/Kconfig +++ b/components/spi_flash/Kconfig @@ -100,6 +100,28 @@ menu "SPI Flash driver" this option, and the lock will be bypassed on SPI1 bus. Otherwise if extra devices are needed to attach to SPI1 bus, enable this option. + 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 5629e2973..91d77c77c 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -44,6 +44,7 @@ #include "cache_utils.h" #include "esp_flash.h" #include "esp_attr.h" +#include "esp_timer.h" esp_rom_spiflash_result_t IRAM_ATTR spi_flash_write_encrypted_chip(size_t dest_addr, const void *src, size_t size); @@ -238,7 +239,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); @@ -250,6 +257,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 ae89f98d59c3391cf68cf4678e6e161fbac28d30 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 | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/components/spi_flash/esp_flash_api.c b/components/spi_flash/esp_flash_api.c index a5c04a47b..3dd70b4bf 100644 --- a/components/spi_flash/esp_flash_api.c +++ b/components/spi_flash/esp_flash_api.c @@ -23,6 +23,8 @@ #include "sdkconfig.h" #include "esp_heap_caps.h" #include "esp_flash_internal.h" +#include +#include "esp_timer.h" static const char TAG[] = "spi_flash"; @@ -337,8 +339,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 +365,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 0f6fe0c8e9a81ba4f0de47e4a199e8bf18b719ee 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 8cbd1e6fc..98b55c554 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 \ @@ -32,6 +33,7 @@ INCLUDE_DIRS := \ soc/include \ soc/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 6c5dc266e..8807a39bd 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 \ @@ -25,6 +27,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 304f67e42a4b251a7dc79f4179d4dba670c07e99 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 c9dd305a1..678585248 100644 --- a/components/spi_flash/Kconfig +++ b/components/spi_flash/Kconfig @@ -100,6 +100,14 @@ menu "SPI Flash driver" this option, and the lock will be bypassed on SPI1 bus. Otherwise if extra devices are needed to attach to SPI1 bus, enable this option. + 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 91d77c77c..81fa35fce 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -247,11 +247,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 bc50bd2806d4485d7d4917fbc0b6892a81dbe9b8 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 3dd70b4bf..5bcdc20b0 100644 --- a/components/spi_flash/esp_flash_api.c +++ b/components/spi_flash/esp_flash_api.c @@ -351,13 +351,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;