feat(spi_flash): Support configurable tSUS in flash suspend

This commit is contained in:
Cao Sen Miao
2023-10-19 11:37:20 +08:00
parent 8768c9231c
commit dcff5220a7
10 changed files with 93 additions and 17 deletions

View File

@@ -108,6 +108,14 @@ menu "Main Flash configuration"
Also refer to `Concurrency Constraints for Flash on SPI1` > `Flash Auto Suspend Feature`
before enabling this option.
config SPI_FLASH_SUSPEND_TSUS_VAL_US
int "SPI flash tSUS value (refer to chapter AC CHARACTERISTICS)"
default 50
range 20 100
help
This config is used for setting Tsus parameter. Tsus means CS# high to next command after
suspend. You can refer to the chapter of AC CHARACTERISTICS of flash datasheet.
endmenu
endmenu

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -117,6 +117,7 @@ esp_flash_t *esp_flash_default_chip = NULL;
.auto_sus_en = true,\
.cs_setup = 1,\
}
#define TSUS_VAL_SUSPEND CONFIG_SPI_FLASH_SUSPEND_TSUS_VAL_US
#endif //!CONFIG_SPI_FLASH_AUTO_SUSPEND
#endif // Other target
@@ -356,6 +357,15 @@ esp_err_t esp_flash_init_default_chip(void)
cfg.clock_src_freq = spi_flash_ll_get_source_clock_freq_mhz(cfg.host_id);
#if CONFIG_SPI_FLASH_AUTO_SUSPEND
if (TSUS_VAL_SUSPEND > 400 || TSUS_VAL_SUSPEND < 20) {
// Assume that the tsus value cannot larger than 400 (because the performance might be really bad)
// And value cannot smaller than 20 (never see that small tsus value, might be wrong)
return ESP_ERR_INVALID_ARG;
}
cfg.tsus_val = TSUS_VAL_SUSPEND;
#endif // CONFIG_SPI_FLASH_AUTO_SUSPEND
//the host is already initialized, only do init for the data and load it to the host
esp_err_t err = memspi_host_init_pointers(&esp_flash_default_host, &cfg);
if (err != ESP_OK) {

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -596,10 +596,15 @@ spi_flash_caps_t spi_flash_chip_generic_get_caps(esp_flash_t *chip)
// 32M-bits address support
// flash suspend support
// Only `XMC` support suspend for now.
// XMC support suspend
if (chip->chip_id >> 16 == 0x20) {
caps_flags |= SPI_FLASH_CHIP_CAP_SUSPEND;
}
// FM support suspend
if (chip->chip_id >> 16 == 0xa1) {
caps_flags |= SPI_FLASH_CHIP_CAP_SUSPEND;
}
// flash read unique id.
caps_flags |= SPI_FLASH_CHIP_CAP_UNIQUE_ID;
return caps_flags;
@@ -790,8 +795,8 @@ esp_err_t spi_flash_common_set_io_mode(esp_flash_t *chip, esp_flash_wrsr_func_t
esp_err_t spi_flash_chip_generic_suspend_cmd_conf(esp_flash_t *chip)
{
// Only XMC support auto-suspend
if (chip->chip_id >> 16 != 0x20) {
// chips which support auto-suspend
if (chip->chip_id >> 16 != 0x20 && chip->chip_id >> 16 != 0xa1) {
ESP_EARLY_LOGE(TAG, "The flash you use doesn't support auto suspend, only \'XMC\' is supported");
return ESP_ERR_NOT_SUPPORTED;
}

View File

@@ -121,14 +121,10 @@ TEST_CASE("flash suspend test", "[spi_flash][suspend]")
};
TEST_ESP_OK(gptimer_new_timer(&timer_config, &gptimer));
/**
set alarm_count is 2500.
So, in this case, ISR duration time is around 2240 and ISR interval time is around 2470
so ISR_interval - ISR_duration is around 230us. Just a little bit larger than `tsus` value.
*/
// For pre-test, set alarm_count as a larger value.
gptimer_alarm_config_t alarm_config = {
.reload_count = 0,
.alarm_count = 2500,
.alarm_count = 10000,
.flags.auto_reload_on_alarm = true,
};
TEST_ESP_OK(gptimer_set_alarm_action(gptimer, &alarm_config));
@@ -151,11 +147,61 @@ TEST_CASE("flash suspend test", "[spi_flash][suspend]")
RECORD_TIME_END(erase_time);
TEST_ESP_OK(gptimer_stop(gptimer));
TEST_ESP_OK(gptimer_disable(gptimer));
uint32_t isr_duration_time = s_isr_time / times;
ESP_LOGI(TAG, "--------------------Pre Test...--------------------");
ESP_LOGI(TAG, "Flash Driver Erase Operation finishes, duration:\n\t\t%0.2f us", GET_US_BY_CCOUNT(erase_time));
ESP_LOGI(TAG, "During Erase, ISR callback function(in flash) response time:\n\t\t%0.2f us", GET_US_BY_CCOUNT(s_flash_func_time / times));
ESP_LOGI(TAG, "During Erase, ISR duration time:\n\t\t%0.2f us", GET_US_BY_CCOUNT(isr_duration_time));
ESP_LOGI(TAG, "During Erase, ISR interval time:\n\t\t%0.2f us", GET_US_BY_CCOUNT(s_isr_interval_time / (times - 1)));
// init all time parameters
s_flash_func_t1 = 0;
s_flash_func_t2 = 0;
s_flash_func_time = 0;
s_isr_t1 = 0;
s_isr_t2 = 0;
s_isr_time = 0;
s_isr_interval_t1 = 0;
s_isr_interval_t2 = 0;
s_isr_interval_time = 0;
times = 0;
// run test again for validate the tSUS value
/**
set alarm_count is duration_time + Tsus value.
So, in this case, ISR duration time is around 2217 and ISR interval time is around 2259(tested value, can change each time)
so ISR_interval - ISR_duration is around 42us. Just a little bit larger than `tsus` value.
*/
alarm_config.alarm_count = GET_US_BY_CCOUNT(isr_duration_time) + CONFIG_SPI_FLASH_SUSPEND_TSUS_VAL_US,
TEST_ESP_OK(gptimer_set_alarm_action(gptimer, &alarm_config));
TEST_ESP_OK(gptimer_register_event_callbacks(gptimer, &cbs, &is_flash));
TEST_ESP_OK(gptimer_enable(gptimer));
TEST_ESP_OK(gptimer_start(gptimer));
erase_time = 0;
RECORD_TIME_START();
TEST_ESP_OK(esp_flash_erase_region(part->flash_chip, part->address, part->size));
TEST_ESP_OK(esp_flash_write(part->flash_chip, large_const_buffer, part->address, sizeof(large_const_buffer)));
RECORD_TIME_END(erase_time);
TEST_ESP_OK(gptimer_stop(gptimer));
isr_duration_time = GET_US_BY_CCOUNT(s_isr_time / times);
uint32_t isr_interval_time = GET_US_BY_CCOUNT(s_isr_interval_time / (times - 1));
ESP_LOGI(TAG, "--------------------Formal Test...--------------------");
ESP_LOGI(TAG, "Flash Driver Erase Operation finishes, duration:\n\t\t%0.2f us", GET_US_BY_CCOUNT(erase_time));
ESP_LOGI(TAG, "During Erase, ISR callback function(in flash) response time:\n\t\t%0.2f us", GET_US_BY_CCOUNT(s_flash_func_time / times));
ESP_LOGI(TAG, "During Erase, ISR duration time:\n\t\t%0.2f us", GET_US_BY_CCOUNT(s_isr_time / times));
ESP_LOGI(TAG, "During Erase, ISR interval time:\n\t\t%0.2f us", GET_US_BY_CCOUNT(s_isr_interval_time / (times - 1)));
ESP_LOGI(TAG, "The tsus value which passes the test is:\n\t\t%ld us", isr_interval_time - isr_duration_time);
// 15 stands for threshold. We allow the interval time minus duration time is little bit larger than TSUS value
TEST_ASSERT_LESS_THAN(CONFIG_SPI_FLASH_SUSPEND_TSUS_VAL_US + 15, isr_interval_time - isr_duration_time);
ESP_LOGI(TAG, "Reasonable value!");
ESP_LOGI(TAG, "Finish");
TEST_ESP_OK(gptimer_disable(gptimer));