forked from espressif/esp-idf
feat(driver_spi): slave hd driver sleep retention support
This commit is contained in:
@ -13,6 +13,7 @@
|
|||||||
#include "freertos/queue.h"
|
#include "freertos/queue.h"
|
||||||
#include "freertos/ringbuf.h"
|
#include "freertos/ringbuf.h"
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
|
#include "esp_private/sleep_retention.h"
|
||||||
#include "esp_private/spi_common_internal.h"
|
#include "esp_private/spi_common_internal.h"
|
||||||
#include "esp_private/spi_share_hw_ctrl.h"
|
#include "esp_private/spi_share_hw_ctrl.h"
|
||||||
#include "esp_private/esp_cache_private.h"
|
#include "esp_private/esp_cache_private.h"
|
||||||
@ -36,7 +37,7 @@ typedef struct {
|
|||||||
} spi_slave_hd_trans_priv_t;
|
} spi_slave_hd_trans_priv_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool dma_enabled;
|
spi_host_device_t host_id;
|
||||||
spi_dma_ctx_t *dma_ctx;
|
spi_dma_ctx_t *dma_ctx;
|
||||||
uint16_t internal_mem_align_size;
|
uint16_t internal_mem_align_size;
|
||||||
int max_transfer_sz;
|
int max_transfer_sz;
|
||||||
@ -79,6 +80,17 @@ static void s_spi_slave_hd_append_legacy_isr(void *arg);
|
|||||||
|
|
||||||
static void s_spi_slave_hd_segment_isr(void *arg);
|
static void s_spi_slave_hd_segment_isr(void *arg);
|
||||||
|
|
||||||
|
#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||||
|
static esp_err_t s_spi_create_sleep_retention_cb(void *arg)
|
||||||
|
{
|
||||||
|
spi_slave_hd_slot_t *host = arg;
|
||||||
|
return sleep_retention_entries_create(spi_reg_retention_info[host->host_id - 1].entry_array,
|
||||||
|
spi_reg_retention_info[host->host_id - 1].array_size,
|
||||||
|
REGDMA_LINK_PRI_GPSPI,
|
||||||
|
spi_reg_retention_info[host->host_id - 1].module_id);
|
||||||
|
}
|
||||||
|
#endif // SOC_SPI_SUPPORT_SLEEP_RETENTION
|
||||||
|
|
||||||
esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *bus_config, const spi_slave_hd_slot_config_t *config)
|
esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *bus_config, const spi_slave_hd_slot_config_t *config)
|
||||||
{
|
{
|
||||||
bool spi_chan_claimed;
|
bool spi_chan_claimed;
|
||||||
@ -86,10 +98,11 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
|
|||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
|
|
||||||
SPIHD_CHECK(VALID_HOST(host_id), "invalid host", ESP_ERR_INVALID_ARG);
|
SPIHD_CHECK(VALID_HOST(host_id), "invalid host", ESP_ERR_INVALID_ARG);
|
||||||
|
//DMA is mandatory required for slave HD driver, check here for better experience to `transmit` api
|
||||||
#if CONFIG_IDF_TARGET_ESP32S2
|
#if CONFIG_IDF_TARGET_ESP32S2
|
||||||
SPIHD_CHECK(config->dma_chan == SPI_DMA_DISABLED || config->dma_chan == (int)host_id || config->dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel", ESP_ERR_INVALID_ARG);
|
SPIHD_CHECK(config->dma_chan == (int)host_id || config->dma_chan == SPI_DMA_CH_AUTO, "dma is required or invalid channel", ESP_ERR_INVALID_ARG);
|
||||||
#elif SOC_GDMA_SUPPORTED
|
#elif SOC_GDMA_SUPPORTED
|
||||||
SPIHD_CHECK(config->dma_chan == SPI_DMA_DISABLED || config->dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel, chip only support spi dma channel auto-alloc", ESP_ERR_INVALID_ARG);
|
SPIHD_CHECK(config->dma_chan == SPI_DMA_CH_AUTO, "dma is required or invalid channel, only support SPI_DMA_CH_AUTO", ESP_ERR_INVALID_ARG);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
spi_chan_claimed = spicommon_periph_claim(host_id, "slave_hd");
|
spi_chan_claimed = spicommon_periph_claim(host_id, "slave_hd");
|
||||||
@ -101,54 +114,49 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
spihost[host_id] = host;
|
spihost[host_id] = host;
|
||||||
|
host->host_id = host_id;
|
||||||
host->int_spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
host->int_spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||||
host->dma_enabled = (config->dma_chan != SPI_DMA_DISABLED);
|
|
||||||
host->append_mode = append_mode;
|
host->append_mode = append_mode;
|
||||||
|
|
||||||
if (host->dma_enabled) {
|
ret = spicommon_dma_chan_alloc(host_id, config->dma_chan, &host->dma_ctx);
|
||||||
ret = spicommon_dma_chan_alloc(host_id, config->dma_chan, &host->dma_ctx);
|
if (ret != ESP_OK) {
|
||||||
if (ret != ESP_OK) {
|
goto cleanup;
|
||||||
goto cleanup;
|
}
|
||||||
}
|
|
||||||
#if SOC_GDMA_SUPPORTED
|
#if SOC_GDMA_SUPPORTED
|
||||||
gdma_strategy_config_t dma_strategy = {
|
gdma_strategy_config_t dma_strategy = {
|
||||||
.auto_update_desc = true,
|
.auto_update_desc = true,
|
||||||
.eof_till_data_popped = true,
|
.eof_till_data_popped = true,
|
||||||
};
|
};
|
||||||
gdma_apply_strategy(host->dma_ctx->tx_dma_chan, &dma_strategy);
|
gdma_apply_strategy(host->dma_ctx->tx_dma_chan, &dma_strategy);
|
||||||
#else
|
#else
|
||||||
spi_dma_ll_enable_out_auto_wrback(SPI_LL_GET_HW(host->dma_ctx->tx_dma_chan.host_id), host->dma_ctx->tx_dma_chan.chan_id, 1);
|
spi_dma_ll_enable_out_auto_wrback(SPI_LL_GET_HW(host->dma_ctx->tx_dma_chan.host_id), host->dma_ctx->tx_dma_chan.chan_id, 1);
|
||||||
spi_dma_ll_set_out_eof_generation(SPI_LL_GET_HW(host->dma_ctx->tx_dma_chan.host_id), host->dma_ctx->tx_dma_chan.chan_id, 1);
|
spi_dma_ll_set_out_eof_generation(SPI_LL_GET_HW(host->dma_ctx->tx_dma_chan.host_id), host->dma_ctx->tx_dma_chan.chan_id, 1);
|
||||||
#endif
|
#endif
|
||||||
ret = spicommon_dma_desc_alloc(host->dma_ctx, bus_config->max_transfer_sz, &host->max_transfer_sz);
|
ret = spicommon_dma_desc_alloc(host->dma_ctx, bus_config->max_transfer_sz, &host->max_transfer_sz);
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
host->hal.dma_desc_num = host->dma_ctx->dma_desc_num;
|
host->hal.dma_desc_num = host->dma_ctx->dma_desc_num;
|
||||||
host->hal.dmadesc_tx = heap_caps_malloc(sizeof(spi_slave_hd_hal_desc_append_t) * host->hal.dma_desc_num, MALLOC_CAP_DEFAULT);
|
host->hal.dmadesc_tx = heap_caps_malloc(sizeof(spi_slave_hd_hal_desc_append_t) * host->hal.dma_desc_num, MALLOC_CAP_DEFAULT);
|
||||||
host->hal.dmadesc_rx = heap_caps_malloc(sizeof(spi_slave_hd_hal_desc_append_t) * host->hal.dma_desc_num, MALLOC_CAP_DEFAULT);
|
host->hal.dmadesc_rx = heap_caps_malloc(sizeof(spi_slave_hd_hal_desc_append_t) * host->hal.dma_desc_num, MALLOC_CAP_DEFAULT);
|
||||||
if (!(host->hal.dmadesc_tx && host->hal.dmadesc_rx)) {
|
if (!(host->hal.dmadesc_tx && host->hal.dmadesc_rx)) {
|
||||||
ret = ESP_ERR_NO_MEM;
|
ret = ESP_ERR_NO_MEM;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
//Pair each desc to each possible trans
|
//Pair each desc to each possible trans
|
||||||
for (int i = 0; i < host->hal.dma_desc_num; i ++) {
|
for (int i = 0; i < host->hal.dma_desc_num; i ++) {
|
||||||
host->hal.dmadesc_tx[i].desc = &host->dma_ctx->dmadesc_tx[i];
|
host->hal.dmadesc_tx[i].desc = &host->dma_ctx->dmadesc_tx[i];
|
||||||
host->hal.dmadesc_rx[i].desc = &host->dma_ctx->dmadesc_rx[i];
|
host->hal.dmadesc_rx[i].desc = &host->dma_ctx->dmadesc_rx[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||||
size_t alignment;
|
size_t alignment;
|
||||||
esp_cache_get_alignment(MALLOC_CAP_DMA, &alignment);
|
esp_cache_get_alignment(MALLOC_CAP_DMA, &alignment);
|
||||||
host->internal_mem_align_size = alignment;
|
host->internal_mem_align_size = alignment;
|
||||||
#else
|
#else
|
||||||
host->internal_mem_align_size = 4;
|
host->internal_mem_align_size = 4;
|
||||||
#endif
|
#endif
|
||||||
} else {
|
|
||||||
//We're limited to non-DMA transfers: the SPI work registers can hold (72 for S2, 64 for others) bytes at most.
|
|
||||||
host->max_transfer_sz = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = spicommon_bus_initialize_io(host_id, bus_config, SPICOMMON_BUSFLAG_SLAVE | bus_config->flags, &host->flags);
|
ret = spicommon_bus_initialize_io(host_id, bus_config, SPICOMMON_BUSFLAG_SLAVE | bus_config->flags, &host->flags);
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
@ -159,7 +167,7 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
|
|||||||
|
|
||||||
spi_slave_hd_hal_config_t hal_config = {
|
spi_slave_hd_hal_config_t hal_config = {
|
||||||
.host_id = host_id,
|
.host_id = host_id,
|
||||||
.dma_enabled = host->dma_enabled,
|
.dma_enabled = true,
|
||||||
.append_mode = append_mode,
|
.append_mode = append_mode,
|
||||||
.mode = config->mode,
|
.mode = config->mode,
|
||||||
.tx_lsbfirst = (config->flags & SPI_SLAVE_HD_RXBIT_LSBFIRST),
|
.tx_lsbfirst = (config->flags & SPI_SLAVE_HD_RXBIT_LSBFIRST),
|
||||||
@ -178,6 +186,32 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
|
|||||||
esp_pm_lock_acquire(host->pm_lock);
|
esp_pm_lock_acquire(host->pm_lock);
|
||||||
#endif //CONFIG_PM_ENABLE
|
#endif //CONFIG_PM_ENABLE
|
||||||
|
|
||||||
|
#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||||
|
sleep_retention_module_init_param_t init_param = {
|
||||||
|
.cbs = {
|
||||||
|
.create = {
|
||||||
|
.handle = s_spi_create_sleep_retention_cb,
|
||||||
|
.arg = host,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.depends = RETENTION_MODULE_BITMAP_INIT(CLOCK_SYSTEM),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ESP_OK == sleep_retention_module_init(spi_reg_retention_info[host_id - 1].module_id, &init_param)) {
|
||||||
|
if ((bus_config->flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) && (sleep_retention_module_allocate(spi_reg_retention_info[host_id - 1].module_id) != ESP_OK)) {
|
||||||
|
// even though the sleep retention create failed, SPI driver should still work, so just warning here
|
||||||
|
ESP_LOGW(TAG, "Alloc sleep recover failed, spi may hold power on");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// even the sleep retention init failed, SPI driver should still work, so just warning here
|
||||||
|
ESP_LOGW(TAG, "Init sleep recover failed, spi may offline after sleep");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (bus_config->flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) {
|
||||||
|
ESP_LOGE(TAG, "power down peripheral in sleep is not enabled or not supported on your target");
|
||||||
|
}
|
||||||
|
#endif // SOC_SPI_SUPPORT_SLEEP_RETENTION
|
||||||
|
|
||||||
//Create Queues and Semaphores
|
//Create Queues and Semaphores
|
||||||
host->tx_ret_queue = xQueueCreate(config->queue_size, sizeof(spi_slave_hd_trans_priv_t));
|
host->tx_ret_queue = xQueueCreate(config->queue_size, sizeof(spi_slave_hd_trans_priv_t));
|
||||||
host->rx_ret_queue = xQueueCreate(config->queue_size, sizeof(spi_slave_hd_trans_priv_t));
|
host->rx_ret_queue = xQueueCreate(config->queue_size, sizeof(spi_slave_hd_trans_priv_t));
|
||||||
@ -279,6 +313,17 @@ esp_err_t spi_slave_hd_deinit(spi_host_device_t host_id)
|
|||||||
}
|
}
|
||||||
esp_intr_free(host->intr);
|
esp_intr_free(host->intr);
|
||||||
esp_intr_free(host->intr_dma);
|
esp_intr_free(host->intr_dma);
|
||||||
|
|
||||||
|
#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||||
|
const periph_retention_module_t retention_id = spi_reg_retention_info[host_id - 1].module_id;
|
||||||
|
if (sleep_retention_is_module_created(retention_id)) {
|
||||||
|
assert(sleep_retention_is_module_inited(retention_id));
|
||||||
|
sleep_retention_module_free(retention_id);
|
||||||
|
}
|
||||||
|
if (sleep_retention_is_module_inited(retention_id)) {
|
||||||
|
sleep_retention_module_deinit(retention_id);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_PM_ENABLE
|
#ifdef CONFIG_PM_ENABLE
|
||||||
if (host->pm_lock) {
|
if (host->pm_lock) {
|
||||||
esp_pm_lock_release(host->pm_lock);
|
esp_pm_lock_release(host->pm_lock);
|
||||||
@ -287,13 +332,12 @@ esp_err_t spi_slave_hd_deinit(spi_host_device_t host_id)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
spicommon_periph_free(host_id);
|
spicommon_periph_free(host_id);
|
||||||
if (host->dma_enabled) {
|
free(host->dma_ctx->dmadesc_tx);
|
||||||
free(host->dma_ctx->dmadesc_tx);
|
free(host->dma_ctx->dmadesc_rx);
|
||||||
free(host->dma_ctx->dmadesc_rx);
|
free(host->hal.dmadesc_tx);
|
||||||
free(host->hal.dmadesc_tx);
|
free(host->hal.dmadesc_rx);
|
||||||
free(host->hal.dmadesc_rx);
|
spicommon_dma_chan_free(host->dma_ctx);
|
||||||
spicommon_dma_chan_free(host->dma_ctx);
|
|
||||||
}
|
|
||||||
free(host);
|
free(host);
|
||||||
spihost[host_id] = NULL;
|
spihost[host_id] = NULL;
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
|
@ -7,18 +7,20 @@
|
|||||||
Tests for the spi slave hd mode
|
Tests for the spi slave hd mode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "string.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "test_utils.h"
|
#include "test_utils.h"
|
||||||
#include "test_spi_utils.h"
|
#include "test_spi_utils.h"
|
||||||
#include "soc/spi_periph.h"
|
|
||||||
#include "esp_serial_slave_link/essl_spi.h"
|
|
||||||
#include "test_dualboard_utils.h"
|
#include "test_dualboard_utils.h"
|
||||||
|
#include "hal/spi_ll.h"
|
||||||
#if SOC_SPI_SUPPORT_SLAVE_HD_VER2
|
#include "driver/gpio.h"
|
||||||
#include "driver/spi_slave_hd.h"
|
#include "driver/spi_slave_hd.h"
|
||||||
|
#include "esp_serial_slave_link/essl_spi.h"
|
||||||
|
#include "esp_private/sleep_cpu.h"
|
||||||
|
#include "esp_private/esp_sleep_internal.h"
|
||||||
|
#include "esp_private/esp_pmu.h"
|
||||||
|
|
||||||
#if (TEST_SPI_PERIPH_NUM >= 2) //These will be only enabled on chips with 2 or more SPI peripherals
|
#if (TEST_SPI_PERIPH_NUM >= 2) //These will be only enabled on chips with 2 or more SPI peripherals
|
||||||
|
|
||||||
#include "esp_rom_gpio.h"
|
#include "esp_rom_gpio.h"
|
||||||
|
|
||||||
#define TEST_BUFFER_SIZE 256 ///< buffer size of each wrdma buffer in fifo mode
|
#define TEST_BUFFER_SIZE 256 ///< buffer size of each wrdma buffer in fifo mode
|
||||||
@ -110,7 +112,6 @@ static void init_slave_hd(int mode, bool append_mode, const spi_slave_hd_callbac
|
|||||||
#endif
|
#endif
|
||||||
spi_slave_hd_slot_config_t slave_hd_cfg = SPI_SLOT_TEST_DEFAULT_CONFIG();
|
spi_slave_hd_slot_config_t slave_hd_cfg = SPI_SLOT_TEST_DEFAULT_CONFIG();
|
||||||
slave_hd_cfg.mode = mode;
|
slave_hd_cfg.mode = mode;
|
||||||
slave_hd_cfg.dma_chan = SPI_DMA_CH_AUTO;
|
|
||||||
if (append_mode) {
|
if (append_mode) {
|
||||||
slave_hd_cfg.flags |= SPI_SLAVE_HD_APPEND_MODE;
|
slave_hd_cfg.flags |= SPI_SLAVE_HD_APPEND_MODE;
|
||||||
}
|
}
|
||||||
@ -680,16 +681,7 @@ static void hd_slave(void)
|
|||||||
spi_bus_config_t bus_cfg = SPI_BUS_TEST_DEFAULT_CONFIG();
|
spi_bus_config_t bus_cfg = SPI_BUS_TEST_DEFAULT_CONFIG();
|
||||||
bus_cfg.max_transfer_sz = 14000 * 30;
|
bus_cfg.max_transfer_sz = 14000 * 30;
|
||||||
|
|
||||||
spi_slave_hd_slot_config_t slave_hd_cfg = {
|
spi_slave_hd_slot_config_t slave_hd_cfg = SPI_SLOT_TEST_DEFAULT_CONFIG();
|
||||||
.spics_io_num = PIN_NUM_CS,
|
|
||||||
.dma_chan = SPI_DMA_CH_AUTO,
|
|
||||||
.flags = 0,
|
|
||||||
.mode = 0,
|
|
||||||
.command_bits = 8,
|
|
||||||
.address_bits = 8,
|
|
||||||
.dummy_bits = 8,
|
|
||||||
.queue_size = 10,
|
|
||||||
};
|
|
||||||
TEST_ESP_OK(spi_slave_hd_init(TEST_SLAVE_HOST, &bus_cfg, &slave_hd_cfg));
|
TEST_ESP_OK(spi_slave_hd_init(TEST_SLAVE_HOST, &bus_cfg, &slave_hd_cfg));
|
||||||
|
|
||||||
unity_wait_for_signal("master ready");
|
unity_wait_for_signal("master ready");
|
||||||
@ -831,16 +823,7 @@ static void hd_slave_quad(void)
|
|||||||
.max_transfer_sz = 14000 * 30
|
.max_transfer_sz = 14000 * 30
|
||||||
};
|
};
|
||||||
|
|
||||||
spi_slave_hd_slot_config_t slave_hd_cfg = {
|
spi_slave_hd_slot_config_t slave_hd_cfg = SPI_SLOT_TEST_DEFAULT_CONFIG();
|
||||||
.spics_io_num = PIN_NUM_CS,
|
|
||||||
.dma_chan = SPI_DMA_CH_AUTO,
|
|
||||||
.flags = 0,
|
|
||||||
.mode = 0,
|
|
||||||
.command_bits = 8,
|
|
||||||
.address_bits = 8,
|
|
||||||
.dummy_bits = 8,
|
|
||||||
.queue_size = 10,
|
|
||||||
};
|
|
||||||
TEST_ESP_OK(spi_slave_hd_init(TEST_SLAVE_HOST, &bus_cfg, &slave_hd_cfg));
|
TEST_ESP_OK(spi_slave_hd_init(TEST_SLAVE_HOST, &bus_cfg, &slave_hd_cfg));
|
||||||
|
|
||||||
WORD_ALIGNED_ATTR uint8_t *slave_send_buf = heap_caps_malloc(BUF_SIZE, MALLOC_CAP_DMA);
|
WORD_ALIGNED_ATTR uint8_t *slave_send_buf = heap_caps_malloc(BUF_SIZE, MALLOC_CAP_DMA);
|
||||||
@ -928,7 +911,6 @@ void slave_run_append(void)
|
|||||||
|
|
||||||
spi_slave_hd_slot_config_t slave_hd_cfg = SPI_SLOT_TEST_DEFAULT_CONFIG();
|
spi_slave_hd_slot_config_t slave_hd_cfg = SPI_SLOT_TEST_DEFAULT_CONFIG();
|
||||||
slave_hd_cfg.flags |= SPI_SLAVE_HD_APPEND_MODE;
|
slave_hd_cfg.flags |= SPI_SLAVE_HD_APPEND_MODE;
|
||||||
slave_hd_cfg.dma_chan = SPI_DMA_CH_AUTO;
|
|
||||||
TEST_ESP_OK(spi_slave_hd_init(TEST_SPI_HOST, &bus_cfg, &slave_hd_cfg));
|
TEST_ESP_OK(spi_slave_hd_init(TEST_SPI_HOST, &bus_cfg, &slave_hd_cfg));
|
||||||
|
|
||||||
unity_wait_for_signal("Master ready");
|
unity_wait_for_signal("Master ready");
|
||||||
@ -1032,9 +1014,12 @@ void master_run_essl(void)
|
|||||||
bus_cfg.max_transfer_sz = 50000;
|
bus_cfg.max_transfer_sz = 50000;
|
||||||
TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST, &bus_cfg, SPI_DMA_CH_AUTO));
|
TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST, &bus_cfg, SPI_DMA_CH_AUTO));
|
||||||
|
|
||||||
spi_device_interface_config_t dev_cfg = SPI_SLOT_TEST_DEFAULT_CONFIG();
|
spi_device_interface_config_t dev_cfg = SPI_DEVICE_TEST_DEFAULT_CONFIG();
|
||||||
dev_cfg.clock_speed_hz = 1 * 1000 * 1000;
|
|
||||||
dev_cfg.flags = SPI_DEVICE_HALFDUPLEX;
|
dev_cfg.flags = SPI_DEVICE_HALFDUPLEX;
|
||||||
|
dev_cfg.clock_speed_hz = 1 * 1000 * 1000;
|
||||||
|
dev_cfg.command_bits = 8;
|
||||||
|
dev_cfg.address_bits = 8;
|
||||||
|
dev_cfg.dummy_bits = 8;
|
||||||
TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &dev_cfg, &devhd));
|
TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &dev_cfg, &devhd));
|
||||||
|
|
||||||
printf("\n================Master Tx==================\n");
|
printf("\n================Master Tx==================\n");
|
||||||
@ -1076,6 +1061,170 @@ void master_run_essl(void)
|
|||||||
TEST_ESP_OK(spi_bus_remove_device(devhd));
|
TEST_ESP_OK(spi_bus_remove_device(devhd));
|
||||||
TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST));
|
TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_MULTIPLE_DEVICES("SPI Slave HD: Append mode", "[spi_ms]", master_run_essl, slave_run_append);
|
TEST_CASE_MULTIPLE_DEVICES("SPI Slave HD: Append mode", "[spi_ms]", master_run_essl, slave_run_append);
|
||||||
#endif //SOC_SPI_SUPPORT_SLAVE_HD_VER2
|
|
||||||
|
#define TEST_SLP_BUF_ID 12
|
||||||
|
#define TEST_SLP_BUF_VAL 0xDEADBEEF
|
||||||
|
TEST_CASE("test_spi_slave_hd_sleep_retention", "[spi]")
|
||||||
|
{
|
||||||
|
// Prepare a TOP PD sleep
|
||||||
|
TEST_ESP_OK(esp_sleep_enable_timer_wakeup(1 * 1000 * 1000));
|
||||||
|
#if ESP_SLEEP_POWER_DOWN_CPU
|
||||||
|
sleep_cpu_configure(true);
|
||||||
|
#endif
|
||||||
|
esp_sleep_context_t sleep_ctx;
|
||||||
|
esp_sleep_set_sleep_context(&sleep_ctx);
|
||||||
|
|
||||||
|
uint32_t slave_hd_cmd[2][2] = {{SPI_LL_BASE_CMD_HD_WRDMA, SPI_LL_BASE_CMD_HD_WR_END}, {SPI_LL_BASE_CMD_HD_RDDMA, SPI_LL_BASE_CMD_HD_INT0}};
|
||||||
|
uint32_t slave_share_sig = TEST_SLP_BUF_VAL;
|
||||||
|
uint8_t slv_send[14] = "I'm slave x\n", slv_rexcv[14];
|
||||||
|
uint8_t mst_txbuff[17] = " I'm master x\n", mst_rxbuff[17]; //more than 3 byte to hold cmd,addrs,dummy
|
||||||
|
uint8_t share_sig_buff[7] = {0}; // cmd + addr + dummy + uint32_t
|
||||||
|
uint8_t *mst_send = &mst_txbuff[3], *mst_rexcv = &mst_rxbuff[3];
|
||||||
|
spi_slave_hd_data_t *ret_trans, tx_data = {
|
||||||
|
.data = slv_send,
|
||||||
|
.len = sizeof(slv_send),
|
||||||
|
}, rx_data = {
|
||||||
|
.data = slv_rexcv,
|
||||||
|
.len = sizeof(slv_rexcv),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (uint8_t allow_pd = 0; allow_pd < 2; allow_pd ++) {
|
||||||
|
spi_bus_config_t bus_cfg = SPI_BUS_TEST_DEFAULT_CONFIG();
|
||||||
|
bus_cfg.flags = (allow_pd) ? SPICOMMON_BUSFLAG_SLP_ALLOW_PD : 0;
|
||||||
|
bus_cfg.flags |= SPICOMMON_BUSFLAG_GPIO_PINS;
|
||||||
|
spi_slave_hd_slot_config_t slave_hd_cfg = SPI_SLOT_TEST_DEFAULT_CONFIG();
|
||||||
|
TEST_ESP_OK(spi_slave_hd_init(TEST_SLAVE_HOST, &bus_cfg, &slave_hd_cfg));
|
||||||
|
gpio_pullup_en(slave_hd_cfg.spics_io_num);
|
||||||
|
vTaskDelay(1);
|
||||||
|
|
||||||
|
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(esp_light_sleep_start());
|
||||||
|
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
|
||||||
|
// 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
|
||||||
|
// test slave hd segment transactions
|
||||||
|
slv_send[11] = cnt + '0';
|
||||||
|
mst_send[11] = cnt + 'A';
|
||||||
|
memset(mst_rexcv, 0, sizeof(slv_send));
|
||||||
|
memset(slv_rexcv, 0, sizeof(slv_rexcv));
|
||||||
|
TEST_ESP_OK(spi_slave_hd_queue_trans(TEST_SLAVE_HOST, SPI_SLAVE_CHAN_TX, &tx_data, portMAX_DELAY));
|
||||||
|
TEST_ESP_OK(spi_slave_hd_queue_trans(TEST_SLAVE_HOST, SPI_SLAVE_CHAN_RX, &rx_data, portMAX_DELAY));
|
||||||
|
|
||||||
|
// tx rx transaction
|
||||||
|
mst_txbuff[0] = slave_hd_cmd[0][0];
|
||||||
|
spi_master_trans_impl_gpio(bus_cfg, slave_hd_cfg.spics_io_num, 0, mst_txbuff, NULL, sizeof(mst_txbuff));
|
||||||
|
spi_master_trans_impl_gpio(bus_cfg, slave_hd_cfg.spics_io_num, 0, &slave_hd_cmd[0][1], NULL, 3);
|
||||||
|
mst_rxbuff[0] = slave_hd_cmd[1][0];
|
||||||
|
spi_master_trans_impl_gpio(bus_cfg, slave_hd_cfg.spics_io_num, 0, mst_rxbuff, mst_rxbuff, sizeof(mst_rxbuff));
|
||||||
|
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_RX, &ret_trans, portMAX_DELAY));
|
||||||
|
printf("master rx %s", mst_rexcv);
|
||||||
|
printf("slave rx %s", slv_rexcv);
|
||||||
|
spitest_cmp_or_dump(slv_send, mst_rexcv, sizeof(slv_send));
|
||||||
|
spitest_cmp_or_dump(mst_send, slv_rexcv, sizeof(slv_rexcv));
|
||||||
|
|
||||||
|
// test slave hd share registers
|
||||||
|
slave_share_sig += cnt;
|
||||||
|
spi_slave_hd_write_buffer(TEST_SLAVE_HOST, TEST_SLP_BUF_ID, (uint8_t *)&slave_share_sig, sizeof(uint32_t));
|
||||||
|
memset(share_sig_buff, 0, sizeof(share_sig_buff));
|
||||||
|
share_sig_buff[0] = SPI_LL_BASE_CMD_HD_RDBUF; // cmd
|
||||||
|
share_sig_buff[1] = TEST_SLP_BUF_ID; // addr
|
||||||
|
spi_master_trans_impl_gpio(bus_cfg, slave_hd_cfg.spics_io_num, 0, share_sig_buff, share_sig_buff, sizeof(share_sig_buff));
|
||||||
|
printf("slave reg %lX\n", *((uint32_t *)&share_sig_buff[3]));
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(slave_share_sig, *((uint32_t *)&share_sig_buff[3]));
|
||||||
|
}
|
||||||
|
spi_slave_hd_deinit(TEST_SLAVE_HOST);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_sleep_set_sleep_context(NULL);
|
||||||
|
#if ESP_SLEEP_POWER_DOWN_CPU
|
||||||
|
TEST_ESP_OK(sleep_cpu_configure(false));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TEST_SLP_TRANS_NUM 3
|
||||||
|
TEST_CASE("test_spi_slave_hd_append_sleep_retention", "[spi]")
|
||||||
|
{
|
||||||
|
// Prepare a TOP PD sleep
|
||||||
|
TEST_ESP_OK(esp_sleep_enable_timer_wakeup(1 * 1000 * 1000));
|
||||||
|
#if ESP_SLEEP_POWER_DOWN_CPU
|
||||||
|
sleep_cpu_configure(true);
|
||||||
|
#endif
|
||||||
|
esp_sleep_context_t sleep_ctx;
|
||||||
|
esp_sleep_set_sleep_context(&sleep_ctx);
|
||||||
|
|
||||||
|
uint32_t slave_hd_cmd[2][2] = {{SPI_LL_BASE_CMD_HD_WRDMA, SPI_LL_BASE_CMD_HD_WR_END}, {SPI_LL_BASE_CMD_HD_RDDMA, SPI_LL_BASE_CMD_HD_INT0}};
|
||||||
|
uint8_t slv_rexcv[14], slv_send[TEST_SLP_TRANS_NUM][14] = {{"I'm append x\n"}, {"I'm append x\n"}, {"I'm append x\n"}};
|
||||||
|
uint8_t mst_txbuff[17] = " I'm master x\n", mst_rxbuff[17]; //more than 3 byte to hold cmd,addrs,dummy
|
||||||
|
uint8_t *mst_send = &mst_txbuff[3], *mst_rexcv = &mst_rxbuff[3];
|
||||||
|
spi_slave_hd_data_t *ret_trans, tx_data[TEST_SLP_TRANS_NUM], rx_data = {
|
||||||
|
.data = slv_rexcv,
|
||||||
|
.len = sizeof(slv_rexcv),
|
||||||
|
};
|
||||||
|
|
||||||
|
spi_bus_config_t bus_cfg = SPI_BUS_TEST_DEFAULT_CONFIG();
|
||||||
|
bus_cfg.max_transfer_sz = 4092 * 4; // append mode require at least 2 for tx and 2 for rx dma descs
|
||||||
|
bus_cfg.flags = SPICOMMON_BUSFLAG_SLP_ALLOW_PD;
|
||||||
|
bus_cfg.flags |= SPICOMMON_BUSFLAG_GPIO_PINS;
|
||||||
|
spi_slave_hd_slot_config_t slave_hd_cfg = SPI_SLOT_TEST_DEFAULT_CONFIG();
|
||||||
|
slave_hd_cfg.flags |= SPI_SLAVE_HD_APPEND_MODE;
|
||||||
|
TEST_ESP_OK(spi_slave_hd_init(TEST_SLAVE_HOST, &bus_cfg, &slave_hd_cfg));
|
||||||
|
gpio_pullup_en(slave_hd_cfg.spics_io_num);
|
||||||
|
vTaskDelay(1);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 2; i++) {
|
||||||
|
printf("Going into sleep with power down ...\n");
|
||||||
|
TEST_ESP_OK(esp_light_sleep_start());
|
||||||
|
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
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// append transaction first
|
||||||
|
for (uint8_t cnt = 0; cnt < TEST_SLP_TRANS_NUM; cnt ++) {
|
||||||
|
slv_send[cnt][11] = cnt + i + '0';
|
||||||
|
tx_data[cnt].data = slv_send[cnt];
|
||||||
|
tx_data[cnt].len = sizeof(slv_send[0]);
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
// test slave hd append transactions
|
||||||
|
for (uint8_t cnt = 0; cnt < TEST_SLP_TRANS_NUM; cnt ++) {
|
||||||
|
mst_send[11] = cnt + i + 'A';
|
||||||
|
memset(mst_rexcv, 0, sizeof(slv_send[0]));
|
||||||
|
memset(slv_rexcv, 0, sizeof(slv_rexcv));
|
||||||
|
|
||||||
|
// tx rx append transaction
|
||||||
|
mst_txbuff[0] = slave_hd_cmd[0][0];
|
||||||
|
spi_master_trans_impl_gpio(bus_cfg, slave_hd_cfg.spics_io_num, 0, mst_txbuff, NULL, sizeof(mst_txbuff));
|
||||||
|
spi_master_trans_impl_gpio(bus_cfg, slave_hd_cfg.spics_io_num, 0, &slave_hd_cmd[0][1], NULL, 3);
|
||||||
|
mst_rxbuff[0] = slave_hd_cmd[1][0];
|
||||||
|
spi_master_trans_impl_gpio(bus_cfg, slave_hd_cfg.spics_io_num, 0, mst_rxbuff, mst_rxbuff, sizeof(mst_rxbuff));
|
||||||
|
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_RX, &ret_trans, portMAX_DELAY));
|
||||||
|
printf("master rx %s", mst_rexcv);
|
||||||
|
printf("slave rx %s", slv_rexcv);
|
||||||
|
spitest_cmp_or_dump(slv_send[cnt], mst_rexcv, sizeof(slv_send[0]));
|
||||||
|
spitest_cmp_or_dump(mst_send, slv_rexcv, sizeof(slv_rexcv));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spi_slave_hd_deinit(TEST_SLAVE_HOST);
|
||||||
|
esp_sleep_set_sleep_context(NULL);
|
||||||
|
#if ESP_SLEEP_POWER_DOWN_CPU
|
||||||
|
TEST_ESP_OK(sleep_cpu_configure(false));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
CONFIG_PM_ENABLE=y
|
||||||
|
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
|
||||||
|
CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y
|
||||||
|
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||||
|
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||||
|
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
@ -1,2 +1,4 @@
|
|||||||
CONFIG_FREERTOS_HZ=1000
|
CONFIG_FREERTOS_HZ=1000
|
||||||
CONFIG_ESP_TASK_WDT=n
|
CONFIG_ESP_TASK_WDT_INIT=n
|
||||||
|
# primitives for checking sleep internal state
|
||||||
|
CONFIG_ESP_SLEEP_DEBUG=y
|
||||||
|
@ -69,7 +69,7 @@ static const uint32_t spi_regs_map[4] = {0x31ff, 0x33fffc0, 0x0, 0x0};
|
|||||||
/* Additional interrupt setting is required by idf SPI drivers after register recovered */ \
|
/* Additional interrupt setting is required by idf SPI drivers after register recovered */ \
|
||||||
[1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_GPSPI_LINK(1), \
|
[1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_GPSPI_LINK(1), \
|
||||||
SPI_DMA_INT_SET_REG(num), \
|
SPI_DMA_INT_SET_REG(num), \
|
||||||
SPI_TRANS_DONE_INT_SET | SPI_DMA_SEG_TRANS_DONE_INT_SET , \
|
SPI_TRANS_DONE_INT_SET | SPI_DMA_SEG_TRANS_DONE_INT_SET | SPI_SLV_CMD7_INT_SET | SPI_SLV_CMD8_INT_SET , \
|
||||||
UINT32_MAX, 1, 0), \
|
UINT32_MAX, 1, 0), \
|
||||||
.owner = ENTRY(0) | ENTRY(2) }, \
|
.owner = ENTRY(0) | ENTRY(2) }, \
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ static const uint32_t spi_regs_map[4] = {0x31ff, 0x33fffc0, 0x0, 0x0};
|
|||||||
/* Additional interrupt setting is required by idf SPI drivers after register recovered */ \
|
/* Additional interrupt setting is required by idf SPI drivers after register recovered */ \
|
||||||
[1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_GPSPI_LINK(1), \
|
[1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_GPSPI_LINK(1), \
|
||||||
SPI_DMA_INT_SET_REG(num), \
|
SPI_DMA_INT_SET_REG(num), \
|
||||||
SPI_TRANS_DONE_INT_SET | SPI_DMA_SEG_TRANS_DONE_INT_SET , \
|
SPI_TRANS_DONE_INT_SET | SPI_DMA_SEG_TRANS_DONE_INT_SET | SPI_SLV_CMD7_INT_SET | SPI_SLV_CMD8_INT_SET , \
|
||||||
UINT32_MAX, 1, 0), \
|
UINT32_MAX, 1, 0), \
|
||||||
.owner = ENTRY(0) | ENTRY(2) }, \
|
.owner = ENTRY(0) | ENTRY(2) }, \
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ static const uint32_t spi_regs_map[4] = {0x31ff, 0x33fffc0, 0x0, 0x0};
|
|||||||
/* Additional interrupt setting is required by idf SPI drivers after register recovered */ \
|
/* Additional interrupt setting is required by idf SPI drivers after register recovered */ \
|
||||||
[1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_GPSPI_LINK(1), \
|
[1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_GPSPI_LINK(1), \
|
||||||
SPI_DMA_INT_SET_REG(num), \
|
SPI_DMA_INT_SET_REG(num), \
|
||||||
SPI_TRANS_DONE_INT_SET | SPI_DMA_SEG_TRANS_DONE_INT_SET , \
|
SPI_TRANS_DONE_INT_SET | SPI_DMA_SEG_TRANS_DONE_INT_SET | SPI_SLV_CMD7_INT_SET | SPI_SLV_CMD8_INT_SET , \
|
||||||
UINT32_MAX, 1, 0), \
|
UINT32_MAX, 1, 0), \
|
||||||
.owner = ENTRY(0) | ENTRY(2) }, \
|
.owner = ENTRY(0) | ENTRY(2) }, \
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ static const uint32_t spi_regs_map[4] = {0x31ff, 0x33fffc0, 0x0, 0x0};
|
|||||||
/* Additional interrupt setting is required by idf SPI drivers after register recovered */ \
|
/* Additional interrupt setting is required by idf SPI drivers after register recovered */ \
|
||||||
[1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_GPSPI_LINK(1), \
|
[1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_GPSPI_LINK(1), \
|
||||||
SPI_DMA_INT_SET_REG(num), \
|
SPI_DMA_INT_SET_REG(num), \
|
||||||
SPI_TRANS_DONE_INT_SET | SPI_DMA_SEG_TRANS_DONE_INT_SET , \
|
SPI_TRANS_DONE_INT_SET | SPI_DMA_SEG_TRANS_DONE_INT_SET | SPI_SLV_CMD7_INT_SET | SPI_SLV_CMD8_INT_SET , \
|
||||||
UINT32_MAX, 1, 0), \
|
UINT32_MAX, 1, 0), \
|
||||||
.owner = ENTRY(0) | ENTRY(2) }, \
|
.owner = ENTRY(0) | ENTRY(2) }, \
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ static const uint32_t spi_regs_map[4] = {0x31ff, 0x33fffc0, 0x0, 0x0};
|
|||||||
/* Additional interrupt setting is required by idf SPI drivers after register recovered */ \
|
/* Additional interrupt setting is required by idf SPI drivers after register recovered */ \
|
||||||
[1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_GPSPI_LINK(1), \
|
[1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_GPSPI_LINK(1), \
|
||||||
SPI_DMA_INT_SET_REG(num), \
|
SPI_DMA_INT_SET_REG(num), \
|
||||||
SPI_TRANS_DONE_INT_SET | SPI_DMA_SEG_TRANS_DONE_INT_SET , \
|
SPI_TRANS_DONE_INT_SET | SPI_DMA_SEG_TRANS_DONE_INT_SET | SPI_SLV_CMD7_INT_SET | SPI_SLV_CMD8_INT_SET , \
|
||||||
UINT32_MAX, 1, 0), \
|
UINT32_MAX, 1, 0), \
|
||||||
.owner = ENTRY(0) }, \
|
.owner = ENTRY(0) }, \
|
||||||
}
|
}
|
||||||
|
@ -121,6 +121,16 @@ Receiving General Purpose Interrupts from the Master
|
|||||||
|
|
||||||
When the master sends ``CMD8``, ``CMD9`` or ``CMDA``, the slave corresponding is triggered. Currently the ``CMD8`` is permanently used to indicate the termination of ``Rd_DMA`` segments. To receive general-purpose interrupts, register callbacks for ``CMD9`` and ``CMDA`` when the slave is initialized, see :ref:`spi_slave_hd_callbacks`.
|
When the master sends ``CMD8``, ``CMD9`` or ``CMDA``, the slave corresponding is triggered. Currently the ``CMD8`` is permanently used to indicate the termination of ``Rd_DMA`` segments. To receive general-purpose interrupts, register callbacks for ``CMD9`` and ``CMDA`` when the slave is initialized, see :ref:`spi_slave_hd_callbacks`.
|
||||||
|
|
||||||
|
.. only:: SOC_SPI_SUPPORT_SLEEP_RETENTION
|
||||||
|
|
||||||
|
Sleep Retention
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
{IDF_TARGET_NAME} supports to retain the SPI register context before entering **light sleep** and restore them after waking up. This means you don't have to re-init the SPI driver after the light sleep.
|
||||||
|
|
||||||
|
This feature can be enabled by setting the flag :c:macro:`SPICOMMON_BUSFLAG_SLP_ALLOW_PD`. It will allow the system to power down the SPI in light sleep, meanwhile save the register context. It can help to save more power consumption with some extra cost of the memory.
|
||||||
|
|
||||||
|
Notice that when GPSPI is working as a slave, it is **not** support to enter sleep when any transaction (including TX and RX) is not finished.
|
||||||
|
|
||||||
.. only:: not esp32
|
.. only:: not esp32
|
||||||
|
|
||||||
|
@ -121,6 +121,16 @@ SPI 从机半双工模式
|
|||||||
|
|
||||||
当主机发送 ``CMD8``、``CMD9`` 或 ``CMDA`` 时,从机会触发相应的动作。目前,``CMD8`` 固定用于指示 ``Rd_DMA`` 段的终止。要接收通用中断,可以在从机初始化时为 ``CMD9`` 和 ``CMDA`` 注册回调函数,详情请参阅 :ref:`spi_slave_hd_callbacks`。
|
当主机发送 ``CMD8``、``CMD9`` 或 ``CMDA`` 时,从机会触发相应的动作。目前,``CMD8`` 固定用于指示 ``Rd_DMA`` 段的终止。要接收通用中断,可以在从机初始化时为 ``CMD9`` 和 ``CMDA`` 注册回调函数,详情请参阅 :ref:`spi_slave_hd_callbacks`。
|
||||||
|
|
||||||
|
.. only:: SOC_SPI_SUPPORT_SLEEP_RETENTION
|
||||||
|
|
||||||
|
睡眠保留
|
||||||
|
^^^^^^^^
|
||||||
|
|
||||||
|
{IDF_TARGET_NAME} 支持在进入 **Light Sleep** 之前保留 SPI 寄存器中的内容,并在唤醒后恢复。即程序不需要在 **Light Sleep** 唤醒后重新配置 SPI。
|
||||||
|
|
||||||
|
该特性可以通过置位配置中的 :c:macro:`SPICOMMON_BUSFLAG_SLP_ALLOW_PD` 标志位启用。启用后驱动允许系统在 Light Sleep 时对 SPI 掉电,同时保存寄存器配置。它可以帮助降低轻度睡眠时的功耗,但需要花费一些额外的存储来保存寄存器的配置。
|
||||||
|
|
||||||
|
注意在 Slave 角色下,不支持在所有传输(发送和接收)未完成时进入睡眠,否则将会出错。
|
||||||
|
|
||||||
.. only:: not esp32
|
.. only:: not esp32
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user