Skip to content

Commit 409397f

Browse files
committed
fix(i2s): lock APB when using apll with DFS feature
Closes espressif#14707 Append to the commit ad9021a.
1 parent 69bd12d commit 409397f

File tree

10 files changed

+49
-13
lines changed

10 files changed

+49
-13
lines changed

components/driver/deprecated/i2s_legacy.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1479,6 +1479,11 @@ static esp_err_t i2s_init_legacy(i2s_port_t i2s_num, int intr_alloc_flag)
14791479
/* Create power management lock */
14801480
#ifdef CONFIG_PM_ENABLE
14811481
esp_pm_lock_type_t pm_lock = ESP_PM_APB_FREQ_MAX;
1482+
#if SOC_I2S_SUPPORTS_APLL
1483+
if (p_i2s[i2s_num]->use_apll) {
1484+
pm_lock = ESP_PM_NO_LIGHT_SLEEP;
1485+
}
1486+
#endif // SOC_I2S_SUPPORTS_APLL
14821487
ESP_RETURN_ON_ERROR(esp_pm_lock_create(pm_lock, 0, "i2s_driver", &p_i2s[i2s_num]->pm_lock), TAG, "I2S pm lock error");
14831488
#endif //CONFIG_PM_ENABLE
14841489

components/esp_driver_dac/dac_continuous.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ esp_err_t dac_continuous_new_channels(const dac_continuous_config_t *cont_cfg, d
228228

229229
/* Create PM lock */
230230
#if CONFIG_PM_ENABLE
231-
esp_pm_lock_type_t pm_lock_type = ESP_PM_APB_FREQ_MAX;
231+
esp_pm_lock_type_t pm_lock_type = cont_cfg->clk_src == DAC_DIGI_CLK_SRC_APLL ? ESP_PM_NO_LIGHT_SLEEP : ESP_PM_APB_FREQ_MAX;
232232
ESP_GOTO_ON_ERROR(esp_pm_lock_create(pm_lock_type, 0, "dac_driver", &handle->pm_lock), err3, TAG, "Failed to create DAC pm lock");
233233
#endif
234234
handle->chan_cnt = __builtin_popcount(cont_cfg->chan_mask);

components/esp_driver_i2s/i2s_pdm.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -202,6 +202,13 @@ esp_err_t i2s_channel_init_pdm_tx_mode(i2s_chan_handle_t handle, const i2s_pdm_t
202202

203203
#ifdef CONFIG_PM_ENABLE
204204
esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;
205+
#if SOC_I2S_SUPPORTS_APLL && SOC_I2S_HW_VERSION_2
206+
if (pdm_tx_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
207+
/* Only I2S HW 2 supports to adjust APB frequency while using APLL clock source
208+
* HW 1 will have timing issue because the DMA and I2S are under different clock domains */
209+
pm_type = ESP_PM_NO_LIGHT_SLEEP;
210+
}
211+
#endif // SOC_I2S_SUPPORTS_APLL
205212
ESP_RETURN_ON_ERROR(esp_pm_lock_create(pm_type, 0, "i2s_driver", &handle->pm_lock), TAG, "I2S pm lock create failed");
206213
#endif
207214

@@ -249,8 +256,10 @@ esp_err_t i2s_channel_reconfig_pdm_tx_clock(i2s_chan_handle_t handle, const i2s_
249256
if (pdm_tx_cfg->clk_cfg.clk_src != clk_cfg->clk_src) {
250257
ESP_GOTO_ON_ERROR(esp_pm_lock_delete(handle->pm_lock), err, TAG, "I2S delete old pm lock failed");
251258
esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;
252-
#if SOC_I2S_SUPPORTS_APLL
259+
#if SOC_I2S_SUPPORTS_APLL && SOC_I2S_HW_VERSION_2
253260
if (clk_cfg->clk_src == I2S_CLK_SRC_APLL) {
261+
/* Only I2S HW 2 supports to adjust APB frequency while using APLL clock source
262+
* HW 1 will have timing issue because the DMA and I2S are under different clock domains */
254263
pm_type = ESP_PM_NO_LIGHT_SLEEP;
255264
}
256265
#endif // SOC_I2S_SUPPORTS_APLL
@@ -488,8 +497,10 @@ esp_err_t i2s_channel_init_pdm_rx_mode(i2s_chan_handle_t handle, const i2s_pdm_r
488497

489498
#ifdef CONFIG_PM_ENABLE
490499
esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;
491-
#if SOC_I2S_SUPPORTS_APLL
500+
#if SOC_I2S_SUPPORTS_APLL && SOC_I2S_HW_VERSION_2
492501
if (pdm_rx_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
502+
/* Only I2S HW 2 supports to adjust APB frequency while using APLL clock source
503+
* HW 1 will have timing issue because the DMA and I2S are under different clock domains */
493504
pm_type = ESP_PM_NO_LIGHT_SLEEP;
494505
}
495506
#endif // SOC_I2S_SUPPORTS_APLL
@@ -540,8 +551,10 @@ esp_err_t i2s_channel_reconfig_pdm_rx_clock(i2s_chan_handle_t handle, const i2s_
540551
if (pdm_rx_cfg->clk_cfg.clk_src != clk_cfg->clk_src) {
541552
ESP_GOTO_ON_ERROR(esp_pm_lock_delete(handle->pm_lock), err, TAG, "I2S delete old pm lock failed");
542553
esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;
543-
#if SOC_I2S_SUPPORTS_APLL
554+
#if SOC_I2S_SUPPORTS_APLL && SOC_I2S_HW_VERSION_2
544555
if (clk_cfg->clk_src == I2S_CLK_SRC_APLL) {
556+
/* Only I2S HW 2 supports to adjust APB frequency while using APLL clock source
557+
* HW 1 will have timing issue because the DMA and I2S are under different clock domains */
545558
pm_type = ESP_PM_NO_LIGHT_SLEEP;
546559
}
547560
#endif // SOC_I2S_SUPPORTS_APLL

components/esp_driver_i2s/i2s_std.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -245,6 +245,13 @@ esp_err_t i2s_channel_init_std_mode(i2s_chan_handle_t handle, const i2s_std_conf
245245

246246
#ifdef CONFIG_PM_ENABLE
247247
esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;
248+
#if SOC_I2S_SUPPORTS_APLL && SOC_I2S_HW_VERSION_2
249+
if (std_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
250+
/* Only I2S HW 2 supports to adjust APB frequency while using APLL clock source
251+
* HW 1 will have timing issue because the DMA and I2S are under different clock domains */
252+
pm_type = ESP_PM_NO_LIGHT_SLEEP;
253+
}
254+
#endif // SOC_I2S_SUPPORTS_APLL
248255
ESP_RETURN_ON_ERROR(esp_pm_lock_create(pm_type, 0, "i2s_driver", &handle->pm_lock), TAG, "I2S pm lock create failed");
249256
#endif
250257

@@ -293,8 +300,10 @@ esp_err_t i2s_channel_reconfig_std_clock(i2s_chan_handle_t handle, const i2s_std
293300
if (std_cfg->clk_cfg.clk_src != clk_cfg->clk_src) {
294301
ESP_GOTO_ON_ERROR(esp_pm_lock_delete(handle->pm_lock), err, TAG, "I2S delete old pm lock failed");
295302
esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;
296-
#if SOC_I2S_SUPPORTS_APLL
303+
#if SOC_I2S_SUPPORTS_APLL && SOC_I2S_HW_VERSION_2
297304
if (clk_cfg->clk_src == I2S_CLK_SRC_APLL) {
305+
/* Only I2S HW 2 supports to adjust APB frequency while using APLL clock source
306+
* HW 1 will have timing issue because the DMA and I2S are under different clock domains */
298307
pm_type = ESP_PM_NO_LIGHT_SLEEP;
299308
}
300309
#endif // SOC_I2S_SUPPORTS_APLL

components/esp_driver_i2s/i2s_tdm.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,13 @@ esp_err_t i2s_channel_init_tdm_mode(i2s_chan_handle_t handle, const i2s_tdm_conf
254254
#endif
255255
#ifdef CONFIG_PM_ENABLE
256256
esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;
257+
#if SOC_I2S_SUPPORTS_APLL && SOC_I2S_HW_VERSION_2
258+
if (tdm_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
259+
/* Only I2S HW 2 supports to adjust APB frequency while using APLL clock source
260+
* HW 1 will have timing issue because the DMA and I2S are under different clock domains */
261+
pm_type = ESP_PM_NO_LIGHT_SLEEP;
262+
}
263+
#endif // SOC_I2S_SUPPORTS_APLL
257264
ESP_RETURN_ON_ERROR(esp_pm_lock_create(pm_type, 0, "i2s_driver", &handle->pm_lock), TAG, "I2S pm lock create failed");
258265
#endif
259266

@@ -302,8 +309,10 @@ esp_err_t i2s_channel_reconfig_tdm_clock(i2s_chan_handle_t handle, const i2s_tdm
302309
if (tdm_cfg->clk_cfg.clk_src != clk_cfg->clk_src) {
303310
ESP_GOTO_ON_ERROR(esp_pm_lock_delete(handle->pm_lock), err, TAG, "I2S delete old pm lock failed");
304311
esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;
305-
#if SOC_I2S_SUPPORTS_APLL
312+
#if SOC_I2S_SUPPORTS_APLL && SOC_I2S_HW_VERSION_2
306313
if (clk_cfg->clk_src == I2S_CLK_SRC_APLL) {
314+
/* Only I2S HW 2 supports to adjust APB frequency while using APLL clock source
315+
* HW 1 will have timing issue because the DMA and I2S are under different clock domains */
307316
pm_type = ESP_PM_NO_LIGHT_SLEEP;
308317
}
309318
#endif // SOC_I2S_SUPPORTS_APLL

components/esp_lcd/i80/esp_lcd_panel_io_i2s.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -667,7 +667,7 @@ static esp_err_t i2s_lcd_select_periph_clock(esp_lcd_i80_bus_handle_t bus, lcd_c
667667
// create pm lock based on different clock source
668668
// clock sources like PLL and XTAL will be turned off in light sleep
669669
#if CONFIG_PM_ENABLE
670-
ESP_RETURN_ON_ERROR(esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "i80_bus_lcd", &bus->pm_lock), TAG, "create pm lock failed");
670+
ESP_RETURN_ON_ERROR(esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "i80_bus_lcd", &bus->pm_lock), TAG, "create pm lock failed");
671671
#endif
672672
return ESP_OK;
673673
}

docs/en/api-reference/peripherals/dac.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ Power Management
9696

9797
When the power management is enabled (i.e., :ref:`CONFIG_PM_ENABLE` is on), the system will adjust or stop the clock source of DAC before entering Light-sleep mode, thus potential influence to the DAC signals may lead to false data conversion.
9898

99-
When using DAC driver in continuous mode, it can prevent the system from changing or stopping the clock source in DMA or cosine mode by acquiring a power management lock. The power lock type will be set to :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_APB_FREQ_MAX`. Whenever the DAC is converting (i.e., DMA or cosine wave generator is working), the driver guarantees that the power management lock is acquired after calling :cpp:func:`dac_continuous_enable`. Likewise, the driver will release the lock when :cpp:func:`dac_continuous_disable` is called.
99+
When using DAC driver in continuous mode, it can prevent the system from changing or stopping the clock source in DMA or cosine mode by acquiring a power management lock. When the clock source is generated from APB, the lock type will be set to :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_APB_FREQ_MAX`. When the clock source is APLL (only in DMA mode), it will be set to :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_NO_LIGHT_SLEEP`. Whenever the DAC is converting (i.e., DMA or cosine wave generator is working), the driver guarantees that the power management lock is acquired after calling :cpp:func:`dac_continuous_enable`. Likewise, the driver will release the lock when :cpp:func:`dac_continuous_disable` is called.
100100

101101
IRAM Safe
102102
^^^^^^^^^

docs/en/api-reference/peripherals/i2s.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ Power Management
243243

244244
When the power management is enabled (i.e., :ref:`CONFIG_PM_ENABLE` is on), the system will adjust or stop the source clock of I2S before entering Light-sleep, thus potentially changing the I2S signals and leading to transmitting or receiving invalid data.
245245

246-
The I2S driver can prevent the system from changing or stopping the source clock by acquiring a power management lock. The power lock type will be set to :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_APB_FREQ_MAX`. 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.
246+
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.
247247

248248
.. only:: SOC_I2S_SUPPORT_SLEEP_RETENTION
249249

docs/zh_CN/api-reference/peripherals/dac.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ DAC 外设中包含一个余弦波发生器,可以在通道上产生余弦波
9696

9797
启用电源管理时(即开启 :ref:`CONFIG_PM_ENABLE`),系统会在进入 Light-sleep 模式前调整或停止 DAC 时钟源,这可能会影响 DAC 信号,从而导致数据无法正确转换。
9898

99-
在连续模式下使用 DAC 驱动时,可以通过获取电源管理锁来防止系统在 DMA 或余弦波模式下改变或停止时钟源。电源锁的类型将被设置为 :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_APB_FREQ_MAX`。在进行 DAC 转换时(即 DMA 或余弦波发生器运行时),驱动程序会保证在调用 :cpp:func:`dac_continuous_enable` 后获取电源管理锁。同样地,在调用 :cpp:func:`dac_continuous_disable` 时,驱动程序会释放锁。
99+
在连续模式下使用 DAC 驱动时,可以通过获取电源管理锁来防止系统在 DMA 或余弦波模式下改变或停止时钟源。时钟源为 APB 时,锁的类型将被设置为 :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_APB_FREQ_MAX`。时钟源为 APLL 时(仅在 DMA 模式下),锁的类型将被设置为 :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_NO_LIGHT_SLEEP`。在进行 DAC 转换时(即 DMA 或余弦波发生器运行时),驱动程序会保证在调用 :cpp:func:`dac_continuous_enable` 后获取电源管理锁。同样地,在调用 :cpp:func:`dac_continuous_disable` 时,驱动程序会释放锁。
100100

101101
IRAM 安全
102102
^^^^^^^^^

docs/zh_CN/api-reference/peripherals/i2s.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ I2S 驱动中的资源可分为三个级别:
237237

238238
电源管理启用(即开启 :ref:`CONFIG_PM_ENABLE`)时,系统将在进入 Light-sleep 前调整或停止 I2S 时钟源,这可能会影响 I2S 信号,从而导致传输或接收的数据无效。
239239

240-
I2S 驱动可以获取电源管理锁,从而防止系统设置更改或时钟源被禁用。电源锁的类型将被设置为 :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_APB_FREQ_MAX`。用户通过 I2S 读写时(即调用 :cpp:func:`i2s_channel_read` 或 :cpp:func:`i2s_channel_write`),驱动程序将获取电源管理锁,并在读写完成后释放锁。
240+
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`),驱动程序将获取电源管理锁,并在读写完成后释放锁。
241241

242242
.. only:: SOC_I2S_SUPPORT_SLEEP_RETENTION
243243

0 commit comments

Comments
 (0)