mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-30 19:19:21 +00:00
feat(spi_flash): Support configurable tSUS in flash suspend
This commit is contained in:
@@ -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
|
||||
|
||||
|
@@ -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) {
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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));
|
||||
|
Reference in New Issue
Block a user