|
| 1 | +/* |
| 2 | + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: Apache-2.0 |
| 5 | + */ |
| 6 | +#include <stdio.h> |
| 7 | +#include <string.h> |
| 8 | +#include "sdkconfig.h" |
| 9 | +#include "freertos/FreeRTOS.h" |
| 10 | +#include "freertos/task.h" |
| 11 | +#include "unity.h" |
| 12 | +#include "unity_test_utils.h" |
| 13 | +#include "driver/i2s_std.h" |
| 14 | +#include "driver/uart.h" |
| 15 | +#include "soc/i2s_struct.h" |
| 16 | +#include "esp_sleep.h" |
| 17 | +#include "esp_private/sleep_cpu.h" |
| 18 | +#include "esp_private/esp_sleep_internal.h" |
| 19 | +#include "esp_private/esp_pmu.h" |
| 20 | +#include "../../test_inc/test_i2s.h" |
| 21 | + |
| 22 | +#define TEST_I2S_PD_SLEEP (SOC_I2S_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP) |
| 23 | + |
| 24 | +extern void i2s_read_write_test(i2s_chan_handle_t tx_chan, i2s_chan_handle_t rx_chan); |
| 25 | + |
| 26 | +static void s_test_i2s_enter_light_sleep(int sec, bool allow_power_down) |
| 27 | +{ |
| 28 | + esp_sleep_context_t sleep_ctx; |
| 29 | + esp_sleep_set_sleep_context(&sleep_ctx); |
| 30 | + printf("Entering light sleep for %d seconds\n", sec); |
| 31 | +#if ESP_SLEEP_POWER_DOWN_CPU |
| 32 | + printf("Enable CPU power down\n"); |
| 33 | + TEST_ESP_OK(sleep_cpu_configure(true)); |
| 34 | +#endif |
| 35 | + uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM); |
| 36 | + TEST_ESP_OK(esp_sleep_enable_timer_wakeup(sec * 1000 * 1000)); |
| 37 | + TEST_ESP_OK(esp_light_sleep_start()); |
| 38 | + |
| 39 | +#if ESP_SLEEP_POWER_DOWN_CPU |
| 40 | + TEST_ESP_OK(sleep_cpu_configure(false)); |
| 41 | +#endif |
| 42 | + printf("Woke up from light sleep\n"); |
| 43 | + |
| 44 | + TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result); |
| 45 | +#if SOC_I2S_SUPPORT_SLEEP_RETENTION |
| 46 | + // check if the power domain also is powered down |
| 47 | + TEST_ASSERT_EQUAL(allow_power_down ? PMU_SLEEP_PD_TOP : 0, (sleep_ctx.sleep_flags) & PMU_SLEEP_PD_TOP); |
| 48 | +#endif |
| 49 | + esp_sleep_set_sleep_context(NULL); |
| 50 | +} |
| 51 | + |
| 52 | +static void s_test_i2s_sleep(i2s_chan_handle_t tx_handle, i2s_chan_handle_t rx_handle, bool allow_power_down) |
| 53 | +{ |
| 54 | + /* Enter light sleep before I2S channel enabled and wake up after 1 second */ |
| 55 | + s_test_i2s_enter_light_sleep(1, allow_power_down); |
| 56 | + /* Check whether I2S can work correctly after light sleep */ |
| 57 | + TEST_ESP_OK(i2s_channel_enable(tx_handle)); |
| 58 | + TEST_ESP_OK(i2s_channel_enable(rx_handle)); |
| 59 | + i2s_read_write_test(tx_handle, rx_handle); |
| 60 | +} |
| 61 | + |
| 62 | +static void s_test_i2s_power_on_sleep(i2s_chan_handle_t tx_handle, i2s_chan_handle_t rx_handle) |
| 63 | +{ |
| 64 | + s_test_i2s_sleep(tx_handle, rx_handle, false); |
| 65 | +} |
| 66 | + |
| 67 | +#if TEST_I2S_PD_SLEEP |
| 68 | +static void s_test_i2s_power_down_sleep(i2s_chan_handle_t tx_handle, i2s_chan_handle_t rx_handle) |
| 69 | +{ |
| 70 | +#if SOC_GDMA_SUPPORT_SLEEP_RETENTION |
| 71 | + s_test_i2s_sleep(tx_handle, rx_handle, true); |
| 72 | +#else |
| 73 | + /* I2S retention is depended on GDMA retention. |
| 74 | + * Only take two registers as sample to check the I2S retention when GDMA retention has not been supported. */ |
| 75 | + i2s_tx_conf_reg_t tx_reg_before_slp = I2S0.tx_conf; |
| 76 | + i2s_rx_conf_reg_t rx_reg_before_slp = I2S0.rx_conf; |
| 77 | + /* Enter light sleep before I2S channel enabled and wake up after 1 second */ |
| 78 | + s_test_i2s_enter_light_sleep(1, true); |
| 79 | + /* Only check whether the register values are restored if GDMA retention has not been supported */ |
| 80 | + i2s_tx_conf_reg_t tx_reg_after_slp = I2S0.tx_conf; |
| 81 | + i2s_rx_conf_reg_t rx_reg_after_slp = I2S0.rx_conf; |
| 82 | + |
| 83 | + TEST_ASSERT_EQUAL_UINT32(tx_reg_before_slp.val, tx_reg_after_slp.val); |
| 84 | + TEST_ASSERT_EQUAL_UINT32(rx_reg_before_slp.val, rx_reg_after_slp.val); |
| 85 | + |
| 86 | + TEST_ESP_OK(i2s_channel_enable(tx_handle)); |
| 87 | + TEST_ESP_OK(i2s_channel_enable(rx_handle)); |
| 88 | + |
| 89 | + tx_reg_before_slp.val = I2S0.tx_conf.val; |
| 90 | + rx_reg_before_slp.val = I2S0.rx_conf.val; |
| 91 | + /* Enter light sleep before I2S channel enabled and wake up after 1 second */ |
| 92 | + s_test_i2s_enter_light_sleep(1, true); |
| 93 | + /* Only check whether the register values are restored if GDMA retention has not been supported */ |
| 94 | + tx_reg_after_slp.val = I2S0.tx_conf.val; |
| 95 | + rx_reg_after_slp.val = I2S0.rx_conf.val; |
| 96 | + |
| 97 | + TEST_ASSERT_EQUAL_UINT32(tx_reg_before_slp.val, tx_reg_after_slp.val); |
| 98 | + TEST_ASSERT_EQUAL_UINT32(rx_reg_before_slp.val, rx_reg_after_slp.val); |
| 99 | +#endif // SOC_GDMA_SUPPORT_SLEEP_RETENTION |
| 100 | +} |
| 101 | +#endif // TEST_I2S_PD_SLEEP |
| 102 | + |
| 103 | +void test_i2s_sleep_usability(bool allow_power_down) |
| 104 | +{ |
| 105 | + i2s_chan_handle_t tx_handle; |
| 106 | + i2s_chan_handle_t rx_handle; |
| 107 | + |
| 108 | + i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER); |
| 109 | + chan_cfg.allow_pd = allow_power_down; |
| 110 | + i2s_std_config_t std_cfg = { |
| 111 | + .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE), |
| 112 | + .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(SAMPLE_BITS, I2S_SLOT_MODE_STEREO), |
| 113 | + .gpio_cfg = I2S_TEST_MASTER_DEFAULT_PIN, |
| 114 | + }; |
| 115 | + std_cfg.gpio_cfg.din = std_cfg.gpio_cfg.dout; |
| 116 | + TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle)); |
| 117 | + TEST_ESP_OK(i2s_channel_init_std_mode(tx_handle, &std_cfg)); |
| 118 | + TEST_ESP_OK(i2s_channel_init_std_mode(rx_handle, &std_cfg)); |
| 119 | + |
| 120 | + if (!allow_power_down) { |
| 121 | + s_test_i2s_power_on_sleep(tx_handle, rx_handle); |
| 122 | + } |
| 123 | +#if TEST_I2S_PD_SLEEP |
| 124 | + else { |
| 125 | + s_test_i2s_power_down_sleep(tx_handle, rx_handle); |
| 126 | + } |
| 127 | +#endif |
| 128 | + |
| 129 | + printf("I2S works as expected after light sleep\n"); |
| 130 | + |
| 131 | + TEST_ESP_OK(i2s_channel_disable(tx_handle)); |
| 132 | + TEST_ESP_OK(i2s_channel_disable(rx_handle)); |
| 133 | + TEST_ESP_OK(i2s_del_channel(tx_handle)); |
| 134 | + TEST_ESP_OK(i2s_del_channel(rx_handle)); |
| 135 | +} |
| 136 | + |
| 137 | +TEST_CASE("I2S_light_sleep_usability_test", "[i2s]") |
| 138 | +{ |
| 139 | + printf("\nTesting I2S power on light sleep...\n"); |
| 140 | + test_i2s_sleep_usability(false); |
| 141 | +#if TEST_I2S_PD_SLEEP |
| 142 | + printf("\nTesting I2S power down light sleep...\n"); |
| 143 | + test_i2s_sleep_usability(true); |
| 144 | +#endif |
| 145 | +} |
0 commit comments