dac_dma.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*
  2. * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. /**
  7. * This file is a target specific for DAC DMA peripheral
  8. * Target: ESP32
  9. * DAC DMA peripheral (data source): I2S0 (i.e. use I2S DMA to transmit data)
  10. * DAC DMA interrupt source: I2S0
  11. * DAC digital controller clock source: I2S ws signal (root clock: D2PLL or APLL)
  12. */
  13. #include "freertos/FreeRTOS.h"
  14. #include "sdkconfig.h"
  15. #include "hal/adc_ll.h"
  16. #include "hal/i2s_hal.h"
  17. #include "hal/i2s_types.h"
  18. #include "hal/clk_tree_ll.h"
  19. #include "soc/i2s_periph.h"
  20. #include "../dac_priv_dma.h"
  21. #include "esp_private/i2s_platform.h"
  22. #include "esp_private/esp_clk.h"
  23. #include "clk_ctrl_os.h"
  24. #if CONFIG_DAC_ENABLE_DEBUG_LOG
  25. // The local log level must be defined before including esp_log.h
  26. // Set the maximum log level for this source file
  27. #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
  28. #endif
  29. #include "esp_check.h"
  30. #include "esp_attr.h"
  31. #define DAC_DMA_PERIPH_I2S_NUM 0
  32. #define DAC_DMA_PERIPH_I2S_BIT_WIDTH 16 // Fixed bit width, only the high 8 bits take effect
  33. typedef struct {
  34. void *periph_dev; /* DMA peripheral device address */
  35. intr_handle_t intr_handle; /* Interrupt handle */
  36. bool use_apll; /* Whether use APLL as clock source */
  37. } dac_dma_periph_i2s_t;
  38. static dac_dma_periph_i2s_t *s_ddp = NULL; // Static DAC DMA peripheral structure pointer
  39. static const char *TAG = "DAC_DMA";
  40. static uint32_t s_dac_set_apll_freq(uint32_t mclk)
  41. {
  42. /* Calculate the expected APLL */
  43. int div = (int)((CLK_LL_APLL_MIN_HZ / mclk) + 1);
  44. /* apll_freq = mclk * div
  45. * when div = 1, hardware will still divide 2
  46. * when div = 0, hardware will divide 255
  47. * So the div here should be at least 2 */
  48. div = div < 2 ? 2 : div;
  49. uint32_t expt_freq = mclk * div;
  50. /* Set APLL coefficients to the given frequency */
  51. uint32_t real_freq = 0;
  52. esp_err_t ret = periph_rtc_apll_freq_set(expt_freq, &real_freq);
  53. if (ret == ESP_ERR_INVALID_ARG) {
  54. return 0;
  55. }
  56. if (ret == ESP_ERR_INVALID_STATE) {
  57. ESP_LOGW(TAG, "APLL is occupied already, it is working at %"PRIu32" Hz", real_freq);
  58. }
  59. ESP_LOGD(TAG, "APLL expected frequency is %"PRIu32" Hz, real frequency is %"PRIu32" Hz", expt_freq, real_freq);
  60. return real_freq;
  61. }
  62. /**
  63. * @brief Calculate and set DAC data frequency
  64. * @note DAC frequency is decided by I2S WS frequency, the clock source of I2S is D2PLL or APLL on ESP32
  65. * freq_hz = ws = bclk / I2S_LL_AD_BCK_FACTOR
  66. * @param freq_hz DAC byte transmit frequency
  67. * @return
  68. * - ESP_OK config success
  69. * - ESP_ERR_INVALID_ARG invalid frequency
  70. */
  71. static esp_err_t s_dac_dma_periph_set_clock(uint32_t freq_hz, bool is_apll)
  72. {
  73. /* Calculate clock coefficients */
  74. uint32_t bclk = freq_hz * I2S_LL_AD_BCK_FACTOR;
  75. uint32_t bclk_div = DAC_DMA_PERIPH_I2S_BIT_WIDTH;
  76. uint32_t mclk = bclk * bclk_div;
  77. uint32_t sclk; // use 160M PLL clock as default, minimum support freq: 19.6 KHz maximum support freq: 2.5 MHz
  78. if (is_apll) {
  79. sclk = s_dac_set_apll_freq(mclk);
  80. ESP_RETURN_ON_FALSE(sclk, ESP_ERR_INVALID_ARG, TAG, "set APLL coefficients failed");
  81. } else {
  82. // [clk_tree] TODO: replace the following clock by clk_tree API
  83. sclk = esp_clk_apb_freq() * 2; // D2PLL
  84. }
  85. uint32_t mclk_div = sclk / mclk;
  86. /* Check if the configuration is correct */
  87. ESP_RETURN_ON_FALSE(sclk / (float)mclk > 1.99, ESP_ERR_INVALID_ARG, TAG, "Frequency is too large, the mclk division is below minimum value 2");
  88. ESP_RETURN_ON_FALSE(mclk_div < 256, ESP_ERR_INVALID_ARG, TAG, "Frequency is too small, the mclk division exceed the maximum value 255");
  89. ESP_LOGD(TAG, "[sclk] %"PRIu32" [mclk] %"PRIu32" [mclk_div] %"PRIu32" [bclk] %"PRIu32" [bclk_div] %"PRIu32, sclk, mclk, mclk_div, bclk, bclk_div);
  90. i2s_ll_tx_clk_set_src(s_ddp->periph_dev, is_apll ? I2S_CLK_SRC_APLL : I2S_CLK_SRC_DEFAULT);
  91. hal_utils_clk_div_t mclk_div_coeff = {};
  92. i2s_hal_calc_mclk_precise_division(sclk, mclk, &mclk_div_coeff);
  93. i2s_ll_tx_set_mclk(s_ddp->periph_dev, &mclk_div_coeff);
  94. i2s_ll_tx_set_bck_div_num(s_ddp->periph_dev, bclk_div);
  95. return ESP_OK;
  96. }
  97. esp_err_t dac_dma_periph_init(uint32_t freq_hz, bool is_alternate, bool is_apll)
  98. {
  99. #if CONFIG_DAC_ENABLE_DEBUG_LOG
  100. esp_log_level_set(TAG, ESP_LOG_DEBUG);
  101. #endif
  102. esp_err_t ret = ESP_OK;
  103. /* Acquire DMA peripheral */
  104. ESP_RETURN_ON_ERROR(i2s_platform_acquire_occupation(DAC_DMA_PERIPH_I2S_NUM, "dac_dma"), TAG, "Failed to acquire DAC DMA peripheral");
  105. /* Allocate DAC DMA peripheral object */
  106. s_ddp = (dac_dma_periph_i2s_t *)heap_caps_calloc(1, sizeof(dac_dma_periph_i2s_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
  107. ESP_GOTO_ON_FALSE(s_ddp, ESP_ERR_NO_MEM, err, TAG, "No memory for DAC DMA object");
  108. s_ddp->periph_dev = (void *)I2S_LL_GET_HW(DAC_DMA_PERIPH_I2S_NUM);
  109. if (is_apll) {
  110. periph_rtc_apll_acquire();
  111. s_ddp->use_apll = true;
  112. }
  113. ESP_GOTO_ON_ERROR(s_dac_dma_periph_set_clock(freq_hz, is_apll), err, TAG, "Failed to set clock of DMA peripheral");
  114. i2s_ll_enable_builtin_dac(s_ddp->periph_dev, true);
  115. i2s_ll_tx_reset(s_ddp->periph_dev);
  116. i2s_ll_tx_set_slave_mod(s_ddp->periph_dev, false);
  117. i2s_ll_tx_set_sample_bit(s_ddp->periph_dev, DAC_DMA_PERIPH_I2S_BIT_WIDTH, DAC_DMA_PERIPH_I2S_BIT_WIDTH);
  118. i2s_ll_tx_enable_mono_mode(s_ddp->periph_dev, !is_alternate);
  119. i2s_ll_tx_select_std_slot(s_ddp->periph_dev, I2S_STD_SLOT_BOTH, !is_alternate);
  120. i2s_ll_tx_enable_msb_shift(s_ddp->periph_dev, false);
  121. i2s_ll_tx_set_ws_width(s_ddp->periph_dev, DAC_DMA_PERIPH_I2S_BIT_WIDTH);
  122. i2s_ll_tx_enable_msb_right(s_ddp->periph_dev, false);
  123. i2s_ll_tx_enable_right_first(s_ddp->periph_dev, true);
  124. /* Should always enable fifo */
  125. i2s_ll_tx_force_enable_fifo_mod(s_ddp->periph_dev, true);
  126. i2s_ll_dma_enable_auto_write_back(s_ddp->periph_dev, true);
  127. /* Enable the interrupts */
  128. i2s_ll_enable_intr(s_ddp->periph_dev, I2S_LL_EVENT_TX_EOF | I2S_LL_EVENT_TX_TEOF, true);
  129. return ret;
  130. err:
  131. dac_dma_periph_deinit();
  132. return ret;
  133. }
  134. esp_err_t dac_dma_periph_deinit(void)
  135. {
  136. ESP_RETURN_ON_FALSE(s_ddp->intr_handle == NULL, ESP_ERR_INVALID_STATE, TAG, "The interrupt is not deregistered yet");
  137. ESP_RETURN_ON_ERROR(i2s_platform_release_occupation(DAC_DMA_PERIPH_I2S_NUM), TAG, "Failed to release DAC DMA peripheral");
  138. i2s_ll_enable_intr(s_ddp->periph_dev, I2S_LL_EVENT_TX_EOF | I2S_LL_EVENT_TX_TEOF, false);
  139. if (s_ddp) {
  140. if (s_ddp->use_apll) {
  141. periph_rtc_apll_release();
  142. s_ddp->use_apll = false;
  143. }
  144. free(s_ddp);
  145. s_ddp = NULL;
  146. }
  147. return ESP_OK;
  148. }
  149. int dac_dma_periph_get_intr_signal(void)
  150. {
  151. return i2s_periph_signal[DAC_DMA_PERIPH_I2S_NUM].irq;
  152. }
  153. static void s_dac_dma_periph_reset(void)
  154. {
  155. i2s_ll_tx_reset(s_ddp->periph_dev);
  156. i2s_ll_tx_reset_dma(s_ddp->periph_dev);
  157. i2s_ll_tx_reset_fifo(s_ddp->periph_dev);
  158. }
  159. static void s_dac_dma_periph_start(void)
  160. {
  161. i2s_ll_enable_dma(s_ddp->periph_dev,true);
  162. i2s_ll_tx_enable_intr(s_ddp->periph_dev);
  163. i2s_ll_tx_start(s_ddp->periph_dev);
  164. i2s_ll_dma_enable_eof_on_fifo_empty(s_ddp->periph_dev, true);
  165. i2s_ll_dma_enable_auto_write_back(s_ddp->periph_dev, true);
  166. }
  167. static void s_dac_dma_periph_stop(void)
  168. {
  169. i2s_ll_tx_stop(s_ddp->periph_dev);
  170. i2s_ll_tx_stop_link(s_ddp->periph_dev);
  171. i2s_ll_tx_disable_intr(s_ddp->periph_dev);
  172. i2s_ll_enable_dma(s_ddp->periph_dev, false);
  173. i2s_ll_dma_enable_eof_on_fifo_empty(s_ddp->periph_dev, false);
  174. i2s_ll_dma_enable_auto_write_back(s_ddp->periph_dev, false);
  175. }
  176. void dac_dma_periph_enable(void)
  177. {
  178. /* Reset */
  179. s_dac_dma_periph_reset();
  180. /* Start */
  181. s_dac_dma_periph_start();
  182. }
  183. void dac_dma_periph_disable(void)
  184. {
  185. /* Reset */
  186. s_dac_dma_periph_reset();
  187. /* Stop */
  188. s_dac_dma_periph_stop();
  189. }
  190. uint32_t IRAM_ATTR dac_dma_periph_intr_is_triggered(void)
  191. {
  192. uint32_t status = i2s_ll_get_intr_status(s_ddp->periph_dev);
  193. if (status == 0) {
  194. //Avoid spurious interrupt
  195. return false;
  196. }
  197. i2s_ll_clear_intr_status(s_ddp->periph_dev, status);
  198. uint32_t ret = 0;
  199. ret |= (status & I2S_LL_EVENT_TX_EOF) ? DAC_DMA_EOF_INTR : 0;
  200. ret |= (status & I2S_LL_EVENT_TX_TEOF) ? DAC_DMA_TEOF_INTR : 0;
  201. return ret;
  202. }
  203. uint32_t IRAM_ATTR dac_dma_periph_intr_get_eof_desc(void)
  204. {
  205. uint32_t finish_desc;
  206. i2s_ll_tx_get_eof_des_addr(s_ddp->periph_dev, &finish_desc);
  207. return finish_desc;
  208. }
  209. void dac_dma_periph_dma_trans_start(uint32_t desc_addr)
  210. {
  211. i2s_ll_tx_start_link(s_ddp->periph_dev, desc_addr);
  212. }