mirror of
https://github.com/espressif/esp-idf.git
synced 2026-06-11 11:42:39 +02:00
feat(driver_spi): slave hd driver sleep retention support
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/ringbuf.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_private/sleep_retention.h"
|
||||
#include "esp_private/spi_common_internal.h"
|
||||
#include "esp_private/spi_share_hw_ctrl.h"
|
||||
#include "esp_private/esp_cache_private.h"
|
||||
@@ -36,7 +37,7 @@ typedef struct {
|
||||
} spi_slave_hd_trans_priv_t;
|
||||
|
||||
typedef struct {
|
||||
bool dma_enabled;
|
||||
spi_host_device_t host_id;
|
||||
spi_dma_ctx_t *dma_ctx;
|
||||
uint16_t internal_mem_align_size;
|
||||
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);
|
||||
|
||||
#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)
|
||||
{
|
||||
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;
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
|
||||
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;
|
||||
}
|
||||
spihost[host_id] = host;
|
||||
host->host_id = host_id;
|
||||
host->int_spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
host->dma_enabled = (config->dma_chan != SPI_DMA_DISABLED);
|
||||
host->append_mode = append_mode;
|
||||
|
||||
if (host->dma_enabled) {
|
||||
ret = spicommon_dma_chan_alloc(host_id, config->dma_chan, &host->dma_ctx);
|
||||
if (ret != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
ret = spicommon_dma_chan_alloc(host_id, config->dma_chan, &host->dma_ctx);
|
||||
if (ret != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
#if SOC_GDMA_SUPPORTED
|
||||
gdma_strategy_config_t dma_strategy = {
|
||||
.auto_update_desc = true,
|
||||
.eof_till_data_popped = true,
|
||||
};
|
||||
gdma_apply_strategy(host->dma_ctx->tx_dma_chan, &dma_strategy);
|
||||
gdma_strategy_config_t dma_strategy = {
|
||||
.auto_update_desc = true,
|
||||
.eof_till_data_popped = true,
|
||||
};
|
||||
gdma_apply_strategy(host->dma_ctx->tx_dma_chan, &dma_strategy);
|
||||
#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_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_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);
|
||||
#endif
|
||||
ret = spicommon_dma_desc_alloc(host->dma_ctx, bus_config->max_transfer_sz, &host->max_transfer_sz);
|
||||
if (ret != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
ret = spicommon_dma_desc_alloc(host->dma_ctx, bus_config->max_transfer_sz, &host->max_transfer_sz);
|
||||
if (ret != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
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_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)) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto cleanup;
|
||||
}
|
||||
//Pair each desc to each possible trans
|
||||
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_rx[i].desc = &host->dma_ctx->dmadesc_rx[i];
|
||||
}
|
||||
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_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)) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto cleanup;
|
||||
}
|
||||
//Pair each desc to each possible trans
|
||||
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_rx[i].desc = &host->dma_ctx->dmadesc_rx[i];
|
||||
}
|
||||
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
size_t alignment;
|
||||
esp_cache_get_alignment(MALLOC_CAP_DMA, &alignment);
|
||||
host->internal_mem_align_size = alignment;
|
||||
size_t alignment;
|
||||
esp_cache_get_alignment(MALLOC_CAP_DMA, &alignment);
|
||||
host->internal_mem_align_size = alignment;
|
||||
#else
|
||||
host->internal_mem_align_size = 4;
|
||||
host->internal_mem_align_size = 4;
|
||||
#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);
|
||||
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 = {
|
||||
.host_id = host_id,
|
||||
.dma_enabled = host->dma_enabled,
|
||||
.dma_enabled = true,
|
||||
.append_mode = append_mode,
|
||||
.mode = config->mode,
|
||||
.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);
|
||||
#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
|
||||
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));
|
||||
@@ -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_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
|
||||
if (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
|
||||
|
||||
spicommon_periph_free(host_id);
|
||||
if (host->dma_enabled) {
|
||||
free(host->dma_ctx->dmadesc_tx);
|
||||
free(host->dma_ctx->dmadesc_rx);
|
||||
free(host->hal.dmadesc_tx);
|
||||
free(host->hal.dmadesc_rx);
|
||||
spicommon_dma_chan_free(host->dma_ctx);
|
||||
}
|
||||
free(host->dma_ctx->dmadesc_tx);
|
||||
free(host->dma_ctx->dmadesc_rx);
|
||||
free(host->hal.dmadesc_tx);
|
||||
free(host->hal.dmadesc_rx);
|
||||
spicommon_dma_chan_free(host->dma_ctx);
|
||||
|
||||
free(host);
|
||||
spihost[host_id] = NULL;
|
||||
return ESP_OK;
|
||||
|
||||
@@ -7,18 +7,20 @@
|
||||
Tests for the spi slave hd mode
|
||||
*/
|
||||
|
||||
#include "string.h"
|
||||
#include "esp_log.h"
|
||||
#include "test_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"
|
||||
|
||||
#if SOC_SPI_SUPPORT_SLAVE_HD_VER2
|
||||
#include "hal/spi_ll.h"
|
||||
#include "driver/gpio.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
|
||||
|
||||
#include "esp_rom_gpio.h"
|
||||
|
||||
#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
|
||||
spi_slave_hd_slot_config_t slave_hd_cfg = SPI_SLOT_TEST_DEFAULT_CONFIG();
|
||||
slave_hd_cfg.mode = mode;
|
||||
slave_hd_cfg.dma_chan = SPI_DMA_CH_AUTO;
|
||||
if (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();
|
||||
bus_cfg.max_transfer_sz = 14000 * 30;
|
||||
|
||||
spi_slave_hd_slot_config_t slave_hd_cfg = {
|
||||
.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,
|
||||
};
|
||||
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));
|
||||
|
||||
unity_wait_for_signal("master ready");
|
||||
@@ -831,16 +823,7 @@ static void hd_slave_quad(void)
|
||||
.max_transfer_sz = 14000 * 30
|
||||
};
|
||||
|
||||
spi_slave_hd_slot_config_t slave_hd_cfg = {
|
||||
.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,
|
||||
};
|
||||
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));
|
||||
|
||||
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();
|
||||
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));
|
||||
|
||||
unity_wait_for_signal("Master ready");
|
||||
@@ -1032,9 +1014,12 @@ void master_run_essl(void)
|
||||
bus_cfg.max_transfer_sz = 50000;
|
||||
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();
|
||||
dev_cfg.clock_speed_hz = 1 * 1000 * 1000;
|
||||
spi_device_interface_config_t dev_cfg = SPI_DEVICE_TEST_DEFAULT_CONFIG();
|
||||
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));
|
||||
|
||||
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_free(TEST_SPI_HOST));
|
||||
}
|
||||
|
||||
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_ESP_TASK_WDT=n
|
||||
CONFIG_ESP_TASK_WDT_INIT=n
|
||||
# primitives for checking sleep internal state
|
||||
CONFIG_ESP_SLEEP_DEBUG=y
|
||||
|
||||
Reference in New Issue
Block a user