Merge branch 'bugfix/erase_with_vtaskdelay_v4.1' into 'release/v4.1'

spi_flash: Add vTaskDelay while a long erasing (v4.1)

See merge request espressif/esp-idf!8598
This commit is contained in:
Michael (XIAO Xufeng) 2020-05-18 11:01:50 +08:00
commit e9d4659175
7 changed files with 109 additions and 4 deletions

View File

@ -84,6 +84,36 @@ menu "SPI Flash driver"
The implementation of SPI flash has been greatly changed in IDF v4.0. The implementation of SPI flash has been greatly changed in IDF v4.0.
Enable this option to use the legacy implementation. 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
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" menu "Auto-detect flash chips"
config SPI_FLASH_SUPPORT_ISSI_CHIP config SPI_FLASH_SUPPORT_ISSI_CHIP

View File

@ -23,6 +23,9 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
#include "esp_flash_internal.h" #include "esp_flash_internal.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include "esp_timer.h"
static const char TAG[] = "spi_flash"; static const char TAG[] = "spi_flash";
@ -337,20 +340,27 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui
err = spiflash_end(chip, err); 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) { 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); err = spiflash_start(chip);
if (err != ESP_OK) { if (err != ESP_OK) {
return err; return err;
} }
#ifndef CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE
// If possible erase an entire multi-sector block // If possible erase an entire multi-sector block
if (block_erase_size > 0 && len >= block_erase_size && (start % block_erase_size) == 0) { if (block_erase_size > 0 && len >= block_erase_size && (start % block_erase_size) == 0) {
err = chip->chip_drv->erase_block(chip, start); err = chip->chip_drv->erase_block(chip, start);
start += block_erase_size; start += block_erase_size;
len -= block_erase_size; len -= block_erase_size;
} } else
else { #endif
{
// Otherwise erase individual sector only // Otherwise erase individual sector only
err = chip->chip_drv->erase_sector(chip, start); err = chip->chip_drv->erase_sector(chip, start);
start += sector_size; start += sector_size;
@ -358,6 +368,14 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui
} }
err = spiflash_end(chip, err); 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; return err;
} }

View File

@ -42,6 +42,7 @@
#include "cache_utils.h" #include "cache_utils.h"
#include "esp_flash.h" #include "esp_flash.h"
#include "esp_attr.h" #include "esp_attr.h"
#include "esp_timer.h"
/* bytes erased by SPIEraseBlock() ROM function */ /* bytes erased by SPIEraseBlock() ROM function */
@ -235,18 +236,34 @@ esp_err_t IRAM_ATTR spi_flash_erase_range(size_t start_addr, size_t size)
esp_rom_spiflash_result_t rc; esp_rom_spiflash_result_t rc;
rc = spi_flash_unlock(); rc = spi_flash_unlock();
if (rc == ESP_ROM_SPIFLASH_RESULT_OK) { 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; ) { 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(); spi_flash_guard_start();
#ifndef CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE
if (sector % sectors_per_block == 0 && end - sector >= sectors_per_block) { if (sector % sectors_per_block == 0 && end - sector >= sectors_per_block) {
rc = esp_rom_spiflash_erase_block(sector / sectors_per_block); rc = esp_rom_spiflash_erase_block(sector / sectors_per_block);
sector += sectors_per_block; sector += sectors_per_block;
COUNTER_ADD_BYTES(erase, sectors_per_block * SPI_FLASH_SEC_SIZE); COUNTER_ADD_BYTES(erase, sectors_per_block * SPI_FLASH_SEC_SIZE);
} else { } else
#endif
{
rc = esp_rom_spiflash_erase_sector(sector); rc = esp_rom_spiflash_erase_sector(sector);
++sector; ++sector;
COUNTER_ADD_BYTES(erase, SPI_FLASH_SEC_SIZE); COUNTER_ADD_BYTES(erase, SPI_FLASH_SEC_SIZE);
} }
spi_flash_guard_end(); 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); COUNTER_STOP(erase);

View File

@ -17,6 +17,7 @@ INCLUDE_DIRS := \
app_update/include \ app_update/include \
driver/include \ driver/include \
esp32/include \ esp32/include \
esp_timer/include \
freertos/include \ freertos/include \
log/include \ log/include \
newlib/include \ newlib/include \
@ -31,6 +32,7 @@ INCLUDE_DIRS := \
soc/esp32/include \ soc/esp32/include \
soc/include \ soc/include \
esp32/include \ esp32/include \
esp_timer/include \
bootloader_support/include \ bootloader_support/include \
app_update/include \ app_update/include \
spi_flash/include \ spi_flash/include \

View File

@ -4,6 +4,7 @@ SOURCE_FILES := \
newlib/lock.c \ newlib/lock.c \
esp32/crc.cpp \ esp32/crc.cpp \
esp32/esp_random.c \ esp32/esp_random.c \
esp_timer/src/esp_timer.c \
bootloader_support/src/bootloader_common.c bootloader_support/src/bootloader_common.c
INCLUDE_DIRS := \ INCLUDE_DIRS := \
@ -12,6 +13,7 @@ INCLUDE_DIRS := \
app_update/include \ app_update/include \
driver/include \ driver/include \
esp32/include \ esp32/include \
esp_timer/include \
freertos/include \ freertos/include \
log/include \ log/include \
newlib/include \ newlib/include \
@ -24,6 +26,7 @@ INCLUDE_DIRS := \
xtensa/include \ xtensa/include \
xtensa/esp32/include \ xtensa/esp32/include \
esp32/include \ esp32/include \
esp_timer/include \
bootloader_support/include \ bootloader_support/include \
app_update/include \ app_update/include \
spi_flash/include \ spi_flash/include \

View File

@ -0,0 +1,15 @@
#pragma once
#include <stdint.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
int64_t esp_timer_get_time(void);
#ifdef __cplusplus
}
#endif

View File

@ -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;
}