Skip to content

Commit a155b98

Browse files
committed
Merge branch 'feat/spi_master_sleep_retention' into 'master'
feat(driver_spi): spi master support sleep retention(recovery) Closes IDF-9775 See merge request espressif/esp-idf!33742
2 parents 92d3355 + 2f9456b commit a155b98

File tree

42 files changed

+701
-410
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+701
-410
lines changed

components/esp_driver_spi/include/driver/spi_common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ extern "C"
6464
#define SPICOMMON_BUSFLAG_IO4_IO7 (1<<8) ///< Check existing of IO4~IO7 pins. Or indicates IO4~IO7 pins initialized.
6565
#define SPICOMMON_BUSFLAG_OCTAL (SPICOMMON_BUSFLAG_QUAD|SPICOMMON_BUSFLAG_IO4_IO7) ///< Check existing of MOSI/MISO/WP/HD/SPIIO4/SPIIO5/SPIIO6/SPIIO7 pins as output. Or indicates bus able to work under octal mode.
6666
#define SPICOMMON_BUSFLAG_NATIVE_PINS SPICOMMON_BUSFLAG_IOMUX_PINS
67+
#define SPICOMMON_BUSFLAG_SLP_ALLOW_PD (1<<9) ///< Allow to power down the peripheral during light sleep, and auto recover then.
6768

6869
/**
6970
* @brief SPI DMA channels

components/esp_driver_spi/src/gpspi/spi_common.c

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "esp_private/spi_common_internal.h"
2222
#include "esp_private/spi_share_hw_ctrl.h"
2323
#include "esp_private/esp_cache_private.h"
24+
#include "esp_private/sleep_retention.h"
2425
#include "esp_dma_utils.h"
2526
#include "hal/spi_hal.h"
2627
#include "hal/gpio_hal.h"
@@ -49,6 +50,7 @@ static const char *SPI_TAG = "spi";
4950

5051
typedef struct {
5152
int host_id;
53+
_lock_t mutex; // mutex for controller
5254
spi_destroy_func_t destroy_func;
5355
void* destroy_arg;
5456
spi_bus_attr_t bus_attr;
@@ -587,7 +589,8 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
587589
}
588590

589591
uint32_t missing_flag = flags & ~temp_flag;
590-
missing_flag &= ~SPICOMMON_BUSFLAG_MASTER;//don't check this flag
592+
missing_flag &= ~SPICOMMON_BUSFLAG_MASTER; //don't check this flag
593+
missing_flag &= ~SPICOMMON_BUSFLAG_SLP_ALLOW_PD;
591594

592595
if (missing_flag != 0) {
593596
//check pins existence
@@ -778,6 +781,16 @@ spi_bus_lock_handle_t spi_bus_lock_get_by_id(spi_host_device_t host_id)
778781
return bus_ctx[host_id]->bus_attr.lock;
779782
}
780783

784+
#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
785+
static esp_err_t s_bus_create_sleep_retention_cb(void *arg)
786+
{
787+
spicommon_bus_context_t *ctx = arg;
788+
return sleep_retention_entries_create(spi_reg_retention_info[ctx->host_id - 1].entry_array,
789+
spi_reg_retention_info[ctx->host_id - 1].array_size,
790+
REGDMA_LINK_PRI_GPSPI,
791+
spi_reg_retention_info[ctx->host_id - 1].module_id);
792+
}
793+
#endif // SOC_SPI_SUPPORT_SLEEP_RETENTION
781794
//----------------------------------------------------------master bus init-------------------------------------------------------//
782795
esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *bus_config, spi_dma_chan_t dma_chan)
783796
{
@@ -846,6 +859,34 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *
846859
goto cleanup;
847860
}
848861

862+
#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
863+
sleep_retention_module_init_param_t init_param = {
864+
.cbs = {
865+
.create = {
866+
.handle = s_bus_create_sleep_retention_cb,
867+
.arg = ctx,
868+
},
869+
},
870+
.depends = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM),
871+
};
872+
873+
_lock_acquire(&ctx->mutex);
874+
if (sleep_retention_module_init(spi_reg_retention_info[host_id - 1].module_id, &init_param) == ESP_OK) {
875+
if ((bus_attr->bus_cfg.flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) && (sleep_retention_module_allocate(spi_reg_retention_info[host_id - 1].module_id) != ESP_OK)) {
876+
// even though the sleep retention create failed, SPI driver should still work, so just warning here
877+
ESP_LOGW(SPI_TAG, "alloc sleep recover failed, peripherals may hold power on");
878+
}
879+
} else {
880+
// even the sleep retention init failed, SPI driver should still work, so just warning here
881+
ESP_LOGW(SPI_TAG, "init sleep recover failed, spi may offline after sleep");
882+
}
883+
_lock_release(&ctx->mutex);
884+
#else
885+
if (bus_attr->bus_cfg.flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) {
886+
ESP_LOGE(SPI_TAG, "power down peripheral in sleep is not enabled or not supported on your target");
887+
}
888+
#endif // SOC_SPI_SUPPORT_SLEEP_RETENTION
889+
849890
#ifdef CONFIG_PM_ENABLE
850891
err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_master",
851892
&bus_attr->pm_lock);
@@ -927,9 +968,24 @@ esp_err_t spi_bus_free(spi_host_device_t host_id)
927968
}
928969
spicommon_bus_free_io_cfg(&bus_attr->bus_cfg);
929970

971+
#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
972+
const periph_retention_module_t retention_id = spi_reg_retention_info[host_id - 1].module_id;
973+
_lock_acquire(&ctx->mutex);
974+
if (sleep_retention_get_created_modules() & BIT(retention_id)) {
975+
assert(sleep_retention_get_inited_modules() & BIT(retention_id));
976+
sleep_retention_module_free(retention_id);
977+
}
978+
if (sleep_retention_get_inited_modules() & BIT(retention_id)) {
979+
sleep_retention_module_deinit(retention_id);
980+
}
981+
_lock_release(&ctx->mutex);
982+
_lock_close(&ctx->mutex);
983+
#endif
984+
930985
#ifdef CONFIG_PM_ENABLE
931986
esp_pm_lock_delete(bus_attr->pm_lock);
932987
#endif
988+
933989
spi_bus_deinit_lock(bus_attr->lock);
934990
if (ctx->dma_ctx) {
935991
free(ctx->dma_ctx->dmadesc_tx);

components/esp_driver_spi/src/gpspi/spi_master.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,8 +345,7 @@ static esp_err_t spi_master_deinit_driver(void* arg)
345345
int host_id = host->id;
346346
SPI_CHECK(is_valid_host(host_id), "invalid host_id", ESP_ERR_INVALID_ARG);
347347

348-
int x;
349-
for (x = 0; x < DEV_NUM_MAX; x++) {
348+
for (int x = 0; x < DEV_NUM_MAX; x++) {
350349
SPI_CHECK(host->device[x] == NULL, "not all CSses freed", ESP_ERR_INVALID_STATE);
351350
}
352351

components/esp_driver_spi/test_apps/master/main/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ set(srcs
88

99
# sct test using slave hd APIs, need slave hd support
1010
# tmp skip sct test under iram_safe, both sct and slave hd are not cleaned
11-
if(CONFIG_SOC_SPI_SUPPORT_SLAVE_HD_VER2 AND NOT CONFIG_COMPILER_DUMP_RTL_FILES)
11+
if(CONFIG_SOC_SPI_SUPPORT_SLAVE_HD_VER2 AND CONFIG_SOC_SPI_SCT_SUPPORTED AND NOT CONFIG_COMPILER_DUMP_RTL_FILES)
1212
list(APPEND srcs "test_spi_master_sct.c")
1313
endif()
1414

components/esp_driver_spi/test_apps/master/main/test_spi_master.c

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
#include "esp_private/cache_utils.h"
2020
#include "esp_private/spi_common_internal.h"
2121
#include "esp_private/esp_clk.h"
22+
#include "esp_private/sleep_cpu.h"
23+
#include "esp_private/esp_sleep_internal.h"
24+
#include "esp_private/esp_pmu.h"
2225
#include "esp_heap_caps.h"
2326
#include "esp_clk_tree.h"
2427
#include "esp_timer.h"
@@ -1788,3 +1791,135 @@ TEST_CASE("test_bus_free_safty_to_remain_devices", "[spi]")
17881791
TEST_ESP_OK(spi_bus_remove_device(dev1));
17891792
TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST));
17901793
}
1794+
1795+
TEST_CASE("test_spi_master_sleep_retention", "[spi]")
1796+
{
1797+
// Prepare a TOP PD sleep
1798+
TEST_ESP_OK(esp_sleep_enable_timer_wakeup(1 * 1000 * 1000));
1799+
#if ESP_SLEEP_POWER_DOWN_CPU
1800+
TEST_ESP_OK(sleep_cpu_configure(true));
1801+
#endif
1802+
esp_sleep_context_t sleep_ctx;
1803+
esp_sleep_set_sleep_context(&sleep_ctx);
1804+
1805+
spi_device_handle_t dev_handle;
1806+
spi_bus_config_t buscfg = SPI_BUS_TEST_DEFAULT_CONFIG();
1807+
spi_device_interface_config_t devcfg = SPI_DEVICE_TEST_DEFAULT_CONFIG();
1808+
buscfg.flags |= SPICOMMON_BUSFLAG_GPIO_PINS;
1809+
buscfg.flags |= SPICOMMON_BUSFLAG_SLP_ALLOW_PD;
1810+
uint8_t send[16] = "hello spi x\n";
1811+
uint8_t recv[16];
1812+
spi_transaction_t trans_cfg = {
1813+
.length = 8 * sizeof(send),
1814+
.tx_buffer = send,
1815+
.rx_buffer = recv,
1816+
};
1817+
1818+
for (int periph = SPI2_HOST; periph < SPI_HOST_MAX; periph ++) {
1819+
for (int test_dma = 0; test_dma <= 1; test_dma ++) {
1820+
int use_dma = SPI_DMA_DISABLED;
1821+
#if SOC_GDMA_SUPPORT_SLEEP_RETENTION // TODO: IDF-11317 test dma on esp32 and s2
1822+
use_dma = test_dma ? SPI_DMA_CH_AUTO : SPI_DMA_DISABLED;
1823+
#endif
1824+
printf("Retention on GPSPI%d with dma: %d\n", periph + 1, use_dma);
1825+
TEST_ESP_OK(spi_bus_initialize(periph, &buscfg, use_dma));
1826+
// set spi "self-loop" after bus initialized
1827+
spitest_gpio_output_sel(buscfg.miso_io_num, FUNC_GPIO, spi_periph_signal[periph].spid_out);
1828+
TEST_ESP_OK(spi_bus_add_device(periph, &devcfg, &dev_handle));
1829+
1830+
for (uint8_t cnt = 0; cnt < 3; cnt ++) {
1831+
printf("Going into sleep...\n");
1832+
TEST_ESP_OK(esp_light_sleep_start());
1833+
printf("Waked up!\n");
1834+
1835+
// check if the sleep happened as expected
1836+
TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result);
1837+
#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
1838+
// check if the power domain also is powered down
1839+
TEST_ASSERT_EQUAL((buscfg.flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) ? PMU_SLEEP_PD_TOP : 0, (sleep_ctx.sleep_flags) & PMU_SLEEP_PD_TOP);
1840+
#endif
1841+
memset(recv, 0, sizeof(recv));
1842+
send[10] = cnt + 'A';
1843+
TEST_ESP_OK(spi_device_transmit(dev_handle, &trans_cfg));
1844+
printf("%s", recv);
1845+
spitest_cmp_or_dump(trans_cfg.tx_buffer, trans_cfg.rx_buffer, sizeof(send));
1846+
}
1847+
1848+
TEST_ESP_OK(spi_bus_remove_device(dev_handle));
1849+
TEST_ESP_OK(spi_bus_free(periph));
1850+
}
1851+
}
1852+
1853+
esp_sleep_set_sleep_context(NULL);
1854+
#if ESP_SLEEP_POWER_DOWN_CPU
1855+
TEST_ESP_OK(sleep_cpu_configure(false));
1856+
#endif
1857+
}
1858+
1859+
#if 0 /* Temp disable, TODO: IDFCI-2455*/
1860+
#if CONFIG_PM_ENABLE
1861+
TEST_CASE("test_spi_master_auto_sleep_retention", "[spi]")
1862+
{
1863+
// Configure dynamic frequency scaling:
1864+
// maximum and minimum frequencies are set in sdkconfig,
1865+
// automatic light sleep is enabled if tickless idle support is enabled.
1866+
uint32_t xtal_hz = 0;
1867+
esp_clk_tree_src_get_freq_hz(SOC_MOD_CLK_XTAL, ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT, &xtal_hz);
1868+
esp_pm_config_t pm_config = {
1869+
.max_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ,
1870+
.min_freq_mhz = xtal_hz / 1000000,
1871+
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
1872+
.light_sleep_enable = true,
1873+
#endif
1874+
};
1875+
TEST_ESP_OK(esp_pm_configure(&pm_config));
1876+
esp_sleep_context_t sleep_ctx;
1877+
esp_sleep_set_sleep_context(&sleep_ctx);
1878+
1879+
for (uint8_t allow_pd = 0; allow_pd < 2; allow_pd ++) {
1880+
spi_bus_config_t buscfg = SPI_BUS_TEST_DEFAULT_CONFIG();
1881+
buscfg.flags = (allow_pd) ? SPICOMMON_BUSFLAG_SLP_ALLOW_PD : 0;
1882+
buscfg.flags |= SPICOMMON_BUSFLAG_GPIO_PINS;
1883+
TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST, &buscfg, SPI_DMA_DISABLED));
1884+
// set spi "self-loop" after bus initialized
1885+
spitest_gpio_output_sel(buscfg.miso_io_num, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spid_out);
1886+
1887+
spi_device_handle_t dev_handle;
1888+
spi_device_interface_config_t devcfg = SPI_DEVICE_TEST_DEFAULT_CONFIG();
1889+
TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &devcfg, &dev_handle));
1890+
1891+
uint8_t send[13] = "hello spi 0\n";
1892+
uint8_t recv[13];
1893+
spi_transaction_t trans_cfg = {
1894+
.length = 8 * sizeof(send),
1895+
.tx_buffer = send,
1896+
.rx_buffer = recv,
1897+
};
1898+
1899+
for (uint8_t cnt = 0; cnt < 3; cnt ++) {
1900+
printf("Going into Auto sleep with power %s ...\n", (buscfg.flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) ? "down" : "hold");
1901+
vTaskDelay(1000); //auto light sleep here
1902+
printf("Waked up!\n");
1903+
1904+
// check if the sleep happened as expected
1905+
TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result);
1906+
#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
1907+
// check if the power domain also is powered down
1908+
TEST_ASSERT_EQUAL((buscfg.flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) ? PMU_SLEEP_PD_TOP : 0, (sleep_ctx.sleep_flags) & PMU_SLEEP_PD_TOP);
1909+
#endif
1910+
memset(recv, 0, sizeof(recv));
1911+
send[10] = cnt + '0';
1912+
TEST_ESP_OK(spi_device_polling_transmit(dev_handle, &trans_cfg));
1913+
printf("%s", recv);
1914+
spitest_cmp_or_dump(trans_cfg.tx_buffer, trans_cfg.rx_buffer, sizeof(send));
1915+
}
1916+
1917+
TEST_ESP_OK(spi_bus_remove_device(dev_handle));
1918+
TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST));
1919+
}
1920+
esp_sleep_set_sleep_context(NULL);
1921+
pm_config.light_sleep_enable = false;
1922+
TEST_ESP_OK(esp_pm_configure(&pm_config));
1923+
}
1924+
#endif //CONFIG_PM_ENABLE
1925+
#endif // 0

0 commit comments

Comments
 (0)