Parcourir la source

Driver(dac): fix DAC-DMA driver and unit test

Michael (XIAO Xufeng) il y a 5 ans
Parent
commit
847a697c93

+ 5 - 3
components/driver/CMakeLists.txt

@@ -1,6 +1,6 @@
 set(srcs
     "adc_common.c"
-    "dac.c"
+    "dac_common.c"
     "gpio.c"
     "i2c.c"
     "i2s.c"
@@ -32,7 +32,8 @@ if(IDF_TARGET STREQUAL "esp32")
                      "sdmmc_host.c"
                      "sdmmc_transaction.c"
                      "esp32/touch_sensor.c"
-                     "esp32/adc.c")
+                     "esp32/adc.c"
+                     "esp32/dac.c")
     list(APPEND includes "esp32/include")
 endif()
 
@@ -40,7 +41,8 @@ if(IDF_TARGET STREQUAL "esp32s2")
     list(APPEND srcs "esp32s2/rtc_tempsensor.c"
                      "esp32s2/touch_sensor.c"
                      "esp32s2/adc.c"
-                     "esp32s2/adc2_init_cal.c")
+                     "esp32s2/adc2_init_cal.c"
+                     "esp32s2/dac.c")
     # currently only S2 beta has its own target-specific includes
     list(APPEND includes "esp32s2/include")
 endif()

+ 1 - 19
components/driver/dac.c → components/driver/dac_common.c

@@ -107,24 +107,6 @@ esp_err_t dac_out_voltage(dac_channel_t channel, uint8_t dac_value)
     return ESP_OK;
 }
 
-esp_err_t dac_i2s_enable(void)
-{
-    portENTER_CRITICAL(&rtc_spinlock);
-    dac_hal_dma_enable();
-    portEXIT_CRITICAL(&rtc_spinlock);
-
-    return ESP_OK;
-}
-
-esp_err_t dac_i2s_disable(void)
-{
-    portENTER_CRITICAL(&rtc_spinlock);
-    dac_hal_dma_disable();
-    portEXIT_CRITICAL(&rtc_spinlock);
-
-    return ESP_OK;
-}
-
 esp_err_t dac_cw_generator_enable(void)
 {
     portENTER_CRITICAL(&rtc_spinlock);
@@ -145,7 +127,7 @@ esp_err_t dac_cw_generator_disable(void)
 
 esp_err_t dac_cw_generator_config(dac_cw_config_t *cw)
 {
-    assert(cw != NULL);
+    if (!cw) return ESP_ERR_INVALID_ARG;
 
     portENTER_CRITICAL(&rtc_spinlock);
     dac_hal_cw_generator_config(cw);

+ 51 - 0
components/driver/esp32/dac.c

@@ -0,0 +1,51 @@
+// Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+#include <string.h>
+#include "esp_log.h"
+#include "esp_err.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/semphr.h"
+#include "freertos/timers.h"
+#include "driver/rtc_io.h"
+#include "driver/dac.h"
+#include "soc/dac_periph.h"
+#include "hal/dac_hal.h"
+
+extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished.
+#define DAC_ENTER_CRITICAL()  portENTER_CRITICAL(&rtc_spinlock)
+#define DAC_EXIT_CRITICAL()  portEXIT_CRITICAL(&rtc_spinlock)
+
+/*---------------------------------------------------------------
+                    Digital controller setting
+---------------------------------------------------------------*/
+
+esp_err_t dac_i2s_enable(void)
+{
+    DAC_ENTER_CRITICAL();
+    dac_hal_digi_enable_dma(true);
+    DAC_EXIT_CRITICAL();
+
+    return ESP_OK;
+}
+
+esp_err_t dac_i2s_disable(void)
+{
+    DAC_ENTER_CRITICAL();
+    dac_hal_digi_enable_dma(false);
+    DAC_EXIT_CRITICAL();
+
+    return ESP_OK;
+}

+ 44 - 0
components/driver/esp32/include/driver/dac.h

@@ -0,0 +1,44 @@
+// Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include "driver/dac_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*---------------------------------------------------------------
+                    Digital controller setting
+---------------------------------------------------------------*/
+
+/**
+ * @brief Enable DAC output data from I2S
+ *
+ * @return
+ *     - ESP_OK success
+ */
+esp_err_t dac_i2s_enable(void);
+
+/**
+ * @brief Disable DAC output data from I2S
+ *
+ * @return
+ *     - ESP_OK success
+ */
+esp_err_t dac_i2s_disable(void);
+
+#ifdef __cplusplus
+}
+#endif

+ 36 - 0
components/driver/esp32s2/adc.c

@@ -21,6 +21,7 @@
 #include "freertos/xtensa_api.h"
 #include "freertos/semphr.h"
 #include "freertos/timers.h"
+#include "esp_pm.h"
 #include "esp_intr_alloc.h"
 #include "driver/periph_ctrl.h"
 #include "driver/rtc_io.h"
@@ -57,6 +58,10 @@ extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate posi
 #define ADC_ENTER_CRITICAL()  portENTER_CRITICAL(&rtc_spinlock)
 #define ADC_EXIT_CRITICAL()  portEXIT_CRITICAL(&rtc_spinlock)
 
+#ifdef CONFIG_PM_ENABLE
+static esp_pm_lock_handle_t s_adc_digi_arbiter_lock = NULL;
+#endif  //CONFIG_PM_ENABLE
+
 /*---------------------------------------------------------------
                     Digital controller setting
 ---------------------------------------------------------------*/
@@ -72,6 +77,12 @@ esp_err_t adc_digi_init(void)
 
 esp_err_t adc_digi_deinit(void)
 {
+#ifdef CONFIG_PM_ENABLE
+    if (s_adc_digi_arbiter_lock) {
+        esp_pm_lock_delete(s_adc_digi_arbiter_lock);
+        s_adc_digi_arbiter_lock = NULL;
+    }
+#endif
     ADC_ENTER_CRITICAL();
     adc_hal_digi_init();
     ADC_EXIT_CRITICAL();
@@ -80,6 +91,22 @@ esp_err_t adc_digi_deinit(void)
 
 esp_err_t adc_digi_controller_config(const adc_digi_config_t *config)
 {
+#ifdef CONFIG_PM_ENABLE
+    esp_err_t err;
+    if (s_adc_digi_arbiter_lock == NULL) {
+        if (config->dig_clk.use_apll) {
+            err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "adc_dma", &s_adc_digi_arbiter_lock);
+        } else {
+            err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "adc_dma", &s_adc_digi_arbiter_lock);
+        }
+        if (err != ESP_OK) {
+            s_adc_digi_arbiter_lock = NULL;
+            ESP_LOGE(ADC_TAG, "ADC-DMA pm lock error");
+            return err;
+        }
+    }
+#endif //CONFIG_PM_ENABLE
+
     ADC_ENTER_CRITICAL();
     adc_hal_digi_controller_config(config);
     ADC_EXIT_CRITICAL();
@@ -158,6 +185,10 @@ esp_err_t adc_set_controller(adc_unit_t adc_unit, adc_controller_t ctrl)
 
 esp_err_t adc_digi_start(void)
 {
+#ifdef CONFIG_PM_ENABLE
+    ADC_CHECK((s_adc_digi_arbiter_lock), "Should start after call `adc_digi_controller_config`", ESP_FAIL);
+    esp_pm_lock_acquire(s_adc_digi_arbiter_lock);
+#endif
     ADC_ENTER_CRITICAL();
     adc_hal_digi_enable();
     ADC_EXIT_CRITICAL();
@@ -166,6 +197,11 @@ esp_err_t adc_digi_start(void)
 
 esp_err_t adc_digi_stop(void)
 {
+#ifdef CONFIG_PM_ENABLE
+    if (s_adc_digi_arbiter_lock) {
+        esp_pm_lock_release(s_adc_digi_arbiter_lock);
+    }
+#endif
     ADC_ENTER_CRITICAL();
     adc_hal_digi_disable();
     ADC_EXIT_CRITICAL();

+ 146 - 0
components/driver/esp32s2/dac.c

@@ -0,0 +1,146 @@
+// Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+#include <string.h>
+#include "esp_log.h"
+#include "esp_err.h"
+#include "esp_pm.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/semphr.h"
+#include "freertos/timers.h"
+#include "driver/rtc_io.h"
+#include "driver/dac.h"
+#include "soc/dac_periph.h"
+#include "hal/dac_hal.h"
+
+static const char *DAC_TAG = "DAC";
+
+#define DAC_CHECK(a, str, ret_val) ({                                               \
+    if (!(a)) {                                                                     \
+        ESP_LOGE(DAC_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str);   \
+        return (ret_val);                                                           \
+    }                                                                               \
+})
+
+extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished.
+#define DAC_ENTER_CRITICAL()  portENTER_CRITICAL(&rtc_spinlock)
+#define DAC_EXIT_CRITICAL()  portEXIT_CRITICAL(&rtc_spinlock)
+
+#ifdef CONFIG_PM_ENABLE
+static esp_pm_lock_handle_t s_dac_digi_lock = NULL;
+#endif  //CONFIG_PM_ENABLE
+
+/*---------------------------------------------------------------
+                    Digital controller setting
+---------------------------------------------------------------*/
+
+esp_err_t dac_digi_init(void)
+{
+    DAC_ENTER_CRITICAL();
+    dac_hal_digi_init();
+    DAC_EXIT_CRITICAL();
+
+    return ESP_OK;
+}
+
+esp_err_t dac_digi_deinit(void)
+{
+#ifdef CONFIG_PM_ENABLE
+    if (s_dac_digi_lock) {
+        esp_pm_lock_delete(s_dac_digi_lock);
+        s_dac_digi_lock = NULL;
+    }
+#endif
+    DAC_ENTER_CRITICAL();
+    dac_hal_digi_deinit();
+    DAC_EXIT_CRITICAL();
+
+    return ESP_OK;
+}
+
+esp_err_t dac_digi_controller_config(const dac_digi_config_t *cfg)
+{
+    DAC_CHECK(cfg->mode < DAC_CONV_MAX, "DAC mode error", ESP_ERR_INVALID_ARG);
+    DAC_CHECK(cfg->interval > 0 && cfg->interval < 4096, "DAC interval error", ESP_ERR_INVALID_ARG);
+    DAC_CHECK(cfg->dig_clk.div_num < 256, "DAC clk div_num error", ESP_ERR_INVALID_ARG);
+    DAC_CHECK(cfg->dig_clk.div_b > 0 && cfg->dig_clk.div_b < 64, "DAC clk div_b error", ESP_ERR_INVALID_ARG);
+    DAC_CHECK(cfg->dig_clk.div_a < 64, "DAC clk div_a error", ESP_ERR_INVALID_ARG);
+#ifdef CONFIG_PM_ENABLE
+    esp_err_t err;
+    if (s_dac_digi_lock == NULL) {
+        if (cfg->dig_clk.use_apll) {
+            err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "dac_dma", &s_dac_digi_lock);
+        } else {
+            err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "dac_dma", &s_dac_digi_lock);
+        }
+        if (err != ESP_OK) {
+            s_dac_digi_lock = NULL;
+            ESP_LOGE(DAC_TAG, "DAC-DMA pm lock error");
+            return err;
+        }
+    }
+#endif //CONFIG_PM_ENABLE
+
+    DAC_ENTER_CRITICAL();
+    dac_hal_digi_controller_config(cfg);
+    DAC_EXIT_CRITICAL();
+
+    return ESP_OK;
+}
+
+esp_err_t dac_digi_start(void)
+{
+#ifdef CONFIG_PM_ENABLE
+    DAC_CHECK((s_dac_digi_lock), "Should start after call `dac_digi_controller_config`", ESP_FAIL);
+    esp_pm_lock_acquire(s_dac_digi_lock);
+#endif
+    DAC_ENTER_CRITICAL();
+    dac_hal_digi_start();
+    DAC_EXIT_CRITICAL();
+
+    return ESP_OK;
+}
+
+esp_err_t dac_digi_stop(void)
+{
+#ifdef CONFIG_PM_ENABLE
+    if (s_dac_digi_lock) {
+        esp_pm_lock_release(s_dac_digi_lock);
+    }
+#endif
+    DAC_ENTER_CRITICAL();
+    dac_hal_digi_stop();
+    DAC_EXIT_CRITICAL();
+
+    return ESP_OK;
+}
+
+esp_err_t dac_digi_fifo_reset(void)
+{
+    DAC_ENTER_CRITICAL();
+    dac_hal_digi_fifo_reset();
+    DAC_EXIT_CRITICAL();
+
+    return ESP_OK;
+}
+
+esp_err_t dac_digi_reset(void)
+{
+    DAC_ENTER_CRITICAL();
+    dac_hal_digi_reset();
+    DAC_EXIT_CRITICAL();
+
+    return ESP_OK;
+}

+ 80 - 0
components/driver/esp32s2/include/driver/dac.h

@@ -0,0 +1,80 @@
+// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include "driver/dac_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*---------------------------------------------------------------
+                    Digital controller setting
+---------------------------------------------------------------*/
+
+/**
+ * @brief DAC digital controller initialization.
+ * @return
+ *     - ESP_OK success
+ */
+esp_err_t dac_digi_init(void);
+
+/**
+ * @brief DAC digital controller deinitialization.
+ * @return
+ *     - ESP_OK success
+ */
+esp_err_t dac_digi_deinit(void);
+
+/**
+ * @brief Setting the DAC digital controller.
+ *
+ * @param cfg Pointer to digital controller paramter. See ``dac_digi_config_t``.
+ * 
+ * @return
+ *     - ESP_OK success
+ *     - ESP_ERR_INVALID_ARG Parameter error
+ */
+esp_err_t dac_digi_controller_config(const dac_digi_config_t *cfg);
+
+/**
+ * @brief DAC digital controller start output voltage.
+ * @return
+ *     - ESP_OK success
+ */
+esp_err_t dac_digi_start(void);
+
+/**
+ * @brief DAC digital controller stop output voltage.
+ * @return
+ *     - ESP_OK success
+ */
+esp_err_t dac_digi_stop(void);
+
+/**
+ * @brief Reset DAC digital controller FIFO.
+ * @return
+ *     - ESP_OK success
+ */
+esp_err_t dac_digi_fifo_reset(void);
+
+/**
+ * @brief Reset DAC digital controller.
+ * @return
+ *     - ESP_OK success
+ */
+esp_err_t dac_digi_reset(void);
+
+#ifdef __cplusplus
+}
+#endif

+ 1 - 16
components/driver/include/driver/dac.h → components/driver/include/driver/dac_common.h

@@ -67,22 +67,6 @@ esp_err_t dac_output_enable(dac_channel_t channel);
  */
 esp_err_t dac_output_disable(dac_channel_t channel);
 
-/**
- * @brief Enable DAC output data from I2S
- *
- * @return
- *     - ESP_OK success
- */
-esp_err_t dac_i2s_enable(void);
-
-/**
- * @brief Disable DAC output data from I2S
- *
- * @return
- *     - ESP_OK success
- */
-esp_err_t dac_i2s_disable(void);
-
 /**
  * @brief Enable cosine wave generator output.
  *
@@ -105,6 +89,7 @@ esp_err_t dac_cw_generator_disable(void);
  * @param cw Configuration.
  * @return
  *     - ESP_OK success
+ *     - ESP_ERR_INVALID_ARG The parameter is NULL.
  */
 esp_err_t dac_cw_generator_config(dac_cw_config_t *cw);
 

+ 33 - 56
components/driver/test/adc_dma_test/test_esp32s2.c

@@ -32,7 +32,6 @@
 #include "esp_log.h"
 #include "nvs_flash.h"
 #include "test_utils.h"
-#include "soc/spi_reg.h"
 #include "soc/adc_periph.h"
 #include "test/test_common_adc.h"
 
@@ -40,6 +39,7 @@
 
 #include "soc/system_reg.h"
 #include "soc/lldesc.h"
+#include "test/test_adc_dac_dma.h"
 
 static const char *TAG = "test_adc";
 
@@ -87,9 +87,6 @@ static adc_channel_t adc_list[SOC_ADC_PATT_LEN_MAX] = {
 /* For ESP32S2, it should use same atten, or, it will have error. */
 #define TEST_ADC_ATTEN_DEFAULT (ADC_ATTEN_11db)
 
-/*******************************************/
-/**           SPI DMA INIT CODE            */
-/*******************************************/
 extern esp_err_t adc_digi_reset(void);
 
 /* Work mode.
@@ -99,7 +96,7 @@ extern esp_err_t adc_digi_reset(void);
  * */
 #define SAR_SIMPLE_NUM  512  // Set sample number of enabled unit.
 /* Use two DMA linker to save ADC data. ADC sample 1 times -> 2 byte data -> 2 DMA link buf. */
-#define SAR_DMA_DATA_SIZE(unit, sample_num)     (SAR_EOF_NUMBER(unit, sample_num)) //
+#define SAR_DMA_DATA_SIZE(unit, sample_num)     (SAR_EOF_NUMBER(unit, sample_num))
 #define SAR_EOF_NUMBER(unit, sample_num)        ((sample_num) * (unit))
 #define SAR_MEAS_LIMIT_NUM(unit, sample_num)    (SAR_SIMPLE_NUM)
 #define SAR_SIMPLE_TIMEOUT_MS  1000
@@ -113,7 +110,6 @@ typedef struct dma_msg {
 static uint8_t link_buf[2][SAR_DMA_DATA_SIZE(2, SAR_SIMPLE_NUM)] = {0};
 static lldesc_t dma1 = {0};
 static lldesc_t dma2 = {0};
-static bool adc_dma_flag = false;
 static QueueHandle_t que_adc = NULL;
 static adc_dma_event_t adc_evt;
 
@@ -137,34 +133,13 @@ static IRAM_ATTR void adc_dma_isr(void *arg)
     }
 }
 
-/** Register ADC-DMA handler. */
-static esp_err_t adc_dma_isr_register(void (*fun)(void *), void *arg)
-{
-    esp_err_t ret = ESP_FAIL;
-    ret = esp_intr_alloc(ETS_SPI3_DMA_INTR_SOURCE, 0, fun, arg, NULL);
-    return ret;
-}
-
-/** Reset DMA linker pointer and start DMA. */
-static void dma_linker_restart(void)
-{
-    REG_SET_BIT(SPI_DMA_IN_LINK_REG(3), SPI_INLINK_STOP);
-    REG_CLR_BIT(SPI_DMA_IN_LINK_REG(3), SPI_INLINK_START);
-    SET_PERI_REG_BITS(SPI_DMA_IN_LINK_REG(3), SPI_INLINK_ADDR, (uint32_t)&dma1, 0);
-    REG_SET_BIT(SPI_DMA_CONF_REG(3), SPI_IN_RST);
-    REG_CLR_BIT(SPI_DMA_CONF_REG(3), SPI_IN_RST);
-    REG_CLR_BIT(SPI_DMA_IN_LINK_REG(3), SPI_INLINK_STOP);
-    REG_SET_BIT(SPI_DMA_IN_LINK_REG(3), SPI_INLINK_START);
-}
-
 /**
  * DMA liner initialization and start.
  * @param is_loop
  *     - true: The two dma linked lists are connected end to end, with no end mark (eof).
  *     - false: The two dma linked lists are connected end to end, with end mark (eof).
- * @param int_mask DMA interrupt types.
  */
-static void dma_linker_init(adc_unit_t adc, bool is_loop, uint32_t int_mask)
+static uint32_t adc_dma_linker_init(adc_unit_t adc, bool is_loop)
 {
     dma1 = (lldesc_t) {
         .size = SAR_DMA_DATA_SIZE((adc > 2) ? 2 : 1, SAR_SIMPLE_NUM),
@@ -182,26 +157,9 @@ static void dma_linker_init(adc_unit_t adc, bool is_loop, uint32_t int_mask)
     } else {
         dma2.qe.stqe_next = NULL;
     }
-    REG_SET_BIT(DPORT_PERIP_CLK_EN_REG, DPORT_APB_SARADC_CLK_EN_M);
-    REG_SET_BIT(DPORT_PERIP_CLK_EN_REG, DPORT_SPI3_DMA_CLK_EN_M);
-    REG_SET_BIT(DPORT_PERIP_CLK_EN_REG, DPORT_SPI3_CLK_EN);
-    REG_CLR_BIT(DPORT_PERIP_RST_EN_REG, DPORT_SPI3_DMA_RST_M);
-    REG_CLR_BIT(DPORT_PERIP_RST_EN_REG, DPORT_SPI3_RST_M);
-    if (!adc_dma_flag) {
-        que_adc = xQueueCreate(5, sizeof(adc_dma_event_t));
-        adc_dma_isr_register(adc_dma_isr, NULL);
-        adc_dma_flag = true;
-    }
-    REG_WRITE(SPI_DMA_INT_CLR_REG(3), 0xFFFFFFFF);
-    REG_WRITE(SPI_DMA_INT_ENA_REG(3), int_mask);
-    dma_linker_restart();
-    printf("reg addr 0x%08x 0x%08x \n", SPI_DMA_IN_LINK_REG(3), (uint32_t)&dma1);
+    return (uint32_t)&dma1;
 }
 
-/*******************************************/
-/**           SPI DMA INIT CODE END        */
-/*******************************************/
-
 #define DEBUG_CHECK_ENABLE  1
 #define DEBUG_PRINT_ENABLE  1
 #define DEBUG_CHECK_ERROR   10
@@ -284,7 +242,7 @@ static esp_err_t adc_dma_data_check(adc_unit_t adc, int ideal_level)
     return ESP_OK;
 }
 
-static esp_err_t adc_dma_data_multi_st_check(adc_unit_t adc)
+static esp_err_t adc_dma_data_multi_st_check(adc_unit_t adc, void *dma_addr, uint32_t int_mask)
 {
     adc_dma_event_t evt;
 
@@ -300,7 +258,7 @@ static esp_err_t adc_dma_data_multi_st_check(adc_unit_t adc)
         }
     }
     TEST_ESP_OK( adc_digi_stop() );
-    dma_linker_restart();
+    adc_dac_dma_linker_start(DMA_ONLY_ADC_INLINK, (void *)dma_addr, int_mask);
     adc_digi_reset();
     TEST_ESP_OK( adc_dma_data_check(adc, -1) ); // Don't check data.
 
@@ -316,7 +274,7 @@ static esp_err_t adc_dma_data_multi_st_check(adc_unit_t adc)
         }
     }
     TEST_ESP_OK( adc_digi_stop() );
-    dma_linker_restart();
+    adc_dac_dma_linker_start(DMA_ONLY_ADC_INLINK, (void *)dma_addr, int_mask);
     adc_digi_reset();
     TEST_ESP_OK( adc_dma_data_check(adc, 1) );
 
@@ -332,7 +290,7 @@ static esp_err_t adc_dma_data_multi_st_check(adc_unit_t adc)
         }
     }
     TEST_ESP_OK( adc_digi_stop() );
-    dma_linker_restart();
+    adc_dac_dma_linker_start(DMA_ONLY_ADC_INLINK, (void *)dma_addr, int_mask);
     adc_digi_reset();
     TEST_ESP_OK( adc_dma_data_check(adc, 0) );
 
@@ -348,7 +306,7 @@ static esp_err_t adc_dma_data_multi_st_check(adc_unit_t adc)
         }
     }
     TEST_ESP_OK( adc_digi_stop() );
-    dma_linker_restart();
+    adc_dac_dma_linker_start(DMA_ONLY_ADC_INLINK, (void *)dma_addr, int_mask);
     adc_digi_reset();
     TEST_ESP_OK( adc_dma_data_check(adc, 2) );
 
@@ -468,11 +426,22 @@ int test_adc_dig_dma_single_unit(adc_unit_t adc)
     }
     TEST_ESP_OK( adc_digi_controller_config(&config) );
 
-    dma_linker_init(adc, false, SPI_IN_SUC_EOF_INT_ENA);
+    /* ADC-DMA linker init */
+    if (que_adc == NULL) {
+        que_adc = xQueueCreate(5, sizeof(adc_dma_event_t));
+    } else {
+        xQueueReset(que_adc);
+    }
+    uint32_t int_mask = SPI_IN_SUC_EOF_INT_ENA;
+    uint32_t dma_addr = adc_dma_linker_init(adc, false);
+    adc_dac_dma_isr_register(adc_dma_isr, NULL, int_mask);
+    adc_dac_dma_linker_start(DMA_ONLY_ADC_INLINK, (void *)dma_addr, int_mask);
 
     TEST_ESP_OK( adc_check_patt_table(adc, adc_test_num, adc_list[adc_test_num - 1]) );
-    adc_dma_data_multi_st_check(adc);
-
+    adc_dma_data_multi_st_check(adc, (void *)dma_addr, int_mask);
+    
+    adc_dac_dma_linker_deinit();
+    adc_dac_dma_isr_deregister(adc_dma_isr, NULL);
     TEST_ESP_OK( adc_digi_deinit() );
     return 0;
 }
@@ -564,7 +533,16 @@ int test_adc_dig_scope_debug_unit(adc_unit_t adc)
     }
     TEST_ESP_OK( adc_digi_controller_config(&config) );
 
-    dma_linker_init(adc, false, SPI_IN_DONE_INT_ENA & SPI_IN_SUC_EOF_INT_ENA);
+        /* ADC-DMA linker init */
+    if (que_adc == NULL) {
+        que_adc = xQueueCreate(5, sizeof(adc_dma_event_t));
+    } else {
+        xQueueReset(que_adc);
+    }
+    uint32_t int_mask = SPI_IN_SUC_EOF_INT_ENA;
+    uint32_t dma_addr = adc_dma_linker_init(adc, false);
+    adc_dac_dma_isr_register(adc_dma_isr, NULL, int_mask);
+    adc_dac_dma_linker_start(DMA_ONLY_ADC_INLINK, (void *)dma_addr, int_mask);
 
     ESP_LOGI(TAG, "adc IO fake tie middle, test ...");
     for (int i = 0; i < adc_test_num; i++) {
@@ -629,7 +607,6 @@ TEST_CASE("test_adc_digi_slope_debug", "[adc_dma][ignore]")
         TEST_ASSERT_EQUAL( xQueueReceive(que_adc, &evt, portMAX_DELAY), pdTRUE );
         if (evt.int_msk & SPI_IN_SUC_EOF_INT_ST) {
             TEST_ESP_OK( adc_digi_stop() );
-            dma_linker_restart();
             adc_digi_reset();
             for (int cnt = 0; cnt < 2; cnt++) {
                 ets_printf("cnt%d\n", cnt);

+ 365 - 0
components/driver/test/dac_dma_test/test_esp32s2.c

@@ -0,0 +1,365 @@
+// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/*
+ Tests for the dac device driver
+*/
+
+#include "esp_system.h"
+#include "esp_intr_alloc.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+#include "driver/adc.h"
+#include "driver/dac.h"
+#include "driver/rtc_io.h"
+#include "driver/gpio.h"
+#include "unity.h"
+#include "esp_system.h"
+#include "esp_event.h"
+#include "esp_wifi.h"
+#include "esp_log.h"
+#include "nvs_flash.h"
+#include "test_utils.h"
+#include "soc/spi_reg.h"
+#include "soc/adc_periph.h"
+#include "soc/dac_periph.h"
+#include "test/test_common_adc.h"
+
+#if !DISABLED_FOR_TARGETS(ESP8266, ESP32) // This testcase for ESP32S2
+
+#include "soc/system_reg.h"
+#include "esp32s2/rom/lldesc.h"
+#include "test/test_adc_dac_dma.h"
+
+static const char *TAG = "test_adc";
+
+#define PLATFORM_SELECT            (1)  //0: pxp; 1: chip
+#if (PLATFORM_SELECT == 0)              //PXP platform
+#include "soc/apb_ctrl_reg.h"
+#define SET_BREAK_POINT(flag) REG_WRITE(APB_CTRL_DATE_REG, flag)
+//PXP clk is slower.
+#define SYS_DELAY_TIME_MOM    (1/40)
+#define RTC_SLOW_CLK_FLAG     1     // Slow clock is 32KHz.
+static void test_pxp_deinit_io(void)
+{
+    for (int i = 0; i < 22; i++) {
+        rtc_gpio_init(i);
+    }
+}
+#else
+//PXP clk is slower.
+#define SET_BREAK_POINT(flag)
+#define SYS_DELAY_TIME_MOM    (1)
+#define RTC_SLOW_CLK_FLAG     0     // Slow clock is 32KHz.
+#endif
+
+#define SAR_SIMPLE_NUM  512  // Set out number of enabled unit.
+
+typedef struct dma_msg {
+    uint32_t int_msk;
+    uint8_t *data;
+    uint32_t data_len;
+} dac_dma_event_t;
+
+static QueueHandle_t que_dac = NULL;
+static uint8_t link_buf[2][SAR_SIMPLE_NUM*2] = {0};
+static lldesc_t dma1 = {0};
+static lldesc_t dma2 = {0};
+
+/*******************************************/
+/**           DAC-DMA INIT CODE            */
+/*******************************************/
+
+/**
+ * DMA liner initialization and start.
+ * @param is_loop
+ *     - true: The two dma linked lists are connected end to end, with no end mark (eof).
+ *     - false: The two dma linked lists are connected end to end, with end mark (eof).
+ * @param int_mask DMA interrupt types.
+ */
+uint32_t dac_dma_linker_init(bool is_alter, bool is_loop)
+{
+    /* The DAC output is a sawtooth wave. */
+    if (is_alter) {
+        for(int i=0; i<SAR_SIMPLE_NUM*2; i++) {
+            if(i%2){
+                link_buf[0][i] = i%256;
+            }else{
+                link_buf[0][i] = 256-i%256;
+            }
+            if(i%2){
+                link_buf[1][i] = i%256;
+            }else{
+                link_buf[1][i] = 256-i%256;
+            }
+        }
+    } else {
+        for(int i=0; i<SAR_SIMPLE_NUM; i++) {
+            link_buf[0][i] = i%256;
+            link_buf[1][i] = i%256;
+        }
+    }
+    dma1 = (lldesc_t) {
+        .size = (is_alter) ? SAR_SIMPLE_NUM*2 : SAR_SIMPLE_NUM,
+        .length = (is_alter) ? SAR_SIMPLE_NUM*2 : SAR_SIMPLE_NUM,
+        .eof = 0,
+        .owner = 1,
+        .buf = &link_buf[0][0],
+        .qe.stqe_next = &dma2,
+    };
+    dma2 = (lldesc_t) {
+        .size = (is_alter) ? SAR_SIMPLE_NUM*2 : SAR_SIMPLE_NUM,
+        .length = (is_alter) ? SAR_SIMPLE_NUM*2 : SAR_SIMPLE_NUM,
+        .owner = 1,
+        .buf = &link_buf[1][0],
+    };
+    if (is_loop) {
+        dma2.eof = 0;
+        dma2.qe.stqe_next = &dma1;
+    } else {
+        dma2.eof = 1;
+        dma2.qe.stqe_next = NULL;
+    }
+    return (uint32_t)&dma1;
+}
+
+/** ADC-DMA ISR handler. */
+static IRAM_ATTR void dac_dma_isr(void * arg)
+{
+    uint32_t int_st = REG_READ(SPI_DMA_INT_ST_REG(3));
+    int task_awoken = pdFALSE;
+    dac_dma_event_t adc_evt;
+    adc_evt.int_msk = int_st;
+    REG_WRITE(SPI_DMA_INT_CLR_REG(3), int_st);
+    xQueueSendFromISR(que_dac, &adc_evt, &task_awoken);
+    ESP_EARLY_LOGV(TAG, "int msk%x, raw%x", int_st, REG_READ(SPI_DMA_INT_RAW_REG(3)));
+
+    if (task_awoken == pdTRUE) {
+        portYIELD_FROM_ISR();
+    }
+}
+
+/**
+ * Testcase: Check the interrupt types of DAC-DMA.
+ */
+void test_dac_dig_dma_intr_check(dac_digi_convert_mode_t mode)
+{
+    ESP_LOGI(TAG, "  >> %s - dac mode %d<<  ", __func__, mode);
+
+    dac_dma_event_t evt;
+
+    dac_digi_init();
+    const dac_digi_config_t cfg = {
+        .mode = mode,
+        .interval = 100,
+        .dig_clk.use_apll = false,  // APB clk
+        .dig_clk.div_num = 79,
+        .dig_clk.div_b = 1,
+        .dig_clk.div_a = 0,
+    };
+    dac_digi_controller_config(&cfg);
+    dac_output_enable(DAC_CHANNEL_1);
+    dac_output_enable(DAC_CHANNEL_2);
+
+    /* DAC-DMA linker init */
+    if (que_dac == NULL) {
+        que_dac = xQueueCreate(5, sizeof(dac_dma_event_t));
+    } else {
+        xQueueReset(que_dac);
+    }
+    uint32_t int_mask = SPI_OUT_DONE_INT_ENA | SPI_OUT_EOF_INT_ENA | SPI_OUT_TOTAL_EOF_INT_ENA;
+    uint32_t dma_addr = dac_dma_linker_init(mode, false);
+    adc_dac_dma_isr_register(dac_dma_isr, NULL, int_mask);
+    adc_dac_dma_linker_start(DMA_ONLY_DAC_OUTLINK, (void *)dma_addr, int_mask);
+
+    /* ADC-DMA start output */
+    dac_digi_start();
+
+    /* Check interrupt type */
+    while (int_mask) {
+        TEST_ASSERT_EQUAL( xQueueReceive(que_dac, &evt, 2000 / portTICK_RATE_MS), pdTRUE );
+        ESP_LOGI(TAG, "DAC-DMA intr type 0x%x", evt.int_msk);
+        if (evt.int_msk & int_mask) {
+            int_mask &= (~evt.int_msk);
+        }
+    }
+
+    ESP_LOGI(TAG, "DAC-DMA intr test over");
+    adc_dac_dma_linker_deinit();
+    adc_dac_dma_isr_deregister(dac_dma_isr, NULL);
+    TEST_ESP_OK( dac_digi_deinit() );
+}
+
+TEST_CASE("DAC-DMA interrupt test", "[dac]")
+{
+    test_dac_dig_dma_intr_check(DAC_CONV_NORMAL);
+    test_dac_dig_dma_intr_check(DAC_CONV_ALTER);
+}
+
+/*******************************************/
+/**           SPI DMA INIT CODE            */
+/*******************************************/
+
+#include "sys/queue.h"
+static bool adc_dac_dma_isr_flag = false;
+
+/*---------------------------------------------------------------
+                        INTERRUPT HANDLER
+---------------------------------------------------------------*/
+
+typedef struct adc_dac_dma_isr_handler_ {
+    uint32_t mask;
+    intr_handler_t handler;
+    void* handler_arg;
+    SLIST_ENTRY(adc_dac_dma_isr_handler_) next;
+} adc_dac_dma_isr_handler_t;
+
+static SLIST_HEAD(adc_dac_dma_isr_handler_list_, adc_dac_dma_isr_handler_) s_adc_dac_dma_isr_handler_list =
+        SLIST_HEAD_INITIALIZER(s_adc_dac_dma_isr_handler_list);
+portMUX_TYPE s_isr_handler_list_lock = portMUX_INITIALIZER_UNLOCKED;
+static intr_handle_t s_adc_dac_dma_isr_handle;
+
+static IRAM_ATTR void adc_dac_dma_isr_default(void* arg)
+{
+    uint32_t status = REG_READ(SPI_DMA_INT_ST_REG(3));
+    adc_dac_dma_isr_handler_t* it;
+    portENTER_CRITICAL_ISR(&s_isr_handler_list_lock);
+    SLIST_FOREACH(it, &s_adc_dac_dma_isr_handler_list, next) {
+        if (it->mask & status) {
+            portEXIT_CRITICAL_ISR(&s_isr_handler_list_lock);
+            (*it->handler)(it->handler_arg);
+            portENTER_CRITICAL_ISR(&s_isr_handler_list_lock);
+        }
+    }
+    portEXIT_CRITICAL_ISR(&s_isr_handler_list_lock);
+    REG_WRITE(SPI_DMA_INT_CLR_REG(3), status);
+}
+
+static esp_err_t adc_dac_dma_isr_ensure_installed(void)
+{
+    esp_err_t err = ESP_OK;
+    portENTER_CRITICAL(&s_isr_handler_list_lock);
+    if (s_adc_dac_dma_isr_handle) {
+        goto out;
+    }
+    REG_WRITE(SPI_DMA_INT_ENA_REG(3), 0);
+    REG_WRITE(SPI_DMA_INT_CLR_REG(3), UINT32_MAX);
+    err = esp_intr_alloc(ETS_SPI3_DMA_INTR_SOURCE, 0, &adc_dac_dma_isr_default, NULL, &s_adc_dac_dma_isr_handle);
+    if (err != ESP_OK) {
+        goto out;
+    }
+
+out:
+    portEXIT_CRITICAL(&s_isr_handler_list_lock);
+    return err;
+}
+
+esp_err_t adc_dac_dma_isr_register(intr_handler_t handler, void* handler_arg, uint32_t intr_mask)
+{
+    esp_err_t err = adc_dac_dma_isr_ensure_installed();
+    if (err != ESP_OK) {
+        return err;
+    }
+
+    adc_dac_dma_isr_handler_t* item = malloc(sizeof(*item));
+    if (item == NULL) {
+        return ESP_ERR_NO_MEM;
+    }
+    item->handler = handler;
+    item->handler_arg = handler_arg;
+    item->mask = intr_mask;
+    portENTER_CRITICAL(&s_isr_handler_list_lock);
+    SLIST_INSERT_HEAD(&s_adc_dac_dma_isr_handler_list, item, next);
+    portEXIT_CRITICAL(&s_isr_handler_list_lock);
+    return ESP_OK;
+}
+
+esp_err_t adc_dac_dma_isr_deregister(intr_handler_t handler, void* handler_arg)
+{
+    adc_dac_dma_isr_handler_t* it;
+    adc_dac_dma_isr_handler_t* prev = NULL;
+    bool found = false;
+    portENTER_CRITICAL(&s_isr_handler_list_lock);
+    SLIST_FOREACH(it, &s_adc_dac_dma_isr_handler_list, next) {
+        if (it->handler == handler && it->handler_arg == handler_arg) {
+            if (it == SLIST_FIRST(&s_adc_dac_dma_isr_handler_list)) {
+                SLIST_REMOVE_HEAD(&s_adc_dac_dma_isr_handler_list, next);
+            } else {
+                SLIST_REMOVE_AFTER(prev, next);
+            }
+            found = true;
+            free(it);
+            break;
+        }
+        prev = it;
+    }
+    portEXIT_CRITICAL(&s_isr_handler_list_lock);
+    return found ? ESP_OK : ESP_ERR_INVALID_STATE;
+}
+
+void adc_dac_dma_linker_start(spi_dma_link_type_t type, void *dma_addr, uint32_t int_msk)
+{
+    REG_SET_BIT(DPORT_PERIP_CLK_EN_REG, DPORT_APB_SARADC_CLK_EN_M);
+    REG_SET_BIT(DPORT_PERIP_CLK_EN_REG, DPORT_SPI3_DMA_CLK_EN_M);
+    REG_SET_BIT(DPORT_PERIP_CLK_EN_REG, DPORT_SPI3_CLK_EN);
+    REG_CLR_BIT(DPORT_PERIP_RST_EN_REG, DPORT_SPI3_DMA_RST_M);
+    REG_CLR_BIT(DPORT_PERIP_RST_EN_REG, DPORT_SPI3_RST_M);
+    REG_WRITE(SPI_DMA_INT_CLR_REG(3), 0xFFFFFFFF);
+    REG_WRITE(SPI_DMA_INT_ENA_REG(3), int_msk | REG_READ(SPI_DMA_INT_ENA_REG(3)));
+    if (type & DMA_ONLY_ADC_INLINK) {
+        REG_SET_BIT(SPI_DMA_IN_LINK_REG(3), SPI_INLINK_STOP);
+        REG_CLR_BIT(SPI_DMA_IN_LINK_REG(3), SPI_INLINK_START);
+        SET_PERI_REG_BITS(SPI_DMA_IN_LINK_REG(3), SPI_INLINK_ADDR, (uint32_t)dma_addr, 0);
+        REG_SET_BIT(SPI_DMA_CONF_REG(3), SPI_IN_RST);
+        REG_CLR_BIT(SPI_DMA_CONF_REG(3), SPI_IN_RST);
+        REG_CLR_BIT(SPI_DMA_IN_LINK_REG(3), SPI_INLINK_STOP);
+        REG_SET_BIT(SPI_DMA_IN_LINK_REG(3), SPI_INLINK_START);
+    }
+    if (type & DMA_ONLY_DAC_OUTLINK) {
+        REG_SET_BIT(SPI_DMA_OUT_LINK_REG(3), SPI_OUTLINK_STOP);
+        REG_CLR_BIT(SPI_DMA_OUT_LINK_REG(3), SPI_OUTLINK_START);
+        SET_PERI_REG_BITS(SPI_DMA_OUT_LINK_REG(3), SPI_OUTLINK_ADDR, (uint32_t)dma_addr, 0);
+        REG_SET_BIT(SPI_DMA_CONF_REG(3), SPI_OUT_RST);
+        REG_CLR_BIT(SPI_DMA_CONF_REG(3), SPI_OUT_RST);
+        REG_CLR_BIT(SPI_DMA_OUT_LINK_REG(3), SPI_OUTLINK_STOP);
+        REG_SET_BIT(SPI_DMA_OUT_LINK_REG(3), SPI_OUTLINK_START);
+    }
+}
+
+void adc_dac_dma_linker_stop(spi_dma_link_type_t type)
+{
+    if (type & DMA_ONLY_ADC_INLINK) {
+        REG_SET_BIT(SPI_DMA_IN_LINK_REG(3), SPI_INLINK_STOP);
+        REG_CLR_BIT(SPI_DMA_IN_LINK_REG(3), SPI_INLINK_START);
+    }
+    if (type & DMA_ONLY_DAC_OUTLINK) {
+        REG_SET_BIT(SPI_DMA_OUT_LINK_REG(3), SPI_OUTLINK_STOP);
+        REG_CLR_BIT(SPI_DMA_OUT_LINK_REG(3), SPI_OUTLINK_START);
+    }
+}
+
+void adc_dac_dma_linker_deinit(void)
+{
+    adc_dac_dma_linker_stop(DMA_BOTH_ADC_DAC);
+    REG_WRITE(SPI_DMA_INT_CLR_REG(3), 0xFFFFFFFF);
+    REG_WRITE(SPI_DMA_INT_ENA_REG(3), 0);
+    adc_dac_dma_isr_flag = false;
+}
+
+/*******************************************/
+/**           SPI DMA INIT CODE END        */
+/*******************************************/
+
+#endif // !DISABLED_FOR_TARGETS(ESP8266, ESP32)

+ 67 - 0
components/driver/test/include/test/test_adc_dac_dma.h

@@ -0,0 +1,67 @@
+// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#if !DISABLED_FOR_TARGETS(ESP8266, ESP32) // This testcase for ESP32S2
+
+/**
+ * SPI DMA type.
+ */
+typedef enum {
+    DMA_ONLY_ADC_INLINK = BIT(1),   /*!<Select ADC-DMA config. */
+    DMA_ONLY_DAC_OUTLINK = BIT(2),  /*!<Select DAC-DMA config. */
+    DMA_BOTH_ADC_DAC,               /*!<Select DAC-DMA and ADC-DMA config. */
+#define DMA_BOTH_ADC_DAC (DMA_ONLY_ADC_INLINK | DMA_ONLY_DAC_OUTLINK)
+} spi_dma_link_type_t;
+
+/**
+ * Register SPI-DMA interrupt handler.
+ *
+ * @param handler       Handler.
+ * @param handler_arg   Handler parameter.
+ * @param intr_mask     DMA interrupt type mask.
+ */
+esp_err_t adc_dac_dma_isr_register(intr_handler_t handler, void* handler_arg, uint32_t intr_mask);
+
+/**
+ * Deregister SPI-DMA interrupt handler.
+ *
+ * @param handler       Handler.
+ * @param handler_arg   Handler parameter.
+ */
+esp_err_t adc_dac_dma_isr_deregister(intr_handler_t handler, void* handler_arg);
+
+/**
+ * Reset DMA linker pointer and start DMA.
+ *
+ * @param type     DMA linker type. See ``spi_dma_link_type_t``.
+ * @param dma_addr DMA linker addr.
+ * @param int_msk  DMA interrupt type mask.
+ */
+void adc_dac_dma_linker_start(spi_dma_link_type_t type, void *dma_addr, uint32_t int_msk);
+
+/**
+ * Stop DMA.
+ *
+ * @param type DMA linker type. See ``spi_dma_link_type_t``.
+ */
+void adc_dac_dma_linker_stop(spi_dma_link_type_t type);
+
+/**
+ * Deinit SPI3 DMA. Disable interrupt, stop DMA trans.
+ */
+void adc_dac_dma_linker_deinit(void);
+
+#endif

+ 1 - 1
components/driver/test/include/test/test_common_adc.h

@@ -31,4 +31,4 @@ void adc_fake_tie_middle(adc_unit_t adc_unit, adc_channel_t channel);
 void adc_fake_tie_high(adc_unit_t adc_unit, adc_channel_t channel);
 void adc_fake_tie_low(adc_unit_t adc_unit, adc_channel_t channel);
 void adc_io_normal(adc_unit_t adc_unit, adc_channel_t channel);
-/**@}*/
+/**@}*/

+ 5 - 2
components/soc/include/hal/adc_types.h

@@ -117,6 +117,8 @@ typedef struct {
 /**
  * @brief ADC digital controller (DMA mode) clock system setting.
  *        Expression: controller_clk = (`APLL` or `APB`) / (div_num + div_a / div_b + 1).
+ *
+ * @note: The clocks of the DAC digital controller use the ADC digital controller clock divider.
  */
 typedef struct {
     bool use_apll;      /*!<true: use APLL clock; false: use APB clock. */
@@ -246,14 +248,15 @@ typedef struct {
                                     pattern table one by one. For each controller the scan sequence has at most 16 different rules before repeating itself. */
     uint32_t adc2_pattern_len;  /*!<Refer to ``adc1_pattern_len`` */
     adc_digi_pattern_table_t *adc1_pattern;  /*!<Pointer to pattern table for digital controller. The table size defined by `adc1_pattern_len`. */
-    adc_digi_pattern_table_t *adc2_pattern;  /*!<Refer to ``adc1_pattern`` */
+    adc_digi_pattern_table_t *adc2_pattern;  /*!<Refer to `adc1_pattern` */
     adc_digi_convert_mode_t conv_mode;       /*!<ADC conversion mode for digital controller. See ``adc_digi_convert_mode_t``. */
     adc_digi_output_format_t format;         /*!<ADC output data format for digital controller. See ``adc_digi_output_format_t``. */
     uint32_t interval;          /*!<The number of interval clock cycles for the digital controller to trigger the measurement.
                                     The unit is the divided clock. Range: 40 ~ 4095.
                                     Expression: `trigger_meas_freq` = `controller_clk` / 2 / interval. Refer to ``adc_digi_clk_t``.
                                     Note: The sampling rate of each channel is also related to the conversion mode (See ``adc_digi_convert_mode_t``) and pattern table settings. */
-    adc_digi_clk_t dig_clk;     /*!<ADC digital controller clock divider settings. Refer to ``adc_digi_clk_t`` */
+    adc_digi_clk_t dig_clk;     /*!<ADC digital controller clock divider settings. Refer to ``adc_digi_clk_t``.
+                                    Note: The clocks of the DAC digital controller use the ADC digital controller clock divider. */
     uint32_t dma_eof_num;       /*!<DMA eof num of adc digital controller.
                                     If the number of measurements reaches `dma_eof_num`, then `dma_in_suc_eof` signal is generated in DMA.
                                     Note: The converted data in the DMA in link buffer will be multiple of two bytes. */

+ 2 - 7
components/soc/include/hal/dac_hal.h

@@ -75,11 +75,6 @@
 void dac_hal_cw_generator_config(dac_cw_config_t *cw);
 
 /**
- * Enable DAC output data from DMA.
+ * Enable/disable DAC output data from DMA.
  */
-#define dac_hal_dma_enable() dac_ll_dma_enable()
-
-/**
- * Disable DAC output data from DMA.
- */
-#define dac_hal_dma_disable() dac_ll_dma_disable()
+#define dac_hal_digi_enable_dma(enable) dac_ll_digi_enable_dma(enable)

+ 28 - 1
components/soc/include/hal/dac_types.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include "soc/dac_caps.h"
+#include "hal/adc_types.h"
 #include "sdkconfig.h"
 
 typedef enum {
@@ -37,4 +38,30 @@ typedef struct {
     uint32_t freq;          /*!< Set frequency of cosine wave generator output. Range: 130(130Hz) ~ 55000(100KHz). */
     int8_t offset;          /*!< Set the voltage value of the DC component of the cosine wave generator output.
                                  Note: Unreasonable settings can cause waveform to be oversaturated. Range: -128 ~ 127. */
-} dac_cw_config_t;
+} dac_cw_config_t;
+
+#ifdef CONFIG_IDF_TARGET_ESP32S2
+
+/**
+ * @brief DAC digital controller (DMA mode) work mode.
+ */
+typedef enum {
+    DAC_CONV_NORMAL,        /*!< The data in the DMA buffer is simultaneously output to the enable channel of the DAC. */
+    DAC_CONV_ALTER,         /*!< The data in the DMA buffer is alternately output to the enable channel of the DAC. */
+    DAC_CONV_MAX
+} dac_digi_convert_mode_t;
+
+/**
+ * @brief DAC digital controller (DMA mode) configuration parameters.
+ */
+typedef struct {
+    dac_digi_convert_mode_t mode;   /*!<DAC digital controller (DMA mode) work mode. See ``dac_digi_convert_mode_t``. */
+    uint32_t interval;          /*!<The number of interval clock cycles for the DAC digital controller to output voltage.
+                                    The unit is the divided clock. Range: 1 ~ 4095.
+                                    Expression: `dac_output_freq` = `controller_clk` / interval. Refer to ``adc_digi_clk_t``.
+                                    Note: The sampling rate of each channel is also related to the conversion mode (See ``dac_digi_convert_mode_t``) and pattern table settings. */
+    adc_digi_clk_t dig_clk;     /*!<DAC digital controller clock divider settings. Refer to ``adc_digi_clk_t``.
+                                    Note: The clocks of the DAC digital controller use the ADC digital controller clock divider. */
+} dac_digi_config_t;
+
+#endif //CONFIG_IDF_TARGET_ESP32S2

+ 4 - 14
components/soc/src/esp32/include/hal/dac_ll.h

@@ -184,25 +184,15 @@ static inline void dac_ll_cw_set_dc_offset(dac_channel_t channel, int8_t offset)
 /*           DAC DMA API's          */
 /************************************/
 /**
- * Enable DAC output data from I2S DMA.
+ * Enable/disable DAC output data from I2S DMA.
  * I2S_CLK connect to DAC_CLK, I2S_DATA_OUT connect to DAC_DATA.
  */
-static inline void dac_ll_dma_enable(void)
+static inline void dac_ll_digi_enable_dma(bool enable)
 {
-    SENS.sar_dac_ctrl1.dac_dig_force = 1;
-    SENS.sar_dac_ctrl1.dac_clk_inv = 1;
+    SENS.sar_dac_ctrl1.dac_dig_force = enable;
+    SENS.sar_dac_ctrl1.dac_clk_inv = enable;
 }
 
-/**
- * Disable DAC output data from I2S DMA.
- */
-static inline void dac_ll_dma_disable(void)
-{
-    SENS.sar_dac_ctrl1.dac_dig_force = 0;
-    SENS.sar_dac_ctrl1.dac_clk_inv = 0;
-}
-
-
 #ifdef __cplusplus
 }
 #endif

+ 1 - 0
components/soc/src/esp32s2/CMakeLists.txt

@@ -1,4 +1,5 @@
 set(srcs "adc_hal.c"
+        "dac_hal.c"
         "brownout_hal.c"
         "rtc_clk.c"
         "rtc_clk_init.c"

+ 4 - 1
components/soc/src/esp32s2/adc_hal.c

@@ -16,7 +16,7 @@
 
 #include "hal/adc_hal.h"
 #include "hal/adc_types.h"
-#include "esp_log.h"
+
 /*---------------------------------------------------------------
                     Digital controller setting
 ---------------------------------------------------------------*/
@@ -96,6 +96,9 @@ void adc_hal_digi_controller_config(const adc_digi_config_t *cfg)
  * Enable clock and select clock source for ADC digital controller.
  * Expression: controller_clk = (`APLL` or `APB`) / (div_num + div_a / div_b + 1).
  *
+ * @note ADC and DAC digital controller share the same frequency divider.
+ *       Please set a reasonable frequency division factor to meet the sampling frequency of the ADC and the output frequency of the DAC.
+ *
  * @param clk Refer to ``adc_digi_clk_t``.
  */
 void adc_hal_digi_clk_config(const adc_digi_clk_t *clk)

+ 55 - 0
components/soc/src/esp32s2/dac_hal.c

@@ -0,0 +1,55 @@
+// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// The HAL layer for ADC (esp32s2 specific part)
+
+#include "hal/dac_hal.h"
+#include "hal/adc_hal.h"
+#include "hal/dac_types.h"
+
+/*---------------------------------------------------------------
+                    Digital controller setting
+---------------------------------------------------------------*/
+
+void dac_hal_digi_init(void)
+{
+    dac_ll_digi_clk_inv(true);
+}
+
+void dac_hal_digi_deinit(void)
+{
+    dac_ll_digi_trigger_output(false);
+    dac_ll_digi_enable_dma(false);
+    dac_ll_digi_fifo_reset();
+    dac_ll_digi_reset();
+}
+
+void dac_hal_digi_controller_config(const dac_digi_config_t *cfg)
+{
+    dac_ll_digi_set_convert_mode(cfg->mode);
+    dac_ll_digi_set_trigger_interval(cfg->interval);
+    adc_hal_digi_clk_config(&cfg->dig_clk);
+}
+
+void dac_hal_digi_start(void)
+{
+    dac_ll_digi_enable_dma(true);
+    dac_ll_digi_trigger_output(true);
+}
+
+void dac_hal_digi_stop(void)
+{
+    dac_ll_digi_trigger_output(false);
+    dac_ll_digi_enable_dma(false);
+}

+ 3 - 0
components/soc/src/esp32s2/include/hal/adc_hal.h

@@ -83,6 +83,9 @@ void adc_hal_digi_disable(void);
  * Enable clock and select clock source for ADC digital controller.
  * Expression: controller_clk = (`APLL` or `APB`) / (div_num + div_a / div_b + 1).
  *
+ * @note ADC and DAC digital controller share the same frequency divider.
+ *       Please set a reasonable frequency division factor to meet the sampling frequency of the ADC and the output frequency of the DAC.
+ *
  * @param clk Refer to ``adc_digi_clk_t``.
  */
 void adc_hal_digi_clk_config(const adc_digi_clk_t *clk);

+ 76 - 0
components/soc/src/esp32s2/include/hal/dac_hal.h

@@ -0,0 +1,76 @@
+// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/*******************************************************************************
+ * NOTICE
+ * The hal is not public api, don't use in application code.
+ * See readme.md in soc/include/hal/readme.md
+ ******************************************************************************/
+
+// The HAL layer for DAC (esp32s2 specific part)
+
+#pragma once
+
+#include "hal/dac_ll.h"
+#include "hal/dac_types.h"
+
+#include_next "hal/dac_hal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*---------------------------------------------------------------
+                    Digital controller setting
+---------------------------------------------------------------*/
+/**
+ * Digital controller initialization.
+ */
+void dac_hal_digi_init(void);
+
+/**
+ * Digital controller deinitialization.
+ */
+void dac_hal_digi_deinit(void);
+
+/**
+ * Setting the DAC digital controller.
+ *
+ * @param cfg Pointer to digital controller paramter.
+ */
+void dac_hal_digi_controller_config(const dac_digi_config_t *cfg);
+
+/**
+ * DAC digital controller start output voltage.
+ */
+void dac_hal_digi_start(void);
+
+/**
+ * DAC digital controller stop output voltage.
+ */
+void dac_hal_digi_stop(void);
+
+/**
+ * Reset DAC digital controller FIFO.
+ */
+#define dac_hal_digi_fifo_reset() dac_ll_digi_fifo_reset()
+
+/**
+ * Reset DAC digital controller.
+ */
+#define dac_hal_digi_reset() dac_ll_digi_reset()
+
+#ifdef __cplusplus
+}
+#endif

+ 71 - 11
components/soc/src/esp32s2/include/hal/dac_ll.h

@@ -23,15 +23,16 @@
 #include <stdlib.h>
 #include "soc/dac_periph.h"
 #include "hal/dac_types.h"
+#include "soc/apb_saradc_struct.h"
+#include "soc/apb_saradc_reg.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /*---------------------------------------------------------------
-                    RTC controller setting
+                    DAC common setting
 ---------------------------------------------------------------*/
-
 /**
  * Power on dac module and start output voltage.
  *
@@ -59,6 +60,9 @@ static inline void dac_ll_power_down(dac_channel_t channel)
     }
 }
 
+/*---------------------------------------------------------------
+                    RTC controller setting
+---------------------------------------------------------------*/
 /**
  * Output voltage with value (8 bit).
  *
@@ -204,23 +208,79 @@ static inline void dac_ll_cw_set_dc_offset(dac_channel_t channel, int8_t offset)
 /************************************/
 /*           DAC DMA API's          */
 /************************************/
+
+/**
+ * Enable/disable invert the DAC digital controller clock signal.
+ * 
+ * @param enable true or false.
+ */
+static inline void dac_ll_digi_clk_inv(bool enable)
+{
+    SENS.sar_dac_ctrl1.dac_clk_inv = enable;
+}
+
+/**
+ * Enable/disable DAC-DMA mode for dac digital controller.
+ */
+static inline void dac_ll_digi_enable_dma(bool enable)
+{
+    SENS.sar_dac_ctrl1.dac_dig_force = enable;
+    APB_SARADC.apb_dac_ctrl.apb_dac_trans = enable;
+}
+
+/**
+ * Sets the number of interval clock cycles for the digital controller to trigger the DAC output.
+ * Expression: `dac_output_freq` = `controller_clk` / interval.
+ *
+ * @note The clocks of the DAC digital controller use the ADC digital controller clock divider.
+ *
+ * @param cycle The number of clock cycles for the trigger output interval. The unit is the divided clock.
+ */
+static inline void dac_ll_digi_set_trigger_interval(uint32_t cycle)
+{
+    APB_SARADC.apb_dac_ctrl.dac_timer_target = cycle;
+}
+
+/**
+ * Enable/disable DAC digital controller to trigger the DAC output.
+ *
+ * @param enable true or false.
+ */
+static inline void dac_ll_digi_trigger_output(bool enable)
+{
+    APB_SARADC.apb_dac_ctrl.dac_timer_en = enable;
+}
+
+/**
+ * Set DAC conversion mode for digital controller.
+ *
+ * @param mode Conversion mode select. See ``dac_digi_convert_mode_t``.
+ */
+static inline void dac_ll_digi_set_convert_mode(dac_digi_convert_mode_t mode)
+{
+    if (mode == DAC_CONV_NORMAL) {
+        APB_SARADC.apb_dac_ctrl.apb_dac_alter_mode = 0;
+    } else {
+        APB_SARADC.apb_dac_ctrl.apb_dac_alter_mode = 1;
+    }
+}
+
 /**
- * Enable DAC output data from I2S DMA.
- * I2S_CLK connect to DAC_CLK, I2S_DATA_OUT connect to DAC_DATA.
+ * Reset FIFO of DAC digital controller.
  */
-static inline void dac_ll_dma_enable(void)
+static inline void dac_ll_digi_fifo_reset(void)
 {
-    SENS.sar_dac_ctrl1.dac_dig_force = 1;
-    SENS.sar_dac_ctrl1.dac_clk_inv = 1;
+    APB_SARADC.apb_dac_ctrl.dac_reset_fifo = 1;
+    APB_SARADC.apb_dac_ctrl.dac_reset_fifo = 0;
 }
 
 /**
- * Disable DAC output data from I2S DMA.
+ * Reset DAC digital controller.
  */
-static inline void dac_ll_dma_disable(void)
+static inline void dac_ll_digi_reset(void)
 {
-    SENS.sar_dac_ctrl1.dac_dig_force = 0;
-    SENS.sar_dac_ctrl1.dac_clk_inv = 0;
+    APB_SARADC.apb_dac_ctrl.apb_dac_rst = 1;
+    APB_SARADC.apb_dac_ctrl.apb_dac_rst = 0;
 }
 
 #ifdef __cplusplus

+ 2 - 1
docs/Doxyfile

@@ -86,7 +86,6 @@ INPUT = \
     ##
     ## Peripherals - API Reference
     ##
-    $(IDF_PATH)/components/driver/include/driver/dac.h \
     $(IDF_PATH)/components/driver/include/driver/gpio.h \
     $(IDF_PATH)/components/driver/include/driver/rtc_io.h \
     $(IDF_PATH)/components/driver/include/driver/i2c.h \
@@ -101,12 +100,14 @@ INPUT = \
     $(IDF_PATH)/components/driver/include/driver/spi_master.h \
     $(IDF_PATH)/components/driver/include/driver/spi_slave.h \
     $(IDF_PATH)/components/driver/$(IDF_TARGET)/include/driver/adc.h \
+    $(IDF_PATH)/components/driver/$(IDF_TARGET)/include/driver/dac.h \
     $(IDF_PATH)/components/driver/$(IDF_TARGET)/include/driver/touch_sensor.h \
     $(IDF_PATH)/components/driver/esp32s2/include/driver/temp_sensor.h \
     $(IDF_PATH)/components/driver/include/driver/timer.h \
     $(IDF_PATH)/components/driver/include/driver/touch_sensor_common.h \
     $(IDF_PATH)/components/driver/include/driver/twai.h \
     $(IDF_PATH)/components/driver/include/driver/adc_common.h \
+    $(IDF_PATH)/components/driver/include/driver/dac_common.h \
     $(IDF_PATH)/components/driver/include/driver/uart.h \
     $(IDF_PATH)/components/esp_adc_cal/include/esp_adc_cal.h \
     $(IDF_PATH)/components/esp32s2/include/esp_hmac.h \

+ 1 - 0
docs/en/api-reference/peripherals/dac.rst

@@ -34,6 +34,7 @@ API Reference
 -------------
 
 .. include-build-file:: inc/dac.inc
+.. include-build-file:: inc/dac_common.inc
 
 GPIO Lookup Macros
 ^^^^^^^^^^^^^^^^^^

+ 1 - 1
tools/ci/config/target-test.yml

@@ -546,7 +546,7 @@ UT_034:
 
 UT_035:
   extends: .unit_test_s2_template
-  parallel: 37
+  parallel: 38
   tags:
     - ESP32S2_IDF
     - UT_T1_1