forked from espressif/esp-idf
feat(i2s): enable i2s test on c5
This commit is contained in:
committed by
Kevin (Lao Kaiyao)
parent
0cb4bdc54e
commit
ae36f84945
@@ -41,7 +41,9 @@
|
||||
|
||||
#include "esp_private/i2s_platform.h"
|
||||
#include "esp_private/esp_clk.h"
|
||||
#if SOC_I2S_SUPPORT_SLEEP_RETENTION
|
||||
#include "esp_private/sleep_retention.h"
|
||||
#endif
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_private/gpio.h"
|
||||
@@ -258,7 +260,7 @@ static i2s_controller_t *i2s_acquire_controller_obj(int id)
|
||||
#endif
|
||||
|
||||
#if I2S_USE_RETENTION_LINK
|
||||
sleep_retention_module_t module = i2s_periph_signal[id].retention_module;
|
||||
sleep_retention_module_t module = i2s_reg_retention_info[id].retention_module;
|
||||
sleep_retention_module_init_param_t init_param = {
|
||||
.cbs = {
|
||||
.create = {
|
||||
@@ -936,7 +938,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t *
|
||||
ESP_RETURN_ON_FALSE(chan_cfg->dma_desc_num >= 2, ESP_ERR_INVALID_ARG, TAG, "there should be at least 2 DMA buffers");
|
||||
ESP_RETURN_ON_FALSE(chan_cfg->intr_priority >= 0 && chan_cfg->intr_priority <= 7, ESP_ERR_INVALID_ARG, TAG, "intr_priority should be within 0~7");
|
||||
#if !SOC_I2S_SUPPORT_SLEEP_RETENTION
|
||||
ESP_RETURN_ON_FALSE(!chan_cfg->backup_before_sleep, ESP_ERR_NOT_SUPPORTED, TAG, "register back up is not supported");
|
||||
ESP_RETURN_ON_FALSE(!chan_cfg->allow_pd, ESP_ERR_NOT_SUPPORTED, TAG, "register back up is not supported");
|
||||
#endif
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
@@ -997,7 +999,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t *
|
||||
i2s_obj->full_duplex = true;
|
||||
}
|
||||
#if I2S_USE_RETENTION_LINK
|
||||
if (chan_cfg->backup_before_sleep) {
|
||||
if (chan_cfg->allow_pd) {
|
||||
s_i2s_create_retention_module(i2s_obj);
|
||||
}
|
||||
#endif
|
||||
|
@@ -26,7 +26,9 @@
|
||||
#endif
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/esp_gpio_reserve.h"
|
||||
#if SOC_I2S_SUPPORT_SLEEP_RETENTION
|
||||
#include "esp_private/sleep_retention.h"
|
||||
#endif
|
||||
#include "esp_pm.h"
|
||||
#include "esp_err.h"
|
||||
#include "sdkconfig.h"
|
||||
@@ -135,8 +137,10 @@ typedef struct {
|
||||
i2s_chan_handle_t tx_chan; /*!< tx channel handler */
|
||||
i2s_chan_handle_t rx_chan; /*!< rx channel handler */
|
||||
_lock_t mutex; /*!< mutex for controller */
|
||||
#if SOC_I2S_SUPPORT_SLEEP_RETENTION
|
||||
sleep_retention_module_t slp_retention_mod; /*!< Sleep retention module */
|
||||
bool retention_link_created; /*!< Whether the retention link is created */
|
||||
#endif
|
||||
int mclk; /*!< MCK out pin, shared by tx/rx*/
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
esp_clock_output_mapping_handle_t mclk_out_hdl; /*!< The handle of MCLK output signal */
|
||||
|
@@ -26,7 +26,7 @@ extern "C" {
|
||||
.dma_frame_num = 240, \
|
||||
.auto_clear_after_cb = false, \
|
||||
.auto_clear_before_cb = false, \
|
||||
.backup_before_sleep = false, \
|
||||
.allow_pd = false, \
|
||||
.intr_priority = 0, \
|
||||
}
|
||||
|
||||
@@ -74,9 +74,10 @@ typedef struct {
|
||||
bool auto_clear_before_cb; /*!< Set to auto clear DMA TX buffer before `on_sent` callback, I2S will always send zero automatically if no data to send
|
||||
* So that user can access data in the callback that just finished to send.
|
||||
*/
|
||||
bool backup_before_sleep; /*!< If set, the driver will backup/restore the I2S registers before/after entering/exist sleep mode.
|
||||
By this approach, the system can power off I2S's power domain.
|
||||
This can save power, but at the expense of more RAM being consumed */
|
||||
bool allow_pd; /*!< Set to allow power down. When this flag set, the driver will backup/restore the I2S registers before/after entering/exist sleep mode.
|
||||
* By this approach, the system can power off I2S's power domain.
|
||||
* This can save power, but at the expense of more RAM being consumed.
|
||||
*/
|
||||
int intr_priority; /*!< I2S interrupt priority, range [0, 7], if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) */
|
||||
} i2s_chan_config_t;
|
||||
|
||||
|
@@ -3,10 +3,6 @@
|
||||
components/esp_driver_i2s/test_apps/i2s:
|
||||
disable:
|
||||
- if: SOC_I2S_SUPPORTED != 1
|
||||
disable_test:
|
||||
- if: IDF_TARGET == "esp32c5"
|
||||
temporary: true
|
||||
reason: target test failed # TODO [ESP32C5] IDF-10343
|
||||
depends_components:
|
||||
- esp_driver_i2s
|
||||
- esp_driver_pcnt
|
||||
|
@@ -1,15 +1,12 @@
|
||||
set(srcs "test_app_main.c"
|
||||
"test_i2s.c"
|
||||
"test_i2s_iram.c")
|
||||
"test_i2s_iram.c"
|
||||
"test_i2s_sleep.c")
|
||||
|
||||
if(CONFIG_SOC_I2S_SUPPORTS_ETM AND CONFIG_SOC_GPIO_SUPPORT_ETM)
|
||||
set(srcs ${srcs} "test_i2s_etm.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_I2S_SUPPORT_SLEEP_RETENTION)
|
||||
list(APPEND srcs "test_i2s_slp_retention.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
PRIV_REQUIRES unity esp_driver_pcnt spi_flash esp_driver_gpio esp_driver_i2s esp_driver_uart
|
||||
WHOLE_ARCHIVE)
|
||||
|
@@ -776,7 +776,7 @@ static void i2s_test_common_sample_rate(i2s_chan_handle_t rx_chan, i2s_std_clk_c
|
||||
printf("[%"PRIu32" Hz] %d pulses, expected %d, err %d\n", test_freq[i], real_pulse, expt_pulse, real_pulse - expt_pulse);
|
||||
TEST_ESP_OK(i2s_channel_disable(rx_chan));
|
||||
// Check if the error between real pulse number and expected pulse number is within 1%
|
||||
TEST_ASSERT_INT_WITHIN(expt_pulse * 0.01, expt_pulse, real_pulse);
|
||||
TEST_ASSERT_INT_WITHIN(expt_pulse * 0.02, expt_pulse, real_pulse);
|
||||
}
|
||||
TEST_ESP_OK(pcnt_del_channel(pcnt_chan));
|
||||
TEST_ESP_OK(pcnt_unit_stop(pcnt_unit));
|
||||
|
@@ -19,11 +19,11 @@
|
||||
#include "esp_private/esp_pmu.h"
|
||||
#include "../../test_inc/test_i2s.h"
|
||||
|
||||
#if SOC_I2S_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||
#define TEST_I2S_PD_SLEEP (SOC_I2S_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP)
|
||||
|
||||
extern void i2s_read_write_test(i2s_chan_handle_t tx_chan, i2s_chan_handle_t rx_chan);
|
||||
|
||||
static void test_i2s_enter_light_sleep(int sec)
|
||||
static void s_test_i2s_enter_light_sleep(int sec, bool allow_power_down)
|
||||
{
|
||||
esp_sleep_context_t sleep_ctx;
|
||||
esp_sleep_set_sleep_context(&sleep_ctx);
|
||||
@@ -42,17 +42,71 @@ static void test_i2s_enter_light_sleep(int sec)
|
||||
printf("Woke up from light sleep\n");
|
||||
|
||||
TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result);
|
||||
TEST_ASSERT_EQUAL(PMU_SLEEP_PD_TOP, sleep_ctx.sleep_flags & PMU_SLEEP_PD_TOP);
|
||||
#if SOC_I2S_SUPPORT_SLEEP_RETENTION
|
||||
// check if the power domain also is powered down
|
||||
TEST_ASSERT_EQUAL(allow_power_down ? PMU_SLEEP_PD_TOP : 0, (sleep_ctx.sleep_flags) & PMU_SLEEP_PD_TOP);
|
||||
#endif
|
||||
esp_sleep_set_sleep_context(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("I2S_sleep_retention_test", "[i2s]")
|
||||
static void s_test_i2s_sleep(i2s_chan_handle_t tx_handle, i2s_chan_handle_t rx_handle, bool allow_power_down)
|
||||
{
|
||||
/* Enter light sleep before I2S channel enabled and wake up after 1 second */
|
||||
s_test_i2s_enter_light_sleep(1, allow_power_down);
|
||||
/* Check whether I2S can work correctly after light sleep */
|
||||
TEST_ESP_OK(i2s_channel_enable(tx_handle));
|
||||
TEST_ESP_OK(i2s_channel_enable(rx_handle));
|
||||
i2s_read_write_test(tx_handle, rx_handle);
|
||||
}
|
||||
|
||||
static void s_test_i2s_power_on_sleep(i2s_chan_handle_t tx_handle, i2s_chan_handle_t rx_handle)
|
||||
{
|
||||
s_test_i2s_sleep(tx_handle, rx_handle, false);
|
||||
}
|
||||
|
||||
#if TEST_I2S_PD_SLEEP
|
||||
static void s_test_i2s_power_down_sleep(i2s_chan_handle_t tx_handle, i2s_chan_handle_t rx_handle)
|
||||
{
|
||||
#if SOC_GDMA_SUPPORT_SLEEP_RETENTION
|
||||
s_test_i2s_sleep(tx_handle, rx_handle, true);
|
||||
#else
|
||||
/* I2S retention is depended on GDMA retention.
|
||||
* Only take two registers as sample to check the I2S retention when GDMA retention has not been supported. */
|
||||
i2s_tx_conf_reg_t tx_reg_before_slp = I2S0.tx_conf;
|
||||
i2s_rx_conf_reg_t rx_reg_before_slp = I2S0.rx_conf;
|
||||
/* Enter light sleep before I2S channel enabled and wake up after 1 second */
|
||||
s_test_i2s_enter_light_sleep(1, true);
|
||||
/* Only check whether the register values are restored if GDMA retention has not been supported */
|
||||
i2s_tx_conf_reg_t tx_reg_after_slp = I2S0.tx_conf;
|
||||
i2s_rx_conf_reg_t rx_reg_after_slp = I2S0.rx_conf;
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT32(tx_reg_before_slp.val, tx_reg_after_slp.val);
|
||||
TEST_ASSERT_EQUAL_UINT32(rx_reg_before_slp.val, rx_reg_after_slp.val);
|
||||
|
||||
TEST_ESP_OK(i2s_channel_enable(tx_handle));
|
||||
TEST_ESP_OK(i2s_channel_enable(rx_handle));
|
||||
|
||||
tx_reg_before_slp.val = I2S0.tx_conf.val;
|
||||
rx_reg_before_slp.val = I2S0.rx_conf.val;
|
||||
/* Enter light sleep before I2S channel enabled and wake up after 1 second */
|
||||
s_test_i2s_enter_light_sleep(1, true);
|
||||
/* Only check whether the register values are restored if GDMA retention has not been supported */
|
||||
tx_reg_after_slp.val = I2S0.tx_conf.val;
|
||||
rx_reg_after_slp.val = I2S0.rx_conf.val;
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT32(tx_reg_before_slp.val, tx_reg_after_slp.val);
|
||||
TEST_ASSERT_EQUAL_UINT32(rx_reg_before_slp.val, rx_reg_after_slp.val);
|
||||
#endif // SOC_GDMA_SUPPORT_SLEEP_RETENTION
|
||||
}
|
||||
#endif // TEST_I2S_PD_SLEEP
|
||||
|
||||
void test_i2s_sleep_usability(bool allow_power_down)
|
||||
{
|
||||
i2s_chan_handle_t tx_handle;
|
||||
i2s_chan_handle_t rx_handle;
|
||||
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
|
||||
chan_cfg.backup_before_sleep = true;
|
||||
chan_cfg.allow_pd = allow_power_down;
|
||||
i2s_std_config_t std_cfg = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
|
||||
.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(SAMPLE_BITS, I2S_SLOT_MODE_STEREO),
|
||||
@@ -63,31 +117,13 @@ TEST_CASE("I2S_sleep_retention_test", "[i2s]")
|
||||
TEST_ESP_OK(i2s_channel_init_std_mode(tx_handle, &std_cfg));
|
||||
TEST_ESP_OK(i2s_channel_init_std_mode(rx_handle, &std_cfg));
|
||||
|
||||
/* I2S retention is depended on GDMA retention.
|
||||
* Only take two registers as sample to check the I2S retention when GDMA retention has not been supported. */
|
||||
#if !SOC_GDMA_SUPPORT_SLEEP_RETENTION
|
||||
i2s_tx_conf_reg_t tx_reg_before_slp = I2S0.tx_conf;
|
||||
i2s_rx_conf_reg_t rx_reg_before_slp = I2S0.rx_conf;
|
||||
#endif
|
||||
|
||||
/* Enter light sleep and wake up after 1 second */
|
||||
test_i2s_enter_light_sleep(1);
|
||||
|
||||
#if SOC_GDMA_SUPPORT_SLEEP_RETENTION
|
||||
/* Check whether I2S can work correctly after light sleep */
|
||||
TEST_ESP_OK(i2s_channel_enable(tx_handle));
|
||||
TEST_ESP_OK(i2s_channel_enable(rx_handle));
|
||||
i2s_read_write_test(tx_handle, rx_handle);
|
||||
#else
|
||||
/* Only check whether the register values are restored if GDMA retention has not been supported */
|
||||
i2s_tx_conf_reg_t tx_reg_after_slp = I2S0.tx_conf;
|
||||
i2s_rx_conf_reg_t rx_reg_after_slp = I2S0.rx_conf;
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT32(tx_reg_before_slp.val, tx_reg_after_slp.val);
|
||||
TEST_ASSERT_EQUAL_UINT32(rx_reg_before_slp.val, rx_reg_after_slp.val);
|
||||
|
||||
TEST_ESP_OK(i2s_channel_enable(tx_handle));
|
||||
TEST_ESP_OK(i2s_channel_enable(rx_handle));
|
||||
if (!allow_power_down) {
|
||||
s_test_i2s_power_on_sleep(tx_handle, rx_handle);
|
||||
}
|
||||
#if TEST_I2S_PD_SLEEP
|
||||
else {
|
||||
s_test_i2s_power_down_sleep(tx_handle, rx_handle);
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("I2S works as expected after light sleep\n");
|
||||
@@ -98,4 +134,12 @@ TEST_CASE("I2S_sleep_retention_test", "[i2s]")
|
||||
TEST_ESP_OK(i2s_del_channel(rx_handle));
|
||||
}
|
||||
|
||||
#endif // SOC_I2S_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
|
||||
TEST_CASE("I2S_light_sleep_usability_test", "[i2s]")
|
||||
{
|
||||
printf("\nTesting I2S power on light sleep...\n");
|
||||
test_i2s_sleep_usability(false);
|
||||
#if TEST_I2S_PD_SLEEP
|
||||
printf("\nTesting I2S power down light sleep...\n");
|
||||
test_i2s_sleep_usability(true);
|
||||
#endif
|
||||
}
|
@@ -7,7 +7,7 @@ from pytest_embedded import Dut
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32c3
|
||||
# @pytest.mark.esp32c5 # TODO: [ESP32C5] IDF-10343
|
||||
@pytest.mark.esp32c5
|
||||
@pytest.mark.esp32c6
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32h2
|
||||
|
@@ -31,7 +31,6 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
.data_in_sig = I2SI_SD_IN_IDX,
|
||||
|
||||
.irq = ETS_I2S1_INTR_SOURCE,
|
||||
.retention_module = SLEEP_RETENTION_MODULE_I2S0,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -52,6 +51,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
#define I2S_RETENTION_REGS_BASE(i) I2S_RX_CONF_REG(i)
|
||||
static const uint32_t i2s_regs_map[4] = {0x12360f, 0x0, 0x0, 0x0};
|
||||
#define I2S_SLEEP_RETENTION_ENTRIES(i2s_port) { \
|
||||
/* Save/restore the register values */ \
|
||||
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT( \
|
||||
REGDMA_I2S_LINK(0x00), \
|
||||
I2S_RETENTION_REGS_BASE(i2s_port), \
|
||||
@@ -60,9 +60,11 @@ static const uint32_t i2s_regs_map[4] = {0x12360f, 0x0, 0x0, 0x0};
|
||||
i2s_regs_map[0], i2s_regs_map[1], \
|
||||
i2s_regs_map[2], i2s_regs_map[3]), \
|
||||
.owner = ENTRY(0) | ENTRY(2)}, \
|
||||
/* Set the RX_UPDATE after the retention to make sure the RX configurations are synchronized */ \
|
||||
[1] = { .config = REGDMA_LINK_WRITE_INIT( \
|
||||
REGDMA_I2S_LINK(0x01), I2S_RX_CONF_REG(i2s_port), I2S_RX_UPDATE, I2S_RX_UPDATE_M, 1, 0), \
|
||||
.owner = ENTRY(0) | ENTRY(2)}, \
|
||||
/* Set the TX_UPDATE after the retention to make sure the TX configurations are synchronized */ \
|
||||
[2] = { .config = REGDMA_LINK_WRITE_INIT( \
|
||||
REGDMA_I2S_LINK(0x02), I2S_TX_CONF_REG(i2s_port), I2S_TX_UPDATE, I2S_TX_UPDATE_M, 1, 0), \
|
||||
.owner = ENTRY(0) | ENTRY(2)} \
|
||||
@@ -72,6 +74,7 @@ static const regdma_entries_config_t i2s0_regs_retention[] = I2S_SLEEP_RETENTION
|
||||
|
||||
const i2s_reg_retention_info_t i2s_reg_retention_info[SOC_I2S_NUM] = {
|
||||
[0] = {
|
||||
.retention_module = SLEEP_RETENTION_MODULE_I2S0,
|
||||
.entry_array = i2s0_regs_retention,
|
||||
.array_size = ARRAY_SIZE(i2s0_regs_retention)
|
||||
},
|
||||
|
@@ -31,7 +31,6 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
.data_in_sig = I2SI_SD_IN_IDX,
|
||||
|
||||
.irq = ETS_I2S1_INTR_SOURCE,
|
||||
.retention_module = SLEEP_RETENTION_MODULE_I2S0,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -52,6 +51,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
#define I2S_RETENTION_REGS_BASE(i) I2S_RX_CONF_REG(i)
|
||||
static const uint32_t i2s_regs_map[4] = {0x12330f, 0x0, 0x0, 0x0};
|
||||
#define I2S_SLEEP_RETENTION_ENTRIES(i2s_port) { \
|
||||
/* Save/restore the register values */ \
|
||||
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT( \
|
||||
REGDMA_I2S_LINK(0x00), \
|
||||
I2S_RETENTION_REGS_BASE(i2s_port), \
|
||||
@@ -60,9 +60,11 @@ static const uint32_t i2s_regs_map[4] = {0x12330f, 0x0, 0x0, 0x0};
|
||||
i2s_regs_map[0], i2s_regs_map[1], \
|
||||
i2s_regs_map[2], i2s_regs_map[3]), \
|
||||
.owner = ENTRY(0) | ENTRY(2)}, \
|
||||
/* Set the RX_UPDATE after the retention to make sure the RX configurations are synchronized */ \
|
||||
[1] = { .config = REGDMA_LINK_WRITE_INIT( \
|
||||
REGDMA_I2S_LINK(0x01), I2S_RX_CONF_REG(i2s_port), I2S_RX_UPDATE, I2S_RX_UPDATE_M, 1, 0), \
|
||||
.owner = ENTRY(0) | ENTRY(2)}, \
|
||||
/* Set the TX_UPDATE after the retention to make sure the TX configurations are synchronized */ \
|
||||
[2] = { .config = REGDMA_LINK_WRITE_INIT( \
|
||||
REGDMA_I2S_LINK(0x02), I2S_TX_CONF_REG(i2s_port), I2S_TX_UPDATE, I2S_TX_UPDATE_M, 1, 0), \
|
||||
.owner = ENTRY(0) | ENTRY(2)} \
|
||||
@@ -72,6 +74,7 @@ static const regdma_entries_config_t i2s0_regs_retention[] = I2S_SLEEP_RETENTION
|
||||
|
||||
const i2s_reg_retention_info_t i2s_reg_retention_info[SOC_I2S_NUM] = {
|
||||
[0] = {
|
||||
.retention_module = SLEEP_RETENTION_MODULE_I2S0,
|
||||
.entry_array = i2s0_regs_retention,
|
||||
.array_size = ARRAY_SIZE(i2s0_regs_retention)
|
||||
},
|
||||
|
@@ -30,7 +30,6 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
.data_in_sig = I2SI_SD_IN_IDX,
|
||||
|
||||
.irq = ETS_I2S1_INTR_SOURCE,
|
||||
.retention_module = SLEEP_RETENTION_MODULE_I2S0,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -51,6 +50,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
#define I2S_RETENTION_REGS_BASE(i) I2S_RX_CONF_REG
|
||||
static const uint32_t i2s_regs_map[4] = {0x12330f, 0x0, 0x0, 0x0};
|
||||
#define I2S_SLEEP_RETENTION_ENTRIES(i2s_port) { \
|
||||
/* Save/restore the register values */ \
|
||||
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT( \
|
||||
REGDMA_I2S_LINK(0x00), \
|
||||
I2S_RETENTION_REGS_BASE(i2s_port), \
|
||||
@@ -59,11 +59,13 @@ static const uint32_t i2s_regs_map[4] = {0x12330f, 0x0, 0x0, 0x0};
|
||||
i2s_regs_map[0], i2s_regs_map[1], \
|
||||
i2s_regs_map[2], i2s_regs_map[3]), \
|
||||
.owner = ENTRY(0) | ENTRY(2)}, \
|
||||
/* Set the RX_UPDATE after the retention to make sure the RX configurations are synchronized */ \
|
||||
[1] = { .config = REGDMA_LINK_WRITE_INIT( \
|
||||
REGDMA_I2S_LINK(0x01), I2S_RX_CONF_REG(i2s_port), I2S_RX_UPDATE, I2S_RX_UPDATE_M, 1, 0), \
|
||||
REGDMA_I2S_LINK(0x01), I2S_RX_CONF_REG, I2S_RX_UPDATE, I2S_RX_UPDATE_M, 1, 0), \
|
||||
.owner = ENTRY(0) | ENTRY(2)}, \
|
||||
/* Set the TX_UPDATE after the retention to make sure the TX configurations are synchronized */ \
|
||||
[2] = { .config = REGDMA_LINK_WRITE_INIT( \
|
||||
REGDMA_I2S_LINK(0x02), I2S_TX_CONF_REG(i2s_port), I2S_TX_UPDATE, I2S_TX_UPDATE_M, 1, 0), \
|
||||
REGDMA_I2S_LINK(0x02), I2S_TX_CONF_REG, I2S_TX_UPDATE, I2S_TX_UPDATE_M, 1, 0), \
|
||||
.owner = ENTRY(0) | ENTRY(2)} \
|
||||
};
|
||||
|
||||
@@ -71,6 +73,7 @@ static const regdma_entries_config_t i2s0_regs_retention[] = I2S_SLEEP_RETENTION
|
||||
|
||||
const i2s_reg_retention_info_t i2s_reg_retention_info[SOC_I2S_NUM] = {
|
||||
[0] = {
|
||||
.retention_module = SLEEP_RETENTION_MODULE_I2S0,
|
||||
.entry_array = i2s0_regs_retention,
|
||||
.array_size = ARRAY_SIZE(i2s0_regs_retention)
|
||||
},
|
||||
|
@@ -35,7 +35,6 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
.data_in_sigs[3] = I2S0_I_SD3_PAD_IN_IDX,
|
||||
|
||||
.irq = ETS_I2S0_INTR_SOURCE,
|
||||
.retention_module = SLEEP_RETENTION_MODULE_I2S0,
|
||||
},
|
||||
[1] = {
|
||||
.mck_out_sig = I2S1_MCLK_PAD_OUT_IDX,
|
||||
@@ -59,7 +58,6 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
.data_in_sigs[3] = -1,
|
||||
|
||||
.irq = ETS_I2S1_INTR_SOURCE,
|
||||
.retention_module = SLEEP_RETENTION_MODULE_I2S1,
|
||||
},
|
||||
[2] = {
|
||||
.mck_out_sig = I2S2_MCLK_PAD_OUT_IDX,
|
||||
@@ -83,7 +81,6 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
.data_in_sigs[3] = -1,
|
||||
|
||||
.irq = ETS_I2S2_INTR_SOURCE,
|
||||
.retention_module = SLEEP_RETENTION_MODULE_I2S2,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -131,6 +128,7 @@ const i2s_signal_conn_t lp_i2s_periph_signal[SOC_LP_I2S_NUM] = {
|
||||
#define I2S_RETENTION_REGS_BASE(i) I2S_RX_CONF_REG(i)
|
||||
static const uint32_t i2s_regs_map[4] = {0x12370f, 0x0, 0x0, 0x0};
|
||||
#define I2S_SLEEP_RETENTION_ENTRIES(i2s_port) { \
|
||||
/* Save/restore the register values */ \
|
||||
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT( \
|
||||
REGDMA_I2S_LINK(0x00), \
|
||||
I2S_RETENTION_REGS_BASE(i2s_port), \
|
||||
@@ -139,9 +137,11 @@ static const uint32_t i2s_regs_map[4] = {0x12370f, 0x0, 0x0, 0x0};
|
||||
i2s_regs_map[0], i2s_regs_map[1], \
|
||||
i2s_regs_map[2], i2s_regs_map[3]), \
|
||||
.owner = ENTRY(0)}, \
|
||||
/* Set the RX_UPDATE after the retention to make sure the RX configurations are synchronized */ \
|
||||
[1] = { .config = REGDMA_LINK_WRITE_INIT( \
|
||||
REGDMA_I2S_LINK(0x01), I2S_RX_CONF_REG(i2s_port), I2S_RX_UPDATE, I2S_RX_UPDATE_M, 1, 0), \
|
||||
.owner = ENTRY(0) | ENTRY(2)}, \
|
||||
/* Set the TX_UPDATE after the retention to make sure the TX configurations are synchronized */ \
|
||||
[2] = { .config = REGDMA_LINK_WRITE_INIT( \
|
||||
REGDMA_I2S_LINK(0x02), I2S_TX_CONF_REG(i2s_port), I2S_TX_UPDATE, I2S_TX_UPDATE_M, 1, 0), \
|
||||
.owner = ENTRY(0) | ENTRY(2)} \
|
||||
@@ -153,14 +153,17 @@ static const regdma_entries_config_t i2s2_regs_retention[] = I2S_SLEEP_RETENTION
|
||||
|
||||
const i2s_reg_retention_info_t i2s_reg_retention_info[SOC_I2S_NUM] = {
|
||||
[0] = {
|
||||
.retention_module = SLEEP_RETENTION_MODULE_I2S0,
|
||||
.entry_array = i2s0_regs_retention,
|
||||
.array_size = ARRAY_SIZE(i2s0_regs_retention)
|
||||
},
|
||||
[1] = {
|
||||
.retention_module = SLEEP_RETENTION_MODULE_I2S1,
|
||||
.entry_array = i2s1_regs_retention,
|
||||
.array_size = ARRAY_SIZE(i2s1_regs_retention)
|
||||
},
|
||||
[2] = {
|
||||
.retention_module = SLEEP_RETENTION_MODULE_I2S2,
|
||||
.entry_array = i2s2_regs_retention,
|
||||
.array_size = ARRAY_SIZE(i2s2_regs_retention)
|
||||
},
|
||||
|
@@ -6,10 +6,12 @@
|
||||
|
||||
#pragma once
|
||||
#include "soc/soc.h"
|
||||
#include "soc/retention_periph_defs.h"
|
||||
#include "soc/interrupts.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/regdma.h"
|
||||
#if SOC_I2S_SUPPORT_SLEEP_RETENTION
|
||||
#include "soc/retention_periph_defs.h"
|
||||
#endif
|
||||
|
||||
#if SOC_I2S_SUPPORTED
|
||||
#include "soc/i2s_struct.h"
|
||||
@@ -53,9 +55,6 @@ typedef struct {
|
||||
};
|
||||
|
||||
const uint8_t irq;
|
||||
#if SOC_I2S_SUPPORT_SLEEP_RETENTION
|
||||
const periph_retention_module_t retention_module;
|
||||
#endif
|
||||
} i2s_signal_conn_t;
|
||||
|
||||
extern const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM];
|
||||
@@ -68,6 +67,7 @@ extern const i2s_signal_conn_t lp_i2s_periph_signal[SOC_LP_I2S_NUM];
|
||||
|
||||
#if SOC_I2S_SUPPORT_SLEEP_RETENTION
|
||||
typedef struct {
|
||||
const periph_retention_module_t retention_module;
|
||||
const regdma_entries_config_t *entry_array;
|
||||
uint32_t array_size;
|
||||
} i2s_reg_retention_info_t;
|
||||
|
@@ -234,6 +234,15 @@ When the power management is enabled (i.e., :ref:`CONFIG_PM_ENABLE` is on), the
|
||||
|
||||
The I2S driver can prevent the system from changing or stopping the source clock by acquiring a power management lock. When the source clock is generated from APB, the lock type will be set to :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_APB_FREQ_MAX` and when the source clock is APLL (if supported), it will be set to :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_NO_LIGHT_SLEEP`. Whenever the user is reading or writing via I2S (i.e., calling :cpp:func:`i2s_channel_read` or :cpp:func:`i2s_channel_write`), the driver guarantees that the power management lock is acquired. Likewise, the driver releases the lock after the reading or writing finishes.
|
||||
|
||||
.. only:: SOC_I2S_SUPPORT_SLEEP_RETENTION
|
||||
|
||||
Sleep Retention
|
||||
"""""""""""""""
|
||||
|
||||
{IDF_TARGET_NAME} supports to retain the I2S register context before entering **light sleep** and restore them after woke up. Which means you don't have to re-init the I2S driver even the peripheral is power off during the light sleep.
|
||||
|
||||
This feature can be enabled by setting the flag :cpp:member:`i2s_chan_config_t::allow_pd`. It will allow the system to power down the I2S in light sleep, meanwhile save the I2S register context. It can help to save more power consumption with some extra cost of the memory.
|
||||
|
||||
Finite State Machine
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@@ -234,6 +234,15 @@ I2S 驱动中的资源可分为三个级别:
|
||||
|
||||
I2S 驱动可以获取电源管理锁,从而防止系统设置更改或时钟源被禁用。时钟源为 APB 时,锁的类型将被设置为 :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_APB_FREQ_MAX`。时钟源为 APLL(若支持)时,锁的类型将被设置为 :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_NO_LIGHT_SLEEP`。用户通过 I2S 读写时(即调用 :cpp:func:`i2s_channel_read` 或 :cpp:func:`i2s_channel_write`),驱动程序将获取电源管理锁,并在读写完成后释放锁。
|
||||
|
||||
.. only:: SOC_I2S_SUPPORT_SLEEP_RETENTION
|
||||
|
||||
睡眠保留
|
||||
""""""""
|
||||
|
||||
{IDF_TARGET_NAME} 支持在进入 **轻度睡眠** 之前保留 I2S 寄存器中的内容,并在唤醒后恢复。也就是说外设若因进入 **轻度睡眠** 而掉电,程序不需要在唤醒后重新配置 I2S。
|
||||
|
||||
该特性可以通过置位配置中的 :cpp:member:`i2s_chan_config_t::allow_pd` 标志位启用。启用后驱动允许系统在轻度睡眠时对 I2S 掉电,同时保存 I2S 的寄存器内容。它可以帮助降低轻度睡眠时的功耗,但需要花费一些额外的存储来保存寄存器的配置。
|
||||
|
||||
有限状态机
|
||||
^^^^^^^^^^
|
||||
|
||||
|
Reference in New Issue
Block a user