dfiver(dac): add dac dma driver and unit test

This commit is contained in:
fuzhibo 2020-04-08 21:56:14 +08:00 committed by bot
parent cf3be75844
commit 0914dfbb6a
24 changed files with 1081 additions and 132 deletions

View File

@ -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()

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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_init();
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();

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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

View File

@ -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);
/**@}*/
/**@}*/

View File

@ -131,6 +131,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. */
@ -260,14 +262,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. */

View File

@ -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)

View File

@ -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

View File

@ -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

View File

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

View File

@ -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)

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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 DAC output data from I2S DMA.
* I2S_CLK connect to DAC_CLK, I2S_DATA_OUT connect to DAC_DATA.
* Enable/disable invert the DAC digital controller clock signal.
*
* @param enable true or false.
*/
static inline void dac_ll_dma_enable(void)
static inline void dac_ll_digi_clk_inv(bool enable)
{
SENS.sar_dac_ctrl1.dac_dig_force = 1;
SENS.sar_dac_ctrl1.dac_clk_inv = 1;
SENS.sar_dac_ctrl1.dac_clk_inv = enable;
}
/**
* Disable DAC output data from I2S DMA.
* Enable/disable DAC-DMA mode for dac digital controller.
*/
static inline void dac_ll_dma_disable(void)
static inline void dac_ll_digi_enable_dma(bool enable)
{
SENS.sar_dac_ctrl1.dac_dig_force = 0;
SENS.sar_dac_ctrl1.dac_clk_inv = 0;
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;
}
}
/**
* Reset FIFO of DAC digital controller.
*/
static inline void dac_ll_digi_fifo_reset(void)
{
APB_SARADC.apb_dac_ctrl.dac_reset_fifo = 1;
APB_SARADC.apb_dac_ctrl.dac_reset_fifo = 0;
}
/**
* Reset DAC digital controller.
*/
static inline void dac_ll_digi_reset(void)
{
APB_SARADC.apb_dac_ctrl.apb_dac_rst = 1;
APB_SARADC.apb_dac_ctrl.apb_dac_rst = 0;
}
#ifdef __cplusplus

View File

@ -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 \
@ -102,12 +101,14 @@ INPUT = \
$(IDF_PATH)/components/driver/include/driver/spi_slave.h \
$(IDF_PATH)/components/driver/include/driver/spi_slave_hd.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/cp_dma.h \

View File

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