diff --git a/components/driver/CMakeLists.txt b/components/driver/CMakeLists.txt index 7baeaf1f6e..c4113b42c4 100644 --- a/components/driver/CMakeLists.txt +++ b/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() @@ -42,7 +43,7 @@ if(IDF_TARGET STREQUAL "esp32s2") "esp32s2/adc.c" "esp32s2/adc2_init_cal.c" "spi_slave_hd.c" - ) + "esp32s2/dac.c") # currently only S2 beta has its own target-specific includes list(APPEND includes "esp32s2/include") endif() diff --git a/components/driver/dac.c b/components/driver/dac_common.c similarity index 92% rename from components/driver/dac.c rename to components/driver/dac_common.c index 609da1d79d..6fbcc21da4 100644 --- a/components/driver/dac.c +++ b/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); diff --git a/components/driver/esp32/dac.c b/components/driver/esp32/dac.c new file mode 100644 index 0000000000..9c07c22269 --- /dev/null +++ b/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 +#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; +} \ No newline at end of file diff --git a/components/driver/esp32/include/driver/dac.h b/components/driver/esp32/include/driver/dac.h new file mode 100644 index 0000000000..c0a418c190 --- /dev/null +++ b/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 \ No newline at end of file diff --git a/components/driver/esp32s2/adc.c b/components/driver/esp32s2/adc.c index 7eaecace38..5c2e22b7c3 100644 --- a/components/driver/esp32s2/adc.c +++ b/components/driver/esp32s2/adc.c @@ -22,6 +22,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" @@ -56,6 +57,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 ---------------------------------------------------------------*/ @@ -71,6 +76,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_deinit(); ADC_EXIT_CRITICAL(); @@ -79,6 +90,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(); @@ -157,6 +184,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(); @@ -165,6 +196,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(); diff --git a/components/driver/esp32s2/dac.c b/components/driver/esp32s2/dac.c new file mode 100644 index 0000000000..bbba688d23 --- /dev/null +++ b/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 +#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; +} diff --git a/components/driver/esp32s2/include/driver/dac.h b/components/driver/esp32s2/include/driver/dac.h new file mode 100644 index 0000000000..42ead8a760 --- /dev/null +++ b/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 diff --git a/components/driver/include/driver/dac.h b/components/driver/include/driver/dac_common.h similarity index 91% rename from components/driver/include/driver/dac.h rename to components/driver/include/driver/dac_common.h index 86699dd0ae..478841fc73 100644 --- a/components/driver/include/driver/dac.h +++ b/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); diff --git a/components/driver/test/adc_dma_test/test_esp32s2.c b/components/driver/test/adc_dma_test/test_esp32s2.c index 147c0fe24d..e875c1bfe5 100644 --- a/components/driver/test/adc_dma_test/test_esp32s2.c +++ b/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" #include "esp_rom_sys.h" @@ -41,6 +40,7 @@ #include "soc/system_reg.h" #include "soc/lldesc.h" +#include "test/test_adc_dac_dma.h" static const char *TAG = "test_adc"; @@ -88,9 +88,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. @@ -100,7 +97,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 @@ -114,7 +111,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; @@ -138,34 +134,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), @@ -183,26 +158,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 @@ -285,7 +243,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; @@ -301,7 +259,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. @@ -317,7 +275,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) ); @@ -333,7 +291,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) ); @@ -349,7 +307,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) ); @@ -469,11 +427,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; } @@ -565,7 +534,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++) { @@ -630,7 +608,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++) { esp_rom_printf("cnt%d\n", cnt); diff --git a/components/driver/test/dac_dma_test/test_esp32s2.c b/components/driver/test/dac_dma_test/test_esp32s2.c new file mode 100644 index 0000000000..02fcbbcf47 --- /dev/null +++ b/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> %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) \ No newline at end of file diff --git a/components/driver/test/include/test/test_adc_dac_dma.h b/components/driver/test/include/test/test_adc_dac_dma.h new file mode 100644 index 0000000000..83ad30cc1e --- /dev/null +++ b/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), /*!