i2s_pdm.c 26 KB

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