spi_flash: Making flash works more stable when brownout detected

This commit is contained in:
Zhao Ke Ke
2026-03-19 11:47:13 +08:00
parent 792fb3846a
commit 3641c8d194
21 changed files with 302 additions and 27 deletions
+1 -1
View File
@@ -24,7 +24,7 @@ else()
list(APPEND srcs
"src/idf/bootloader_sha.c"
"src/idf/secure_boot_signatures.c")
set(include_dirs "include")
set(include_dirs "include" "include_bootloader")
set(priv_include_dirs "include_bootloader")
set(requires soc) #unfortunately the header directly uses SOC registers
set(priv_requires spi_flash mbedtls efuse)
@@ -119,6 +119,13 @@ esp_err_t bootloader_flash_erase_sector(size_t sector);
*/
esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size);
/**
* @brief Reset the flash chip (66H + 99H).
*
* @return ESP_OK if success, otherwise ESP_FAIL.
*/
esp_err_t bootloader_flash_reset_chip(void);
/* Cache MMU block size */
#define MMU_BLOCK_SIZE 0x00010000
@@ -58,6 +58,16 @@ uint32_t bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_n
*/
esp_err_t bootloader_flash_xmc_startup(void);
/**
* @brief Execute a flash command (for use in brownout reset flow).
* @param command Command byte
* @param mosi_data MOSI data
* @param mosi_len MOSI length in bits
* @param miso_len MISO length in bits
* @return MISO data read
*/
uint32_t bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len);
#ifdef __cplusplus
}
#endif
@@ -18,6 +18,8 @@
#include <esp_spi_flash.h> /* including in bootloader for error values */
#include <esp_flash_encrypt.h>
#include "flash_qio_mode.h"
#include "esp_attr.h"
#include "soc/spi_struct.h"
#ifndef BOOTLOADER_BUILD
/* Normal app version maps to esp_spi_flash.h operations...
@@ -292,3 +294,27 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
return spi_to_esp_err(rc);
}
#endif
/* ESP32-only: brownout flash reset (66H+99H) - built for both app and bootloader */
static inline void bootloader_mspi_reset(void)
{
SPI1.slave.sync_reset = 0;
SPI0.slave.sync_reset = 0;
SPI1.slave.sync_reset = 1;
SPI0.slave.sync_reset = 1;
SPI1.slave.sync_reset = 0;
SPI0.slave.sync_reset = 0;
}
esp_err_t IRAM_ATTR bootloader_flash_reset_chip(void)
{
bootloader_mspi_reset();
/* Send extra command so host is idle before reset command */
bootloader_execute_flash_command(0x05, 0, 0, 0);
if (SPI1.ext2.st != 0) {
return ESP_FAIL;
}
bootloader_execute_flash_command(0x66, 0, 0, 0);
bootloader_execute_flash_command(0x99, 0, 0, 0);
return ESP_OK;
}
@@ -345,6 +345,11 @@ static uint32_t IRAM_ATTR execute_flash_command(uint8_t command, uint32_t mosi_d
dummy_len, mosi_len, mosi_data, miso_len);
}
uint32_t IRAM_ATTR bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len)
{
return execute_flash_command(command, mosi_data, mosi_len, miso_len);
}
// cmd(0x5A) + 24bit address + 8 cycles dummy
uint32_t IRAM_ATTR bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num)
{
+15 -1
View File
@@ -22,6 +22,8 @@
extern "C" {
#endif
#define RTC_INTR_FLAG_IRAM (BIT(0)) /*< Some rtc interrupts can be called with cache disabled */
/**
* @brief Register a handler for specific RTC_CNTL interrupts
*
@@ -33,13 +35,15 @@ extern "C" {
* @param handler_arg argument to be passed to the handler
* @param rtc_intr_mask combination of RTC_CNTL_*_INT_ENA bits indicating the
* sources to call the handler for
* @param flags An ORred mask of the RTC_INTR_FLAG_* defines. Pass 0 for default.
* RTC_INTR_FLAG_IRAM: interrupt can be triggered with cache disabled.
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM not enough memory to allocate handler structure
* - other errors returned by esp_intr_alloc
*/
esp_err_t rtc_isr_register(intr_handler_t handler, void* handler_arg,
uint32_t rtc_intr_mask);
uint32_t rtc_intr_mask, uint32_t flags);
/**
* @brief Deregister the handler previously registered using rtc_isr_register
* @param handler handler function to call (as passed to rtc_isr_register)
@@ -51,6 +55,16 @@ esp_err_t rtc_isr_register(intr_handler_t handler, void* handler_arg,
*/
esp_err_t rtc_isr_deregister(intr_handler_t handler, void* handler_arg);
/**
* @brief Disable the RTC interrupt that is allowed to be executed when cache is disabled.
*/
void rtc_isr_noniram_disable(uint32_t cpu);
/**
* @brief Enable the RTC interrupt that is allowed to be executed when cache is disabled.
*/
void rtc_isr_noniram_enable(uint32_t cpu);
#ifdef __cplusplus
}
#endif
+55 -7
View File
@@ -30,9 +30,11 @@
#include "freertos/semphr.h"
#include "freertos/timers.h"
#include "esp_intr_alloc.h"
#include "esp_heap_caps.h"
#include "sys/lock.h"
#include "driver/rtc_cntl.h"
#include "driver/gpio.h"
#include "esp_attr.h"
#include "adc1_i2s_private.h"
#ifndef NDEBUG
@@ -41,6 +43,11 @@
#endif
#include "sys/queue.h"
#define NOT_REGISTERED (-1)
static void s_rtc_isr_noniram_hook(uint32_t rtc_intr_mask);
static void s_rtc_isr_noniram_hook_relieve(uint32_t rtc_intr_mask);
#define ADC_FSM_RSTB_WAIT_DEFAULT (8)
#define ADC_FSM_START_WAIT_DEFAULT (5)
@@ -440,7 +447,7 @@ inline static touch_pad_t touch_pad_num_wrap(touch_pad_t touch_num)
esp_err_t touch_pad_isr_register(intr_handler_t fn, void* arg)
{
RTC_MODULE_CHECK(fn, "Touch_Pad ISR null", ESP_ERR_INVALID_ARG);
return rtc_isr_register(fn, arg, RTC_CNTL_TOUCH_INT_ST_M);
return rtc_isr_register(fn, arg, RTC_CNTL_TOUCH_INT_ST_M, 0);
}
esp_err_t touch_pad_isr_deregister(intr_handler_t fn, void *arg)
@@ -1949,15 +1956,20 @@ typedef struct rtc_isr_handler_ {
uint32_t mask;
intr_handler_t handler;
void* handler_arg;
uint32_t flags;
SLIST_ENTRY(rtc_isr_handler_) next;
} rtc_isr_handler_t;
static SLIST_HEAD(rtc_isr_handler_list_, rtc_isr_handler_) s_rtc_isr_handler_list =
static DRAM_ATTR uint32_t rtc_intr_cache;
static DRAM_ATTR uint32_t rtc_intr_enabled;
static DRAM_ATTR int rtc_isr_cpu = NOT_REGISTERED;
static DRAM_ATTR SLIST_HEAD(rtc_isr_handler_list_, rtc_isr_handler_) s_rtc_isr_handler_list =
SLIST_HEAD_INITIALIZER(s_rtc_isr_handler_list);
portMUX_TYPE s_rtc_isr_handler_list_lock = portMUX_INITIALIZER_UNLOCKED;
static DRAM_ATTR portMUX_TYPE s_rtc_isr_handler_list_lock = portMUX_INITIALIZER_UNLOCKED;
static intr_handle_t s_rtc_isr_handle;
static void rtc_isr(void* arg)
IRAM_ATTR static void rtc_isr(void* arg)
{
uint32_t status = REG_READ(RTC_CNTL_INT_ST_REG);
rtc_isr_handler_t* it;
@@ -1983,10 +1995,11 @@ static esp_err_t rtc_isr_ensure_installed()
REG_WRITE(RTC_CNTL_INT_ENA_REG, 0);
REG_WRITE(RTC_CNTL_INT_CLR_REG, UINT32_MAX);
err = esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, 0, &rtc_isr, NULL, &s_rtc_isr_handle);
err = esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, ESP_INTR_FLAG_IRAM, &rtc_isr, NULL, &s_rtc_isr_handle);
if (err != ESP_OK) {
goto out;
}
rtc_isr_cpu = esp_intr_get_cpu(s_rtc_isr_handle);
out:
portEXIT_CRITICAL(&s_rtc_isr_handler_list_lock);
@@ -1994,21 +2007,27 @@ out:
}
esp_err_t rtc_isr_register(intr_handler_t handler, void* handler_arg, uint32_t rtc_intr_mask)
esp_err_t rtc_isr_register(intr_handler_t handler, void* handler_arg, uint32_t rtc_intr_mask, uint32_t flags)
{
esp_err_t err = rtc_isr_ensure_installed();
if (err != ESP_OK) {
return err;
}
rtc_isr_handler_t* item = malloc(sizeof(*item));
rtc_isr_handler_t* item = heap_caps_malloc(sizeof(*item), MALLOC_CAP_INTERNAL);
if (item == NULL) {
return ESP_ERR_NO_MEM;
}
item->handler = handler;
item->handler_arg = handler_arg;
item->mask = rtc_intr_mask;
item->flags = flags;
portENTER_CRITICAL(&s_rtc_isr_handler_list_lock);
if (flags & RTC_INTR_FLAG_IRAM) {
s_rtc_isr_noniram_hook(rtc_intr_mask);
} else {
s_rtc_isr_noniram_hook_relieve(rtc_intr_mask);
}
SLIST_INSERT_HEAD(&s_rtc_isr_handler_list, item, next);
portEXIT_CRITICAL(&s_rtc_isr_handler_list_lock);
return ESP_OK;
@@ -2028,6 +2047,9 @@ esp_err_t rtc_isr_deregister(intr_handler_t handler, void* handler_arg)
SLIST_REMOVE_AFTER(prev, next);
}
found = true;
if (it->flags & RTC_INTR_FLAG_IRAM) {
s_rtc_isr_noniram_hook_relieve(it->mask);
}
free(it);
break;
}
@@ -2036,3 +2058,29 @@ esp_err_t rtc_isr_deregister(intr_handler_t handler, void* handler_arg)
portEXIT_CRITICAL(&s_rtc_isr_handler_list_lock);
return found ? ESP_OK : ESP_ERR_INVALID_STATE;
}
static void s_rtc_isr_noniram_hook(uint32_t rtc_intr_mask)
{
rtc_intr_cache |= rtc_intr_mask;
}
static void s_rtc_isr_noniram_hook_relieve(uint32_t rtc_intr_mask)
{
rtc_intr_cache &= ~rtc_intr_mask;
}
IRAM_ATTR void rtc_isr_noniram_disable(uint32_t cpu)
{
if (rtc_isr_cpu == cpu) {
rtc_intr_enabled |= RTCCNTL.int_ena.val;
RTCCNTL.int_ena.val &= rtc_intr_cache;
}
}
IRAM_ATTR void rtc_isr_noniram_enable(uint32_t cpu)
{
if (rtc_isr_cpu == cpu) {
RTCCNTL.int_ena.val = rtc_intr_enabled;
rtc_intr_enabled = 0;
}
}
+7
View File
@@ -14,6 +14,8 @@ menu "ESP32-specific"
config ESP32_REV_MIN_0
bool "Rev 0"
# Brownout on Rev 0 is bugged, must use interrupt
select ESP_SYSTEM_BROWNOUT_INTR
config ESP32_REV_MIN_1
bool "Rev 1"
config ESP32_REV_MIN_2
@@ -586,6 +588,11 @@ menu "ESP32-specific"
default 6 if ESP32_BROWNOUT_DET_LVL_SEL_6
default 7 if ESP32_BROWNOUT_DET_LVL_SEL_7
config ESP_SYSTEM_BROWNOUT_INTR
bool
default n
help
Brownout restart via interrupt (for ESP32 Rev0 or XMC flash brownout reset).
#Reduce PHY TX power when brownout reset
config ESP32_REDUCE_PHY_TX_POWER
+41 -17
View File
@@ -20,43 +20,67 @@
#include "soc/soc.h"
#include "soc/cpu.h"
#include "soc/rtc_periph.h"
#include "soc/rtc_cntl_reg.h"
#include "esp32/rom/ets_sys.h"
#include "esp_private/system_internal.h"
#include "driver/rtc_cntl.h"
#include "freertos/FreeRTOS.h"
#include "esp_attr.h"
#if CONFIG_ESP_SYSTEM_BROWNOUT_INTR
#include "esp_intr_alloc.h"
#include "bootloader_flash.h"
#include "esp_private/spi_flash_os.h"
#endif
#ifdef CONFIG_ESP32_BROWNOUT_DET_LVL
#define BROWNOUT_DET_LVL CONFIG_ESP32_BROWNOUT_DET_LVL
#else
#define BROWNOUT_DET_LVL 0
#endif //CONFIG_ESP32_BROWNOUT_DET_LVL
#endif
static void rtc_brownout_isr_handler()
IRAM_ATTR static void rtc_brownout_isr_handler(void *arg)
{
/* Normally RTC ISR clears the interrupt flag after the application-supplied
* handler returns. Since restart is called here, the flag needs to be
* cleared manually.
*/
REG_WRITE(RTC_CNTL_INT_CLR_REG, RTC_CNTL_BROWN_OUT_INT_CLR);
/* Stall the other CPU to make sure the code running there doesn't use UART
* at the same time as the following ets_printf.
*/
esp_cpu_stall(!xPortGetCoreID());
esp_reset_reason_set_hint(ESP_RST_BROWNOUT);
ets_printf("\r\nBrownout detector was triggered\r\n\r\n");
#if CONFIG_SPI_FLASH_BROWNOUT_RESET
if (spi_flash_brownout_need_reset()) {
if (spi_flash_brownout_check_erase()) {
bootloader_flash_reset_chip();
}
}
#endif
ets_printf(DRAM_STR("\r\nBrownout detector was triggered\r\n\r\n"));
esp_restart_noos();
}
void esp_brownout_init()
void esp_brownout_init(void)
{
#if CONFIG_ESP_SYSTEM_BROWNOUT_INTR
REG_WRITE(RTC_CNTL_BROWN_OUT_REG,
RTC_CNTL_BROWN_OUT_ENA /* Enable BOD */
| RTC_CNTL_BROWN_OUT_PD_RF_ENA /* Automatically power down RF */
/* Reset timeout must be set to >1 even if BOR feature is not used */
RTC_CNTL_BROWN_OUT_ENA
| RTC_CNTL_BROWN_OUT_CLOSE_FLASH_ENA_M
| RTC_CNTL_BROWN_OUT_PD_RF_ENA_M
| (2 << RTC_CNTL_BROWN_OUT_RST_WAIT_S)
| (BROWNOUT_DET_LVL << RTC_CNTL_DBROWN_OUT_THRES_S));
ESP_ERROR_CHECK( rtc_isr_register(rtc_brownout_isr_handler, NULL, RTC_CNTL_BROWN_OUT_INT_ENA_M) );
REG_WRITE(RTC_CNTL_INT_CLR_REG, RTC_CNTL_BROWN_OUT_INT_CLR);
#else
REG_WRITE(RTC_CNTL_BROWN_OUT_REG,
RTC_CNTL_BROWN_OUT_ENA
| RTC_CNTL_BROWN_OUT_RST_ENA
| RTC_CNTL_BROWN_OUT_PD_RF_ENA_M
| (2 << RTC_CNTL_BROWN_OUT_RST_WAIT_S)
| (BROWNOUT_DET_LVL << RTC_CNTL_DBROWN_OUT_THRES_S));
#endif
ESP_ERROR_CHECK(rtc_isr_register(rtc_brownout_isr_handler, NULL, RTC_CNTL_BROWN_OUT_INT_ENA_M, RTC_INTR_FLAG_IRAM));
REG_SET_BIT(RTC_CNTL_INT_ENA_REG, RTC_CNTL_BROWN_OUT_INT_ENA_M);
}
void esp_brownout_disable(void)
{
REG_CLR_BIT(RTC_CNTL_INT_ENA_REG, RTC_CNTL_BROWN_OUT_INT_ENA_M);
rtc_isr_deregister(rtc_brownout_isr_handler, NULL);
REG_WRITE(RTC_CNTL_BROWN_OUT_REG, 0);
}
+3
View File
@@ -4,6 +4,9 @@
COMPONENT_SRCDIRS := .
# Access bootloader_support private headers (bootloader_flash.h) used by brownout.c
COMPONENT_PRIV_INCLUDEDIRS += ../bootloader_support/include_bootloader
ifdef CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
# This linker script must come before esp32.project.ld
LINKER_SCRIPTS += esp32.extram.bss.ld
+4
View File
@@ -62,6 +62,7 @@
#include "esp_app_trace.h"
#include "esp_private/dbg_stubs.h"
#include "esp_flash_encrypt.h"
#include "esp_private/spi_flash_os.h"
#include "esp32/spiram.h"
#include "esp_clk_internal.h"
#include "esp_timer.h"
@@ -431,6 +432,9 @@ void start_cpu0_default(void)
esp_flash_app_init();
esp_err_t flash_ret = esp_flash_init_default_chip();
assert(flash_ret == ESP_OK);
#if CONFIG_SPI_FLASH_BROWNOUT_RESET
spi_flash_needs_reset_check();
#endif
#ifdef CONFIG_PM_ENABLE
esp_pm_impl_init();
+3
View File
@@ -28,6 +28,7 @@
#include "esp_log.h"
#include "esp_intr_alloc.h"
#include "esp_attr.h"
#include "driver/rtc_cntl.h"
#include <limits.h>
#include <assert.h>
#if !CONFIG_FREERTOS_UNICORE
@@ -866,6 +867,7 @@ void IRAM_ATTR esp_intr_noniram_disable()
{
int oldint;
int cpu=xPortGetCoreID();
rtc_isr_noniram_disable(cpu);
int intmask=~non_iram_int_mask[cpu];
if (non_iram_int_disabled_flag[cpu]) abort();
non_iram_int_disabled_flag[cpu]=true;
@@ -884,6 +886,7 @@ void IRAM_ATTR esp_intr_noniram_disable()
void IRAM_ATTR esp_intr_noniram_enable()
{
int cpu=xPortGetCoreID();
rtc_isr_noniram_enable(cpu);
int intmask=non_iram_int_disabled[cpu];
if (!non_iram_int_disabled_flag[cpu]) abort();
non_iram_int_disabled_flag[cpu]=false;
+1
View File
@@ -13,6 +13,7 @@ else()
set(srcs
"partition.c"
"spi_flash_rom_patch.c"
"flash_brownout_hook.c"
)
# New implementation after IDF v4.0
list(APPEND cache_srcs
+20
View File
@@ -122,6 +122,26 @@ menu "SPI Flash driver"
Enable this option to override flash size with latest ESPTOOLPY_FLASHSIZE value from
the app header if the size in the bootloader header is incorrect.
menu "SPI Flash behavior when brownout"
config SPI_FLASH_BROWNOUT_RESET_XMC
bool "Enable sending reset when brownout for XMC flash chips"
default y
select SPI_FLASH_BROWNOUT_RESET
help
When this option is selected, the patch will be enabled for XMC.
Follow the recommended flow by XMC for better stability.
config SPI_FLASH_BROWNOUT_RESET
bool
default n
select ESP_SYSTEM_BROWNOUT_INTR
help
When brownout happens during flash erase/write operations,
send reset command to stop the flash operations to improve stability.
endmenu
menu "Auto-detect flash chips"
config SPI_FLASH_SUPPORT_ISSI_CHIP
@@ -0,0 +1,41 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include "esp_attr.h"
#include "sdkconfig.h"
#include "esp32/rom/spi_flash.h"
#if CONFIG_SPI_FLASH_BROWNOUT_RESET
static bool flash_brownout_needs_reset = false;
static bool flash_erasing = false;
void spi_flash_needs_reset_check(void)
{
#if CONFIG_SPI_FLASH_BROWNOUT_RESET_XMC
if ((g_rom_flashchip.device_id >> 16) == 0x20) {
flash_brownout_needs_reset = true;
}
#endif
}
void IRAM_ATTR spi_flash_set_erasing_flag(bool status)
{
flash_erasing = status;
}
bool spi_flash_brownout_need_reset(void)
{
return flash_brownout_needs_reset;
}
bool spi_flash_brownout_check_erase(void)
{
return flash_erasing;
}
#endif /* CONFIG_SPI_FLASH_BROWNOUT_RESET */
+9
View File
@@ -36,6 +36,9 @@
#include "cache_utils.h"
#include "esp_flash.h"
#include "esp_timer.h"
#if CONFIG_SPI_FLASH_BROWNOUT_RESET
#include "esp_private/spi_flash_os.h"
#endif
/* bytes erased by SPIEraseBlock() ROM function */
#define BLOCK_ERASE_SIZE 65536
@@ -246,6 +249,9 @@ 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();
#if CONFIG_SPI_FLASH_BROWNOUT_RESET
spi_flash_set_erasing_flag(true);
#endif
#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);
@@ -258,6 +264,9 @@ esp_err_t IRAM_ATTR spi_flash_erase_range(size_t start_addr, size_t size)
++sector;
COUNTER_ADD_BYTES(erase, SPI_FLASH_SEC_SIZE);
}
#if CONFIG_SPI_FLASH_BROWNOUT_RESET
spi_flash_set_erasing_flag(false);
#endif
spi_flash_guard_end();
#ifdef CONFIG_SPI_FLASH_YIELD_DURING_ERASE
no_yield_time_us += (esp_timer_get_time() - start_time_us);
+4
View File
@@ -53,6 +53,10 @@ typedef struct {
/** Yield to other tasks. Called during erase operations. */
esp_err_t (*yield)(void *arg);
#define SPI_FLASH_OS_IS_ERASING_STATUS_FLAG (1u << 0)
/** Call to set flash operation status (e.g. erasing). */
void (*set_flash_op_status)(uint32_t op_status);
} esp_flash_os_functions_t;
/** @brief Structure to describe a SPI flash chip connected to the system.
@@ -0,0 +1,17 @@
// Copyright 2015-2022 Espressif Systems (Shanghai) CO LTD
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void spi_flash_needs_reset_check(void);
void spi_flash_set_erasing_flag(bool status);
bool spi_flash_brownout_need_reset(void);
bool spi_flash_brownout_check_erase(void);
#ifdef __cplusplus
}
#endif
+1
View File
@@ -2,6 +2,7 @@
archive: libspi_flash.a
entries:
spi_flash_rom_patch (noflash_text)
flash_brownout_hook (noflash)
spi_flash_chip_generic (noflash)
spi_flash_chip_issi (noflash)
spi_flash_chip_gd(noflash)
@@ -17,6 +17,13 @@
#include "spi_flash_chip_generic.h"
#include "spi_flash_defs.h"
#include "esp_log.h"
#include "esp_private/spi_flash_os.h"
#define SET_FLASH_ERASE_STATUS(chip, status) do { \
if ((chip)->os_func->set_flash_op_status) { \
(chip)->os_func->set_flash_op_status(status); \
} \
} while (0)
static const char TAG[] = "chip_generic";
@@ -86,15 +93,18 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip)
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_DEFAULT_IDLE_TIMEOUT_MS * 1000);
}
if (err == ESP_OK) {
SET_FLASH_ERASE_STATUS(chip, SPI_FLASH_OS_IS_ERASING_STATUS_FLAG);
chip->host->erase_chip(chip->host);
//to save time, flush cache here
if (chip->host->flush_cache) {
err = chip->host->flush_cache(chip->host, 0, chip->size);
if (err != ESP_OK) {
SET_FLASH_ERASE_STATUS(chip, 0);
return err;
}
}
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_GENERIC_CHIP_ERASE_TIMEOUT_MS * 1000);
SET_FLASH_ERASE_STATUS(chip, 0);
}
return err;
}
@@ -106,15 +116,18 @@ esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_DEFAULT_IDLE_TIMEOUT_MS * 1000);
}
if (err == ESP_OK) {
SET_FLASH_ERASE_STATUS(chip, SPI_FLASH_OS_IS_ERASING_STATUS_FLAG);
chip->host->erase_sector(chip->host, start_address);
//to save time, flush cache here
if (chip->host->flush_cache) {
err = chip->host->flush_cache(chip->host, start_address, chip->chip_drv->sector_size);
if (err != ESP_OK) {
SET_FLASH_ERASE_STATUS(chip, 0);
return err;
}
}
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_GENERIC_SECTOR_ERASE_TIMEOUT_MS * 1000);
SET_FLASH_ERASE_STATUS(chip, 0);
}
return err;
}
@@ -126,15 +139,18 @@ esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_a
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_DEFAULT_IDLE_TIMEOUT_MS * 1000);
}
if (err == ESP_OK) {
SET_FLASH_ERASE_STATUS(chip, SPI_FLASH_OS_IS_ERASING_STATUS_FLAG);
chip->host->erase_block(chip->host, start_address);
//to save time, flush cache here
if (chip->host->flush_cache) {
err = chip->host->flush_cache(chip->host, start_address, chip->chip_drv->block_erase_size);
if (err != ESP_OK) {
SET_FLASH_ERASE_STATUS(chip, 0);
return err;
}
}
err = chip->chip_drv->wait_idle(chip, SPI_FLASH_GENERIC_BLOCK_ERASE_TIMEOUT_MS * 1000);
SET_FLASH_ERASE_STATUS(chip, 0);
}
return err;
}
+16 -1
View File
@@ -18,6 +18,7 @@
#include "esp_spi_flash.h" //for ``g_flash_guard_default_ops``
#include "esp_flash.h"
#include "esp_flash_partitions.h"
#include "esp_private/spi_flash_os.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
@@ -103,6 +104,14 @@ static IRAM_ATTR esp_err_t main_flash_region_protected(void* arg, size_t start_a
}
}
#if CONFIG_SPI_FLASH_BROWNOUT_RESET
static IRAM_ATTR void main_flash_op_status(uint32_t op_status)
{
bool is_erasing = (op_status & SPI_FLASH_OS_IS_ERASING_STATUS_FLAG) != 0;
spi_flash_set_erasing_flag(is_erasing);
}
#endif
static DRAM_ATTR spi1_app_func_arg_t spi1_arg = {
.host_id = 0, //for SPI1,
.no_protect = true,
@@ -128,13 +137,19 @@ const DRAM_ATTR esp_flash_os_functions_t esp_flash_spi1_default_os_functions = {
.region_protected = main_flash_region_protected,
.delay_us = delay_us,
.yield = spi_flash_os_yield,
#if CONFIG_SPI_FLASH_BROWNOUT_RESET
.set_flash_op_status = main_flash_op_status,
#else
.set_flash_op_status = NULL,
#endif
};
const esp_flash_os_functions_t esp_flash_spi23_default_os_functions = {
.start = spi23_start,
.end = spi23_end,
.delay_us = delay_us,
.yield = spi_flash_os_yield
.yield = spi_flash_os_yield,
.set_flash_op_status = NULL,
};
esp_err_t esp_flash_init_os_functions(esp_flash_t *chip, int host_id)