Merge branch 'feat/spi_master_sleep_retention_v5.2' into 'release/v5.2'

feat(driver_spi): spi master support sleep retention(recovery) (v5.2)

See merge request espressif/esp-idf!44368
This commit is contained in:
morris
2025-12-26 19:19:59 +08:00
19 changed files with 315 additions and 219 deletions
+59 -1
View File
@@ -18,6 +18,7 @@
#include "driver/spi_master.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/spi_common_internal.h"
#include "esp_private/sleep_retention.h"
#include "hal/spi_hal.h"
#include "hal/gpio_hal.h"
#if CONFIG_IDF_TARGET_ESP32
@@ -60,6 +61,7 @@ static const char *SPI_TAG = "spi";
typedef struct {
int host_id;
_lock_t mutex; // mutex for controller
spi_destroy_func_t destroy_func;
void* destroy_arg;
spi_bus_attr_t bus_attr;
@@ -600,7 +602,8 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
}
uint32_t missing_flag = flags & ~temp_flag;
missing_flag &= ~SPICOMMON_BUSFLAG_MASTER;//don't check this flag
missing_flag &= ~SPICOMMON_BUSFLAG_MASTER; //don't check this flag
missing_flag &= ~SPICOMMON_BUSFLAG_SLP_ALLOW_PD;
if (missing_flag != 0) {
//check pins existence
@@ -787,6 +790,18 @@ spi_bus_lock_handle_t spi_bus_lock_get_by_id(spi_host_device_t host_id)
return bus_ctx[host_id]->bus_attr.lock;
}
#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
#include "sleep_gpspi_reteniton_context.inc"
static esp_err_t s_bus_create_sleep_retention_cb(void *arg)
{
spicommon_bus_context_t *ctx = arg;
return sleep_retention_entries_create(spi_reg_retention_info[ctx->host_id - 1].entry_array,
spi_reg_retention_info[ctx->host_id - 1].array_size,
REGDMA_LINK_PRI_GPSPI,
spi_reg_retention_info[ctx->host_id - 1].module_id);
}
#endif // SOC_SPI_SUPPORT_SLEEP_RETENTION
//----------------------------------------------------------master bus init-------------------------------------------------------//
esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *bus_config, spi_dma_chan_t dma_chan)
{
@@ -865,6 +880,35 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *
goto cleanup;
}
#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_bus_create_sleep_retention_cb,
.arg = ctx,
},
},
.depends = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM),
};
_lock_acquire(&ctx->mutex);
sleep_retention_module_t module_id = spi_reg_retention_info[host_id - 1].module_id;
if (sleep_retention_module_init(module_id, &init_param) == ESP_OK) {
if ((bus_attr->bus_cfg.flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) && (sleep_retention_module_allocate(module_id) != ESP_OK)) {
// even though the sleep retention create failed, SPI driver should still work, so just warning here
ESP_LOGW(SPI_TAG, "alloc sleep recover failed, peripherals may hold power on");
}
} else {
// even the sleep retention init failed, SPI driver should still work, so just warning here
ESP_LOGW(SPI_TAG, "init sleep recover failed, spi may offline after sleep");
}
_lock_release(&ctx->mutex);
#else
if (bus_attr->bus_cfg.flags & SPICOMMON_BUSFLAG_SLP_ALLOW_PD) {
ESP_LOGE(SPI_TAG, "power down peripheral in sleep is not enabled or not supported on your target");
}
#endif // SOC_SPI_SUPPORT_SLEEP_RETENTION
#ifdef CONFIG_PM_ENABLE
err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_master",
&bus_attr->pm_lock);
@@ -925,6 +969,20 @@ esp_err_t spi_bus_free(spi_host_device_t host_id)
spicommon_bus_free_io_cfg(&bus_attr->bus_cfg);
#if SOC_SPI_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
const sleep_retention_module_t module_id = spi_reg_retention_info[host_id - 1].module_id;
_lock_acquire(&ctx->mutex);
if (sleep_retention_get_created_modules() & BIT(module_id)) {
assert(sleep_retention_get_inited_modules() & BIT(module_id));
sleep_retention_module_free(module_id);
}
if (sleep_retention_get_inited_modules() & BIT(module_id)) {
sleep_retention_module_deinit(module_id);
}
_lock_release(&ctx->mutex);
_lock_close(&ctx->mutex);
#endif
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_delete(bus_attr->pm_lock);
#endif
+1 -2
View File
@@ -304,8 +304,7 @@ static esp_err_t spi_master_deinit_driver(void* arg)
int host_id = host->id;
SPI_CHECK(is_valid_host(host_id), "invalid host_id", ESP_ERR_INVALID_ARG);
int x;
for (x=0; x<DEV_NUM_MAX; x++) {
for (int x = 0; x < DEV_NUM_MAX; x++) {
SPI_CHECK(host->device[x] == NULL, "not all CSses freed", ESP_ERR_INVALID_STATE);
}
@@ -64,6 +64,7 @@ extern "C"
#define SPICOMMON_BUSFLAG_IO4_IO7 (1<<8) ///< Check existing of IO4~IO7 pins. Or indicates IO4~IO7 pins initialized.
#define SPICOMMON_BUSFLAG_OCTAL (SPICOMMON_BUSFLAG_QUAD|SPICOMMON_BUSFLAG_IO4_IO7) ///< Check existing of MOSI/MISO/WP/HD/SPIIO4/SPIIO5/SPIIO6/SPIIO7 pins as output. Or indicates bus able to work under octal mode.
#define SPICOMMON_BUSFLAG_NATIVE_PINS SPICOMMON_BUSFLAG_IOMUX_PINS
#define SPICOMMON_BUSFLAG_SLP_ALLOW_PD (1<<9) ///< Allow to power down the peripheral during light sleep, and auto recover then.
/**
* @brief SPI DMA channels
@@ -18,6 +18,9 @@
#include "esp_private/cache_utils.h"
#include "esp_private/spi_common_internal.h"
#include "esp_private/esp_clk.h"
#include "esp_private/sleep_cpu.h"
#include "esp_private/esp_sleep_internal.h"
#include "esp_private/esp_pmu.h"
#include "esp_heap_caps.h"
#include "esp_clk_tree.h"
#include "esp_log.h"
@@ -1769,3 +1772,60 @@ static void test_iram_slave_normal(void)
TEST_CASE_MULTIPLE_DEVICES("SPI_Master:IRAM_safe", "[spi_ms]", test_master_iram, test_iram_slave_normal);
#endif
#endif //p4 slave support
#if !CONFIG_IDF_TARGET_ESP32P4 // TODO: IDF-7528, IDF-7529
TEST_CASE("test_spi_master_sleep_retention", "[spi]")
{
// Prepare a TOP PD sleep
TEST_ESP_OK(esp_sleep_enable_timer_wakeup(1 * 1000 * 1000));
#if SOC_PM_SUPPORT_CPU_PD
TEST_ESP_OK(sleep_cpu_configure(true));
#endif
spi_device_handle_t dev_handle;
spi_bus_config_t buscfg = SPI_BUS_TEST_DEFAULT_CONFIG();
spi_device_interface_config_t devcfg = SPI_DEVICE_TEST_DEFAULT_CONFIG();
buscfg.flags |= SPICOMMON_BUSFLAG_GPIO_PINS;
buscfg.flags |= SPICOMMON_BUSFLAG_SLP_ALLOW_PD;
uint8_t send[16] = "hello spi x\n";
uint8_t recv[16];
spi_transaction_t trans_cfg = {
.length = 8 * sizeof(send),
.tx_buffer = send,
.rx_buffer = recv,
};
for (int periph = SPI2_HOST; periph < SPI_HOST_MAX; periph ++) {
for (int test_dma = 0; test_dma <= 1; test_dma ++) {
int use_dma = SPI_DMA_DISABLED;
#if SOC_GDMA_SUPPORT_SLEEP_RETENTION // TODO: IDF-11317 test dma on esp32 and s2
use_dma = test_dma ? SPI_DMA_CH_AUTO : SPI_DMA_DISABLED;
#endif
printf("Retention on GPSPI%d with dma: %d\n", periph + 1, use_dma);
TEST_ESP_OK(spi_bus_initialize(periph, &buscfg, use_dma));
// set spi "self-loop" after bus initialized
spitest_gpio_output_sel(buscfg.miso_io_num, FUNC_GPIO, spi_periph_signal[periph].spid_out);
TEST_ESP_OK(spi_bus_add_device(periph, &devcfg, &dev_handle));
for (uint8_t cnt = 0; cnt < 3; cnt ++) {
printf("Going into sleep...\n");
TEST_ESP_OK(esp_light_sleep_start());
printf("Waked up!\n");
memset(recv, 0, sizeof(recv));
send[10] = cnt + 'A';
TEST_ESP_OK(spi_device_transmit(dev_handle, &trans_cfg));
printf("%s", recv);
spitest_cmp_or_dump(trans_cfg.tx_buffer, trans_cfg.rx_buffer, sizeof(send));
}
TEST_ESP_OK(spi_bus_remove_device(dev_handle));
TEST_ESP_OK(spi_bus_free(periph));
}
}
#if SOC_PM_SUPPORT_CPU_PD
TEST_ESP_OK(sleep_cpu_configure(false));
#endif
}
#endif // !CONFIG_IDF_TARGET_ESP32P4
@@ -1,3 +1,4 @@
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
@@ -44,6 +44,7 @@ extern "C" {
#define REGDMA_MODEM_BT_BB_LINK(_pri) ((0x16 << 8) | _pri)
#define REGDMA_MODEM_IEEE802154_LINK(_pri) ((0x17 << 8) | _pri)
#define REGDMA_MODEM_GDMA_LINK(_pri) ((0x18 << 8) | _pri)
#define REGDMA_GPSPI_LINK(_pri) ((0x19 << 8) | _pri)
#define REGDMA_MODEM_FE_LINK(_pri) ((0xFF << 8) | _pri)
typedef enum {
@@ -78,6 +79,7 @@ typedef enum regdma_link_mode {
#define REGDMA_LINK_PRI_IEEE802154 REGDMA_LINK_PRI_GENERAL_PERIPH
#define REGDMA_LINK_PRI_GDMA REGDMA_LINK_PRI_GENERAL_PERIPH
#define REGDMA_LINK_PRI_UART REGDMA_LINK_PRI_GENERAL_PERIPH
#define REGDMA_LINK_PRI_GPSPI REGDMA_LINK_PRI_GENERAL_PERIPH
typedef struct regdma_link_head {
volatile uint32_t length: 10, /* total count of registers that need to be backup or restore, unit: 1 word = 4 bytes */
@@ -47,6 +47,7 @@ typedef enum sleep_retention_module {
SLEEP_RETENTION_MODULE_GDMA_CH2 = 26,
SLEEP_RETENTION_MODULE_UART0 = 27,
SLEEP_RETENTION_MODULE_UART1 = 28,
SLEEP_RETENTION_MODULE_GPSPI2 = 29,
SLEEP_RETENTION_MODULE_MAX = 31
} sleep_retention_module_t;
@@ -76,6 +77,8 @@ typedef enum sleep_retention_module_bitmap {
SLEEP_RETENTION_MODULE_BM_UART0 = BIT(SLEEP_RETENTION_MODULE_UART0),
SLEEP_RETENTION_MODULE_BM_UART1 = BIT(SLEEP_RETENTION_MODULE_UART1),
SLEEP_RETENTION_MODULE_BM_GPSPI2 = BIT(SLEEP_RETENTION_MODULE_GPSPI2),
SLEEP_RETENTION_MODULE_BM_ALL = (uint32_t)-1
} sleep_retention_module_bitmap_t;
@@ -86,6 +89,7 @@ typedef enum sleep_retention_module_bitmap {
| SLEEP_RETENTION_MODULE_BM_ADC \
| SLEEP_RETENTION_MODULE_BM_UART0 \
| SLEEP_RETENTION_MODULE_BM_UART1 \
| SLEEP_RETENTION_MODULE_BM_GPSPI2 \
)
typedef regdma_entry_buf_t sleep_retention_entries_t;
@@ -0,0 +1,57 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/soc_caps.h"
#include "soc/spi_reg.h"
/**
* Backup registers in Light sleep: (total cnt 12)
*
* cmd
* addr
* ctrl
* clock
* user
* user1
* user2
* ms_dlen
* misc
* dma_conf
* dma_int_ena
* slave
*/
#define SPI_RETENTION_REGS_CNT 12
static const uint32_t spi_regs_map[4] = {0x31ff, 0x1000000, 0x0, 0x0};
#define SPI_REG_RETENTION_ENTRIES(num) { \
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_GPSPI_LINK(0), \
REG_SPI_BASE(num), REG_SPI_BASE(num), \
SPI_RETENTION_REGS_CNT, 0, 0, \
spi_regs_map[0], spi_regs_map[1], \
spi_regs_map[2], spi_regs_map[3]), \
.owner = ENTRY(0) | ENTRY(2) }, \
/* Additional interrupt setting is required by idf SPI drivers after register recovered */ \
[1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_GPSPI_LINK(1), \
SPI_DMA_INT_SET_REG(num), \
SPI_TRANS_DONE_INT_SET | SPI_DMA_SEG_TRANS_DONE_INT_SET , \
UINT32_MAX, 1, 0), \
.owner = ENTRY(0) | ENTRY(2) }, \
}
static const sleep_retention_entries_config_t spi2_regs_retention[] = SPI_REG_RETENTION_ENTRIES(2); // '2' for GPSPI2
typedef struct {
const sleep_retention_module_t module_id;
const sleep_retention_entries_config_t *entry_array;
uint32_t array_size;
} spi_reg_retention_info_t;
const spi_reg_retention_info_t spi_reg_retention_info[SOC_SPI_PERIPH_NUM - 1] = { // '-1' to except mspi
{
.module_id = SLEEP_RETENTION_MODULE_GPSPI2,
.entry_array = spi2_regs_retention,
.array_size = ARRAY_SIZE(spi2_regs_retention),
},
};
@@ -0,0 +1,57 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/soc_caps.h"
#include "soc/spi_reg.h"
/**
* Backup registers in Light sleep: (total cnt 12)
*
* cmd
* addr
* ctrl
* clock
* user
* user1
* user2
* ms_dlen
* misc
* dma_conf
* dma_int_ena
* slave
*/
#define SPI_RETENTION_REGS_CNT 12
static const uint32_t spi_regs_map[4] = {0x31ff, 0x1000000, 0x0, 0x0};
#define SPI_REG_RETENTION_ENTRIES(num) { \
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_GPSPI_LINK(0), \
REG_SPI_BASE(num), REG_SPI_BASE(num), \
SPI_RETENTION_REGS_CNT, 0, 0, \
spi_regs_map[0], spi_regs_map[1], \
spi_regs_map[2], spi_regs_map[3]), \
.owner = ENTRY(0) | ENTRY(2) }, \
/* Additional interrupt setting is required by idf SPI drivers after register recovered */ \
[1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_GPSPI_LINK(1), \
SPI_DMA_INT_SET_REG(num), \
SPI_TRANS_DONE_INT_SET | SPI_DMA_SEG_TRANS_DONE_INT_SET , \
UINT32_MAX, 1, 0), \
.owner = ENTRY(0) | ENTRY(2) }, \
}
static const sleep_retention_entries_config_t spi2_regs_retention[] = SPI_REG_RETENTION_ENTRIES(2); // '2' for GPSPI2
typedef struct {
const sleep_retention_module_t module_id;
const sleep_retention_entries_config_t *entry_array;
uint32_t array_size;
} spi_reg_retention_info_t;
const spi_reg_retention_info_t spi_reg_retention_info[SOC_SPI_PERIPH_NUM - 1] = { // '-1' to except mspi
{
.module_id = SLEEP_RETENTION_MODULE_GPSPI2,
.entry_array = spi2_regs_retention,
.array_size = ARRAY_SIZE(spi2_regs_retention),
},
};
+2 -171
View File
@@ -497,177 +497,7 @@ typedef volatile struct spi_dev_s {
uint32_t dma_outlink_dscr_bf1; /*The content of current out descriptor data buffer pointer.*/
uint32_t dma_rx_status; /*spi dma read data from memory status.*/
uint32_t dma_tx_status; /*spi dma write data to memory status.*/
uint32_t reserved_150;
uint32_t reserved_154;
uint32_t reserved_158;
uint32_t reserved_15c;
uint32_t reserved_160;
uint32_t reserved_164;
uint32_t reserved_168;
uint32_t reserved_16c;
uint32_t reserved_170;
uint32_t reserved_174;
uint32_t reserved_178;
uint32_t reserved_17c;
uint32_t reserved_180;
uint32_t reserved_184;
uint32_t reserved_188;
uint32_t reserved_18c;
uint32_t reserved_190;
uint32_t reserved_194;
uint32_t reserved_198;
uint32_t reserved_19c;
uint32_t reserved_1a0;
uint32_t reserved_1a4;
uint32_t reserved_1a8;
uint32_t reserved_1ac;
uint32_t reserved_1b0;
uint32_t reserved_1b4;
uint32_t reserved_1b8;
uint32_t reserved_1bc;
uint32_t reserved_1c0;
uint32_t reserved_1c4;
uint32_t reserved_1c8;
uint32_t reserved_1cc;
uint32_t reserved_1d0;
uint32_t reserved_1d4;
uint32_t reserved_1d8;
uint32_t reserved_1dc;
uint32_t reserved_1e0;
uint32_t reserved_1e4;
uint32_t reserved_1e8;
uint32_t reserved_1ec;
uint32_t reserved_1f0;
uint32_t reserved_1f4;
uint32_t reserved_1f8;
uint32_t reserved_1fc;
uint32_t reserved_200;
uint32_t reserved_204;
uint32_t reserved_208;
uint32_t reserved_20c;
uint32_t reserved_210;
uint32_t reserved_214;
uint32_t reserved_218;
uint32_t reserved_21c;
uint32_t reserved_220;
uint32_t reserved_224;
uint32_t reserved_228;
uint32_t reserved_22c;
uint32_t reserved_230;
uint32_t reserved_234;
uint32_t reserved_238;
uint32_t reserved_23c;
uint32_t reserved_240;
uint32_t reserved_244;
uint32_t reserved_248;
uint32_t reserved_24c;
uint32_t reserved_250;
uint32_t reserved_254;
uint32_t reserved_258;
uint32_t reserved_25c;
uint32_t reserved_260;
uint32_t reserved_264;
uint32_t reserved_268;
uint32_t reserved_26c;
uint32_t reserved_270;
uint32_t reserved_274;
uint32_t reserved_278;
uint32_t reserved_27c;
uint32_t reserved_280;
uint32_t reserved_284;
uint32_t reserved_288;
uint32_t reserved_28c;
uint32_t reserved_290;
uint32_t reserved_294;
uint32_t reserved_298;
uint32_t reserved_29c;
uint32_t reserved_2a0;
uint32_t reserved_2a4;
uint32_t reserved_2a8;
uint32_t reserved_2ac;
uint32_t reserved_2b0;
uint32_t reserved_2b4;
uint32_t reserved_2b8;
uint32_t reserved_2bc;
uint32_t reserved_2c0;
uint32_t reserved_2c4;
uint32_t reserved_2c8;
uint32_t reserved_2cc;
uint32_t reserved_2d0;
uint32_t reserved_2d4;
uint32_t reserved_2d8;
uint32_t reserved_2dc;
uint32_t reserved_2e0;
uint32_t reserved_2e4;
uint32_t reserved_2e8;
uint32_t reserved_2ec;
uint32_t reserved_2f0;
uint32_t reserved_2f4;
uint32_t reserved_2f8;
uint32_t reserved_2fc;
uint32_t reserved_300;
uint32_t reserved_304;
uint32_t reserved_308;
uint32_t reserved_30c;
uint32_t reserved_310;
uint32_t reserved_314;
uint32_t reserved_318;
uint32_t reserved_31c;
uint32_t reserved_320;
uint32_t reserved_324;
uint32_t reserved_328;
uint32_t reserved_32c;
uint32_t reserved_330;
uint32_t reserved_334;
uint32_t reserved_338;
uint32_t reserved_33c;
uint32_t reserved_340;
uint32_t reserved_344;
uint32_t reserved_348;
uint32_t reserved_34c;
uint32_t reserved_350;
uint32_t reserved_354;
uint32_t reserved_358;
uint32_t reserved_35c;
uint32_t reserved_360;
uint32_t reserved_364;
uint32_t reserved_368;
uint32_t reserved_36c;
uint32_t reserved_370;
uint32_t reserved_374;
uint32_t reserved_378;
uint32_t reserved_37c;
uint32_t reserved_380;
uint32_t reserved_384;
uint32_t reserved_388;
uint32_t reserved_38c;
uint32_t reserved_390;
uint32_t reserved_394;
uint32_t reserved_398;
uint32_t reserved_39c;
uint32_t reserved_3a0;
uint32_t reserved_3a4;
uint32_t reserved_3a8;
uint32_t reserved_3ac;
uint32_t reserved_3b0;
uint32_t reserved_3b4;
uint32_t reserved_3b8;
uint32_t reserved_3bc;
uint32_t reserved_3c0;
uint32_t reserved_3c4;
uint32_t reserved_3c8;
uint32_t reserved_3cc;
uint32_t reserved_3d0;
uint32_t reserved_3d4;
uint32_t reserved_3d8;
uint32_t reserved_3dc;
uint32_t reserved_3e0;
uint32_t reserved_3e4;
uint32_t reserved_3e8;
uint32_t reserved_3ec;
uint32_t reserved_3f0;
uint32_t reserved_3f4;
uint32_t reserved_3f8;
uint32_t reserved_150[171];
union {
struct {
uint32_t date: 28; /*SPI register version.*/
@@ -676,6 +506,7 @@ typedef volatile struct spi_dev_s {
uint32_t val;
} date;
} spi_dev_t;
extern spi_dev_t SPI0; /* SPI0 IS FOR INTERNAL USE*/
extern spi_dev_t SPI1;
extern spi_dev_t SPI2;
@@ -919,6 +919,10 @@ config SOC_SPI_SUPPORT_SLAVE_HD_VER2
bool
default y
config SOC_SPI_SUPPORT_SLEEP_RETENTION
bool
default y
config SOC_SPI_SUPPORT_CLK_XTAL
bool
default y
@@ -383,6 +383,7 @@
#define SOC_SPI_SUPPORT_CD_SIG 1
#define SOC_SPI_SUPPORT_CONTINUOUS_TRANS 1
#define SOC_SPI_SUPPORT_SLAVE_HD_VER2 1
#define SOC_SPI_SUPPORT_SLEEP_RETENTION 1
#define SOC_SPI_SUPPORT_CLK_XTAL 1
#define SOC_SPI_SUPPORT_CLK_PLL_F80M 1
#define SOC_SPI_SUPPORT_CLK_RC_FAST 1
@@ -915,6 +915,10 @@ config SOC_SPI_SUPPORT_SLAVE_HD_VER2
bool
default y
config SOC_SPI_SUPPORT_SLEEP_RETENTION
bool
default y
config SOC_SPI_SUPPORT_CLK_XTAL
bool
default y
@@ -395,6 +395,7 @@
#define SOC_SPI_SUPPORT_CD_SIG 1
#define SOC_SPI_SUPPORT_CONTINUOUS_TRANS 1
#define SOC_SPI_SUPPORT_SLAVE_HD_VER2 1
#define SOC_SPI_SUPPORT_SLEEP_RETENTION 1
#define SOC_SPI_SUPPORT_CLK_XTAL 1
#define SOC_SPI_SUPPORT_CLK_PLL_F48M 1
#define SOC_SPI_SUPPORT_CLK_RC_FAST 1
+41 -41
View File
@@ -1,5 +1,5 @@
/**
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -14,7 +14,7 @@ extern "C" {
/** SPI_CMD_REG register
* Command control register
*/
#define SPI_CMD_REG (DR_REG_SPI_BASE + 0x0)
#define SPI_CMD_REG(i) (REG_SPI_BASE(i) + 0x0)
/** SPI_CONF_BITLEN : R/W; bitpos: [17:0]; default: 0;
* Define the APB cycles of SPI_CONF state. Can be configured in CONF state.
*/
@@ -43,7 +43,7 @@ extern "C" {
/** SPI_ADDR_REG register
* Address value register
*/
#define SPI_ADDR_REG (DR_REG_SPI_BASE + 0x4)
#define SPI_ADDR_REG(i) (REG_SPI_BASE(i) + 0x4)
/** SPI_USR_ADDR_VALUE : R/W; bitpos: [31:0]; default: 0;
* Address to slave. Can be configured in CONF state.
*/
@@ -55,7 +55,7 @@ extern "C" {
/** SPI_CTRL_REG register
* SPI control register
*/
#define SPI_CTRL_REG (DR_REG_SPI_BASE + 0x8)
#define SPI_CTRL_REG(i) (REG_SPI_BASE(i) + 0x8)
/** SPI_DUMMY_OUT : R/W; bitpos: [3]; default: 0;
* 0: In the dummy phase, the FSPI bus signals are not output. 1: In the dummy phase,
* the FSPI bus signals are output. Can be configured in CONF state.
@@ -188,7 +188,7 @@ extern "C" {
/** SPI_CLOCK_REG register
* SPI clock control register
*/
#define SPI_CLOCK_REG (DR_REG_SPI_BASE + 0xc)
#define SPI_CLOCK_REG(i) (REG_SPI_BASE(i) + 0xc)
/** SPI_CLKCNT_L : R/W; bitpos: [5:0]; default: 3;
* In the master mode it must be equal to spi_clkcnt_N. In the slave mode it must be
* 0. Can be configured in CONF state.
@@ -221,7 +221,7 @@ extern "C" {
#define SPI_CLKDIV_PRE_V 0x0000000FU
#define SPI_CLKDIV_PRE_S 18
/** SPI_CLK_EQU_SYSCLK : R/W; bitpos: [31]; default: 1;
* In the master mode 1: spi_clk is eqaul to system 0: spi_clk is divided from system
* In the master mode 1: spi_clk is equal to system 0: spi_clk is divided from system
* clock. Can be configured in CONF state.
*/
#define SPI_CLK_EQU_SYSCLK (BIT(31))
@@ -232,7 +232,7 @@ extern "C" {
/** SPI_USER_REG register
* SPI USER control register
*/
#define SPI_USER_REG (DR_REG_SPI_BASE + 0x10)
#define SPI_USER_REG(i) (REG_SPI_BASE(i) + 0x10)
/** SPI_DOUTDIN : R/W; bitpos: [0]; default: 0;
* Set the bit to enable full duplex communication. 1: enable 0: disable. Can be
* configured in CONF state.
@@ -403,7 +403,7 @@ extern "C" {
/** SPI_USER1_REG register
* SPI USER control register 1
*/
#define SPI_USER1_REG (DR_REG_SPI_BASE + 0x14)
#define SPI_USER1_REG(i) (REG_SPI_BASE(i) + 0x14)
/** SPI_USR_DUMMY_CYCLELEN : R/W; bitpos: [7:0]; default: 7;
* The length in spi_clk cycles of dummy phase. The register value shall be
* (cycle_num-1). Can be configured in CONF state.
@@ -449,7 +449,7 @@ extern "C" {
/** SPI_USER2_REG register
* SPI USER control register 2
*/
#define SPI_USER2_REG (DR_REG_SPI_BASE + 0x18)
#define SPI_USER2_REG(i) (REG_SPI_BASE(i) + 0x18)
/** SPI_USR_COMMAND_VALUE : R/W; bitpos: [15:0]; default: 0;
* The value of command. Can be configured in CONF state.
*/
@@ -478,7 +478,7 @@ extern "C" {
/** SPI_MS_DLEN_REG register
* SPI data bit length control register
*/
#define SPI_MS_DLEN_REG (DR_REG_SPI_BASE + 0x1c)
#define SPI_MS_DLEN_REG(i) (REG_SPI_BASE(i) + 0x1c)
/** SPI_MS_DATA_BITLEN : R/W; bitpos: [17:0]; default: 0;
* The value of these bits is the configured SPI transmission data bit length in
* master mode DMA controlled transfer or CPU controlled transfer. The value is also
@@ -493,7 +493,7 @@ extern "C" {
/** SPI_MISC_REG register
* SPI misc register
*/
#define SPI_MISC_REG (DR_REG_SPI_BASE + 0x20)
#define SPI_MISC_REG(i) (REG_SPI_BASE(i) + 0x20)
/** SPI_CS0_DIS : R/W; bitpos: [0]; default: 0;
* SPI CS$n pin enable, 1: disable CS$n, 0: spi_cs$n signal is from/to CS$n pin. Can
* be configured in CONF state.
@@ -634,7 +634,7 @@ extern "C" {
/** SPI_DIN_MODE_REG register
* SPI input delay mode configuration
*/
#define SPI_DIN_MODE_REG (DR_REG_SPI_BASE + 0x24)
#define SPI_DIN_MODE_REG(i) (REG_SPI_BASE(i) + 0x24)
/** SPI_DIN0_MODE : R/W; bitpos: [1:0]; default: 0;
* the input signals are delayed by SPI module clock cycles, 0: input without delayed,
* 1: input with the posedge of clk_apb,2 input with the negedge of clk_apb, 3: input
@@ -725,7 +725,7 @@ extern "C" {
/** SPI_DIN_NUM_REG register
* SPI input delay number configuration
*/
#define SPI_DIN_NUM_REG (DR_REG_SPI_BASE + 0x28)
#define SPI_DIN_NUM_REG(i) (REG_SPI_BASE(i) + 0x28)
/** SPI_DIN0_NUM : R/W; bitpos: [1:0]; default: 0;
* the input signals are delayed by SPI module clock cycles, 0: delayed by 1 cycle, 1:
* delayed by 2 cycles,... Can be configured in CONF state.
@@ -794,7 +794,7 @@ extern "C" {
/** SPI_DOUT_MODE_REG register
* SPI output delay mode configuration
*/
#define SPI_DOUT_MODE_REG (DR_REG_SPI_BASE + 0x2c)
#define SPI_DOUT_MODE_REG(i) (REG_SPI_BASE(i) + 0x2c)
/** SPI_DOUT0_MODE : R/W; bitpos: [0]; default: 0;
* The output signal $n is delayed by the SPI module clock, 0: output without delayed,
* 1: output delay for a SPI module clock cycle at its negative edge. Can be
@@ -880,7 +880,7 @@ extern "C" {
/** SPI_DMA_CONF_REG register
* SPI DMA control register
*/
#define SPI_DMA_CONF_REG (DR_REG_SPI_BASE + 0x30)
#define SPI_DMA_CONF_REG(i) (REG_SPI_BASE(i) + 0x30)
/** SPI_DMA_OUTFIFO_EMPTY : RO; bitpos: [0]; default: 1;
* Records the status of DMA TX FIFO. 1: DMA TX FIFO is not ready for sending data. 0:
* DMA TX FIFO is ready for sending data.
@@ -972,7 +972,7 @@ extern "C" {
/** SPI_DMA_INT_ENA_REG register
* SPI interrupt enable register
*/
#define SPI_DMA_INT_ENA_REG (DR_REG_SPI_BASE + 0x34)
#define SPI_DMA_INT_ENA_REG(i) (REG_SPI_BASE(i) + 0x34)
/** SPI_DMA_INFIFO_FULL_ERR_INT_ENA : R/W; bitpos: [0]; default: 0;
* The enable bit for SPI_DMA_INFIFO_FULL_ERR_INT interrupt.
*/
@@ -1124,7 +1124,7 @@ extern "C" {
/** SPI_DMA_INT_CLR_REG register
* SPI interrupt clear register
*/
#define SPI_DMA_INT_CLR_REG (DR_REG_SPI_BASE + 0x38)
#define SPI_DMA_INT_CLR_REG(i) (REG_SPI_BASE(i) + 0x38)
/** SPI_DMA_INFIFO_FULL_ERR_INT_CLR : WT; bitpos: [0]; default: 0;
* The clear bit for SPI_DMA_INFIFO_FULL_ERR_INT interrupt.
*/
@@ -1276,7 +1276,7 @@ extern "C" {
/** SPI_DMA_INT_RAW_REG register
* SPI interrupt raw register
*/
#define SPI_DMA_INT_RAW_REG (DR_REG_SPI_BASE + 0x3c)
#define SPI_DMA_INT_RAW_REG(i) (REG_SPI_BASE(i) + 0x3c)
/** SPI_DMA_INFIFO_FULL_ERR_INT_RAW : R/WTC/SS; bitpos: [0]; default: 0;
* 1: The current data rate of DMA Rx is smaller than that of SPI, which will lose the
* receive data. 0: Others.
@@ -1450,7 +1450,7 @@ extern "C" {
/** SPI_DMA_INT_ST_REG register
* SPI interrupt status register
*/
#define SPI_DMA_INT_ST_REG (DR_REG_SPI_BASE + 0x40)
#define SPI_DMA_INT_ST_REG(i) (REG_SPI_BASE(i) + 0x40)
/** SPI_DMA_INFIFO_FULL_ERR_INT_ST : RO; bitpos: [0]; default: 0;
* The status bit for SPI_DMA_INFIFO_FULL_ERR_INT interrupt.
*/
@@ -1602,7 +1602,7 @@ extern "C" {
/** SPI_DMA_INT_SET_REG register
* SPI interrupt software set register
*/
#define SPI_DMA_INT_SET_REG (DR_REG_SPI_BASE + 0x44)
#define SPI_DMA_INT_SET_REG(i) (REG_SPI_BASE(i) + 0x44)
/** SPI_DMA_INFIFO_FULL_ERR_INT_SET : WT; bitpos: [0]; default: 0;
* The software set bit for SPI_DMA_INFIFO_FULL_ERR_INT interrupt.
*/
@@ -1754,7 +1754,7 @@ extern "C" {
/** SPI_W0_REG register
* SPI CPU-controlled buffer0
*/
#define SPI_W0_REG (DR_REG_SPI_BASE + 0x98)
#define SPI_W0_REG(i) (REG_SPI_BASE(i) + 0x98)
/** SPI_BUF0 : R/W/SS; bitpos: [31:0]; default: 0;
* data buffer
*/
@@ -1766,7 +1766,7 @@ extern "C" {
/** SPI_W1_REG register
* SPI CPU-controlled buffer1
*/
#define SPI_W1_REG (DR_REG_SPI_BASE + 0x9c)
#define SPI_W1_REG(i) (REG_SPI_BASE(i) + 0x9c)
/** SPI_BUF1 : R/W/SS; bitpos: [31:0]; default: 0;
* data buffer
*/
@@ -1778,7 +1778,7 @@ extern "C" {
/** SPI_W2_REG register
* SPI CPU-controlled buffer2
*/
#define SPI_W2_REG (DR_REG_SPI_BASE + 0xa0)
#define SPI_W2_REG(i) (REG_SPI_BASE(i) + 0xa0)
/** SPI_BUF2 : R/W/SS; bitpos: [31:0]; default: 0;
* data buffer
*/
@@ -1790,7 +1790,7 @@ extern "C" {
/** SPI_W3_REG register
* SPI CPU-controlled buffer3
*/
#define SPI_W3_REG (DR_REG_SPI_BASE + 0xa4)
#define SPI_W3_REG(i) (REG_SPI_BASE(i) + 0xa4)
/** SPI_BUF3 : R/W/SS; bitpos: [31:0]; default: 0;
* data buffer
*/
@@ -1802,7 +1802,7 @@ extern "C" {
/** SPI_W4_REG register
* SPI CPU-controlled buffer4
*/
#define SPI_W4_REG (DR_REG_SPI_BASE + 0xa8)
#define SPI_W4_REG(i) (REG_SPI_BASE(i) + 0xa8)
/** SPI_BUF4 : R/W/SS; bitpos: [31:0]; default: 0;
* data buffer
*/
@@ -1814,7 +1814,7 @@ extern "C" {
/** SPI_W5_REG register
* SPI CPU-controlled buffer5
*/
#define SPI_W5_REG (DR_REG_SPI_BASE + 0xac)
#define SPI_W5_REG(i) (REG_SPI_BASE(i) + 0xac)
/** SPI_BUF5 : R/W/SS; bitpos: [31:0]; default: 0;
* data buffer
*/
@@ -1826,7 +1826,7 @@ extern "C" {
/** SPI_W6_REG register
* SPI CPU-controlled buffer6
*/
#define SPI_W6_REG (DR_REG_SPI_BASE + 0xb0)
#define SPI_W6_REG(i) (REG_SPI_BASE(i) + 0xb0)
/** SPI_BUF6 : R/W/SS; bitpos: [31:0]; default: 0;
* data buffer
*/
@@ -1838,7 +1838,7 @@ extern "C" {
/** SPI_W7_REG register
* SPI CPU-controlled buffer7
*/
#define SPI_W7_REG (DR_REG_SPI_BASE + 0xb4)
#define SPI_W7_REG(i) (REG_SPI_BASE(i) + 0xb4)
/** SPI_BUF7 : R/W/SS; bitpos: [31:0]; default: 0;
* data buffer
*/
@@ -1850,7 +1850,7 @@ extern "C" {
/** SPI_W8_REG register
* SPI CPU-controlled buffer8
*/
#define SPI_W8_REG (DR_REG_SPI_BASE + 0xb8)
#define SPI_W8_REG(i) (REG_SPI_BASE(i) + 0xb8)
/** SPI_BUF8 : R/W/SS; bitpos: [31:0]; default: 0;
* data buffer
*/
@@ -1862,7 +1862,7 @@ extern "C" {
/** SPI_W9_REG register
* SPI CPU-controlled buffer9
*/
#define SPI_W9_REG (DR_REG_SPI_BASE + 0xbc)
#define SPI_W9_REG(i) (REG_SPI_BASE(i) + 0xbc)
/** SPI_BUF9 : R/W/SS; bitpos: [31:0]; default: 0;
* data buffer
*/
@@ -1874,7 +1874,7 @@ extern "C" {
/** SPI_W10_REG register
* SPI CPU-controlled buffer10
*/
#define SPI_W10_REG (DR_REG_SPI_BASE + 0xc0)
#define SPI_W10_REG(i) (REG_SPI_BASE(i) + 0xc0)
/** SPI_BUF10 : R/W/SS; bitpos: [31:0]; default: 0;
* data buffer
*/
@@ -1886,7 +1886,7 @@ extern "C" {
/** SPI_W11_REG register
* SPI CPU-controlled buffer11
*/
#define SPI_W11_REG (DR_REG_SPI_BASE + 0xc4)
#define SPI_W11_REG(i) (REG_SPI_BASE(i) + 0xc4)
/** SPI_BUF11 : R/W/SS; bitpos: [31:0]; default: 0;
* data buffer
*/
@@ -1898,7 +1898,7 @@ extern "C" {
/** SPI_W12_REG register
* SPI CPU-controlled buffer12
*/
#define SPI_W12_REG (DR_REG_SPI_BASE + 0xc8)
#define SPI_W12_REG(i) (REG_SPI_BASE(i) + 0xc8)
/** SPI_BUF12 : R/W/SS; bitpos: [31:0]; default: 0;
* data buffer
*/
@@ -1910,7 +1910,7 @@ extern "C" {
/** SPI_W13_REG register
* SPI CPU-controlled buffer13
*/
#define SPI_W13_REG (DR_REG_SPI_BASE + 0xcc)
#define SPI_W13_REG(i) (REG_SPI_BASE(i) + 0xcc)
/** SPI_BUF13 : R/W/SS; bitpos: [31:0]; default: 0;
* data buffer
*/
@@ -1922,7 +1922,7 @@ extern "C" {
/** SPI_W14_REG register
* SPI CPU-controlled buffer14
*/
#define SPI_W14_REG (DR_REG_SPI_BASE + 0xd0)
#define SPI_W14_REG(i) (REG_SPI_BASE(i) + 0xd0)
/** SPI_BUF14 : R/W/SS; bitpos: [31:0]; default: 0;
* data buffer
*/
@@ -1934,7 +1934,7 @@ extern "C" {
/** SPI_W15_REG register
* SPI CPU-controlled buffer15
*/
#define SPI_W15_REG (DR_REG_SPI_BASE + 0xd4)
#define SPI_W15_REG(i) (REG_SPI_BASE(i) + 0xd4)
/** SPI_BUF15 : R/W/SS; bitpos: [31:0]; default: 0;
* data buffer
*/
@@ -1946,11 +1946,11 @@ extern "C" {
/** SPI_SLAVE_REG register
* SPI slave control register
*/
#define SPI_SLAVE_REG (DR_REG_SPI_BASE + 0xe0)
#define SPI_SLAVE_REG(i) (REG_SPI_BASE(i) + 0xe0)
/** SPI_CLK_MODE : R/W; bitpos: [1:0]; default: 0;
* SPI clock mode bits. 0: SPI clock is off when CS inactive 1: SPI clock is delayed
* one cycle after CS inactive 2: SPI clock is delayed two cycles after CS inactive 3:
* SPI clock is alwasy on. Can be configured in CONF state.
* SPI clock is always on. Can be configured in CONF state.
*/
#define SPI_CLK_MODE 0x00000003U
#define SPI_CLK_MODE_M (SPI_CLK_MODE_V << SPI_CLK_MODE_S)
@@ -2047,7 +2047,7 @@ extern "C" {
/** SPI_SLAVE1_REG register
* SPI slave control register 1
*/
#define SPI_SLAVE1_REG (DR_REG_SPI_BASE + 0xe4)
#define SPI_SLAVE1_REG(i) (REG_SPI_BASE(i) + 0xe4)
/** SPI_SLV_DATA_BITLEN : R/W/SS; bitpos: [17:0]; default: 0;
* The transferred data bit length in SPI slave FD and HD mode.
*/
@@ -2073,7 +2073,7 @@ extern "C" {
/** SPI_CLK_GATE_REG register
* SPI module clock and register clock control
*/
#define SPI_CLK_GATE_REG (DR_REG_SPI_BASE + 0xe8)
#define SPI_CLK_GATE_REG(i) (REG_SPI_BASE(i) + 0xe8)
/** SPI_CLK_EN : R/W; bitpos: [0]; default: 0;
* Set this bit to enable clk gate
*/
@@ -2100,7 +2100,7 @@ extern "C" {
/** SPI_DATE_REG register
* Version control
*/
#define SPI_DATE_REG (DR_REG_SPI_BASE + 0xf0)
#define SPI_DATE_REG(i) (REG_SPI_BASE(i) + 0xf0)
/** SPI_DATE : R/W; bitpos: [27:0]; default: 35656448;
* SPI register version.
*/
@@ -305,6 +305,14 @@ Bus Acquiring
Sometimes you might want to send SPI transactions exclusively and continuously so that it takes as little time as possible. For this, you can use bus acquiring, which helps to suspend transactions (both polling or interrupt) to other Devices until the bus is released. To acquire and release a bus, use the functions :cpp:func:`spi_device_acquire_bus` and :cpp:func:`spi_device_release_bus`.
.. 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.
Driver Usage
------------
@@ -482,7 +490,7 @@ GPIO Matrix and IO_MUX
Most of the chip's peripheral signals have a direct connection to their dedicated IO_MUX pins. However, the signals can also be routed to any other available pins using the less direct GPIO matrix. If at least one signal is routed through the GPIO matrix, then all signals will be routed through it.
When an SPI Host is set to 80 MHz or lower frequencies, routing SPI pins via the GPIO matrix will behave the same compared to routing them via IOMUX.
When an SPI Host is set to 40 MHz or lower frequencies, routing SPI pins via the GPIO matrix will behave the same compared to routing them via IOMUX.
The IO_MUX pins for SPI buses are given below.
@@ -143,6 +143,7 @@ Light-sleep Peripheral Power Down
- TIMG0
- SPI0/1
- SYSTIMER
:SOC_SPI_SUPPORT_SLEEP_RETENTION: - All GPSPIs
The following peripherals are not yet supported:
- ETM
@@ -150,7 +151,6 @@ Light-sleep Peripheral Power Down
- ASSIST_DEBUG
- Trace
- Crypto: AES/ECC/HMAC/RSA/SHA/DS/XTA_AES/ECDSA
- SPI2
- I2C
- I2S
- PCNT
@@ -305,6 +305,14 @@ SPI 总线传输事务由五个阶段构成,详见下表(任意阶段均可
若需连续发送专门的 SPI 传输事务以提高效率,可采用获取总线的方式。获取总线后,与其他设备间的传输事务(包括轮询传输事务或中断传输事务)将处于待处理状态,直到总线被释放。要获取和释放总线,请调用函数 :cpp:func:`spi_device_acquire_bus`:cpp:func:`spi_device_release_bus`
.. 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 掉电,同时保存寄存器配置。它可以帮助降低轻度睡眠时的功耗,但需要花费一些额外的存储来保存寄存器的配置。
使用驱动程序
-----------------
@@ -482,7 +490,7 @@ GPIO 矩阵与 IO_MUX 管脚
芯片的大多数外围信号都与之专用的 IO_MUX 管脚连接,但这些信号也可以通过较不直接的 GPIO 矩阵路由到任何其他可用的管脚。只要有一个信号是通过 GPIO 矩阵路由的,那么所有的信号都将通过它路由。
当 SPI 主机被设置为 80 MHz 或更低的频率时,通过 GPIO 矩阵路由 SPI 管脚的行为将与通过 IOMUX 路由相同。
当 SPI 主机被设置为 40 MHz 或更低的频率时,通过 GPIO 矩阵路由 SPI 管脚的行为将与通过 IOMUX 路由相同。
SPI 总线的 IO_MUX 管脚如下表所示。
@@ -143,6 +143,7 @@ Light-sleep 外设下电
- TIMG0
- SPI0/1
- SYSTIMER
:SOC_SPI_SUPPORT_SLEEP_RETENTION: - All GPSPIs
以下外设尚未支持:
- ETM
@@ -150,7 +151,6 @@ Light-sleep 外设下电
- ASSIST_DEBUG
- Trace
- Crypto: AES/ECC/HMAC/RSA/SHA/DS/XTA_AES/ECDSA
- SPI2
- I2C
- I2S
- PCNT