i2s_pdm.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. /*
  2. * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <string.h>
  7. #include "freertos/FreeRTOS.h"
  8. #include "freertos/semphr.h"
  9. #include "sdkconfig.h"
  10. #if CONFIG_I2S_ENABLE_DEBUG_LOG
  11. // The local log level must be defined before including esp_log.h
  12. // Set the maximum log level for this source file
  13. #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
  14. #endif
  15. #include "hal/i2s_hal.h"
  16. #include "driver/gpio.h"
  17. #include "driver/i2s_pdm.h"
  18. #include "i2s_private.h"
  19. #include "clk_ctrl_os.h"
  20. #include "esp_intr_alloc.h"
  21. #include "esp_check.h"
  22. static const char *TAG = "i2s_pdm";
  23. /*---------------------------------------------------------------
  24. PDM TX
  25. ---------------------------------------------------------------*/
  26. #if SOC_I2S_SUPPORTS_PDM_TX
  27. #define I2S_PDM_TX_BCLK_DIV_MIN 8 /*!< The minimum bclk_div for PDM TX mode */
  28. static esp_err_t i2s_pdm_tx_calculate_clock(i2s_chan_handle_t handle, const i2s_pdm_tx_clk_config_t *clk_cfg, i2s_hal_clock_info_t *clk_info)
  29. {
  30. uint32_t rate = clk_cfg->sample_rate_hz;
  31. i2s_pdm_tx_clk_config_t *pdm_tx_clk = (i2s_pdm_tx_clk_config_t *)clk_cfg;
  32. // Over sampling ratio (integer, mostly should be 1 or 2)
  33. uint32_t over_sample_ratio = pdm_tx_clk->up_sample_fp / pdm_tx_clk->up_sample_fs;
  34. clk_info->bclk = rate * I2S_LL_PDM_BCK_FACTOR * over_sample_ratio;
  35. clk_info->bclk_div = clk_cfg->bclk_div < I2S_PDM_TX_BCLK_DIV_MIN ? I2S_PDM_TX_BCLK_DIV_MIN : clk_cfg->bclk_div;
  36. clk_info->mclk = clk_info->bclk * clk_info->bclk_div;
  37. clk_info->sclk = i2s_get_source_clk_freq(clk_cfg->clk_src, clk_info->mclk);
  38. clk_info->mclk_div = clk_info->sclk / clk_info->mclk;
  39. /* Check if the configuration is correct */
  40. ESP_RETURN_ON_FALSE(clk_info->mclk_div, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large");
  41. /* Set up sampling configuration */
  42. i2s_ll_tx_set_pdm_fpfs(handle->controller->hal.dev, pdm_tx_clk->up_sample_fp, pdm_tx_clk->up_sample_fs);
  43. i2s_ll_tx_set_pdm_over_sample_ratio(handle->controller->hal.dev, over_sample_ratio);
  44. return ESP_OK;
  45. }
  46. static esp_err_t i2s_pdm_tx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_tx_clk_config_t *clk_cfg)
  47. {
  48. esp_err_t ret = ESP_OK;
  49. i2s_pdm_tx_config_t *pdm_tx_cfg = (i2s_pdm_tx_config_t *)(handle->mode_info);
  50. #if SOC_I2S_HW_VERSION_2
  51. ESP_RETURN_ON_FALSE(clk_cfg->clk_src != I2S_CLK_SRC_EXTERNAL, ESP_ERR_INVALID_ARG, TAG, "not support external clock source in pdm mode");
  52. #endif
  53. ESP_RETURN_ON_FALSE(clk_cfg->up_sample_fs <= 480, ESP_ERR_INVALID_ARG, TAG, "up_sample_fs should be within 480");
  54. i2s_hal_clock_info_t clk_info;
  55. /* Calculate clock parameters */
  56. ESP_RETURN_ON_ERROR(i2s_pdm_tx_calculate_clock(handle, clk_cfg, &clk_info), TAG, "clock calculate failed");
  57. ESP_LOGD(TAG, "Clock division info: [sclk] %"PRIu32" Hz [mdiv] %d [mclk] %"PRIu32" Hz [bdiv] %d [bclk] %"PRIu32" Hz",
  58. clk_info.sclk, clk_info.mclk_div, clk_info.mclk, clk_info.bclk_div, clk_info.bclk);
  59. portENTER_CRITICAL(&g_i2s.spinlock);
  60. /* Set clock configurations in HAL*/
  61. I2S_CLOCK_SRC_ATOMIC() {
  62. i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
  63. }
  64. #if SOC_I2S_HW_VERSION_2
  65. /* Work around for PDM TX clock, overwrite the raw division directly to reduce the noise
  66. * This set of coefficients is a special division to reduce the background noise in PDM TX mode */
  67. i2s_ll_tx_set_raw_clk_div(handle->controller->hal.dev, clk_info.mclk_div, 1, 1, 0, 0);
  68. #endif
  69. portEXIT_CRITICAL(&g_i2s.spinlock);
  70. /* Update the mode info: clock configuration */
  71. memcpy(&(pdm_tx_cfg->clk_cfg), clk_cfg, sizeof(i2s_pdm_tx_clk_config_t));
  72. return ret;
  73. }
  74. static esp_err_t i2s_pdm_tx_set_slot(i2s_chan_handle_t handle, const i2s_pdm_tx_slot_config_t *slot_cfg)
  75. {
  76. /* Update the total slot num and active slot num */
  77. handle->total_slot = 2;
  78. handle->active_slot = slot_cfg->slot_mode == I2S_SLOT_MODE_MONO ? 1 : 2;
  79. uint32_t buf_size = i2s_get_buf_size(handle, slot_cfg->data_bit_width, handle->dma.frame_num);
  80. /* The DMA buffer need to re-allocate if the buffer size changed */
  81. if (handle->dma.buf_size != buf_size) {
  82. handle->dma.buf_size = buf_size;
  83. ESP_RETURN_ON_ERROR(i2s_free_dma_desc(handle), TAG, "failed to free the old dma descriptor");
  84. ESP_RETURN_ON_ERROR(i2s_alloc_dma_desc(handle, handle->dma.desc_num, buf_size),
  85. TAG, "allocate memory for dma descriptor failed");
  86. }
  87. /* Share bck and ws signal in full-duplex mode */
  88. i2s_ll_share_bck_ws(handle->controller->hal.dev, handle->controller->full_duplex);
  89. /* Update the mode info: slot configuration */
  90. i2s_pdm_tx_config_t *pdm_tx_cfg = (i2s_pdm_tx_config_t *)handle->mode_info;
  91. memcpy(&(pdm_tx_cfg->slot_cfg), slot_cfg, sizeof(i2s_pdm_tx_slot_config_t));
  92. portENTER_CRITICAL(&g_i2s.spinlock);
  93. /* Configure the hardware to apply PDM format */
  94. bool is_slave = handle->role == I2S_ROLE_SLAVE;
  95. i2s_hal_slot_config_t *slot_hal_cfg = (i2s_hal_slot_config_t *)(&(pdm_tx_cfg->slot_cfg));
  96. #if SOC_I2S_HW_VERSION_2
  97. /* Times 10 to transform the float type to integer because we should avoid float type in hal */
  98. slot_hal_cfg->pdm_tx.hp_cut_off_freq_hzx10 = (uint32_t)(slot_cfg->hp_cut_off_freq_hz * 10);
  99. #endif
  100. i2s_hal_pdm_set_tx_slot(&(handle->controller->hal), is_slave, slot_hal_cfg);
  101. portEXIT_CRITICAL(&g_i2s.spinlock);
  102. return ESP_OK;
  103. }
  104. static esp_err_t i2s_pdm_tx_set_gpio(i2s_chan_handle_t handle, const i2s_pdm_tx_gpio_config_t *gpio_cfg)
  105. {
  106. int id = handle->controller->id;
  107. /* Check validity of selected pins */
  108. ESP_RETURN_ON_FALSE((gpio_cfg->clk == -1 || GPIO_IS_VALID_GPIO(gpio_cfg->clk)),
  109. ESP_ERR_INVALID_ARG, TAG, "clk gpio is invalid");
  110. ESP_RETURN_ON_FALSE((gpio_cfg->dout == -1 || GPIO_IS_VALID_GPIO(gpio_cfg->dout)),
  111. ESP_ERR_INVALID_ARG, TAG, "dout gpio is invalid");
  112. i2s_pdm_tx_config_t *pdm_tx_cfg = (i2s_pdm_tx_config_t *)handle->mode_info;
  113. /* Set data output GPIO */
  114. i2s_gpio_check_and_set(gpio_cfg->dout, i2s_periph_signal[id].data_out_sig, false, false);
  115. #if SOC_I2S_PDM_MAX_TX_LINES > 1
  116. if (pdm_tx_cfg->slot_cfg.line_mode == I2S_PDM_TX_TWO_LINE_DAC) {
  117. i2s_gpio_check_and_set(gpio_cfg->dout2, i2s_periph_signal[id].data_out_sigs[1], false, false);
  118. }
  119. #endif
  120. if (handle->role == I2S_ROLE_SLAVE) {
  121. /* For "tx + slave" mode, select TX signal index for ws and bck */
  122. if (!handle->controller->full_duplex) {
  123. i2s_gpio_check_and_set(gpio_cfg->clk, i2s_periph_signal[id].s_tx_ws_sig, true, gpio_cfg->invert_flags.clk_inv);
  124. /* For "tx + rx + slave" or "rx + slave" mode, select RX signal index for ws and bck */
  125. } else {
  126. i2s_gpio_check_and_set(gpio_cfg->clk, i2s_periph_signal[id].s_rx_ws_sig, true, gpio_cfg->invert_flags.clk_inv);
  127. }
  128. } else {
  129. i2s_gpio_check_and_set(gpio_cfg->clk, i2s_periph_signal[id].m_tx_ws_sig, false, gpio_cfg->invert_flags.clk_inv);
  130. }
  131. #if SOC_I2S_HW_VERSION_2
  132. i2s_ll_mclk_bind_to_tx_clk(handle->controller->hal.dev);
  133. #endif
  134. /* Update the mode info: gpio configuration */
  135. memcpy(&(pdm_tx_cfg->gpio_cfg), gpio_cfg, sizeof(i2s_pdm_tx_gpio_config_t));
  136. return ESP_OK;
  137. }
  138. esp_err_t i2s_channel_init_pdm_tx_mode(i2s_chan_handle_t handle, const i2s_pdm_tx_config_t *pdm_tx_cfg)
  139. {
  140. #if CONFIG_I2S_ENABLE_DEBUG_LOG
  141. esp_log_level_set(TAG, ESP_LOG_DEBUG);
  142. #endif
  143. I2S_NULL_POINTER_CHECK(TAG, handle);
  144. ESP_RETURN_ON_FALSE(handle->dir == I2S_DIR_TX, ESP_ERR_INVALID_ARG, TAG, "This channel handle is not a TX handle");
  145. ESP_RETURN_ON_FALSE(handle->controller->id == I2S_NUM_0, ESP_ERR_INVALID_ARG, TAG, "This channel handle is registered on I2S1, but PDM is only supported on I2S0");
  146. esp_err_t ret = ESP_OK;
  147. xSemaphoreTake(handle->mutex, portMAX_DELAY);
  148. ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_REGISTER, ESP_ERR_INVALID_STATE, err, TAG, "the channel has initialized already");
  149. handle->mode = I2S_COMM_MODE_PDM;
  150. /* Allocate memory for storing the configurations of PDM tx mode */
  151. if (handle->mode_info) {
  152. free(handle->mode_info);
  153. }
  154. handle->mode_info = calloc(1, sizeof(i2s_pdm_tx_config_t));
  155. ESP_GOTO_ON_FALSE(handle->mode_info, ESP_ERR_NO_MEM, err, TAG, "no memory for storing the configurations");
  156. /* i2s_set_pdm_tx_slot should be called before i2s_set_pdm_tx_clock and i2s_pdm_tx_set_gpio
  157. * while initializing, because clock and gpio is relay on the slot */
  158. ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_slot(handle, &pdm_tx_cfg->slot_cfg), err, TAG, "initialize channel failed while setting slot");
  159. ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_gpio(handle, &pdm_tx_cfg->gpio_cfg), err, TAG, "initialize channel failed while setting gpio pins");
  160. #if SOC_I2S_SUPPORTS_APLL
  161. /* Enable APLL and acquire its lock when the clock source is APLL */
  162. if (pdm_tx_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
  163. periph_rtc_apll_acquire();
  164. handle->apll_en = true;
  165. }
  166. #endif
  167. ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_clock(handle, &pdm_tx_cfg->clk_cfg), err, TAG, "initialize channel failed while setting clock");
  168. ESP_GOTO_ON_ERROR(i2s_init_dma_intr(handle, I2S_INTR_ALLOC_FLAGS), err, TAG, "initialize dma interrupt failed");
  169. i2s_ll_tx_enable_pdm(handle->controller->hal.dev);
  170. #ifdef CONFIG_PM_ENABLE
  171. esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;
  172. #if SOC_I2S_SUPPORTS_APLL
  173. if (pdm_tx_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
  174. pm_type = ESP_PM_NO_LIGHT_SLEEP;
  175. }
  176. #endif // SOC_I2S_SUPPORTS_APLL
  177. ESP_RETURN_ON_ERROR(esp_pm_lock_create(pm_type, 0, "i2s_driver", &handle->pm_lock), TAG, "I2S pm lock create failed");
  178. #endif
  179. /* Initialization finished, mark state as ready */
  180. handle->state = I2S_CHAN_STATE_READY;
  181. xSemaphoreGive(handle->mutex);
  182. ESP_LOGD(TAG, "The tx channel on I2S0 has been initialized to PDM TX mode successfully");
  183. return ret;
  184. err:
  185. xSemaphoreGive(handle->mutex);
  186. return ret;
  187. }
  188. esp_err_t i2s_channel_reconfig_pdm_tx_clock(i2s_chan_handle_t handle, const i2s_pdm_tx_clk_config_t *clk_cfg)
  189. {
  190. I2S_NULL_POINTER_CHECK(TAG, handle);
  191. I2S_NULL_POINTER_CHECK(TAG, clk_cfg);
  192. ESP_RETURN_ON_FALSE(handle->dir == I2S_DIR_TX, ESP_ERR_INVALID_ARG, TAG, "This channel handle is not a TX handle");
  193. esp_err_t ret = ESP_OK;
  194. xSemaphoreTake(handle->mutex, portMAX_DELAY);
  195. ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard mode");
  196. ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "invalid state, I2S should be disabled before reconfiguring the clock");
  197. i2s_pdm_tx_config_t *pdm_tx_cfg = (i2s_pdm_tx_config_t *)handle->mode_info;
  198. ESP_GOTO_ON_FALSE(pdm_tx_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
  199. #if SOC_I2S_SUPPORTS_APLL
  200. /* Enable APLL and acquire its lock when the clock source is changed to APLL */
  201. if (clk_cfg->clk_src == I2S_CLK_SRC_APLL && pdm_tx_cfg->clk_cfg.clk_src != I2S_CLK_SRC_APLL) {
  202. periph_rtc_apll_acquire();
  203. handle->apll_en = true;
  204. }
  205. /* Disable APLL and release its lock when clock source is changed to 160M_PLL */
  206. if (clk_cfg->clk_src != I2S_CLK_SRC_APLL && pdm_tx_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
  207. periph_rtc_apll_release();
  208. handle->apll_en = false;
  209. }
  210. #endif
  211. ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_clock(handle, clk_cfg), err, TAG, "update clock failed");
  212. #ifdef CONFIG_PM_ENABLE
  213. // Create/Re-create power management lock
  214. if (pdm_tx_cfg->clk_cfg.clk_src != clk_cfg->clk_src) {
  215. ESP_GOTO_ON_ERROR(esp_pm_lock_delete(handle->pm_lock), err, TAG, "I2S delete old pm lock failed");
  216. esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;
  217. #if SOC_I2S_SUPPORTS_APLL
  218. if (clk_cfg->clk_src == I2S_CLK_SRC_APLL) {
  219. pm_type = ESP_PM_NO_LIGHT_SLEEP;
  220. }
  221. #endif // SOC_I2S_SUPPORTS_APLL
  222. ESP_GOTO_ON_ERROR(esp_pm_lock_create(pm_type, 0, "i2s_driver", &handle->pm_lock), err, TAG, "I2S pm lock create failed");
  223. }
  224. #endif //CONFIG_PM_ENABLE
  225. xSemaphoreGive(handle->mutex);
  226. return ESP_OK;
  227. err:
  228. xSemaphoreGive(handle->mutex);
  229. return ret;
  230. }
  231. esp_err_t i2s_channel_reconfig_pdm_tx_slot(i2s_chan_handle_t handle, const i2s_pdm_tx_slot_config_t *slot_cfg)
  232. {
  233. I2S_NULL_POINTER_CHECK(TAG, handle);
  234. I2S_NULL_POINTER_CHECK(TAG, slot_cfg);
  235. ESP_RETURN_ON_FALSE(handle->dir == I2S_DIR_TX, ESP_ERR_INVALID_ARG, TAG, "This channel handle is not a TX handle");
  236. esp_err_t ret = ESP_OK;
  237. xSemaphoreTake(handle->mutex, portMAX_DELAY);
  238. ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard mode");
  239. ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "invalid state, I2S should be disabled before reconfiguring the slot");
  240. i2s_pdm_tx_config_t *pdm_tx_cfg = (i2s_pdm_tx_config_t *)handle->mode_info;
  241. ESP_GOTO_ON_FALSE(pdm_tx_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
  242. ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_slot(handle, slot_cfg), err, TAG, "set i2s standard slot failed");
  243. /* If the slot bit width changed, then need to update the clock */
  244. uint32_t slot_bits = slot_cfg->slot_bit_width == I2S_SLOT_BIT_WIDTH_AUTO ? slot_cfg->data_bit_width : slot_cfg->slot_bit_width;
  245. if (pdm_tx_cfg->slot_cfg.slot_bit_width == slot_bits) {
  246. ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_clock(handle, &pdm_tx_cfg->clk_cfg), err, TAG, "update clock failed");
  247. }
  248. xSemaphoreGive(handle->mutex);
  249. return ESP_OK;
  250. err:
  251. xSemaphoreGive(handle->mutex);
  252. return ret;
  253. }
  254. esp_err_t i2s_channel_reconfig_pdm_tx_gpio(i2s_chan_handle_t handle, const i2s_pdm_tx_gpio_config_t *gpio_cfg)
  255. {
  256. I2S_NULL_POINTER_CHECK(TAG, handle);
  257. I2S_NULL_POINTER_CHECK(TAG, gpio_cfg);
  258. ESP_RETURN_ON_FALSE(handle->dir == I2S_DIR_TX, ESP_ERR_INVALID_ARG, TAG, "This channel handle is not a TX handle");
  259. esp_err_t ret = ESP_OK;
  260. xSemaphoreTake(handle->mutex, portMAX_DELAY);
  261. ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard mode");
  262. ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "Invalid state, I2S should be disabled before reconfiguring the gpio");
  263. ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_gpio(handle, gpio_cfg), err, TAG, "set i2s standard slot failed");
  264. xSemaphoreGive(handle->mutex);
  265. return ESP_OK;
  266. err:
  267. xSemaphoreGive(handle->mutex);
  268. return ret;
  269. }
  270. #endif
  271. /*---------------------------------------------------------------
  272. PDM RX
  273. ---------------------------------------------------------------*/
  274. #if SOC_I2S_SUPPORTS_PDM_RX
  275. #define I2S_PDM_RX_BCLK_DIV_MIN 8 /*!< The minimum bclk_div for PDM RX mode */
  276. static esp_err_t i2s_pdm_rx_calculate_clock(i2s_chan_handle_t handle, const i2s_pdm_rx_clk_config_t *clk_cfg, i2s_hal_clock_info_t *clk_info)
  277. {
  278. uint32_t rate = clk_cfg->sample_rate_hz;
  279. i2s_pdm_rx_clk_config_t *pdm_rx_clk = (i2s_pdm_rx_clk_config_t *)clk_cfg;
  280. clk_info->bclk = rate * I2S_LL_PDM_BCK_FACTOR * (pdm_rx_clk->dn_sample_mode == I2S_PDM_DSR_16S ? 2 : 1);
  281. clk_info->bclk_div = clk_cfg->bclk_div < I2S_PDM_RX_BCLK_DIV_MIN ? I2S_PDM_RX_BCLK_DIV_MIN : clk_cfg->bclk_div;
  282. clk_info->mclk = clk_info->bclk * clk_info->bclk_div;
  283. clk_info->sclk = i2s_get_source_clk_freq(clk_cfg->clk_src, clk_info->mclk);
  284. clk_info->mclk_div = clk_info->sclk / clk_info->mclk;
  285. /* Check if the configuration is correct */
  286. ESP_RETURN_ON_FALSE(clk_info->mclk_div, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large");
  287. /* Set down-sampling configuration */
  288. i2s_ll_rx_set_pdm_dsr(handle->controller->hal.dev, pdm_rx_clk->dn_sample_mode);
  289. return ESP_OK;
  290. }
  291. static esp_err_t i2s_pdm_rx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_rx_clk_config_t *clk_cfg)
  292. {
  293. esp_err_t ret = ESP_OK;
  294. i2s_pdm_rx_config_t *pdm_rx_cfg = (i2s_pdm_rx_config_t *)(handle->mode_info);
  295. #if SOC_I2S_HW_VERSION_2
  296. ESP_RETURN_ON_FALSE(clk_cfg->clk_src != I2S_CLK_SRC_EXTERNAL, ESP_ERR_INVALID_ARG, TAG, "not support external clock source in pdm mode");
  297. #endif
  298. i2s_hal_clock_info_t clk_info;
  299. /* Calculate clock parameters */
  300. ESP_RETURN_ON_ERROR(i2s_pdm_rx_calculate_clock(handle, clk_cfg, &clk_info), TAG, "clock calculate failed");
  301. ESP_LOGD(TAG, "Clock division info: [sclk] %"PRIu32" Hz [mdiv] %d [mclk] %"PRIu32" Hz [bdiv] %d [bclk] %"PRIu32" Hz",
  302. clk_info.sclk, clk_info.mclk_div, clk_info.mclk, clk_info.bclk_div, clk_info.bclk);
  303. portENTER_CRITICAL(&g_i2s.spinlock);
  304. /* Set clock configurations in HAL*/
  305. I2S_CLOCK_SRC_ATOMIC() {
  306. i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
  307. }
  308. portEXIT_CRITICAL(&g_i2s.spinlock);
  309. /* Update the mode info: clock configuration */
  310. memcpy(&(pdm_rx_cfg->clk_cfg), clk_cfg, sizeof(i2s_pdm_rx_clk_config_t));
  311. return ret;
  312. }
  313. static esp_err_t i2s_pdm_rx_set_slot(i2s_chan_handle_t handle, const i2s_pdm_rx_slot_config_t *slot_cfg)
  314. {
  315. /* Update the total slot num and active slot num */
  316. handle->total_slot = 2;
  317. handle->active_slot = slot_cfg->slot_mode == I2S_SLOT_MODE_MONO ? 1 : 2;
  318. uint32_t buf_size = i2s_get_buf_size(handle, slot_cfg->data_bit_width, handle->dma.frame_num);
  319. /* The DMA buffer need to re-allocate if the buffer size changed */
  320. if (handle->dma.buf_size != buf_size) {
  321. handle->dma.buf_size = buf_size;
  322. ESP_RETURN_ON_ERROR(i2s_free_dma_desc(handle), TAG, "failed to free the old dma descriptor");
  323. ESP_RETURN_ON_ERROR(i2s_alloc_dma_desc(handle, handle->dma.desc_num, buf_size),
  324. TAG, "allocate memory for dma descriptor failed");
  325. }
  326. /* Share bck and ws signal in full-duplex mode */
  327. i2s_ll_share_bck_ws(handle->controller->hal.dev, handle->controller->full_duplex);
  328. /* Update the mode info: slot configuration */
  329. i2s_pdm_rx_config_t *pdm_rx_cfg = (i2s_pdm_rx_config_t *)handle->mode_info;
  330. memcpy(&(pdm_rx_cfg->slot_cfg), slot_cfg, sizeof(i2s_pdm_rx_slot_config_t));
  331. portENTER_CRITICAL(&g_i2s.spinlock);
  332. /* Configure the hardware to apply PDM format */
  333. bool is_slave = (handle->role == I2S_ROLE_SLAVE) | handle->controller->full_duplex;
  334. i2s_hal_slot_config_t *slot_hal_cfg = (i2s_hal_slot_config_t *)(&(pdm_rx_cfg->slot_cfg));
  335. #if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
  336. /* Times 10 to transform the float type to integer because we should avoid float type in hal */
  337. slot_hal_cfg->pdm_rx.hp_cut_off_freq_hzx10 = (uint32_t)(slot_cfg->hp_cut_off_freq_hz * 10);
  338. #endif
  339. i2s_hal_pdm_set_rx_slot(&(handle->controller->hal), is_slave, slot_hal_cfg);
  340. portEXIT_CRITICAL(&g_i2s.spinlock);
  341. return ESP_OK;
  342. }
  343. static esp_err_t i2s_pdm_rx_set_gpio(i2s_chan_handle_t handle, const i2s_pdm_rx_gpio_config_t *gpio_cfg)
  344. {
  345. int id = handle->controller->id;
  346. /* Check validity of selected pins */
  347. ESP_RETURN_ON_FALSE((gpio_cfg->clk == -1 || GPIO_IS_VALID_GPIO(gpio_cfg->clk)),
  348. ESP_ERR_INVALID_ARG, TAG, "clk gpio is invalid");
  349. ESP_RETURN_ON_FALSE((gpio_cfg->din == -1 || GPIO_IS_VALID_GPIO(gpio_cfg->din)),
  350. ESP_ERR_INVALID_ARG, TAG, "dout gpio is invalid");
  351. i2s_pdm_rx_config_t *pdm_rx_cfg = (i2s_pdm_rx_config_t *)handle->mode_info;
  352. /* Set data input GPIO */
  353. #if SOC_I2S_PDM_MAX_RX_LINES > 1
  354. for (int i = 0; i < SOC_I2S_PDM_MAX_RX_LINES; i++) {
  355. if (pdm_rx_cfg->slot_cfg.slot_mask & (0x03 << (i * 2))) {
  356. i2s_gpio_check_and_set(gpio_cfg->dins[i], i2s_periph_signal[id].data_in_sigs[i], true, false);
  357. }
  358. }
  359. #else
  360. i2s_gpio_check_and_set(gpio_cfg->din, i2s_periph_signal[id].data_in_sig, true, false);
  361. #endif
  362. if (handle->role == I2S_ROLE_SLAVE) {
  363. /* For "tx + rx + slave" or "rx + slave" mode, select RX signal index for ws and bck */
  364. i2s_gpio_check_and_set(gpio_cfg->clk, i2s_periph_signal[id].s_rx_ws_sig, true, gpio_cfg->invert_flags.clk_inv);
  365. } else {
  366. if (!handle->controller->full_duplex) {
  367. i2s_gpio_check_and_set(gpio_cfg->clk, i2s_periph_signal[id].m_rx_ws_sig, false, gpio_cfg->invert_flags.clk_inv);
  368. } else {
  369. i2s_gpio_check_and_set(gpio_cfg->clk, i2s_periph_signal[id].m_tx_ws_sig, false, gpio_cfg->invert_flags.clk_inv);
  370. }
  371. }
  372. #if SOC_I2S_HW_VERSION_2
  373. i2s_ll_mclk_bind_to_rx_clk(handle->controller->hal.dev);
  374. #endif
  375. /* Update the mode info: gpio configuration */
  376. memcpy(&(pdm_rx_cfg->gpio_cfg), gpio_cfg, sizeof(i2s_pdm_rx_gpio_config_t));
  377. return ESP_OK;
  378. }
  379. esp_err_t i2s_channel_init_pdm_rx_mode(i2s_chan_handle_t handle, const i2s_pdm_rx_config_t *pdm_rx_cfg)
  380. {
  381. I2S_NULL_POINTER_CHECK(TAG, handle);
  382. ESP_RETURN_ON_FALSE(handle->dir == I2S_DIR_RX, ESP_ERR_INVALID_ARG, TAG, "This channel handle is not a RX handle");
  383. ESP_RETURN_ON_FALSE(handle->controller->id == I2S_NUM_0, ESP_ERR_INVALID_ARG, TAG, "This channel handle is registered on I2S1, but PDM is only supported on I2S0");
  384. esp_err_t ret = ESP_OK;
  385. xSemaphoreTake(handle->mutex, portMAX_DELAY);
  386. ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_REGISTER, ESP_ERR_INVALID_STATE, err, TAG, "the channel has initialized already");
  387. handle->mode = I2S_COMM_MODE_PDM;
  388. /* Allocate memory for storing the configurations of PDM rx mode */
  389. if (handle->mode_info) {
  390. free(handle->mode_info);
  391. }
  392. handle->mode_info = calloc(1, sizeof(i2s_pdm_rx_config_t));
  393. ESP_GOTO_ON_FALSE(handle->mode_info, ESP_ERR_NO_MEM, err, TAG, "no memory for storing the configurations");
  394. /* i2s_set_pdm_rx_slot should be called before i2s_set_pdm_rx_clock and i2s_pdm_rx_set_gpio while initializing, because clock is relay on the slot */
  395. ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_slot(handle, &pdm_rx_cfg->slot_cfg), err, TAG, "initialize channel failed while setting slot");
  396. ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_gpio(handle, &pdm_rx_cfg->gpio_cfg), err, TAG, "initialize channel failed while setting gpio pins");
  397. #if SOC_I2S_SUPPORTS_APLL
  398. /* Enable APLL and acquire its lock when the clock source is APLL */
  399. if (pdm_rx_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
  400. periph_rtc_apll_acquire();
  401. handle->apll_en = true;
  402. }
  403. #endif
  404. ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_clock(handle, &pdm_rx_cfg->clk_cfg), err, TAG, "initialize channel failed while setting clock");
  405. ESP_GOTO_ON_ERROR(i2s_init_dma_intr(handle, I2S_INTR_ALLOC_FLAGS), err, TAG, "initialize dma interrupt failed");
  406. i2s_ll_rx_enable_pdm(handle->controller->hal.dev);
  407. #ifdef CONFIG_PM_ENABLE
  408. esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;
  409. #if SOC_I2S_SUPPORTS_APLL
  410. if (pdm_rx_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
  411. pm_type = ESP_PM_NO_LIGHT_SLEEP;
  412. }
  413. #endif // SOC_I2S_SUPPORTS_APLL
  414. ESP_RETURN_ON_ERROR(esp_pm_lock_create(pm_type, 0, "i2s_driver", &handle->pm_lock), TAG, "I2S pm lock create failed");
  415. #endif
  416. /* Initialization finished, mark state as ready */
  417. handle->state = I2S_CHAN_STATE_READY;
  418. xSemaphoreGive(handle->mutex);
  419. ESP_LOGD(TAG, "The rx channel on I2S0 has been initialized to PDM RX mode successfully");
  420. return ret;
  421. err:
  422. xSemaphoreGive(handle->mutex);
  423. return ret;
  424. }
  425. esp_err_t i2s_channel_reconfig_pdm_rx_clock(i2s_chan_handle_t handle, const i2s_pdm_rx_clk_config_t *clk_cfg)
  426. {
  427. I2S_NULL_POINTER_CHECK(TAG, handle);
  428. I2S_NULL_POINTER_CHECK(TAG, clk_cfg);
  429. ESP_RETURN_ON_FALSE(handle->dir == I2S_DIR_RX, ESP_ERR_INVALID_ARG, TAG, "This channel handle is not a RX handle");
  430. esp_err_t ret = ESP_OK;
  431. xSemaphoreTake(handle->mutex, portMAX_DELAY);
  432. ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard mode");
  433. ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "invalid state, I2S should be disabled before reconfiguring the clock");
  434. i2s_pdm_rx_config_t *pdm_rx_cfg = (i2s_pdm_rx_config_t *)handle->mode_info;
  435. ESP_GOTO_ON_FALSE(pdm_rx_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
  436. #if SOC_I2S_SUPPORTS_APLL
  437. /* Enable APLL and acquire its lock when the clock source is changed to APLL */
  438. if (clk_cfg->clk_src == I2S_CLK_SRC_APLL && pdm_rx_cfg->clk_cfg.clk_src != I2S_CLK_SRC_APLL) {
  439. periph_rtc_apll_acquire();
  440. handle->apll_en = true;
  441. }
  442. /* Disable APLL and release its lock when clock source is changed to 160M_PLL */
  443. if (clk_cfg->clk_src != I2S_CLK_SRC_APLL && pdm_rx_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
  444. periph_rtc_apll_release();
  445. handle->apll_en = false;
  446. }
  447. #endif
  448. ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_clock(handle, clk_cfg), err, TAG, "update clock failed");
  449. #ifdef CONFIG_PM_ENABLE
  450. // Create/Re-create power management lock
  451. if (pdm_rx_cfg->clk_cfg.clk_src != clk_cfg->clk_src) {
  452. ESP_GOTO_ON_ERROR(esp_pm_lock_delete(handle->pm_lock), err, TAG, "I2S delete old pm lock failed");
  453. esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;
  454. #if SOC_I2S_SUPPORTS_APLL
  455. if (clk_cfg->clk_src == I2S_CLK_SRC_APLL) {
  456. pm_type = ESP_PM_NO_LIGHT_SLEEP;
  457. }
  458. #endif // SOC_I2S_SUPPORTS_APLL
  459. ESP_GOTO_ON_ERROR(esp_pm_lock_create(pm_type, 0, "i2s_driver", &handle->pm_lock), err, TAG, "I2S pm lock create failed");
  460. }
  461. #endif //CONFIG_PM_ENABLE
  462. xSemaphoreGive(handle->mutex);
  463. return ESP_OK;
  464. err:
  465. xSemaphoreGive(handle->mutex);
  466. return ret;
  467. }
  468. esp_err_t i2s_channel_reconfig_pdm_rx_slot(i2s_chan_handle_t handle, const i2s_pdm_rx_slot_config_t *slot_cfg)
  469. {
  470. I2S_NULL_POINTER_CHECK(TAG, handle);
  471. I2S_NULL_POINTER_CHECK(TAG, slot_cfg);
  472. ESP_RETURN_ON_FALSE(handle->dir == I2S_DIR_RX, ESP_ERR_INVALID_ARG, TAG, "This channel handle is not a RX handle");
  473. esp_err_t ret = ESP_OK;
  474. xSemaphoreTake(handle->mutex, portMAX_DELAY);
  475. ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard mode");
  476. ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "invalid state, I2S should be disabled before reconfiguring the slot");
  477. i2s_pdm_rx_config_t *pdm_rx_cfg = (i2s_pdm_rx_config_t *)handle->mode_info;
  478. ESP_GOTO_ON_FALSE(pdm_rx_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
  479. ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_slot(handle, slot_cfg), err, TAG, "set i2s standard slot failed");
  480. /* If the slot bit width changed, then need to update the clock */
  481. uint32_t slot_bits = slot_cfg->slot_bit_width == I2S_SLOT_BIT_WIDTH_AUTO ? slot_cfg->data_bit_width : slot_cfg->slot_bit_width;
  482. if (pdm_rx_cfg->slot_cfg.slot_bit_width == slot_bits) {
  483. ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_clock(handle, &pdm_rx_cfg->clk_cfg), err, TAG, "update clock failed");
  484. }
  485. xSemaphoreGive(handle->mutex);
  486. return ESP_OK;
  487. err:
  488. xSemaphoreGive(handle->mutex);
  489. return ret;
  490. }
  491. esp_err_t i2s_channel_reconfig_pdm_rx_gpio(i2s_chan_handle_t handle, const i2s_pdm_rx_gpio_config_t *gpio_cfg)
  492. {
  493. I2S_NULL_POINTER_CHECK(TAG, handle);
  494. I2S_NULL_POINTER_CHECK(TAG, gpio_cfg);
  495. esp_err_t ret = ESP_OK;
  496. xSemaphoreTake(handle->mutex, portMAX_DELAY);
  497. ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard mode");
  498. ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "Invalid state, I2S should be disabled before reconfiguring the gpio");
  499. ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_gpio(handle, gpio_cfg), err, TAG, "set i2s standard slot failed");
  500. xSemaphoreGive(handle->mutex);
  501. return ESP_OK;
  502. err:
  503. xSemaphoreGive(handle->mutex);
  504. return ret;
  505. }
  506. #endif // SOC_I2S_SUPPORTS_PDM_RX