mirror of
https://github.com/espressif/esp-idf
synced 2025-03-09 09:09:10 -04:00
feat(spi_slave): add api for pm lock control
This commit is contained in:
parent
4f2105d03e
commit
923255d7a7
@ -252,6 +252,7 @@ void same_pin_func_sel(spi_bus_config_t bus, spi_device_interface_config_t dev,
|
||||
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)
|
||||
{
|
||||
uint8_t *u8_tx = tx, *u8_rx = rx;
|
||||
gpio_set_level(cs_pin, 1); //ensure CS is inactive before transaction start
|
||||
esp_rom_gpio_connect_out_signal(cs_pin, SIG_GPIO_OUT_IDX, 0, 0);
|
||||
esp_rom_gpio_connect_out_signal(bus.sclk_io_num, SIG_GPIO_OUT_IDX, 0, 0);
|
||||
esp_rom_gpio_connect_out_signal(bus.mosi_io_num, SIG_GPIO_OUT_IDX, 0, 0);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2010-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -80,7 +80,7 @@ struct spi_slave_transaction_t {
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Initialize a SPI bus as a slave interface
|
||||
* @brief Initialize a SPI bus as a slave interface and enable it by default
|
||||
*
|
||||
* @warning SPI0/1 is not supported
|
||||
*
|
||||
@ -119,6 +119,30 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
|
||||
*/
|
||||
esp_err_t spi_slave_free(spi_host_device_t host);
|
||||
|
||||
/**
|
||||
* @brief Enable the spi slave function for an initialized spi host
|
||||
* @note No need to call this function additionally after `spi_slave_initialize`,
|
||||
* because it has been enabled already during the initialization.
|
||||
*
|
||||
* @param host SPI peripheral to be enabled
|
||||
* @return
|
||||
* - ESP_OK On success
|
||||
* - ESP_ERR_INVALID_ARG Unsupported host
|
||||
* - ESP_ERR_INVALID_STATE Peripheral already enabled
|
||||
*/
|
||||
esp_err_t spi_slave_enable(spi_host_device_t host);
|
||||
|
||||
/**
|
||||
* @brief Disable the spi slave function for an initialized spi host
|
||||
*
|
||||
* @param host SPI peripheral to be disabled
|
||||
* @return
|
||||
* - ESP_OK On success
|
||||
* - ESP_ERR_INVALID_ARG Unsupported host
|
||||
* - ESP_ERR_INVALID_STATE Peripheral already disabled
|
||||
*/
|
||||
esp_err_t spi_slave_disable(spi_host_device_t host);
|
||||
|
||||
/**
|
||||
* @brief Queue a SPI transaction for execution
|
||||
*
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2010-2021 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -87,7 +87,7 @@ typedef struct {
|
||||
} spi_slave_hd_slot_config_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize the SPI Slave HD driver.
|
||||
* @brief Initialize the SPI Slave HD driver and enable it by default.
|
||||
*
|
||||
* @param host_id The host to use
|
||||
* @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
|
||||
*/
|
||||
esp_err_t spi_slave_hd_deinit(spi_host_device_t host_id);
|
||||
|
||||
/**
|
||||
* @brief Enable the spi slave HD function for an initialized spi host
|
||||
* @note No need to call this function additionally after `spi_slave_hd_init`,
|
||||
* because it has been enabled already during the initialization.
|
||||
*
|
||||
* @param host_id SPI peripheral to be enabled
|
||||
* @return
|
||||
* - ESP_OK On success
|
||||
* - ESP_ERR_INVALID_ARG Unsupported host_id
|
||||
* - ESP_ERR_INVALID_STATE Peripheral already enabled
|
||||
*/
|
||||
esp_err_t spi_slave_hd_enable(spi_host_device_t host_id);
|
||||
|
||||
/**
|
||||
* @brief Disable the spi slave HD function for an initialized spi host
|
||||
*
|
||||
* @param host_id SPI peripheral to be disabled
|
||||
* @return
|
||||
* - ESP_OK On success
|
||||
* - ESP_ERR_INVALID_ARG Unsupported host_id
|
||||
* - ESP_ERR_INVALID_STATE Peripheral already disabled
|
||||
*/
|
||||
esp_err_t spi_slave_hd_disable(spi_host_device_t host_id);
|
||||
|
||||
/**
|
||||
* @brief Queue transactions (segment mode)
|
||||
*
|
||||
|
@ -44,6 +44,12 @@ typedef dma_descriptor_align4_t spi_dma_desc_t;
|
||||
#define ADDR_CPU_2_DMA(addr) (addr)
|
||||
#endif
|
||||
|
||||
// Status of a spi bus
|
||||
typedef enum {
|
||||
SPI_BUS_FSM_DISABLED, ///< Bus is disabled, clock and power is allowed to be closed.
|
||||
SPI_BUS_FSM_ENABLED, ///< Bus is ready to be used
|
||||
} spi_bus_fsm_t;
|
||||
|
||||
/// Attributes of an SPI bus
|
||||
typedef struct {
|
||||
spi_bus_config_t bus_cfg; ///< Config used to initialize the bus
|
||||
|
@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdatomic.h>
|
||||
#include "esp_types.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_check.h"
|
||||
@ -59,6 +60,7 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
_Atomic spi_bus_fsm_t fsm;
|
||||
spi_bus_config_t bus_config;
|
||||
spi_dma_ctx_t *dma_ctx;
|
||||
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
|
||||
memcpy(&spihost[host]->cfg, slave_config, sizeof(spi_slave_interface_config_t));
|
||||
memcpy(&spihost[host]->bus_config, bus_config, sizeof(spi_bus_config_t));
|
||||
spihost[host]->id = host;
|
||||
atomic_store(&spihost[host]->fsm, SPI_BUS_FSM_ENABLED);
|
||||
spi_slave_hal_context_t *hal = &spihost[host]->hal;
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_slave",
|
||||
&spihost[host]->pm_lock);
|
||||
err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_slave", &spihost[host]->pm_lock);
|
||||
if (err != ESP_OK) {
|
||||
ret = err;
|
||||
goto cleanup;
|
||||
@ -351,6 +353,46 @@ esp_err_t spi_slave_free(spi_host_device_t host)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t spi_slave_enable(spi_host_device_t host)
|
||||
{
|
||||
SPI_CHECK(is_valid_host(host), "invalid host", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(spihost[host], "host not slave or not initialized", ESP_ERR_INVALID_ARG);
|
||||
spi_bus_fsm_t curr_sta = SPI_BUS_FSM_DISABLED;
|
||||
SPI_CHECK(atomic_compare_exchange_strong(&spihost[host]->fsm, &curr_sta, SPI_BUS_FSM_ENABLED), "host already enabled", ESP_ERR_INVALID_STATE);
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_acquire(spihost[host]->pm_lock);
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
// If going to TOP_PD power down, the bus_clock is required during reg_dma, and will be disabled by sleep flow then
|
||||
#if !CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||
SPI_COMMON_RCC_CLOCK_ATOMIC() {
|
||||
spi_ll_enable_bus_clock(host, true);
|
||||
}
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t spi_slave_disable(spi_host_device_t host)
|
||||
{
|
||||
SPI_CHECK(is_valid_host(host), "invalid host", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(spihost[host], "host not slave or not initialized", ESP_ERR_INVALID_ARG);
|
||||
spi_bus_fsm_t curr_sta = SPI_BUS_FSM_ENABLED;
|
||||
SPI_CHECK(atomic_compare_exchange_strong(&spihost[host]->fsm, &curr_sta, SPI_BUS_FSM_DISABLED), "host already disabled", ESP_ERR_INVALID_STATE);
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_release(spihost[host]->pm_lock);
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
// same as above
|
||||
#if !CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||
SPI_COMMON_RCC_CLOCK_ATOMIC() {
|
||||
spi_ll_enable_bus_clock(host, false);
|
||||
}
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void SPI_SLAVE_ISR_ATTR spi_slave_uninstall_priv_trans(spi_host_device_t host, spi_slave_trans_priv_t *priv_trans)
|
||||
{
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
|
@ -4,6 +4,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include "esp_compiler.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
@ -38,6 +39,7 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
spi_host_device_t host_id;
|
||||
_Atomic spi_bus_fsm_t fsm;
|
||||
spi_dma_ctx_t *dma_ctx;
|
||||
uint16_t internal_mem_align_size;
|
||||
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
|
||||
host->host_id = host_id;
|
||||
host->int_spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
host->append_mode = append_mode;
|
||||
atomic_store(&host->fsm, SPI_BUS_FSM_ENABLED);
|
||||
|
||||
ret = spicommon_dma_chan_alloc(host_id, config->dma_chan, &host->dma_ctx);
|
||||
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
|
||||
spi_slave_hd_hal_init(&host->hal, &hal_config);
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_slave", &host->pm_lock);
|
||||
ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_slave_hd", &host->pm_lock);
|
||||
if (ret != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
@ -343,6 +346,46 @@ esp_err_t spi_slave_hd_deinit(spi_host_device_t host_id)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t spi_slave_hd_enable(spi_host_device_t host_id)
|
||||
{
|
||||
SPIHD_CHECK(VALID_HOST(host_id), "invalid host", ESP_ERR_INVALID_ARG);
|
||||
SPIHD_CHECK(spihost[host_id], "host not slave or not initialized", ESP_ERR_INVALID_ARG);
|
||||
spi_bus_fsm_t curr_sta = SPI_BUS_FSM_DISABLED;
|
||||
SPIHD_CHECK(atomic_compare_exchange_strong(&spihost[host_id]->fsm, &curr_sta, SPI_BUS_FSM_ENABLED), "host already enabled", ESP_ERR_INVALID_STATE);
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_acquire(spihost[host_id]->pm_lock);
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
// If going to TOP_PD power down, the bus_clock is required during reg_dma, and will be disabled by sleep flow then
|
||||
#if !CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||
SPI_COMMON_RCC_CLOCK_ATOMIC() {
|
||||
spi_ll_enable_bus_clock(host_id, true);
|
||||
}
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t spi_slave_hd_disable(spi_host_device_t host_id)
|
||||
{
|
||||
SPIHD_CHECK(VALID_HOST(host_id), "invalid host", ESP_ERR_INVALID_ARG);
|
||||
SPIHD_CHECK(spihost[host_id], "host not slave or not initialized", ESP_ERR_INVALID_ARG);
|
||||
spi_bus_fsm_t curr_sta = SPI_BUS_FSM_ENABLED;
|
||||
SPIHD_CHECK(atomic_compare_exchange_strong(&spihost[host_id]->fsm, &curr_sta, SPI_BUS_FSM_DISABLED), "host already disabled", ESP_ERR_INVALID_STATE);
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_release(spihost[host_id]->pm_lock);
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
// same as above
|
||||
#if !CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||
SPI_COMMON_RCC_CLOCK_ATOMIC() {
|
||||
spi_ll_enable_bus_clock(host_id, false);
|
||||
}
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void tx_invoke(spi_slave_hd_slot_t *host)
|
||||
{
|
||||
portENTER_CRITICAL(&host->int_spinlock);
|
||||
|
@ -6,7 +6,7 @@ import pytest
|
||||
# If `test_env` is define, should not run on generic runner
|
||||
@pytest.mark.supported_targets
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.parametrize('config', ['defaults', 'release', 'freertos_compliance', 'freertos_flash',], indirect=True)
|
||||
@pytest.mark.parametrize('config', ['release', 'freertos_compliance', 'freertos_flash',], indirect=True)
|
||||
def test_master_single_dev(case_tester) -> None: # type: ignore
|
||||
for case in case_tester.test_menu:
|
||||
if 'test_env' in case.attributes:
|
||||
@ -17,7 +17,7 @@ def test_master_single_dev(case_tester) -> None: # type: ignore
|
||||
# Job for test_env `external_flash` just for esp32 only
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.flash_multi
|
||||
@pytest.mark.parametrize('config', ['defaults',], indirect=True)
|
||||
@pytest.mark.parametrize('config', ['release',], indirect=True)
|
||||
def test_master_esp_flash(case_tester) -> None: # type: ignore
|
||||
for case in case_tester.test_menu:
|
||||
# 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
|
||||
@pytest.mark.parametrize(
|
||||
'count, config',
|
||||
[
|
||||
(2, 'defaults',),
|
||||
(2, 'release',),
|
||||
(2, 'freertos_compliance',),
|
||||
(2, 'freertos_flash',),
|
||||
|
@ -725,6 +725,7 @@ static IRAM_ATTR void spi_queue_reset_in_isr(void)
|
||||
|
||||
free(slave_isr_send);
|
||||
free(slave_isr_recv);
|
||||
free(dummy_data);
|
||||
free(slave_isr_exp);
|
||||
spi_slave_free(TEST_SPI_HOST);
|
||||
}
|
||||
@ -733,7 +734,6 @@ TEST_CASE_MULTIPLE_DEVICES("SPI_Slave: Test_Queue_Reset_in_ISR", "[spi_ms]", tes
|
||||
#endif // CONFIG_SPI_SLAVE_ISR_IN_IRAM
|
||||
|
||||
#if (SOC_CPU_CORES_NUM > 1) && (!CONFIG_FREERTOS_UNICORE)
|
||||
|
||||
#define TEST_ISR_CNT 100
|
||||
static void test_slave_isr_core_setup_cbk(spi_slave_transaction_t *curr_trans)
|
||||
{
|
||||
@ -782,7 +782,7 @@ TEST_CASE("test_slave_isr_pin_to_core", "[spi]")
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("test spi slave sleep retention", "[spi]")
|
||||
TEST_CASE("test_spi_slave_sleep_retention", "[spi]")
|
||||
{
|
||||
// Prepare a TOP PD sleep
|
||||
TEST_ESP_OK(esp_sleep_enable_timer_wakeup(1 * 1000 * 1000));
|
||||
@ -811,12 +811,14 @@ TEST_CASE("test spi slave sleep retention", "[spi]")
|
||||
|
||||
for (uint8_t cnt = 0; cnt < 3; cnt ++) {
|
||||
printf("Going into sleep with power %s ...\n", (buscfg.flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) ? "down" : "hold");
|
||||
TEST_ESP_OK(spi_slave_disable(TEST_SPI_HOST));
|
||||
TEST_ESP_OK(esp_light_sleep_start());
|
||||
TEST_ESP_OK(spi_slave_enable(TEST_SPI_HOST));
|
||||
printf("Waked up!\n");
|
||||
|
||||
// check if the sleep happened as expected
|
||||
TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result);
|
||||
#if SOC_SPI_SUPPORT_SLEEP_RETENTION
|
||||
#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||
// check if the power domain also is powered down
|
||||
TEST_ASSERT_EQUAL((buscfg.flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) ? PMU_SLEEP_PD_TOP : 0, (sleep_ctx.sleep_flags) & PMU_SLEEP_PD_TOP);
|
||||
#endif
|
||||
|
@ -6,7 +6,7 @@ import pytest
|
||||
# If `test_env` is define, should not run on generic runner
|
||||
@pytest.mark.supported_targets
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.parametrize('config', ['defaults',], indirect=True)
|
||||
@pytest.mark.parametrize('config', ['release', 'iram_safe'], indirect=True)
|
||||
def test_slave_single_dev(case_tester) -> None: # type: ignore
|
||||
for case in case_tester.test_menu:
|
||||
if 'test_env' in case.attributes:
|
||||
@ -19,7 +19,7 @@ def test_slave_single_dev(case_tester) -> None: # type: ignore
|
||||
@pytest.mark.temp_skip_ci(targets=['esp32c61'], reason='no multi-dev runner')
|
||||
@pytest.mark.supported_targets
|
||||
@pytest.mark.generic_multi_device
|
||||
@pytest.mark.parametrize('count, config', [(2, 'defaults'), (2, 'iram_safe')], indirect=True)
|
||||
@pytest.mark.parametrize('count, config', [(2, 'release'), (2, 'iram_safe')], indirect=True)
|
||||
def test_slave_multi_dev(case_tester) -> None: # type: ignore
|
||||
for case in case_tester.test_menu:
|
||||
if case.attributes.get('test_env', 'generic_multi_device') == 'generic_multi_device':
|
||||
|
@ -3,5 +3,6 @@ CONFIG_SPI_MASTER_ISR_IN_IRAM=n
|
||||
CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_NONE=y
|
||||
CONFIG_ESP_IPC_TASK_STACK_SIZE=2048
|
||||
# silent the error check, as the error string are stored in rodata, causing RTL check failure
|
||||
CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y
|
||||
|
@ -1084,9 +1084,11 @@ TEST_CASE("test_spi_slave_hd_sleep_retention", "[spi]")
|
||||
spi_slave_hd_data_t *ret_trans, tx_data = {
|
||||
.data = slv_send,
|
||||
.len = sizeof(slv_send),
|
||||
.flags = SPI_SLAVE_HD_TRANS_DMA_BUFFER_ALIGN_AUTO,
|
||||
}, rx_data = {
|
||||
.data = slv_rexcv,
|
||||
.len = sizeof(slv_rexcv),
|
||||
.flags = SPI_SLAVE_HD_TRANS_DMA_BUFFER_ALIGN_AUTO,
|
||||
};
|
||||
|
||||
for (uint8_t allow_pd = 0; allow_pd < 2; allow_pd ++) {
|
||||
@ -1100,11 +1102,13 @@ TEST_CASE("test_spi_slave_hd_sleep_retention", "[spi]")
|
||||
|
||||
for (uint8_t cnt = 0; cnt < 3; cnt ++) {
|
||||
printf("Going into sleep with power %s ...\n", (bus_cfg.flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) ? "down" : "hold");
|
||||
TEST_ESP_OK(spi_slave_hd_disable(TEST_SLAVE_HOST));
|
||||
TEST_ESP_OK(esp_light_sleep_start());
|
||||
TEST_ESP_OK(spi_slave_hd_enable(TEST_SLAVE_HOST));
|
||||
printf("Waked up!\n");
|
||||
// check if the sleep happened as expected
|
||||
TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result);
|
||||
#if SOC_SPI_SUPPORT_SLEEP_RETENTION
|
||||
#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||
// check if the power domain also is powered down
|
||||
TEST_ASSERT_EQUAL((bus_cfg.flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) ? PMU_SLEEP_PD_TOP : 0, (sleep_ctx.sleep_flags) & PMU_SLEEP_PD_TOP);
|
||||
#endif
|
||||
@ -1125,6 +1129,7 @@ TEST_CASE("test_spi_slave_hd_sleep_retention", "[spi]")
|
||||
spi_master_trans_impl_gpio(bus_cfg, slave_hd_cfg.spics_io_num, 0, &slave_hd_cmd[1][1], NULL, 3);
|
||||
|
||||
// check trans result
|
||||
TEST_ESP_OK(spi_slave_hd_get_trans_res(TEST_SLAVE_HOST, SPI_SLAVE_CHAN_TX, &ret_trans, portMAX_DELAY));
|
||||
TEST_ESP_OK(spi_slave_hd_get_trans_res(TEST_SLAVE_HOST, SPI_SLAVE_CHAN_RX, &ret_trans, portMAX_DELAY));
|
||||
printf("master rx %s", mst_rexcv);
|
||||
printf("slave rx %s", slv_rexcv);
|
||||
@ -1168,6 +1173,7 @@ TEST_CASE("test_spi_slave_hd_append_sleep_retention", "[spi]")
|
||||
spi_slave_hd_data_t *ret_trans, tx_data[TEST_SLP_TRANS_NUM], rx_data = {
|
||||
.data = slv_rexcv,
|
||||
.len = sizeof(slv_rexcv),
|
||||
.flags = SPI_SLAVE_HD_TRANS_DMA_BUFFER_ALIGN_AUTO,
|
||||
};
|
||||
|
||||
spi_bus_config_t bus_cfg = SPI_BUS_TEST_DEFAULT_CONFIG();
|
||||
@ -1182,11 +1188,13 @@ TEST_CASE("test_spi_slave_hd_append_sleep_retention", "[spi]")
|
||||
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
printf("Going into sleep with power down ...\n");
|
||||
TEST_ESP_OK(spi_slave_hd_disable(TEST_SLAVE_HOST));
|
||||
TEST_ESP_OK(esp_light_sleep_start());
|
||||
TEST_ESP_OK(spi_slave_hd_enable(TEST_SLAVE_HOST));
|
||||
printf("Waked up!\n");
|
||||
// check if the sleep happened as expected
|
||||
TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result);
|
||||
#if SOC_SPI_SUPPORT_SLEEP_RETENTION
|
||||
#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||
// check if the power domain also is powered down
|
||||
TEST_ASSERT_EQUAL((bus_cfg.flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) ? PMU_SLEEP_PD_TOP : 0, (sleep_ctx.sleep_flags) & PMU_SLEEP_PD_TOP);
|
||||
#endif
|
||||
@ -1196,6 +1204,7 @@ TEST_CASE("test_spi_slave_hd_append_sleep_retention", "[spi]")
|
||||
slv_send[cnt][11] = cnt + i + '0';
|
||||
tx_data[cnt].data = slv_send[cnt];
|
||||
tx_data[cnt].len = sizeof(slv_send[0]);
|
||||
tx_data[cnt].flags |= SPI_SLAVE_HD_TRANS_DMA_BUFFER_ALIGN_AUTO;
|
||||
TEST_ESP_OK(spi_slave_hd_append_trans(TEST_SLAVE_HOST, SPI_SLAVE_CHAN_TX, &tx_data[cnt], portMAX_DELAY));
|
||||
TEST_ESP_OK(spi_slave_hd_append_trans(TEST_SLAVE_HOST, SPI_SLAVE_CHAN_RX, &rx_data, portMAX_DELAY));
|
||||
}
|
||||
@ -1215,6 +1224,7 @@ TEST_CASE("test_spi_slave_hd_append_sleep_retention", "[spi]")
|
||||
spi_master_trans_impl_gpio(bus_cfg, slave_hd_cfg.spics_io_num, 0, &slave_hd_cmd[1][1], NULL, 3);
|
||||
|
||||
// check append trans result
|
||||
TEST_ESP_OK(spi_slave_hd_get_append_trans_res(TEST_SLAVE_HOST, SPI_SLAVE_CHAN_TX, &ret_trans, portMAX_DELAY));
|
||||
TEST_ESP_OK(spi_slave_hd_get_append_trans_res(TEST_SLAVE_HOST, SPI_SLAVE_CHAN_RX, &ret_trans, portMAX_DELAY));
|
||||
printf("master rx %s", mst_rexcv);
|
||||
printf("slave rx %s", slv_rexcv);
|
||||
|
@ -14,6 +14,7 @@ import pytest
|
||||
@pytest.mark.esp32h2
|
||||
@pytest.mark.esp32p4
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.parametrize('config', ['release'], indirect=True)
|
||||
def test_slave_hd_single_dev(case_tester) -> None: # type: ignore
|
||||
for case in case_tester.test_menu:
|
||||
if 'test_env' in case.attributes:
|
||||
@ -31,7 +32,7 @@ def test_slave_hd_single_dev(case_tester) -> None: # type: ignore
|
||||
@pytest.mark.esp32h2
|
||||
@pytest.mark.esp32p4
|
||||
@pytest.mark.generic_multi_device
|
||||
@pytest.mark.parametrize('count', [2,], indirect=True)
|
||||
@pytest.mark.parametrize('count, config', [(2, 'release')], indirect=True)
|
||||
def test_slave_hd_multi_dev(case_tester) -> None: # type: ignore
|
||||
for case in case_tester.test_menu:
|
||||
if case.attributes.get('test_env', 'generic_multi_device') == 'generic_multi_device':
|
||||
|
@ -95,6 +95,8 @@ Driver Usage
|
||||
|
||||
- Before initiating transactions, fill one or more :cpp:type:`spi_slave_transaction_t` structs with the transaction parameters required. Either queue all transactions by calling the function :cpp:func:`spi_slave_queue_trans` and, at a later time, query the result by using the function :cpp:func:`spi_slave_get_trans_result`, or handle all requests individually by feeding them into :cpp:func:`spi_slave_transmit`. The latter two functions will be blocked until the Host has initiated and finished a transaction, causing the queued data to be sent and received.
|
||||
|
||||
- (Optional) Enable/Disable driver functions: Slave driver supports disabling / enabling driver after it is initialized by calling to :cpp:func:`spi_slave_disable` / :cpp:func:`spi_slave_enable`, to be able to change clock or power config or sleep to save power. By default, the driver state is `enabled` after initialized.
|
||||
|
||||
- (Optional) To unload the SPI slave driver, call :cpp:func:`spi_slave_free`.
|
||||
|
||||
|
||||
|
@ -48,6 +48,11 @@ Call :cpp:func:`spi_slave_hd_init` to initialize the SPI bus as well as the peri
|
||||
|
||||
The :cpp:type:`spi_bus_config_t` specifies how the bus should be initialized, while :cpp:type:`spi_slave_hd_slot_config_t` specifies how the SPI Slave driver should work.
|
||||
|
||||
Enable/Disable Driver (Optional)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Slave driver supports disabling / enabling driver after it is initialized by calling to :cpp:func:`spi_slave_hd_disable` / :cpp:func:`spi_slave_hd_enable`, to be able to change clock or power config or sleep to save power. By default, the driver state is `enabled` after initialized.
|
||||
|
||||
Deinitialization (Optional)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -95,6 +95,8 @@ SPI 传输事务
|
||||
|
||||
- 传输事务开始前,需用要求的事务参数填充一个或多个 :cpp:type:`spi_slave_transaction_t` 结构体。可以通过调用函数 :cpp:func:`spi_slave_queue_trans` 来将所有传输事务排进队列,并在稍后使用函数 :cpp:func:`spi_slave_get_trans_result` 查询结果;也可以将所有请求输入 :cpp:func:`spi_slave_transmit` 中单独处理。主机上的传输事务完成前,后两个函数将被阻塞,以便发送并接收队列中的数据。
|
||||
|
||||
- (可选)启用/禁用驱动程序功能:从机驱动程序支持在程序初始化后通过调用 :cpp:func:`spi_slave_disable` / :cpp:func:`spi_slave_enable` 来禁用/启用驱动程序,以便能够更改时钟或电源配置或休眠以节省电量。默认情况下,驱动程序在初始化后为“启用”状态。
|
||||
|
||||
- (可选)如需卸载 SPI 从机驱动程序,请调用 :cpp:func:`spi_slave_free`。
|
||||
|
||||
|
||||
|
@ -48,6 +48,11 @@ SPI 从机半双工模式
|
||||
|
||||
结构体 :cpp:type:`spi_bus_config_t` 指定了总线的初始化方式,结构体 :cpp:type:`spi_slave_hd_slot_config_t` 指定了 SPI 从机驱动程序的运行方式。
|
||||
|
||||
启用/禁用从机驱动(可选)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
从机驱动程序支持在程序初始化后通过调用 :cpp:func:`spi_slave_hd_disable` / :cpp:func:`spi_slave_hd_enable` 来禁用/启用驱动程序,以便能够更改时钟或电源配置或休眠以节省电量。默认情况下,驱动程序在初始化后为“启用”状态。
|
||||
|
||||
从机反初始化(可选)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -121,7 +121,17 @@ void app_main(void)
|
||||
//spi_slave_transmit does not return until the master has done a transmission, so by here we have sent our data and
|
||||
//received data from the master. Print it.
|
||||
printf("Received: %s\n", recvbuf);
|
||||
|
||||
//pause the slave to save power, transaction will also be paused
|
||||
ret = spi_slave_disable(RCV_HOST);
|
||||
if (ret == ESP_OK) {
|
||||
printf("slave paused ...\n");
|
||||
}
|
||||
vTaskDelay(100); //now is able to sleep or do something to save power, any following transaction will be ignored
|
||||
ret = spi_slave_enable(RCV_HOST);
|
||||
if (ret == ESP_OK) {
|
||||
printf("slave ready !\n");
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user