Skip to content

Commit f2c8b32

Browse files
committed
Merge branch 'feat/spi_slave_pm_add_api' into 'master'
feat(spi_slave): add api for pm lock control See merge request espressif/esp-idf!30766
2 parents f8ff9e4 + 923255d commit f2c8b32

File tree

17 files changed

+197
-20
lines changed

17 files changed

+197
-20
lines changed

components/driver/test_apps/components/test_driver_utils/test_spi_utils.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ void same_pin_func_sel(spi_bus_config_t bus, spi_device_interface_config_t dev,
252252
void spi_master_trans_impl_gpio(spi_bus_config_t bus, uint8_t cs_pin, uint8_t speed_hz, void *tx, void *rx, uint32_t len)
253253
{
254254
uint8_t *u8_tx = tx, *u8_rx = rx;
255+
gpio_set_level(cs_pin, 1); //ensure CS is inactive before transaction start
255256
esp_rom_gpio_connect_out_signal(cs_pin, SIG_GPIO_OUT_IDX, 0, 0);
256257
esp_rom_gpio_connect_out_signal(bus.sclk_io_num, SIG_GPIO_OUT_IDX, 0, 0);
257258
esp_rom_gpio_connect_out_signal(bus.mosi_io_num, SIG_GPIO_OUT_IDX, 0, 0);

components/esp_driver_spi/include/driver/spi_slave.h

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2010-2023 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -80,7 +80,7 @@ struct spi_slave_transaction_t {
8080
};
8181

8282
/**
83-
* @brief Initialize a SPI bus as a slave interface
83+
* @brief Initialize a SPI bus as a slave interface and enable it by default
8484
*
8585
* @warning SPI0/1 is not supported
8686
*
@@ -119,6 +119,30 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
119119
*/
120120
esp_err_t spi_slave_free(spi_host_device_t host);
121121

122+
/**
123+
* @brief Enable the spi slave function for an initialized spi host
124+
* @note No need to call this function additionally after `spi_slave_initialize`,
125+
* because it has been enabled already during the initialization.
126+
*
127+
* @param host SPI peripheral to be enabled
128+
* @return
129+
* - ESP_OK On success
130+
* - ESP_ERR_INVALID_ARG Unsupported host
131+
* - ESP_ERR_INVALID_STATE Peripheral already enabled
132+
*/
133+
esp_err_t spi_slave_enable(spi_host_device_t host);
134+
135+
/**
136+
* @brief Disable the spi slave function for an initialized spi host
137+
*
138+
* @param host SPI peripheral to be disabled
139+
* @return
140+
* - ESP_OK On success
141+
* - ESP_ERR_INVALID_ARG Unsupported host
142+
* - ESP_ERR_INVALID_STATE Peripheral already disabled
143+
*/
144+
esp_err_t spi_slave_disable(spi_host_device_t host);
145+
122146
/**
123147
* @brief Queue a SPI transaction for execution
124148
*

components/esp_driver_spi/include/driver/spi_slave_hd.h

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2010-2021 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -87,7 +87,7 @@ typedef struct {
8787
} spi_slave_hd_slot_config_t;
8888

8989
/**
90-
* @brief Initialize the SPI Slave HD driver.
90+
* @brief Initialize the SPI Slave HD driver and enable it by default.
9191
*
9292
* @param host_id The host to use
9393
* @param bus_config Bus configuration for the bus used
@@ -113,6 +113,30 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
113113
*/
114114
esp_err_t spi_slave_hd_deinit(spi_host_device_t host_id);
115115

116+
/**
117+
* @brief Enable the spi slave HD function for an initialized spi host
118+
* @note No need to call this function additionally after `spi_slave_hd_init`,
119+
* because it has been enabled already during the initialization.
120+
*
121+
* @param host_id SPI peripheral to be enabled
122+
* @return
123+
* - ESP_OK On success
124+
* - ESP_ERR_INVALID_ARG Unsupported host_id
125+
* - ESP_ERR_INVALID_STATE Peripheral already enabled
126+
*/
127+
esp_err_t spi_slave_hd_enable(spi_host_device_t host_id);
128+
129+
/**
130+
* @brief Disable the spi slave HD function for an initialized spi host
131+
*
132+
* @param host_id SPI peripheral to be disabled
133+
* @return
134+
* - ESP_OK On success
135+
* - ESP_ERR_INVALID_ARG Unsupported host_id
136+
* - ESP_ERR_INVALID_STATE Peripheral already disabled
137+
*/
138+
esp_err_t spi_slave_hd_disable(spi_host_device_t host_id);
139+
116140
/**
117141
* @brief Queue transactions (segment mode)
118142
*

components/esp_driver_spi/include/esp_private/spi_common_internal.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ typedef dma_descriptor_align4_t spi_dma_desc_t;
4444
#define ADDR_CPU_2_DMA(addr) (addr)
4545
#endif
4646

47+
// Status of a spi bus
48+
typedef enum {
49+
SPI_BUS_FSM_DISABLED, ///< Bus is disabled, clock and power is allowed to be closed.
50+
SPI_BUS_FSM_ENABLED, ///< Bus is ready to be used
51+
} spi_bus_fsm_t;
52+
4753
/// Attributes of an SPI bus
4854
typedef struct {
4955
spi_bus_config_t bus_cfg; ///< Config used to initialize the bus

components/esp_driver_spi/src/gpspi/spi_slave.c

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
#include <string.h>
8+
#include <stdatomic.h>
89
#include "esp_types.h"
910
#include "esp_attr.h"
1011
#include "esp_check.h"
@@ -59,6 +60,7 @@ typedef struct {
5960

6061
typedef struct {
6162
int id;
63+
_Atomic spi_bus_fsm_t fsm;
6264
spi_bus_config_t bus_config;
6365
spi_dma_ctx_t *dma_ctx;
6466
spi_slave_interface_config_t cfg;
@@ -177,6 +179,7 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
177179
memcpy(&spihost[host]->cfg, slave_config, sizeof(spi_slave_interface_config_t));
178180
memcpy(&spihost[host]->bus_config, bus_config, sizeof(spi_bus_config_t));
179181
spihost[host]->id = host;
182+
atomic_store(&spihost[host]->fsm, SPI_BUS_FSM_ENABLED);
180183
spi_slave_hal_context_t *hal = &spihost[host]->hal;
181184

182185
spihost[host]->dma_enabled = (dma_chan != SPI_DMA_DISABLED);
@@ -224,8 +227,7 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
224227
}
225228

226229
#ifdef CONFIG_PM_ENABLE
227-
err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_slave",
228-
&spihost[host]->pm_lock);
230+
err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_slave", &spihost[host]->pm_lock);
229231
if (err != ESP_OK) {
230232
ret = err;
231233
goto cleanup;
@@ -351,6 +353,46 @@ esp_err_t spi_slave_free(spi_host_device_t host)
351353
return ESP_OK;
352354
}
353355

356+
esp_err_t spi_slave_enable(spi_host_device_t host)
357+
{
358+
SPI_CHECK(is_valid_host(host), "invalid host", ESP_ERR_INVALID_ARG);
359+
SPI_CHECK(spihost[host], "host not slave or not initialized", ESP_ERR_INVALID_ARG);
360+
spi_bus_fsm_t curr_sta = SPI_BUS_FSM_DISABLED;
361+
SPI_CHECK(atomic_compare_exchange_strong(&spihost[host]->fsm, &curr_sta, SPI_BUS_FSM_ENABLED), "host already enabled", ESP_ERR_INVALID_STATE);
362+
363+
#ifdef CONFIG_PM_ENABLE
364+
esp_pm_lock_acquire(spihost[host]->pm_lock);
365+
#endif //CONFIG_PM_ENABLE
366+
367+
// If going to TOP_PD power down, the bus_clock is required during reg_dma, and will be disabled by sleep flow then
368+
#if !CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
369+
SPI_COMMON_RCC_CLOCK_ATOMIC() {
370+
spi_ll_enable_bus_clock(host, true);
371+
}
372+
#endif
373+
return ESP_OK;
374+
}
375+
376+
esp_err_t spi_slave_disable(spi_host_device_t host)
377+
{
378+
SPI_CHECK(is_valid_host(host), "invalid host", ESP_ERR_INVALID_ARG);
379+
SPI_CHECK(spihost[host], "host not slave or not initialized", ESP_ERR_INVALID_ARG);
380+
spi_bus_fsm_t curr_sta = SPI_BUS_FSM_ENABLED;
381+
SPI_CHECK(atomic_compare_exchange_strong(&spihost[host]->fsm, &curr_sta, SPI_BUS_FSM_DISABLED), "host already disabled", ESP_ERR_INVALID_STATE);
382+
383+
#ifdef CONFIG_PM_ENABLE
384+
esp_pm_lock_release(spihost[host]->pm_lock);
385+
#endif //CONFIG_PM_ENABLE
386+
387+
// same as above
388+
#if !CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
389+
SPI_COMMON_RCC_CLOCK_ATOMIC() {
390+
spi_ll_enable_bus_clock(host, false);
391+
}
392+
#endif
393+
return ESP_OK;
394+
}
395+
354396
static void SPI_SLAVE_ISR_ATTR spi_slave_uninstall_priv_trans(spi_host_device_t host, spi_slave_trans_priv_t *priv_trans)
355397
{
356398
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE

components/esp_driver_spi/src/gpspi/spi_slave_hd.c

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

7+
#include <stdatomic.h>
78
#include "esp_compiler.h"
89
#include "esp_log.h"
910
#include "esp_check.h"
@@ -38,6 +39,7 @@ typedef struct {
3839

3940
typedef struct {
4041
spi_host_device_t host_id;
42+
_Atomic spi_bus_fsm_t fsm;
4143
spi_dma_ctx_t *dma_ctx;
4244
uint16_t internal_mem_align_size;
4345
int max_transfer_sz;
@@ -117,6 +119,7 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
117119
host->host_id = host_id;
118120
host->int_spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
119121
host->append_mode = append_mode;
122+
atomic_store(&host->fsm, SPI_BUS_FSM_ENABLED);
120123

121124
ret = spicommon_dma_chan_alloc(host_id, config->dma_chan, &host->dma_ctx);
122125
if (ret != ESP_OK) {
@@ -178,7 +181,7 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
178181
spi_slave_hd_hal_init(&host->hal, &hal_config);
179182

180183
#ifdef CONFIG_PM_ENABLE
181-
ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_slave", &host->pm_lock);
184+
ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_slave_hd", &host->pm_lock);
182185
if (ret != ESP_OK) {
183186
goto cleanup;
184187
}
@@ -343,6 +346,46 @@ esp_err_t spi_slave_hd_deinit(spi_host_device_t host_id)
343346
return ESP_OK;
344347
}
345348

349+
esp_err_t spi_slave_hd_enable(spi_host_device_t host_id)
350+
{
351+
SPIHD_CHECK(VALID_HOST(host_id), "invalid host", ESP_ERR_INVALID_ARG);
352+
SPIHD_CHECK(spihost[host_id], "host not slave or not initialized", ESP_ERR_INVALID_ARG);
353+
spi_bus_fsm_t curr_sta = SPI_BUS_FSM_DISABLED;
354+
SPIHD_CHECK(atomic_compare_exchange_strong(&spihost[host_id]->fsm, &curr_sta, SPI_BUS_FSM_ENABLED), "host already enabled", ESP_ERR_INVALID_STATE);
355+
356+
#ifdef CONFIG_PM_ENABLE
357+
esp_pm_lock_acquire(spihost[host_id]->pm_lock);
358+
#endif //CONFIG_PM_ENABLE
359+
360+
// If going to TOP_PD power down, the bus_clock is required during reg_dma, and will be disabled by sleep flow then
361+
#if !CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
362+
SPI_COMMON_RCC_CLOCK_ATOMIC() {
363+
spi_ll_enable_bus_clock(host_id, true);
364+
}
365+
#endif
366+
return ESP_OK;
367+
}
368+
369+
esp_err_t spi_slave_hd_disable(spi_host_device_t host_id)
370+
{
371+
SPIHD_CHECK(VALID_HOST(host_id), "invalid host", ESP_ERR_INVALID_ARG);
372+
SPIHD_CHECK(spihost[host_id], "host not slave or not initialized", ESP_ERR_INVALID_ARG);
373+
spi_bus_fsm_t curr_sta = SPI_BUS_FSM_ENABLED;
374+
SPIHD_CHECK(atomic_compare_exchange_strong(&spihost[host_id]->fsm, &curr_sta, SPI_BUS_FSM_DISABLED), "host already disabled", ESP_ERR_INVALID_STATE);
375+
376+
#ifdef CONFIG_PM_ENABLE
377+
esp_pm_lock_release(spihost[host_id]->pm_lock);
378+
#endif //CONFIG_PM_ENABLE
379+
380+
// same as above
381+
#if !CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
382+
SPI_COMMON_RCC_CLOCK_ATOMIC() {
383+
spi_ll_enable_bus_clock(host_id, false);
384+
}
385+
#endif
386+
return ESP_OK;
387+
}
388+
346389
static void tx_invoke(spi_slave_hd_slot_t *host)
347390
{
348391
portENTER_CRITICAL(&host->int_spinlock);

components/esp_driver_spi/test_apps/master/pytest_spi_master.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# If `test_env` is define, should not run on generic runner
77
@pytest.mark.supported_targets
88
@pytest.mark.generic
9-
@pytest.mark.parametrize('config', ['defaults', 'release', 'freertos_compliance', 'freertos_flash',], indirect=True)
9+
@pytest.mark.parametrize('config', ['release', 'freertos_compliance', 'freertos_flash',], indirect=True)
1010
def test_master_single_dev(case_tester) -> None: # type: ignore
1111
for case in case_tester.test_menu:
1212
if 'test_env' in case.attributes:
@@ -17,7 +17,7 @@ def test_master_single_dev(case_tester) -> None: # type: ignore
1717
# Job for test_env `external_flash` just for esp32 only
1818
@pytest.mark.esp32
1919
@pytest.mark.flash_multi
20-
@pytest.mark.parametrize('config', ['defaults',], indirect=True)
20+
@pytest.mark.parametrize('config', ['release',], indirect=True)
2121
def test_master_esp_flash(case_tester) -> None: # type: ignore
2222
for case in case_tester.test_menu:
2323
# test case `spi_bus_lock_with_flash` use difference test env
@@ -33,7 +33,6 @@ def test_master_esp_flash(case_tester) -> None: # type: ignore
3333
@pytest.mark.parametrize(
3434
'count, config',
3535
[
36-
(2, 'defaults',),
3736
(2, 'release',),
3837
(2, 'freertos_compliance',),
3938
(2, 'freertos_flash',),

components/esp_driver_spi/test_apps/slave/main/test_spi_slave.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,7 @@ static IRAM_ATTR void spi_queue_reset_in_isr(void)
725725

726726
free(slave_isr_send);
727727
free(slave_isr_recv);
728+
free(dummy_data);
728729
free(slave_isr_exp);
729730
spi_slave_free(TEST_SPI_HOST);
730731
}
@@ -733,7 +734,6 @@ TEST_CASE_MULTIPLE_DEVICES("SPI_Slave: Test_Queue_Reset_in_ISR", "[spi_ms]", tes
733734
#endif // CONFIG_SPI_SLAVE_ISR_IN_IRAM
734735

735736
#if (SOC_CPU_CORES_NUM > 1) && (!CONFIG_FREERTOS_UNICORE)
736-
737737
#define TEST_ISR_CNT 100
738738
static void test_slave_isr_core_setup_cbk(spi_slave_transaction_t *curr_trans)
739739
{
@@ -782,7 +782,7 @@ TEST_CASE("test_slave_isr_pin_to_core", "[spi]")
782782
}
783783
#endif
784784

785-
TEST_CASE("test spi slave sleep retention", "[spi]")
785+
TEST_CASE("test_spi_slave_sleep_retention", "[spi]")
786786
{
787787
// Prepare a TOP PD sleep
788788
TEST_ESP_OK(esp_sleep_enable_timer_wakeup(1 * 1000 * 1000));
@@ -811,12 +811,14 @@ TEST_CASE("test spi slave sleep retention", "[spi]")
811811

812812
for (uint8_t cnt = 0; cnt < 3; cnt ++) {
813813
printf("Going into sleep with power %s ...\n", (buscfg.flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) ? "down" : "hold");
814+
TEST_ESP_OK(spi_slave_disable(TEST_SPI_HOST));
814815
TEST_ESP_OK(esp_light_sleep_start());
816+
TEST_ESP_OK(spi_slave_enable(TEST_SPI_HOST));
815817
printf("Waked up!\n");
816818

817819
// check if the sleep happened as expected
818820
TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result);
819-
#if SOC_SPI_SUPPORT_SLEEP_RETENTION
821+
#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
820822
// check if the power domain also is powered down
821823
TEST_ASSERT_EQUAL((buscfg.flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) ? PMU_SLEEP_PD_TOP : 0, (sleep_ctx.sleep_flags) & PMU_SLEEP_PD_TOP);
822824
#endif

components/esp_driver_spi/test_apps/slave/pytest_spi_slave.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# If `test_env` is define, should not run on generic runner
77
@pytest.mark.supported_targets
88
@pytest.mark.generic
9-
@pytest.mark.parametrize('config', ['defaults',], indirect=True)
9+
@pytest.mark.parametrize('config', ['release', 'iram_safe'], indirect=True)
1010
def test_slave_single_dev(case_tester) -> None: # type: ignore
1111
for case in case_tester.test_menu:
1212
if 'test_env' in case.attributes:
@@ -19,7 +19,7 @@ def test_slave_single_dev(case_tester) -> None: # type: ignore
1919
@pytest.mark.temp_skip_ci(targets=['esp32c61'], reason='no multi-dev runner')
2020
@pytest.mark.supported_targets
2121
@pytest.mark.generic_multi_device
22-
@pytest.mark.parametrize('count, config', [(2, 'defaults'), (2, 'iram_safe')], indirect=True)
22+
@pytest.mark.parametrize('count, config', [(2, 'release'), (2, 'iram_safe')], indirect=True)
2323
def test_slave_multi_dev(case_tester) -> None: # type: ignore
2424
for case in case_tester.test_menu:
2525
if case.attributes.get('test_env', 'generic_multi_device') == 'generic_multi_device':

components/esp_driver_spi/test_apps/slave/sdkconfig.ci.iram_safe

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ CONFIG_SPI_MASTER_ISR_IN_IRAM=n
33
CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
44
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y
55
CONFIG_COMPILER_OPTIMIZATION_NONE=y
6+
CONFIG_ESP_IPC_TASK_STACK_SIZE=2048
67
# silent the error check, as the error string are stored in rodata, causing RTL check failure
78
CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y

0 commit comments

Comments
 (0)