mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
dac: driver-ng framework
This commit is contained in:
parent
9777c9d5b1
commit
351a18415c
@ -99,7 +99,14 @@ if(CONFIG_SOC_SPI_SUPPORT_SLAVE_HD_VER2)
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_TOUCH_SENSOR_SUPPORTED)
|
||||
list(APPEND srcs "touch_sensor_common.c" "${target}/touch_sensor.c")
|
||||
list(APPEND srcs "touch_sensor_common.c"
|
||||
"${target}/touch_sensor.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_DAC_SUPPORTED)
|
||||
list(APPEND srcs "dac.c"
|
||||
"deprecated/dac_common_legacy.c")
|
||||
list(APPEND includes "deprecated/${target}")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_SDIO_SLAVE_SUPPORTED)
|
||||
@ -107,14 +114,12 @@ if(CONFIG_SOC_SDIO_SLAVE_SUPPORTED)
|
||||
endif()
|
||||
|
||||
if(${target} STREQUAL "esp32")
|
||||
list(APPEND srcs "dac_common.c"
|
||||
"deprecated/adc_i2s_deprecated.c"
|
||||
"esp32/dac.c")
|
||||
list(APPEND srcs "deprecated/adc_i2s_deprecated.c"
|
||||
"deprecated/esp32/dac_legacy.c")
|
||||
endif()
|
||||
|
||||
if(${target} STREQUAL "esp32s2")
|
||||
list(APPEND srcs "dac_common.c"
|
||||
"esp32s2/dac.c")
|
||||
list(APPEND srcs "deprecated/esp32s2/dac_legacy.c")
|
||||
endif()
|
||||
|
||||
if(BOOTLOADER_BUILD)
|
||||
|
@ -399,4 +399,29 @@ menu "Driver Configurations"
|
||||
Note that, this option only controls the I2S driver log, will not affect other drivers.
|
||||
endmenu # I2S Configuration
|
||||
|
||||
menu "DAC Configuration"
|
||||
depends on SOC_DAC_SUPPORTED
|
||||
config DAC_ISR_IRAM_SAFE
|
||||
bool "DAC ISR IRAM-Safe"
|
||||
default n
|
||||
help
|
||||
Ensure the DAC interrupt is IRAM-Safe by allowing the interrupt handler to be
|
||||
executable when the cache is disabled (e.g. SPI Flash write).
|
||||
|
||||
config DAC_SUPPRESS_DEPRECATE_WARN
|
||||
bool "Suppress legacy driver deprecated warning"
|
||||
default n
|
||||
help
|
||||
Wether to suppress the deprecation warnings when using legacy DAC driver (driver/DAC.h).
|
||||
If you want to continue using the legacy driver, and don't want to see related deprecation warnings,
|
||||
you can enable this option.
|
||||
|
||||
config DAC_ENABLE_DEBUG_LOG
|
||||
bool "Enable debug log"
|
||||
default n
|
||||
help
|
||||
Wether to enable the debug log message for DAC driver.
|
||||
Note that, this option only controls the DAC driver log, won't affect other drivers.
|
||||
endmenu # DAC Configuration
|
||||
|
||||
endmenu # Driver configurations
|
||||
|
643
components/driver/dac.c
Normal file
643
components/driver/dac.c
Normal file
@ -0,0 +1,643 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/lldesc.h"
|
||||
#include "soc/dac_periph.h"
|
||||
#include "hal/dac_types.h"
|
||||
#include "hal/dac_ll.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "driver/dac_new.h"
|
||||
#include "esp_private/dac_dma.h"
|
||||
|
||||
#include "esp_check.h"
|
||||
|
||||
#define DAC_DMA_MAX_BUF_SIZE 4092
|
||||
#if CONFIG_DAC_ISR_IRAM_SAFE
|
||||
#define DAC_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED)
|
||||
#define DAC_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||
#else
|
||||
#define DAC_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED)
|
||||
#define DAC_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
||||
#endif
|
||||
#define DAC_DMA_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
|
||||
|
||||
typedef enum {
|
||||
DAC_STATE_INITIAL, /* Initial state, dac has been registered */
|
||||
DAC_STATE_OUTPUT_READY, /* DAC channels enabled and ready to output constant voltage */
|
||||
DAC_STATE_DMA_READY, /* DMA mode initialized, but not started */
|
||||
DAC_STATE_CW_READY, /* Cosine wave mode is initialized, but not started */
|
||||
DAC_STATE_DMA_RUNNING, /* DAC DMA dma is running, can't switch mode in this stage */
|
||||
DAC_STATE_CW_RUNNING, /* DAC cosine wave generator is running, can't switch mode in this stage */
|
||||
} dac_state_t;
|
||||
|
||||
typedef struct {
|
||||
QueueHandle_t msg_que;
|
||||
#if CONFIG_DAC_ISR_IRAM_SAFE
|
||||
StaticQueue_t *msg_que_struct; /*!< Static message queue struct */
|
||||
void *msg_que_storage; /*!< Static message queue storage */
|
||||
#endif
|
||||
dac_dma_config_t cfg;
|
||||
lldesc_t **desc;
|
||||
} dac_dma_t;
|
||||
|
||||
typedef struct dac_channel_chain_s {
|
||||
dac_channel_t id;
|
||||
struct dac_channel_chain_s *next;
|
||||
} dac_channel_chain_t;
|
||||
|
||||
struct dac_channel_group_s {
|
||||
uint32_t chan_num;
|
||||
dac_state_t state;
|
||||
SemaphoreHandle_t mutex;
|
||||
#if CONFIG_DAC_ISR_IRAM_SAFE
|
||||
StaticSemaphore_t *mutex_struct; /*!< Static mutex struct */
|
||||
#endif
|
||||
#if CONFIG_PM_ENABLE
|
||||
esp_pm_lock_handle_t pm_lock;
|
||||
#endif
|
||||
bool is_enabled;
|
||||
dac_dma_t dma;
|
||||
dac_cosine_config_t sw_cfg;
|
||||
dac_channel_chain_t *head;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
dac_channel_chain_t *chan[SOC_DAC_PERIPH_NUM];
|
||||
} dac_platform_t;
|
||||
|
||||
static const char *TAG = "DAC";
|
||||
|
||||
static dac_platform_t s_dac = {
|
||||
.chan = {
|
||||
[0 ... SOC_DAC_PERIPH_NUM - 1] = NULL
|
||||
},
|
||||
};
|
||||
|
||||
/* Global dac spin lock for the whole DAC driver */
|
||||
portMUX_TYPE dac_spinlock = portMUX_INITIALIZER_UNLOCKED; // TODO: check rtc_spinlock
|
||||
|
||||
#define DAC_NULL_POINTER_CHECK(p) ESP_RETURN_ON_FALSE((p), ESP_ERR_INVALID_ARG, TAG, "input parameter '"#p"' is NULL")
|
||||
|
||||
static void dac_free_dma_desc(dac_channel_group_handle_t handle)
|
||||
{
|
||||
if (handle->dma.desc == NULL) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < handle->dma.cfg.desc_num; i++) {
|
||||
if (handle->dma.desc[i]) {
|
||||
free(handle->dma.desc[i]);
|
||||
handle->dma.desc[i] = NULL;
|
||||
}
|
||||
}
|
||||
free(handle->dma.desc);
|
||||
handle->dma.desc = NULL;
|
||||
}
|
||||
|
||||
static esp_err_t dac_alloc_dma_desc(dac_channel_group_handle_t handle)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
handle->dma.desc = (lldesc_t **) heap_caps_calloc(handle->dma.cfg.desc_num, sizeof(lldesc_t *), DAC_MEM_ALLOC_CAPS);
|
||||
ESP_RETURN_ON_FALSE(handle->dma.desc, ESP_ERR_NO_MEM, TAG, "Faild to allocate dma descriptor buffer");
|
||||
for (int cnt = 0; cnt < handle->dma.cfg.desc_num; cnt++) {
|
||||
/* Allocate DMA descpriptor */
|
||||
handle->dma.desc[cnt] = (lldesc_t *) heap_caps_calloc(1, sizeof(lldesc_t), DAC_DMA_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(handle->dma.desc[cnt], ESP_ERR_NO_MEM, err, TAG, "failed to allocate dma descriptor");
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
err:
|
||||
/* Free DMA buffer if failed to allocate memory */
|
||||
dac_free_dma_desc(handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void IRAM_ATTR dac_default_intr_handler(void *arg)
|
||||
{
|
||||
dac_channel_group_handle_t handle = (dac_channel_group_handle_t)arg;
|
||||
uint32_t dummy;
|
||||
BaseType_t need_awoke = pdFALSE;
|
||||
BaseType_t tmp;
|
||||
if (dac_dma_periph_intr_is_triggered()) {
|
||||
lldesc_t *fdesc = (lldesc_t *)dac_dma_periph_intr_get_eof_desc();
|
||||
if (xQueueIsQueueFullFromISR(handle->dma.msg_que) == pdTRUE) {
|
||||
xQueueReceiveFromISR(handle->dma.msg_que, &dummy, &tmp);
|
||||
need_awoke |= tmp;
|
||||
}
|
||||
xQueueSendFromISR(handle->dma.msg_que, fdesc, &tmp);
|
||||
need_awoke |= tmp;
|
||||
}
|
||||
if (need_awoke == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
static void dac_free_channel_chain(dac_channel_chain_t *head)
|
||||
{
|
||||
if (head->next) {
|
||||
dac_free_channel_chain(head->next);
|
||||
}
|
||||
s_dac.chan[head->id - 1] = NULL;
|
||||
free(head);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
DAC common APIs
|
||||
---------------------------------------------------------------------------*/
|
||||
esp_err_t dac_new_channel_group(const dac_group_config_t *dac_cfg, dac_channel_group_handle_t *handle)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
DAC_NULL_POINTER_CHECK(dac_cfg);
|
||||
DAC_NULL_POINTER_CHECK(handle);
|
||||
|
||||
ESP_RETURN_ON_FALSE((uint32_t)dac_cfg->chan_sel > 0, ESP_ERR_INVALID_ARG, TAG, "invalid DAC channel");
|
||||
ESP_RETURN_ON_FALSE((32 - __builtin_clz((uint32_t)dac_cfg->chan_sel)) <= SOC_DAC_PERIPH_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid DAC channel");
|
||||
|
||||
dac_channel_group_handle_t group = (dac_channel_group_handle_t)calloc(1, sizeof(struct dac_channel_group_s));
|
||||
ESP_RETURN_ON_FALSE(group, ESP_ERR_NO_MEM, TAG, "No memory for DAC channel group");
|
||||
group->chan_num = 0;
|
||||
group->is_enabled = false;
|
||||
group->state = DAC_STATE_INITIAL; // Set static output as default
|
||||
#if CONFIG_DAC_ISR_IRAM_SAFE
|
||||
group->mutex_struct = (StaticSemaphore_t *)heap_caps_calloc(1, sizeof(StaticSemaphore_t), DAC_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(group->mutex_struct, ESP_ERR_NO_MEM, err, TAG, "No memory for group mutex struct");
|
||||
group->mutex = xSemaphoreCreateMutexStatic(group->mutex_struct);
|
||||
#else
|
||||
group->mutex = xSemaphoreCreateMutex();
|
||||
#endif
|
||||
ESP_GOTO_ON_FALSE(group->mutex, ESP_ERR_NO_MEM, err, TAG, "No memory for group mutex");
|
||||
#if CONFIG_PM_ENABLE
|
||||
ESP_GOTO_ON_ERROR(esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "dac_driver", &group->pm_lock), err, TAG, "Failed to create DAC pm lock");
|
||||
#endif
|
||||
/* Register selected channels and link into a chain*/
|
||||
dac_channel_chain_t *temp = NULL;
|
||||
for (uint32_t msk = (uint32_t)dac_cfg->chan_sel, i = 0; msk != 0; msk >>= 1, i++) {
|
||||
if (msk & 0x01) {
|
||||
/* Allocate memory for the channel when it is enabled */
|
||||
ESP_GOTO_ON_FALSE(!s_dac.chan[i], ESP_ERR_INVALID_STATE, err, TAG, "DAC channel %d has been registered already", i + 1);
|
||||
dac_channel_chain_t *node = (dac_channel_chain_t *)calloc(1, sizeof(dac_channel_chain_t));
|
||||
ESP_GOTO_ON_FALSE(node, ESP_ERR_NO_MEM, err, TAG, "No memory for DAC channel object");
|
||||
node->id = i;
|
||||
s_dac.chan[i] = node;
|
||||
group->chan_num++;
|
||||
/* Link the channel into a chain */
|
||||
if (!temp) {
|
||||
temp = node;
|
||||
group->head = node;
|
||||
} else {
|
||||
temp->next = node;
|
||||
temp = temp->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*handle = group;
|
||||
|
||||
return ret;
|
||||
|
||||
err:
|
||||
/* Free the resource when error occurs */
|
||||
dac_del_channel_group(group);
|
||||
group = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t dac_del_channel_group(dac_channel_group_handle_t handle)
|
||||
{
|
||||
DAC_NULL_POINTER_CHECK(handle);
|
||||
ESP_RETURN_ON_FALSE(handle->state == DAC_STATE_INITIAL, ESP_ERR_INVALID_STATE, TAG, "This DAC group is not deinitialized");
|
||||
ESP_RETURN_ON_FALSE(!handle->is_enabled, ESP_ERR_INVALID_STATE, TAG, "This DAC group is not disabled");
|
||||
|
||||
if (handle->mutex) {
|
||||
vSemaphoreDelete(handle->mutex);
|
||||
}
|
||||
#if CONFIG_DAC_ISR_IRAM_SAFE
|
||||
if (handle->mutex_struct) {
|
||||
free(handle_mutex_struct);
|
||||
}
|
||||
#endif
|
||||
#if CONFIG_PM_ENABLE
|
||||
if (handle->pm_lock) {
|
||||
esp_pm_lock_delete(handle->pm_lock);
|
||||
handle->pm_lock = NULL;
|
||||
}
|
||||
#endif
|
||||
if (handle->head) {
|
||||
dac_free_channel_chain(handle->head);
|
||||
}
|
||||
free(handle);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t dac_channel_group_enable(dac_channel_group_handle_t handle)
|
||||
{
|
||||
DAC_NULL_POINTER_CHECK(handle);
|
||||
ESP_RETURN_ON_FALSE(!handle->is_enabled, ESP_ERR_INVALID_STATE, TAG, "This DAC group has been enabled already");
|
||||
|
||||
xSemaphoreTake(handle->mutex, portMAX_DELAY);
|
||||
|
||||
for (dac_channel_chain_t *p = handle->head; p != NULL; p = p->next) {
|
||||
gpio_num_t gpio_num = (gpio_num_t)dac_periph_signal.dac_channel_io_num[p->id];
|
||||
rtc_gpio_init(gpio_num);
|
||||
rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED);
|
||||
rtc_gpio_pullup_dis(gpio_num);
|
||||
rtc_gpio_pulldown_dis(gpio_num);
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
dac_ll_power_on(p->id);
|
||||
dac_ll_rtc_sync_by_adc(false);
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
}
|
||||
handle->is_enabled = true;
|
||||
/* If the group has not been intialized to other mode, set it `DAC_STATE_OUTPUT_READY` as default */
|
||||
if (handle->state == DAC_STATE_INITIAL) {
|
||||
handle->state = DAC_STATE_OUTPUT_READY;
|
||||
}
|
||||
xSemaphoreGive(handle->mutex);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t dac_channel_group_disable(dac_channel_group_handle_t handle)
|
||||
{
|
||||
DAC_NULL_POINTER_CHECK(handle);
|
||||
ESP_RETURN_ON_FALSE(handle->is_enabled, ESP_ERR_INVALID_STATE, TAG, "This DAC group has not been enabled yet");
|
||||
ESP_RETURN_ON_FALSE(handle->state < DAC_STATE_DMA_RUNNING, ESP_ERR_INVALID_STATE, TAG, "This DAC group is still running");
|
||||
|
||||
xSemaphoreTake(handle->mutex, portMAX_DELAY);
|
||||
for (dac_channel_chain_t *p = handle->head; p != NULL; p = p->next) {
|
||||
gpio_num_t gpio_num = (gpio_num_t)dac_periph_signal.dac_channel_io_num[p->id];
|
||||
rtc_gpio_deinit(gpio_num);
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
dac_ll_power_down(p->id);
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
}
|
||||
handle->is_enabled = false;
|
||||
/* If the group has not been intialized to other mode, set it `DAC_STATE_INITIAL` as default */
|
||||
if (handle->state == DAC_STATE_OUTPUT_READY) {
|
||||
handle->state = DAC_STATE_INITIAL;
|
||||
}
|
||||
xSemaphoreGive(handle->mutex);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
DAC constant voltage outputting APIs
|
||||
---------------------------------------------------------------------------*/
|
||||
esp_err_t dac_channel_group_output_constant_voltage(dac_channel_group_handle_t handle, uint8_t value)
|
||||
{
|
||||
DAC_NULL_POINTER_CHECK(handle);
|
||||
ESP_RETURN_ON_FALSE(handle->is_enabled, ESP_ERR_INVALID_STATE, TAG, "This DAC group has not been enabled");
|
||||
ESP_RETURN_ON_FALSE(handle->state == DAC_STATE_OUTPUT_READY, ESP_ERR_INVALID_STATE, TAG, "This DAC group has been configured to other mode");
|
||||
|
||||
xSemaphoreTake(handle->mutex, portMAX_DELAY);
|
||||
/* Set the constant voltage for each channel in the group */
|
||||
for (dac_channel_chain_t *p = handle->head; p != NULL; p = p->next) {
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
dac_ll_update_output_value(p->id, value);
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
}
|
||||
xSemaphoreGive(handle->mutex);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
DAC DMA outputting APIs
|
||||
---------------------------------------------------------------------------*/
|
||||
esp_err_t dac_channel_group_init_dma_output(dac_channel_group_handle_t handle, const dac_dma_config_t *dma_cfg)
|
||||
{
|
||||
DAC_NULL_POINTER_CHECK(handle);
|
||||
ESP_RETURN_ON_FALSE(handle->state < DAC_STATE_DMA_READY, ESP_ERR_INVALID_STATE, TAG, "This DAC group has been initialized already");
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
xSemaphoreTake(handle->mutex, portMAX_DELAY);
|
||||
|
||||
#if CONFIG_DAC_ISR_IRAM_SAFE
|
||||
handle->dma.msg_que_storage = (uint8_t *)heap_caps_calloc(desc_num - 1, sizeof(lldesc_t *), I2S_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(handle->dma.msg_que_storage, ESP_ERR_NO_MEM, err, TAG, "No memory for message queue storage");
|
||||
handle->dma.msg_que_struct = (StaticQueue_t *)heap_caps_calloc(1, sizeof(StaticQueue_t), I2S_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(handle->dma.msg_que_storage, ESP_ERR_NO_MEM, err, TAG, "No memory for message queue struct");
|
||||
handle->dma.msg_queue = xQueueCreateStatic(desc_num - 1, sizeof(lldesc_t *), handle->dma.msg_que_storage, handle->dma.msg_que_struct);
|
||||
#else
|
||||
handle->dma.msg_que = xQueueCreate(dma_cfg->desc_num - 1, sizeof(lldesc_t *));
|
||||
#endif
|
||||
ESP_GOTO_ON_FALSE(handle->dma.msg_que, ESP_ERR_NO_MEM, err3, TAG, "No memory for message queue");
|
||||
/* Allocate DMA buffer */
|
||||
memcpy(&(handle->dma.cfg), dma_cfg, sizeof(dac_dma_config_t));
|
||||
ESP_GOTO_ON_ERROR(dac_alloc_dma_desc(handle), err2, TAG, "Failed to allocate memory for DMA buffers");
|
||||
|
||||
/* Initialize DAC DMA peripheral */
|
||||
ESP_GOTO_ON_ERROR(dac_dma_periph_init(handle->chan_num, dma_cfg->freq_hz, dma_cfg->chan_mode == DAC_CHANNEL_ALTERNATE), err2, TAG, "Failed to initialize DAC DMA peripheral");
|
||||
/* Register DMA interrupt */
|
||||
ESP_GOTO_ON_ERROR(dac_dma_periph_register_intr(dac_default_intr_handler, handle), err1, TAG, "Failed to register DMA interrupt");
|
||||
/* Connect DAC module to the DMA peripheral */
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
dac_ll_digi_enable_dma(true);
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
|
||||
handle->state = DAC_STATE_DMA_READY;
|
||||
|
||||
xSemaphoreGive(handle->mutex);
|
||||
|
||||
return ret;
|
||||
err1:
|
||||
dac_dma_periph_deinit();
|
||||
err2:
|
||||
dac_free_dma_desc(handle);
|
||||
err3:
|
||||
if (handle->dma.msg_que) {
|
||||
vQueueDelete(handle->dma.msg_que);
|
||||
}
|
||||
#if CONFIG_DAC_ISR_IRAM_SAFE
|
||||
if (handle->dma.msq_que_struct) {
|
||||
free(handle->dma.msq_que_struct);
|
||||
}
|
||||
if (handle->dma.msq_que_storage) {
|
||||
free(handle->dma.msq_que_storage);
|
||||
}
|
||||
#endif
|
||||
xSemaphoreGive(handle->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t dac_channel_group_deinit_dma_output(dac_channel_group_handle_t handle)
|
||||
{
|
||||
DAC_NULL_POINTER_CHECK(handle);
|
||||
ESP_RETURN_ON_FALSE(handle->state == DAC_STATE_DMA_READY, ESP_ERR_INVALID_STATE, TAG,
|
||||
"This DAC group is still running or has been configured to other mode");
|
||||
|
||||
xSemaphoreTake(handle->mutex, portMAX_DELAY);
|
||||
|
||||
/* Free DMA buffer */
|
||||
dac_free_dma_desc(handle);
|
||||
|
||||
/* Deregister DMA interrupt */
|
||||
ESP_RETURN_ON_ERROR(dac_dma_periph_deregister_intr(), TAG, "Failed to deregister DMA interrupt");
|
||||
/* Deinitialize DMA peripheral */
|
||||
ESP_RETURN_ON_ERROR(dac_dma_periph_deinit(), TAG, "Failed to deinitialize DAC DMA peripheral");
|
||||
/* Disconnect DAC module to the DMA peripheral */
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
dac_ll_digi_enable_dma(false);
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
|
||||
if (handle->is_enabled) {
|
||||
handle->state = DAC_STATE_OUTPUT_READY;
|
||||
} else {
|
||||
handle->state = DAC_STATE_INITIAL;
|
||||
}
|
||||
xSemaphoreGive(handle->mutex);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t dac_channel_group_start_dma_output(dac_channel_group_handle_t handle)
|
||||
{
|
||||
DAC_NULL_POINTER_CHECK(handle);
|
||||
ESP_RETURN_ON_FALSE(handle->is_enabled, ESP_ERR_INVALID_STATE, TAG, "This DAC group has not been enabled");
|
||||
ESP_RETURN_ON_FALSE(handle->state == DAC_STATE_DMA_READY, ESP_ERR_INVALID_STATE, TAG,
|
||||
"This DAC group has started already or not working at DMA mode");
|
||||
|
||||
xSemaphoreTake(handle->mutex, portMAX_DELAY);
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_acquire(handle->pm_lock);
|
||||
#endif
|
||||
dac_dma_periph_enable();
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
dac_ll_digi_enable_dma(true);
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
handle->state = DAC_STATE_DMA_RUNNING;
|
||||
xSemaphoreGive(handle->mutex);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t dac_channel_group_stop_dma_output(dac_channel_group_handle_t handle)
|
||||
{
|
||||
DAC_NULL_POINTER_CHECK(handle);
|
||||
ESP_RETURN_ON_FALSE(handle->is_enabled, ESP_ERR_INVALID_STATE, TAG, "This DAC group has not been enabled");
|
||||
ESP_RETURN_ON_FALSE(handle->state == DAC_STATE_DMA_RUNNING, ESP_ERR_INVALID_STATE, TAG,
|
||||
"This DAC group has stopped already or not working at DMA mode");
|
||||
|
||||
xSemaphoreTake(handle->mutex, portMAX_DELAY);
|
||||
dac_dma_periph_disable();
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
dac_ll_digi_enable_dma(false);
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_release(handle->pm_lock);
|
||||
#endif
|
||||
handle->state = DAC_STATE_DMA_READY;
|
||||
xSemaphoreGive(handle->mutex);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static uint32_t dac_load_dma_data(lldesc_t *desc, uint8_t *data, uint32_t size)
|
||||
{
|
||||
uint32_t byte_to_load = size > DAC_DMA_MAX_BUF_SIZE ? DAC_DMA_MAX_BUF_SIZE : size;
|
||||
desc->owner = 1;
|
||||
desc->eof = 1;
|
||||
desc->sosf = 0;
|
||||
desc->length = byte_to_load;
|
||||
desc->size = byte_to_load;
|
||||
desc->buf = data;
|
||||
desc->offset = 0;
|
||||
return byte_to_load;
|
||||
}
|
||||
// TODO: wait until all data sent or all data loaded? If all data loaded, need to monitor end of frame
|
||||
esp_err_t dac_channel_group_write_acyclicly(dac_channel_group_handle_t handle, uint8_t *buf, size_t buf_size, uint32_t timeout_ms)
|
||||
{
|
||||
DAC_NULL_POINTER_CHECK(handle);
|
||||
DAC_NULL_POINTER_CHECK(buf);
|
||||
ESP_RETURN_ON_FALSE(handle->is_enabled, ESP_ERR_INVALID_STATE, TAG, "This DAC group has not been enabled");
|
||||
ESP_RETURN_ON_FALSE(handle->state == DAC_STATE_DMA_RUNNING, ESP_ERR_INVALID_STATE, TAG, "This DAC group is not started");
|
||||
#if CONFIG_DAC_ISR_IRAM_SAFE
|
||||
ESP_RETURN_ON_ERROR(esp_ptr_internal(buf), ESP_ERR_INVALID_ARG, err, TAG, "the buffer is not in internal RAM");
|
||||
#endif
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_RETURN_ON_FALSE(xSemaphoreTake(handle->mutex, pdMS_TO_TICKS(timeout_ms) == pdTRUE), ESP_ERR_TIMEOUT, TAG, "Take semaphore timeout");
|
||||
/* Reset the queue to drop the legacy descriptors */
|
||||
xQueueReset(handle->dma.msg_que);
|
||||
/* Break the legacy descriptor chain for the new data */
|
||||
for (int i=0; i < handle->dma.cfg.desc_num; i++) {
|
||||
handle->dma.desc[i]->empty = 0;
|
||||
}
|
||||
/* Pre-load data to DMA */
|
||||
size_t index = 0;
|
||||
uint32_t pending_desc_cnt = 0;
|
||||
for (int i = 0; i < handle->dma.cfg.desc_num && index < buf_size; i++, pending_desc_cnt++) {
|
||||
index += dac_load_dma_data(handle->dma.desc[i], &buf[index], buf_size - index);
|
||||
/* Link to the previous descriptor */
|
||||
if (i > 0) {
|
||||
handle->dma.desc[i-1]->empty = (uint32_t)handle->dma.desc[i];
|
||||
}
|
||||
}
|
||||
/* Link the start and end desc as a ring if the buffer not loaded conmpletely */
|
||||
handle->dma.desc[pending_desc_cnt-1]->empty = index < buf_size ? (uint32_t)handle->dma.desc[0] : 0;
|
||||
dac_dma_periph_dma_trans_start((uint32_t)handle->dma.desc[0]);
|
||||
/* Wait until all data be sent */
|
||||
for (lldesc_t *finish_desc = NULL; pending_desc_cnt > 0; pending_desc_cnt--) {
|
||||
ESP_GOTO_ON_FALSE(xQueueReceive(handle->dma.msg_que, &finish_desc, pdMS_TO_TICKS(timeout_ms)) == pdTRUE,
|
||||
ESP_ERR_TIMEOUT, err, TAG, "Receive message queue timeout");
|
||||
/* Load those unsent data */
|
||||
if (index < buf_size) {
|
||||
index += dac_load_dma_data(finish_desc, &buf[index], buf_size - index);
|
||||
pending_desc_cnt++;
|
||||
/* If all date loaded, break the ring desc */
|
||||
if (index >= buf_size) {
|
||||
finish_desc->empty = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
err:
|
||||
xSemaphoreGive(handle->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t dac_channel_group_write_cyclicly(dac_channel_group_handle_t handle, uint8_t *buf, size_t buf_size, uint32_t timeout_ms)
|
||||
{
|
||||
DAC_NULL_POINTER_CHECK(handle);
|
||||
ESP_RETURN_ON_FALSE(handle->is_enabled, ESP_ERR_INVALID_STATE, TAG, "This DAC group has not been enabled");
|
||||
ESP_RETURN_ON_FALSE(handle->state == DAC_STATE_DMA_RUNNING, ESP_ERR_INVALID_STATE, TAG, "This DAC group is not started");
|
||||
ESP_RETURN_ON_FALSE(buf_size < (DAC_DMA_MAX_BUF_SIZE * handle->dma.cfg.desc_num),
|
||||
ESP_ERR_INVALID_ARG, TAG, "The cyclic buffer size exceeds the total DMA buffer size: desc_num * %d = %d",
|
||||
DAC_DMA_MAX_BUF_SIZE, DAC_DMA_MAX_BUF_SIZE * handle->dma.cfg.desc_num);
|
||||
#if CONFIG_DAC_ISR_IRAM_SAFE
|
||||
ESP_RETURN_ON_ERROR(esp_ptr_internal(buf), ESP_ERR_INVALID_ARG, err, TAG, "the buffer is not in internal RAM");
|
||||
#endif
|
||||
ESP_RETURN_ON_FALSE(xSemaphoreTake(handle->mutex, pdMS_TO_TICKS(timeout_ms) == pdTRUE), ESP_ERR_TIMEOUT, TAG, "Take semaphore timeout");
|
||||
/* If the buffer size is small, split it into two descriptors */
|
||||
if (buf_size > DAC_DMA_MAX_BUF_SIZE) {
|
||||
size_t index = 0;
|
||||
int i = 0;
|
||||
for (i = 0; (i < handle->dma.cfg.desc_num) && (index < buf_size); i++) {
|
||||
index += dac_load_dma_data(handle->dma.desc[i], &buf[index], buf_size - index);
|
||||
/* Link to the previous descriptor */
|
||||
if (i > 0) {
|
||||
handle->dma.desc[i-1]->empty = (uint32_t)handle->dma.desc[i];
|
||||
}
|
||||
}
|
||||
/* Link as a loop */
|
||||
handle->dma.desc[i-1]->empty = (uint32_t)handle->dma.desc[0];
|
||||
}
|
||||
/* If the buffer size is small, split it into two descriptors */
|
||||
else {
|
||||
uint32_t half = buf_size / 2;
|
||||
dac_load_dma_data(handle->dma.desc[0], buf, half);
|
||||
dac_load_dma_data(handle->dma.desc[1], &buf[half], buf_size - half);
|
||||
handle->dma.desc[0]->empty = (uint32_t)handle->dma.desc[1];
|
||||
handle->dma.desc[1]->empty = (uint32_t)handle->dma.desc[0];
|
||||
}
|
||||
dac_dma_periph_dma_trans_start((uint32_t)handle->dma.desc[0]);
|
||||
xSemaphoreGive(handle->mutex);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
DAC cosine wave outputting APIs
|
||||
---------------------------------------------------------------------------*/
|
||||
esp_err_t dac_channel_group_init_cosine_output(dac_channel_group_handle_t handle, const dac_cosine_config_t *cw_cfg)
|
||||
{
|
||||
DAC_NULL_POINTER_CHECK(handle);
|
||||
DAC_NULL_POINTER_CHECK(cw_cfg);
|
||||
ESP_RETURN_ON_FALSE((handle->state == DAC_STATE_INITIAL) | (handle->state == DAC_STATE_OUTPUT_READY),
|
||||
ESP_ERR_INVALID_STATE, TAG, "This DAC group has been initialized already");
|
||||
ESP_RETURN_ON_FALSE(cw_cfg->freq_hz >= 130, ESP_ERR_NOT_SUPPORTED, TAG, "The cosine wave generator doesn't support frequency below 130 Hz");
|
||||
ESP_RETURN_ON_FALSE(cw_cfg->freq_hz <= 55000, ESP_ERR_NOT_SUPPORTED, TAG, "The cosine wave generator doesn't support frequency beyond 55000 Hz");
|
||||
|
||||
xSemaphoreTake(handle->mutex, portMAX_DELAY);
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
for (dac_channel_chain_t *p = handle->head; p != NULL; p = p->next) {
|
||||
/* Connect DAC module to cosine wave generator */
|
||||
dac_ll_cw_set_channel(p->id, true);
|
||||
/* Set coefficients for cosine wave generator */
|
||||
dac_ll_cw_set_freq(cw_cfg->freq_hz);
|
||||
dac_ll_cw_set_scale(p->id, cw_cfg->scale);
|
||||
dac_ll_cw_set_phase(p->id, cw_cfg->phase);
|
||||
dac_ll_cw_set_dc_offset(p->id, cw_cfg->offset);
|
||||
}
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
handle->state = DAC_STATE_CW_READY;
|
||||
xSemaphoreGive(handle->mutex);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t dac_channel_group_deinit_cosine_output(dac_channel_group_handle_t handle)
|
||||
{
|
||||
DAC_NULL_POINTER_CHECK(handle);
|
||||
ESP_RETURN_ON_FALSE(handle->state == DAC_STATE_CW_READY, ESP_ERR_INVALID_STATE, TAG,
|
||||
"This DAC group is still running or not working at cosine wave mode");
|
||||
|
||||
xSemaphoreTake(handle->mutex, portMAX_DELAY);
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
for (dac_channel_chain_t *p = handle->head; p != NULL; p = p->next) {
|
||||
/* Disonnect DAC module to cosine wave generator */
|
||||
dac_ll_cw_set_channel(p->id, false);
|
||||
}
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
if (handle->is_enabled) {
|
||||
handle->state = DAC_STATE_OUTPUT_READY;
|
||||
} else {
|
||||
handle->state = DAC_STATE_INITIAL;
|
||||
}
|
||||
xSemaphoreGive(handle->mutex);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t dac_channel_group_start_cosine_output(dac_channel_group_handle_t handle)
|
||||
{
|
||||
DAC_NULL_POINTER_CHECK(handle);
|
||||
ESP_RETURN_ON_FALSE(handle->is_enabled, ESP_ERR_INVALID_STATE, TAG, "This DAC group has not been enabled");
|
||||
ESP_RETURN_ON_FALSE(handle->state == DAC_STATE_CW_READY, ESP_ERR_INVALID_STATE, TAG,
|
||||
"This DAC group has started already or not working at cosine wave mode");
|
||||
|
||||
xSemaphoreTake(handle->mutex, portMAX_DELAY);
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_acquire(handle->pm_lock);
|
||||
#endif
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
dac_ll_cw_generator_enable();
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
handle->state = DAC_STATE_CW_RUNNING;
|
||||
xSemaphoreGive(handle->mutex);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t dac_channel_group_stop_cosine_output(dac_channel_group_handle_t handle)
|
||||
{
|
||||
DAC_NULL_POINTER_CHECK(handle);
|
||||
ESP_RETURN_ON_FALSE(handle->is_enabled, ESP_ERR_INVALID_STATE, TAG, "This DAC group has not been enabled");
|
||||
ESP_RETURN_ON_FALSE(handle->state == DAC_STATE_CW_RUNNING, ESP_ERR_INVALID_STATE, TAG,
|
||||
"This DAC group has stopped already or not working at cosine wave mode");
|
||||
|
||||
xSemaphoreTake(handle->mutex, portMAX_DELAY);
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
dac_ll_cw_generator_disable();
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_release(handle->pm_lock);
|
||||
#endif
|
||||
handle->state = DAC_STATE_CW_READY;
|
||||
xSemaphoreGive(handle->mutex);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
#include "driver/dac.h"
|
||||
#include "soc/dac_periph.h"
|
||||
#include "hal/dac_hal.h"
|
||||
#include "hal/dac_types.h"
|
||||
|
||||
extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished.
|
||||
|
||||
@ -116,7 +117,11 @@ esp_err_t dac_cw_generator_config(dac_cw_config_t *cw)
|
||||
ESP_RETURN_ON_FALSE(cw, ESP_ERR_INVALID_ARG, TAG, "invalid clock configuration");
|
||||
|
||||
portENTER_CRITICAL(&rtc_spinlock);
|
||||
dac_hal_cw_generator_config(cw);
|
||||
dac_ll_cw_set_freq(cw->freq);
|
||||
dac_ll_cw_set_scale(cw->en_ch, cw->scale);
|
||||
dac_ll_cw_set_phase(cw->en_ch, cw->phase);
|
||||
dac_ll_cw_set_dc_offset(cw->en_ch, cw->offset);
|
||||
dac_ll_cw_set_channel(cw->en_ch, true);
|
||||
portEXIT_CRITICAL(&rtc_spinlock);
|
||||
|
||||
return ESP_OK;
|
@ -13,7 +13,7 @@ extern "C" {
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "hal/dac_types.h"
|
||||
#include "driver/dac_types_legacy.h"
|
||||
|
||||
/**
|
||||
* @brief Get the GPIO number of a specific DAC channel.
|
30
components/driver/deprecated/driver/dac_types_legacy.h
Normal file
30
components/driver/deprecated/driver/dac_types_legacy.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "driver/dac_types.h"
|
||||
#include "hal/dac_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Config the cosine wave generator function in DAC module.
|
||||
*/
|
||||
typedef struct {
|
||||
dac_channel_t en_ch; /*!< Enable the cosine wave generator of DAC channel. */
|
||||
dac_cw_scale_t scale; /*!< Set the amplitude of the cosine wave generator output. */
|
||||
dac_cw_phase_t phase; /*!< Set the phase of the cosine wave generator output. */
|
||||
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;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
132
components/driver/deprecated/esp32s2/dac_legacy.c
Normal file
132
components/driver/deprecated/esp32s2/dac_legacy.c
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.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 __attribute__((unused)) const char *TAG = "DAC";
|
||||
|
||||
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)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(cfg->mode <= DAC_CONV_ALTER, ESP_ERR_INVALID_ARG, TAG, "DAC mode error");
|
||||
ESP_RETURN_ON_FALSE(cfg->interval > 0 && cfg->interval < 4096, ESP_ERR_INVALID_ARG, TAG, "DAC interval error");
|
||||
ESP_RETURN_ON_FALSE(cfg->dig_clk.div_num < 256, ESP_ERR_INVALID_ARG, TAG, "DAC clk div_num error");
|
||||
ESP_RETURN_ON_FALSE(cfg->dig_clk.div_b > 0 && cfg->dig_clk.div_b < 64, ESP_ERR_INVALID_ARG, TAG, "DAC clk div_b error");
|
||||
ESP_RETURN_ON_FALSE(cfg->dig_clk.div_a < 64, ESP_ERR_INVALID_ARG, TAG, "DAC clk div_a error");
|
||||
#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(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
|
||||
ESP_RETURN_ON_FALSE(s_dac_digi_lock, ESP_FAIL, TAG, "Should start after call `dac_digi_controller_config`");
|
||||
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;
|
||||
}
|
73
components/driver/deprecated/esp32s2/driver/dac.h
Normal file
73
components/driver/deprecated/esp32s2/driver/dac.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#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
|
187
components/driver/esp32/dac_dma.c
Normal file
187
components/driver/esp32/dac_dma.c
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
|
||||
|
||||
#include "hal/i2s_ll.h"
|
||||
#include "hal/i2s_types.h"
|
||||
#include "soc/i2s_periph.h"
|
||||
#include "esp_private/dac_dma.h"
|
||||
#include "esp_private/i2s_platform.h"
|
||||
|
||||
#include "esp_check.h"
|
||||
|
||||
#define DAC_DMA_PERIPH_I2S_NUM 0
|
||||
#define DAC_DMA_PERIPH_I2S_BIT_WIDTH 8
|
||||
|
||||
typedef struct {
|
||||
void *periph_dev; /* DMA peripheral device address */
|
||||
intr_handle_t intr_handle; /* Interrupt handle */
|
||||
} dac_dma_periph_i2s_t;
|
||||
|
||||
static dac_dma_periph_i2s_t *s_ddp = NULL; // Static DAC DMA peripheral structure pointer
|
||||
|
||||
static const char *TAG = "DAC_DMA";
|
||||
|
||||
extern portMUX_TYPE dac_spinlock; /* Global DAC spinlock */
|
||||
|
||||
static esp_err_t dac_dma_periph_set_clock(uint32_t freq_hz){
|
||||
/* Calculate clock coefficients */
|
||||
uint32_t bclk = freq_hz * I2S_LL_AD_BCK_FACTOR;
|
||||
uint32_t bclk_div = DAC_DMA_PERIPH_I2S_BIT_WIDTH;
|
||||
uint32_t mclk = bclk * bclk_div;
|
||||
uint32_t sclk = I2S_LL_BASE_CLK; // use PLL clock as default
|
||||
uint32_t mclk_div = sclk / mclk;
|
||||
|
||||
/* Check if the configuration is correct */
|
||||
// TODO: expand the frequency range
|
||||
ESP_RETURN_ON_FALSE(sclk / (float)mclk > 1.99, ESP_ERR_INVALID_ARG, TAG, "Frequency is too large, the mclk division is below minimum value 2");
|
||||
ESP_RETURN_ON_FALSE(mclk_div < 256, ESP_ERR_INVALID_ARG, TAG, "Frequency is too small, the mclk division exceed the maximum value 255");
|
||||
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
i2s_ll_tx_clk_set_src(s_ddp->periph_dev, I2S_CLK_D2CLK);
|
||||
i2s_ll_tx_set_mclk(s_ddp->periph_dev, sclk, mclk, mclk_div);
|
||||
i2s_ll_tx_set_bck_div_num(s_ddp->periph_dev, bclk_div);
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t dac_dma_periph_init(int chan_num, uint32_t freq_hz, bool is_alternate)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
/* Acquire DMA peripheral */
|
||||
ESP_RETURN_ON_ERROR(i2s_priv_register_object("dac_dma", DAC_DMA_PERIPH_I2S_NUM), TAG, "Failed to acquire DAC DMA peripheral");
|
||||
/* Allocate DAC DMA peripheral object */
|
||||
s_ddp = (dac_dma_periph_i2s_t *)calloc(1, sizeof(dac_dma_periph_i2s_t));
|
||||
ESP_GOTO_ON_FALSE(s_ddp, ESP_ERR_NO_MEM, err, TAG, "No memory for DAC DMA object");
|
||||
s_ddp->periph_dev = (void *)I2S_LL_GET_HW(DAC_DMA_PERIPH_I2S_NUM);
|
||||
|
||||
ESP_GOTO_ON_ERROR(dac_dma_periph_set_clock(freq_hz), err, TAG, "Failed to set clock of DMA peripheral");
|
||||
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
i2s_ll_tx_reset(s_ddp->periph_dev);
|
||||
i2s_ll_tx_set_slave_mod(s_ddp->periph_dev, false);
|
||||
i2s_ll_tx_set_sample_bit(s_ddp->periph_dev, DAC_DMA_PERIPH_I2S_BIT_WIDTH, DAC_DMA_PERIPH_I2S_BIT_WIDTH);
|
||||
i2s_ll_tx_enable_mono_mode(s_ddp->periph_dev, !is_alternate);
|
||||
i2s_ll_tx_enable_msb_shift(s_ddp->periph_dev, false);
|
||||
i2s_ll_tx_set_ws_width(s_ddp->periph_dev, DAC_DMA_PERIPH_I2S_BIT_WIDTH);
|
||||
i2s_ll_tx_enable_msb_right(s_ddp->periph_dev, false);
|
||||
i2s_ll_tx_enable_right_first(s_ddp->periph_dev, true);
|
||||
/* Should always enable fifo */
|
||||
i2s_ll_tx_force_enable_fifo_mod(s_ddp->periph_dev, true);
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
|
||||
return ret;
|
||||
err:
|
||||
dac_dma_periph_deinit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t dac_dma_periph_deinit(void)
|
||||
{
|
||||
ESP_RETURN_ON_ERROR(i2s_priv_deregister_object(DAC_DMA_PERIPH_I2S_NUM), TAG, "Failed to release DAC DMA peripheral");
|
||||
if (s_ddp) {
|
||||
if (s_ddp->intr_handle) {
|
||||
dac_dma_periph_deregister_intr();
|
||||
}
|
||||
free(s_ddp);
|
||||
s_ddp = NULL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t dac_dma_periph_register_intr(intr_handler_t intr_handler_func, void *user_ctx)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(s_ddp, ESP_ERR_INVALID_STATE, TAG, "DAC DMA peripheral has not initialized yet");
|
||||
/* Regigster interrupt */
|
||||
ESP_RETURN_ON_ERROR(esp_intr_alloc(i2s_periph_signal[DAC_DMA_PERIPH_I2S_NUM].irq, ESP_INTR_FLAG_LEVEL1,
|
||||
intr_handler_func, user_ctx, &(s_ddp->intr_handle)),
|
||||
TAG, "Failed to register DAC DMA interrupt");
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
i2s_ll_enable_intr(s_ddp->periph_dev, I2S_LL_EVENT_TX_EOF, true);
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t dac_dma_periph_deregister_intr(void)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(s_ddp, ESP_ERR_INVALID_STATE, TAG, "DAC DMA peripheral has not initialized yet");
|
||||
if (s_ddp->intr_handle) {
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
i2s_ll_enable_intr(s_ddp->periph_dev, I2S_LL_EVENT_TX_EOF, false);
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
esp_intr_free(s_ddp->intr_handle);
|
||||
s_ddp->intr_handle = NULL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void dac_dma_periph_enable(void)
|
||||
{
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
/* Reset */
|
||||
i2s_ll_tx_reset(s_ddp->periph_dev);
|
||||
i2s_ll_tx_reset_dma(s_ddp->periph_dev);
|
||||
i2s_ll_tx_reset_fifo(s_ddp->periph_dev);
|
||||
/* Start */
|
||||
i2s_ll_enable_dma(s_ddp->periph_dev,true);
|
||||
i2s_ll_tx_enable_intr(s_ddp->periph_dev);
|
||||
// i2s_ll_tx_start_link(s_ddp->periph_dev, (uint32_t)desc_addr);
|
||||
// i2s_ll_tx_start(s_ddp->periph_dev);
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
/* Enable interrupt */
|
||||
esp_intr_enable(s_ddp->intr_handle);
|
||||
}
|
||||
|
||||
void dac_dma_periph_disable(void)
|
||||
{
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
/* Reset */
|
||||
i2s_ll_tx_reset(s_ddp->periph_dev);
|
||||
i2s_ll_tx_reset_dma(s_ddp->periph_dev);
|
||||
i2s_ll_tx_reset_fifo(s_ddp->periph_dev);
|
||||
/* Stop */
|
||||
i2s_ll_tx_stop(s_ddp->periph_dev);
|
||||
i2s_ll_tx_stop_link(s_ddp->periph_dev);
|
||||
i2s_ll_tx_disable_intr(s_ddp->periph_dev);
|
||||
i2s_ll_enable_dma(s_ddp->periph_dev, false);
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
/* Disable interrupt */
|
||||
esp_intr_disable(s_ddp->intr_handle);
|
||||
}
|
||||
|
||||
bool inline dac_dma_periph_intr_is_triggered(void)
|
||||
{
|
||||
uint32_t status = i2s_ll_get_intr_status(s_ddp->periph_dev);
|
||||
if (status == 0) {
|
||||
//Avoid spurious interrupt
|
||||
return false;
|
||||
}
|
||||
i2s_ll_clear_intr_status(s_ddp->periph_dev, status);
|
||||
return (status & I2S_LL_EVENT_TX_EOF) != 0;
|
||||
}
|
||||
|
||||
uint32_t inline dac_dma_periph_intr_get_eof_desc(void)
|
||||
{
|
||||
uint32_t finish_desc;
|
||||
i2s_ll_tx_get_eof_des_addr(s_ddp->periph_dev, &finish_desc);
|
||||
return finish_desc;
|
||||
}
|
||||
|
||||
void inline dac_dma_periph_dma_trans_start(uint32_t desc_addr)
|
||||
{
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
// TODO: check whether need to reset
|
||||
i2s_ll_tx_reset(s_ddp->periph_dev);
|
||||
i2s_ll_tx_reset_dma(s_ddp->periph_dev);
|
||||
i2s_ll_tx_reset_fifo(s_ddp->periph_dev);
|
||||
i2s_ll_tx_start_link(s_ddp->periph_dev, desc_addr);
|
||||
i2s_ll_tx_start(s_ddp->periph_dev);
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
}
|
@ -1,414 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_pm.h"
|
||||
#include "esp_check.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "driver/dac.h"
|
||||
#include "soc/dac_periph.h"
|
||||
#include "soc/lldesc.h"
|
||||
#include "hal/dac_hal.h"
|
||||
#include "periph_ctrl.h"
|
||||
#include "driver/spi_common_internal.h"
|
||||
|
||||
static const char *DAC_TAG = "DAC";
|
||||
|
||||
/* On ESP32-S2, DAC-DMA shares the SPI3-DMA channel */
|
||||
#define DAC_USE_SPI3_DMA_CHANNEL SPI3_HOST
|
||||
|
||||
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)
|
||||
|
||||
typedef struct {
|
||||
bool intr_trigger;
|
||||
uint8_t *data;
|
||||
uint32_t data_len;
|
||||
} dac_dma_event_t;
|
||||
|
||||
typedef struct {
|
||||
dac_hal_context_t *hal; /*!< HAL pointer of DAC */
|
||||
QueueHandle_t que_dac_hdl; /*!< DAC queue handler */
|
||||
uint32_t dma_buffer_cnt; /*!< DMA buffer count, number of buffer. */
|
||||
uint32_t dma_buffer_length; /*!< DMA buffer length, length of each buffer. */
|
||||
lldesc_t **desc; /*!< Pointer to DMA descriptor*/
|
||||
bool dac_start_en; /*!< The status of the DAC, 0: stop, 1: start */
|
||||
dac_dma_link_type_t dac_dma_link_type; /*!< The type of the link, see `dac_dma_link_type_t` */
|
||||
esp_pm_lock_handle_t pm_lock; /*!< Spinlock for DAC */
|
||||
spi_host_device_t spi_host; /*!< spi host */
|
||||
intr_handle_t dac_isr_handle; /*!< DAC interrupt handler */
|
||||
} dac_digi_context_t;
|
||||
|
||||
static dac_digi_context_t *s_dac_digi_ctx = NULL;
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
INTERRUPT HANDLER
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
static IRAM_ATTR void dac_dma_isr_default(void *arg)
|
||||
{
|
||||
dac_digi_context_t *p_dac = (dac_digi_context_t *) arg;
|
||||
bool status = dac_dma_hal_get_intr_status(p_dac->hal);
|
||||
dac_dma_hal_clr_intr(p_dac->hal);
|
||||
int task_awoken = pdFALSE;
|
||||
dac_dma_event_t dac_evt;
|
||||
dac_evt.intr_trigger = status;
|
||||
xQueueSendFromISR(s_dac_digi_ctx->que_dac_hdl, &dac_evt, &task_awoken);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Digital controller setting
|
||||
---------------------------------------------------------------*/
|
||||
static lldesc_t** dac_dma_desc_buf_create(int desc_cnt, size_t buf_size)
|
||||
{
|
||||
lldesc_t** pdesc = (lldesc_t**)heap_caps_calloc(1, sizeof(lldesc_t*) * desc_cnt, MALLOC_CAP_DMA);
|
||||
if (pdesc == NULL) {
|
||||
goto _exit;
|
||||
}
|
||||
for (int i = 0; i < desc_cnt; i++) {
|
||||
pdesc[i] = (lldesc_t*)heap_caps_malloc(sizeof(lldesc_t), MALLOC_CAP_DMA);
|
||||
if (pdesc[i] == NULL) {
|
||||
goto _exit;
|
||||
}
|
||||
memset(pdesc[i], 0, sizeof(lldesc_t));
|
||||
}
|
||||
return pdesc;
|
||||
_exit:
|
||||
for (int i = 0; i < desc_cnt; i++) {
|
||||
free(pdesc[i]);
|
||||
}
|
||||
free(pdesc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void dac_dma_write(lldesc_t** pdesc, int desc_cnt, size_t buf_size, const void *buffer)
|
||||
{
|
||||
for (int bux_idx = 0; bux_idx < desc_cnt; bux_idx++) {
|
||||
pdesc[bux_idx]->owner = 1;
|
||||
pdesc[bux_idx]->eof = 1;
|
||||
pdesc[bux_idx]->length = buf_size;
|
||||
pdesc[bux_idx]->size = buf_size;
|
||||
pdesc[bux_idx]->buf = (uint8_t *) buffer;
|
||||
buffer += buf_size;
|
||||
if (s_dac_digi_ctx->dac_dma_link_type == DAC_DMA_LINK_RECURSIVE) {
|
||||
pdesc[bux_idx]->qe.stqe_next = ((bux_idx < (desc_cnt - 1)) ? (pdesc[bux_idx + 1]) : pdesc[0]);
|
||||
} else {
|
||||
pdesc[bux_idx]->qe.stqe_next = ((bux_idx < (desc_cnt - 1)) ? (pdesc[bux_idx + 1]) : NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t dac_digi_initialize(const dac_digi_init_config_t *init_cfg)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(init_cfg->mode < DAC_CONV_MAX, ESP_ERR_INVALID_ARG, DAC_TAG, "DAC mode error");
|
||||
ESP_RETURN_ON_FALSE((init_cfg->interval > 0) && (init_cfg->interval < 4096), ESP_ERR_INVALID_ARG, DAC_TAG, "DAC interval error");
|
||||
|
||||
esp_err_t err = ESP_OK;
|
||||
uint32_t dma_chan = 0;
|
||||
uint32_t dac_chan = 0;
|
||||
if (s_dac_digi_ctx != NULL) {
|
||||
ESP_LOGE(DAC_TAG, "DAC has been installed");
|
||||
err = ESP_FAIL;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
s_dac_digi_ctx = calloc(1, sizeof(dac_digi_context_t));
|
||||
s_dac_digi_ctx->dac_start_en = false;
|
||||
if(s_dac_digi_ctx == NULL){
|
||||
err = ESP_ERR_NO_MEM;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
if (s_dac_digi_ctx->pm_lock == NULL) {
|
||||
err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "dac_dma", &s_dac_digi_ctx->pm_lock);
|
||||
if (err != ESP_OK) {
|
||||
s_dac_digi_ctx->pm_lock = NULL;
|
||||
ESP_LOGE(DAC_TAG, "DAC-DMA pm lock error");
|
||||
goto _exit;
|
||||
}
|
||||
}
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
if (s_dac_digi_ctx->que_dac_hdl == NULL) {
|
||||
s_dac_digi_ctx->que_dac_hdl = xQueueCreate(5, sizeof(dac_dma_event_t));
|
||||
} else {
|
||||
xQueueReset(s_dac_digi_ctx->que_dac_hdl);
|
||||
}
|
||||
|
||||
periph_module_enable(PERIPH_SARADC_MODULE);
|
||||
|
||||
do {
|
||||
if ((init_cfg->dac_chan_msk >> dac_chan) & BIT(0)) {
|
||||
dac_output_enable(dac_chan);
|
||||
dac_chan++;
|
||||
}
|
||||
} while (dac_chan < DAC_CHANNEL_MAX);
|
||||
|
||||
dac_hal_ctrl_config_t ctrl_hal_cfg = {
|
||||
.mode = init_cfg->mode,
|
||||
.interval = init_cfg->interval,
|
||||
};
|
||||
|
||||
dac_hal_digi_controller_configure(&ctrl_hal_cfg);
|
||||
s_dac_digi_ctx->dma_buffer_cnt = init_cfg->dac_dma_cnt;
|
||||
s_dac_digi_ctx->dma_buffer_length = init_cfg->dac_dma_length;
|
||||
s_dac_digi_ctx->dac_dma_link_type = init_cfg->dac_dma_link_type;
|
||||
s_dac_digi_ctx->spi_host = DAC_USE_SPI3_DMA_CHANNEL;
|
||||
|
||||
spicommon_periph_claim(s_dac_digi_ctx->spi_host, "dac");
|
||||
err = spicommon_slave_dma_chan_alloc(s_dac_digi_ctx->spi_host, SPI_DMA_CH_AUTO, &dma_chan, &dma_chan);
|
||||
if (err != ESP_OK) {
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
s_dac_digi_ctx->hal = calloc(1, sizeof(dac_hal_context_t));
|
||||
s_dac_digi_ctx->hal->dev = (void *)SPI_LL_GET_HW(s_dac_digi_ctx->spi_host);
|
||||
s_dac_digi_ctx->hal->dma_chan = dma_chan;
|
||||
|
||||
dac_dma_hal_init(s_dac_digi_ctx->hal);
|
||||
err = esp_intr_alloc(spicommon_irqdma_source_for_host(s_dac_digi_ctx->spi_host), 0, dac_dma_isr_default, s_dac_digi_ctx, &s_dac_digi_ctx->dac_isr_handle);
|
||||
if(err != ESP_OK){
|
||||
goto _exit;
|
||||
}
|
||||
s_dac_digi_ctx->desc = dac_dma_desc_buf_create(s_dac_digi_ctx->dma_buffer_cnt, s_dac_digi_ctx->dma_buffer_length);
|
||||
|
||||
return err;
|
||||
_exit:
|
||||
dac_digi_deinitialize();
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t dac_digi_write_bytes(uint32_t length, const void *buffer, TickType_t ticks_to_wait)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(length <= (s_dac_digi_ctx->dma_buffer_cnt * s_dac_digi_ctx->dma_buffer_length), ESP_ERR_INVALID_ARG, DAC_TAG, "DAC DMA buffer length is larger than DMA buffer.");
|
||||
dac_dma_event_t dac_evt;
|
||||
bool dac_isr_flag = 1;
|
||||
|
||||
|
||||
dac_dma_write(s_dac_digi_ctx->desc, s_dac_digi_ctx->dma_buffer_cnt, s_dac_digi_ctx->dma_buffer_length, buffer);
|
||||
|
||||
dac_dma_hal_trans_start(s_dac_digi_ctx->hal, s_dac_digi_ctx->desc[0]);
|
||||
while (dac_isr_flag) {
|
||||
xQueueReceive(s_dac_digi_ctx->que_dac_hdl, &dac_evt, ticks_to_wait);
|
||||
if (dac_evt.intr_trigger & dac_isr_flag) {
|
||||
dac_isr_flag &= (!dac_evt.intr_trigger);
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t dac_digi_deinitialize(void)
|
||||
{
|
||||
if (!s_dac_digi_ctx) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (s_dac_digi_ctx->dac_start_en == true) {
|
||||
ESP_LOGE(DAC_TAG, "DAC is still working");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
periph_module_disable(PERIPH_SARADC_MODULE);
|
||||
|
||||
spicommon_periph_free(s_dac_digi_ctx->spi_host);
|
||||
spicommon_slave_free_dma(s_dac_digi_ctx->spi_host);
|
||||
|
||||
|
||||
if (s_dac_digi_ctx->que_dac_hdl) {
|
||||
vQueueDelete(s_dac_digi_ctx->que_dac_hdl);
|
||||
s_dac_digi_ctx->que_dac_hdl = NULL;
|
||||
}
|
||||
|
||||
dac_dma_hal_deinit(s_dac_digi_ctx->hal);
|
||||
|
||||
for (int i = 0; i < s_dac_digi_ctx->dma_buffer_cnt; i++) {
|
||||
free(s_dac_digi_ctx->desc[i]);
|
||||
}
|
||||
|
||||
free(s_dac_digi_ctx->hal);
|
||||
free(s_dac_digi_ctx);
|
||||
s_dac_digi_ctx = NULL;
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
if (s_dac_digi_ctx->pm_lock) {
|
||||
esp_pm_lock_delete(s_dac_digi_ctx->pm_lock);
|
||||
s_dac_digi_ctx->pm_lock = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
DAC_ENTER_CRITICAL();
|
||||
dac_hal_digi_deinit();
|
||||
DAC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t __attribute__((unused)) dac_digi_deinit(void)
|
||||
{
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
if (s_dac_digi_ctx->pm_lock) {
|
||||
esp_pm_lock_delete(s_dac_digi_ctx->pm_lock);
|
||||
s_dac_digi_ctx->pm_lock = NULL;
|
||||
}
|
||||
#endif
|
||||
free(s_dac_digi_ctx);
|
||||
DAC_ENTER_CRITICAL();
|
||||
dac_hal_digi_deinit();
|
||||
DAC_EXIT_CRITICAL();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t __attribute__((unused)) dac_digi_controller_config(const dac_digi_config_t *cfg)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(cfg->mode < DAC_CONV_MAX, ESP_ERR_INVALID_ARG, TAG, "DAC mode error");
|
||||
ESP_RETURN_ON_FALSE(cfg->interval > 0 && cfg->interval < 4096, ESP_ERR_INVALID_ARG, TAG, "DAC interval error");
|
||||
ESP_RETURN_ON_FALSE(cfg->dig_clk.div_num < 256, ESP_ERR_INVALID_ARG, TAG, "DAC clk div_num error");
|
||||
ESP_RETURN_ON_FALSE(cfg->dig_clk.div_b > 0 && cfg->dig_clk.div_b < 64, ESP_ERR_INVALID_ARG, TAG, "DAC clk div_b error");
|
||||
ESP_RETURN_ON_FALSE(cfg->dig_clk.div_a < 64, ESP_ERR_INVALID_ARG, TAG, "DAC clk div_a error");
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_err_t err;
|
||||
if (s_dac_digi_ctx->pm_lock == NULL) {
|
||||
if (cfg->dig_clk.use_apll) {
|
||||
err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "dac_dma", &s_dac_digi_ctx->pm_lock);
|
||||
} else {
|
||||
err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "dac_dma", &s_dac_digi_ctx->pm_lock);
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
s_dac_digi_ctx->pm_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)
|
||||
{
|
||||
if (s_dac_digi_ctx->dac_start_en == true) {
|
||||
ESP_LOGE(DAC_TAG, "DAC is already started");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
s_dac_digi_ctx->dac_start_en = true;
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
ESP_RETURN_ON_FALSE((s_dac_digi_ctx->pm_lock), ESP_ERR_INVALID_STATE, DAC_TAG, "Should start after call `dac_digi_controller_config`");
|
||||
esp_pm_lock_acquire(s_dac_digi_ctx->pm_lock);
|
||||
#endif
|
||||
DAC_ENTER_CRITICAL();
|
||||
dac_hal_digi_start();
|
||||
DAC_EXIT_CRITICAL();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t dac_digi_stop(void)
|
||||
{
|
||||
if (s_dac_digi_ctx->dac_start_en == false) {
|
||||
ESP_LOGE(DAC_TAG, "DAC is already stopped");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
s_dac_digi_ctx->dac_start_en = false;
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
if (s_dac_digi_ctx->pm_lock) {
|
||||
esp_pm_lock_release(s_dac_digi_ctx->pm_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;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
esp_err_t __attribute__((deprecated)) dac_digi_init(void)
|
||||
{
|
||||
s_dac_digi_ctx = calloc(1, sizeof(dac_digi_context_t));
|
||||
s_dac_digi_ctx->dac_start_en = false;
|
||||
DAC_ENTER_CRITICAL();
|
||||
dac_hal_digi_init();
|
||||
DAC_EXIT_CRITICAL();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t __attribute__((deprecated)) dac_digi_deinit(void)
|
||||
{
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
if (s_dac_digi_ctx->pm_lock) {
|
||||
esp_pm_lock_delete(s_dac_digi_ctx->pm_lock);
|
||||
s_dac_digi_ctx->pm_lock = NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
free(s_dac_digi_ctx);
|
||||
DAC_ENTER_CRITICAL();
|
||||
dac_hal_digi_deinit();
|
||||
DAC_EXIT_CRITICAL();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t __attribute__((deprecated)) dac_digi_controller_config(const dac_digi_config_t *cfg)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(cfg->mode < DAC_CONV_MAX, ESP_ERR_INVALID_ARG, DAC_TAG, "DAC mode error");
|
||||
ESP_RETURN_ON_FALSE(cfg->interval > 0 && cfg->interval < 4096, ESP_ERR_INVALID_ARG, DAC_TAG, "DAC interval error");
|
||||
ESP_RETURN_ON_FALSE(cfg->dig_clk.div_num < 256, ESP_ERR_INVALID_ARG, DAC_TAG, "DAC clk div_num error");
|
||||
ESP_RETURN_ON_FALSE(cfg->dig_clk.div_b > 0 && cfg->dig_clk.div_b < 64, ESP_ERR_INVALID_ARG, DAC_TAG, "DAC clk div_b error");
|
||||
ESP_RETURN_ON_FALSE(cfg->dig_clk.div_a < 64, ESP_ERR_INVALID_ARG, DAC_TAG, "DAC clk div_a error");
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_err_t err;
|
||||
if (s_dac_digi_ctx->pm_lock == NULL) {
|
||||
if (cfg->dig_clk.use_apll) {
|
||||
err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "dac_dma", &s_dac_digi_ctx->pm_lock);
|
||||
} else {
|
||||
err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "dac_dma", &s_dac_digi_ctx->pm_lock);
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
s_dac_digi_ctx->pm_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;
|
||||
}
|
199
components/driver/esp32s2/dac_dma.c
Normal file
199
components/driver/esp32s2/dac_dma.c
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "hal/spi_ll.h"
|
||||
#include "hal/dac_ll.h"
|
||||
#include "hal/adc_ll.h"
|
||||
#include "soc/lldesc.h"
|
||||
#include "esp_private/dac_dma.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "driver/spi_common_internal.h"
|
||||
#include "esp_check.h"
|
||||
|
||||
#define DAC_DMA_PERIPH_SPI_HOST SPI3_HOST
|
||||
|
||||
typedef struct {
|
||||
void *periph_dev; /* DMA peripheral device address */
|
||||
uint32_t dma_chan;
|
||||
intr_handle_t intr_handle; /* Interrupt handle */
|
||||
} dac_dma_periph_spi_t;
|
||||
|
||||
static dac_dma_periph_spi_t *s_ddp = NULL; // Static DAC DMA peripheral structure pointer
|
||||
|
||||
static const char *TAG = "DAC_DMA";
|
||||
|
||||
extern portMUX_TYPE dac_spinlock; /* Global DAC spinlock */
|
||||
|
||||
/**
|
||||
* @brief Calculate and set DAC data frequency
|
||||
* @note DAC clcok shares clock devider with ADC, the clock source is APB or APLL on ESP32-S2
|
||||
* freq_hz = (source_clk / (clk_div + (b / a) + 1)) / interval
|
||||
* interval range: 1~4095, to avoid decimal as possible, all calculations will base on interval = 4000
|
||||
* @param freq_hz DAC byte frequency
|
||||
* @return
|
||||
* - ESP_OK config success
|
||||
* - ESP_ERR_INVALID_ARG invalid frequency
|
||||
*/
|
||||
// TODO: check clock again, the dma data seems abnormal
|
||||
static esp_err_t dac_dma_periph_set_clock(uint32_t freq_hz){
|
||||
ESP_RETURN_ON_FALSE(freq_hz >= 80, ESP_ERR_INVALID_ARG, TAG, "the DAC frequency should be greater than 80 Hz");
|
||||
// TODO: replace 80000000 with APB or APLL clock frequency
|
||||
// when interval = 4000, max_freq = 20k min_freq = 80
|
||||
uint32_t freq_khz = freq_hz / 1000;
|
||||
/* If freq_khz < 20k, interval = 4000 is enough, so mutiple = 1,
|
||||
* otherwise interval need to zoom out to increase the max_freq,
|
||||
* And in order to avoid decimal as possible, multiple better to be 2^n */
|
||||
uint32_t multiple = freq_khz < 20 ? 1 : 1 << (32 - __builtin_clz(freq_khz / 20)); // Multiple need to be 2^n to avoid decimal
|
||||
uint32_t interval = 4000 / multiple; // Zoom in the max/min supported freq by zooming out interval
|
||||
ESP_RETURN_ON_FALSE(interval > 0, ESP_ERR_INVALID_ARG, TAG, "the DAC frequency is too big");
|
||||
|
||||
uint32_t clk_div = (80000000 / interval) / freq_hz;
|
||||
uint32_t mod = (80000000 / interval) % freq_hz;
|
||||
uint32_t a = 0;
|
||||
uint32_t b = 1;
|
||||
if (mod == 0) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
uint32_t min_diff = mod + 1;
|
||||
for (uint32_t tmp_b = 1; tmp_b < 64; tmp_b++) {
|
||||
uint32_t tmp_a = (uint32_t)(((mod * b) / (float)freq_hz) + 0.5);
|
||||
uint32_t diff = (uint32_t)abs((int)(mod * tmp_b) - (int)(freq_hz * tmp_a));
|
||||
if (diff == 0) {
|
||||
a = tmp_a;
|
||||
b = tmp_b;
|
||||
goto finish;
|
||||
}
|
||||
if (diff < min_diff) {
|
||||
min_diff = diff;
|
||||
a = tmp_a;
|
||||
b = tmp_b;
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
dac_ll_digi_clk_inv(true);
|
||||
dac_ll_digi_set_trigger_interval(interval); // secondary clock division
|
||||
adc_ll_digi_controller_clk_div(clk_div, b, a);
|
||||
adc_ll_digi_clk_sel(false);
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t dac_dma_periph_init(int chan_num, uint32_t freq_hz, bool is_alternate)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
/* Acquire DMA peripheral */
|
||||
ESP_RETURN_ON_FALSE(spicommon_periph_claim(DAC_DMA_PERIPH_SPI_HOST, "dac_dma"), ESP_ERR_NOT_FOUND, TAG, "Failed to acquire DAC DMA peripheral");
|
||||
// TODO: reference count, maybe only required on s2
|
||||
periph_module_enable(PERIPH_SARADC_MODULE);
|
||||
/* Allocate DAC DMA peripheral object */
|
||||
s_ddp = (dac_dma_periph_spi_t *)calloc(1, sizeof(dac_dma_periph_spi_t));
|
||||
ESP_GOTO_ON_FALSE(s_ddp, ESP_ERR_NO_MEM, err, TAG, "No memory for DAC DMA object");
|
||||
s_ddp->periph_dev = (void *)SPI_LL_GET_HW(DAC_DMA_PERIPH_SPI_HOST);
|
||||
// TODO: clock may related to convert mode (mono/stereo)
|
||||
ESP_GOTO_ON_ERROR(dac_dma_periph_set_clock(freq_hz), err, TAG, "Failed to set clock of DMA peripheral");
|
||||
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
dac_ll_digi_set_convert_mode(is_alternate);
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
return ret;
|
||||
err:
|
||||
dac_dma_periph_deinit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t dac_dma_periph_deinit(void)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(spicommon_periph_free(DAC_DMA_PERIPH_SPI_HOST), ESP_FAIL, TAG, "Failed to release DAC DMA peripheral");
|
||||
// TODO: reference count, maybe only required on s2
|
||||
periph_module_disable(PERIPH_SARADC_MODULE);
|
||||
if (s_ddp) {
|
||||
if (s_ddp->intr_handle) {
|
||||
dac_dma_periph_deregister_intr();
|
||||
}
|
||||
free(s_ddp);
|
||||
s_ddp = NULL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t dac_dma_periph_register_intr(intr_handler_t intr_handler_func, void *user_ctx)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(s_ddp, ESP_ERR_INVALID_STATE, TAG, "DAC DMA peripheral has not initialized yet");
|
||||
ESP_RETURN_ON_ERROR(spicommon_dma_chan_alloc(DAC_DMA_PERIPH_SPI_HOST, SPI_DMA_CH_AUTO, &s_ddp->dma_chan, &s_ddp->dma_chan),
|
||||
TAG, "Failed to allocate dma peripheral channel");
|
||||
esp_err_t ret = ESP_OK;
|
||||
/* Regigster interrupt */
|
||||
ESP_GOTO_ON_ERROR(esp_intr_alloc(spicommon_irqdma_source_for_host(DAC_DMA_PERIPH_SPI_HOST),
|
||||
0, intr_handler_func, user_ctx, &(s_ddp->intr_handle)), err, TAG, "Failed to register DAC DMA interrupt");
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
spi_ll_enable_intr(s_ddp->periph_dev, SPI_LL_INTR_OUT_EOF);
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
return ret;
|
||||
err:
|
||||
spicommon_dma_chan_free(DAC_DMA_PERIPH_SPI_HOST);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t dac_dma_periph_deregister_intr(void)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(s_ddp, ESP_ERR_INVALID_STATE, TAG, "DAC DMA peripheral has not initialized yet");
|
||||
ESP_RETURN_ON_ERROR(spicommon_dma_chan_free(DAC_DMA_PERIPH_SPI_HOST), TAG, "Failed to free dma peripheral channel");
|
||||
if (s_ddp->intr_handle) {
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
spi_ll_disable_intr(s_ddp->periph_dev, SPI_LL_INTR_OUT_EOF);
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
esp_intr_free(s_ddp->intr_handle);
|
||||
s_ddp->intr_handle = NULL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void dac_dma_periph_enable(void)
|
||||
{
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
spi_dma_ll_tx_reset(s_ddp->periph_dev, s_ddp->dma_chan);
|
||||
spi_ll_dma_tx_fifo_reset(s_ddp->periph_dev);
|
||||
dac_ll_digi_trigger_output(true);
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
/* Enable interrupt */
|
||||
esp_intr_enable(s_ddp->intr_handle);
|
||||
}
|
||||
|
||||
void dac_dma_periph_disable(void)
|
||||
{
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
spi_dma_ll_tx_reset(s_ddp->periph_dev, s_ddp->dma_chan);
|
||||
spi_ll_dma_tx_fifo_reset(s_ddp->periph_dev);
|
||||
spi_dma_ll_tx_stop(s_ddp->periph_dev, s_ddp->dma_chan);
|
||||
dac_ll_digi_trigger_output(false);
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
/* Disable interrupt */
|
||||
esp_intr_disable(s_ddp->intr_handle);
|
||||
}
|
||||
|
||||
bool IRAM_ATTR dac_dma_periph_intr_is_triggered(void)
|
||||
{
|
||||
uint32_t is_triggered = spi_ll_get_intr(s_ddp->periph_dev, SPI_LL_INTR_OUT_EOF);
|
||||
spi_ll_clear_intr(s_ddp->periph_dev, SPI_LL_INTR_OUT_EOF);
|
||||
return is_triggered;
|
||||
}
|
||||
|
||||
uint32_t IRAM_ATTR dac_dma_periph_intr_get_eof_desc(void)
|
||||
{
|
||||
return spi_dma_ll_get_out_eof_desc_addr(s_ddp->periph_dev, s_ddp->dma_chan);
|
||||
}
|
||||
|
||||
void dac_dma_periph_dma_trans_start(uint32_t desc_addr)
|
||||
{
|
||||
portENTER_CRITICAL(&dac_spinlock);
|
||||
spi_dma_ll_tx_reset(s_ddp->periph_dev, s_ddp->dma_chan);
|
||||
spi_ll_dma_tx_fifo_reset(s_ddp->periph_dev);
|
||||
spi_dma_ll_tx_start(s_ddp->periph_dev, s_ddp->dma_chan, (lldesc_t *)desc_addr);
|
||||
portEXIT_CRITICAL(&dac_spinlock);
|
||||
}
|
@ -1,130 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "driver/dac_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @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 dac_chan_msk; /*!< DAC channel select mask, use BIT(CHAN_X) to mask the channesl */
|
||||
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. */
|
||||
uint32_t dac_dma_cnt; /*!< DMA buffer count, number of buffer. */
|
||||
uint32_t dac_dma_length; /*!< DMA buffer length, length of each buffer. */
|
||||
dac_dma_link_type_t dac_dma_link_type; /*!< The type of the link, see `dac_dma_link_type_t` */
|
||||
} dac_digi_init_config_t;
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Digital controller setting
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Initialize the Digital DAC controller.
|
||||
*
|
||||
* @param init_cfg Pointer to Digital DAC initialization config. Refer to ``dac_digi_config_t``.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid.
|
||||
* - ESP_ERR_NOT_FOUND No free interrupt found with the specified flags
|
||||
* - ESP_ERR_NO_MEM If out of memory
|
||||
* - ESP_OK On success
|
||||
*/
|
||||
esp_err_t dac_digi_initialize(const dac_digi_init_config_t *init_cfg);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize the Digital DAC controller.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_STATE Driver state is invalid.
|
||||
* - ESP_OK On success
|
||||
*/
|
||||
esp_err_t dac_digi_deinitialize(void);
|
||||
|
||||
/**
|
||||
* @brief Write bytes to Digital DAC through DMA.
|
||||
*
|
||||
* @param length the buffer length.
|
||||
* @param[in] buffer Buffer to write to DAC.
|
||||
* @param ticks_to_wait Ticks to wait until there's room in the queue; use portMAX_DELAY to
|
||||
* never time out.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_STATE Driver state is invalid. Usually it means the ADC sampling rate is faster than the task processing rate.
|
||||
* - ESP_ERR_TIMEOUT Operation timed out
|
||||
* - ESP_OK On success
|
||||
*/
|
||||
esp_err_t dac_digi_write_bytes(uint32_t length, const void *buffer, TickType_t ticks_to_wait);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/************************************************************
|
||||
* Deprecated APIs
|
||||
***********************************************************/
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
/**
|
||||
* @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 __attribute__((deprecated)) dac_digi_controller_config(const dac_digi_config_t *cfg);
|
||||
|
||||
/**
|
||||
* @brief DAC digital controller deinitialization.
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
*/
|
||||
esp_err_t __attribute__((deprecated)) dac_digi_deinit(void);
|
||||
|
||||
/**
|
||||
* @brief DAC digital controller initialization.
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
*/
|
||||
esp_err_t __attribute__((deprecated)) dac_digi_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
260
components/driver/include/driver/dac_new.h
Normal file
260
components/driver/include/driver/dac_new.h
Normal file
@ -0,0 +1,260 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "driver/dac_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define DAC_CHANNEL1_IO 25 /*!< ESP32 DAC channel 1 GPIO number: GPIO_NUM_25 */
|
||||
#define DAC_CHANNEL2_IO 26 /*!< ESP32 DAC channel 2 GPIO number: GPIO_NUM_26 */
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define DAC_CHANNEL1_IO 17 /*!< ESP32S2 DAC channel 1 GPIO number: GPIO_NUM_17 */
|
||||
#define DAC_CHANNEL2_IO 18 /*!< ESP32S2 DAC channel 2 GPIO number: GPIO_NUM_17 */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief DAC channel configuration
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
dac_channel_mask_t chan_sel; /*!< Using DAC channel mask to select the channel in the channel group */
|
||||
} dac_group_config_t;
|
||||
|
||||
/**
|
||||
* @brief DAC DMA configration
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t freq_hz; /*!< The frequency of DAC converting each data in DMA mode, unit: Hz */
|
||||
uint32_t desc_num; /*!< The number of DMA descriptor , directly proportional to the max data buffer size while converting in cyclic way */
|
||||
dac_dma_channel_mode_t chan_mode; /*!< DMA channel mode, only take effect when multiple channels enabled in a group, depends converting the buffer alternately or simultaneously */
|
||||
} dac_dma_config_t;
|
||||
|
||||
/**
|
||||
* @brief DAC cosine wave gnerator configuration
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t freq_hz; /*!< The frequency of cosine wave, unit: Hz */
|
||||
dac_cosine_scale_t scale; /*!< The scale of cosine wave amplitude */
|
||||
dac_cosine_phase_t phase; /*!< The phase of cosine wave */
|
||||
int8_t offset; /*!< The DC offset of cosine wave */
|
||||
} dac_cosine_config_t;
|
||||
|
||||
typedef struct dac_channel_group_s *dac_channel_group_handle_t; /*!< DAC group handle of DAC peripheral, one or multiple DAC channels can be controlled by the group handle */
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
DAC common APIs
|
||||
---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Allocate a new DAC channel group
|
||||
*
|
||||
* @param[in] dac_cfg DAC basic configuration
|
||||
* @param[out] handle DAC channel group handle
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG The input parameter is invalid
|
||||
* - ESP_ERR_NO_MEM No memory for a new DAC handle
|
||||
* - ESP_ERR_INVALID_STATE The specified DAC channel is occupied already
|
||||
* - ESP_OK Success to allocate DAC channel group
|
||||
*/
|
||||
esp_err_t dac_new_channel_group(const dac_group_config_t *dac_cfg, dac_channel_group_handle_t *handle);
|
||||
|
||||
/**
|
||||
* @brief Delete and free the DAC channel group
|
||||
*
|
||||
* @param[in] handle DAC channel group handle
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG The input parameter is invalid
|
||||
* - ESP_ERR_INVALID_STATE The channel group is not disabled
|
||||
* - ESP_OK Success to delete the channel group
|
||||
*/
|
||||
esp_err_t dac_del_channel_group(dac_channel_group_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Enabled the DAC channels in the channel group
|
||||
* @note GPIOs of DAC channles will be enabled in this step
|
||||
*
|
||||
* @param[in] handle DAC channel group handle
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG The input parameter is invalid
|
||||
* - ESP_ERR_INVALID_STATE The channel group has enabled already or the channels are running
|
||||
* - ESP_OK Success to enable the channel group
|
||||
*/
|
||||
esp_err_t dac_channel_group_enable(dac_channel_group_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Disable the DAC channels in the channel group
|
||||
*
|
||||
* @param[in] handle DAC channel group handle
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG The input parameter is invalid
|
||||
* - ESP_ERR_INVALID_STATE The channel group has disabled already or the channels are running
|
||||
* - ESP_OK Success to enable the channel group
|
||||
*/
|
||||
esp_err_t dac_channel_group_disable(dac_channel_group_handle_t handle);
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
DAC constant voltage outputting APIs
|
||||
---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief DAC channel group output a constant voltage
|
||||
* @note This function is available when DAC chennel group is enbled
|
||||
*
|
||||
* @param[in] handle DAC channel group handle
|
||||
* @param[in] value The digital value of the constant voltage
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG The input parameter is invalid
|
||||
* - ESP_ERR_INVALID_STATE The channel group is not enabled
|
||||
* - ESP_OK Success to enable the channel group
|
||||
*/
|
||||
esp_err_t dac_channel_group_output_constant_voltage(dac_channel_group_handle_t handle, uint8_t value);
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
DAC continuous outputting APIs
|
||||
---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Initialize the DAC channel group to DMA mode
|
||||
* @note DAC can convert digital data continuously in DMA mode
|
||||
*
|
||||
* @param[in] handle DAC channel group handle
|
||||
* @param[in] dma_cfg DAC DMA configuration
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG The input parameter is invalid
|
||||
* - ESP_ERR_INVALID_STATE The DAC channel group has been initialized already
|
||||
* - ESP_ERR_NO_MEM No memory for DAC DMA mode
|
||||
* - ESP_OK Success to initializing the DAC channel group to DMA mode
|
||||
*/
|
||||
esp_err_t dac_channel_group_init_dma_output(dac_channel_group_handle_t handle, const dac_dma_config_t *dma_cfg);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize the DMA mode of the DAC channel group
|
||||
* @note It can only be deinitialized when the DMA output is stopped
|
||||
*
|
||||
* @param[in] handle DAC channel group handle
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG The input parameter is invalid
|
||||
* - ESP_ERR_INVALID_STATE The DAC DMA is not stopped yet
|
||||
* - ESP_OK Success to deinitialize the DAC DMA mode
|
||||
*/
|
||||
esp_err_t dac_channel_group_deinit_dma_output(dac_channel_group_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Start the DAC DMA output
|
||||
*
|
||||
* @param[in] handle DAC channel group handle
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG The input parameter is invalid
|
||||
* - ESP_ERR_INVALID_STATE The DAC DMA has not been enabled yet or started already
|
||||
* - ESP_OK Success to start the DMA output
|
||||
*/
|
||||
esp_err_t dac_channel_group_start_dma_output(dac_channel_group_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Stop the DAC DMA output
|
||||
*
|
||||
* @param[in] handle DAC channel group handle
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG The input parameter is invalid
|
||||
* - ESP_ERR_INVALID_STATE The DAC DMA is stopped or not disabled already
|
||||
* - ESP_OK Success to stop the DMA output
|
||||
*/
|
||||
esp_err_t dac_channel_group_stop_dma_output(dac_channel_group_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Write DAC DMA data acyclicly
|
||||
* @note The data in buffer will only be converted one time,
|
||||
* This function will be blocked until all data sent successfully or timeout
|
||||
* then the DAC output will keep outputting the voltage of the last data in the buffer
|
||||
*
|
||||
* @param[in] handle DAC channel group handle
|
||||
* @param[in] buf The digital data buffer to convert
|
||||
* @param[in] buf_size The buffer size of digital data buffer
|
||||
* @param[in] timeout_ms The timeout time in mili-second
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG The input parameter is invalid
|
||||
* - ESP_ERR_INVALID_STATE The DAC DMA has not been started or enabled yet
|
||||
* - ESP_ERR_TIMEOUT Waiting for semaphore or message queue timeout
|
||||
* - ESP_OK Success to output the acyclic DAC data by DMA
|
||||
*/
|
||||
esp_err_t dac_channel_group_write_acyclicly(dac_channel_group_handle_t handle, uint8_t *buf, size_t buf_size, uint32_t timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief Write DAC DMA data cyclicly
|
||||
* @note The data in buffer will be converted cyclicly once this function is called,
|
||||
* so the input buffer needs to stay accessable during the convertion,
|
||||
* but this function won't be blocked, it will return once the data loaded into DMA descriptors
|
||||
* @note The buffer size of cyclicly output is limited by the descriptor number while initializing the DMA mode,
|
||||
* Concretely, in order to load all the data into descriptors,
|
||||
* the cyclic buffer size is not supposed to be greater than `desc_num * 4092`
|
||||
*
|
||||
* @param[in] handle DAC channel group handle
|
||||
* @param[in] buf The digital data buffer to convert
|
||||
* @param[in] buf_size The buffer size of digital data buffer
|
||||
* @param[in] timeout_ms The timeout time in mili-second
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG The input parameter is invalid
|
||||
* - ESP_ERR_INVALID_STATE The DAC DMA has not been started or enabled yet
|
||||
* - ESP_ERR_TIMEOUT Waiting for semaphore or message queue timeout
|
||||
* - ESP_OK Success to output the acyclic DAC data by DMA
|
||||
*/
|
||||
esp_err_t dac_channel_group_write_cyclicly(dac_channel_group_handle_t handle, uint8_t *buf, size_t buf_size, uint32_t timeout_ms);
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
DAC cosine wave outputting APIs
|
||||
---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Initialize the DAC channel group to cosine wave mode
|
||||
*
|
||||
* @param[in] handle DAC channel group handle
|
||||
* @param[in] cw_cfg DAC cosine wave generater configuration
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG The input parameter is invalid
|
||||
* - ESP_ERR_INVALID_STATE The DAC channel group has been initialized already
|
||||
* - ESP_OK Success to initialize the DAC channel group into cosine wave mode
|
||||
*/
|
||||
esp_err_t dac_channel_group_init_cosine_output(dac_channel_group_handle_t handle, const dac_cosine_config_t *cw_cfg);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize the DAC channel group to cosine wave mode
|
||||
*
|
||||
* @param[in] handle DAC channel group handle
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG The input parameter is invalid
|
||||
* - ESP_ERR_INVALID_STATE The DAC cosine wave generator is not stopped yet
|
||||
* - ESP_OK Success to deinitialize the DAC DMA mode
|
||||
*/
|
||||
esp_err_t dac_channel_group_deinit_cosine_output(dac_channel_group_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Start the DAC cosine wave generator output
|
||||
*
|
||||
* @param[in] handle DAC channel group handle
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG The input parameter is invalid
|
||||
* - ESP_ERR_INVALID_STATE The DAC channel group has not been enabled yet or started already
|
||||
* - ESP_OK Success to start cosine wave generator
|
||||
*/
|
||||
esp_err_t dac_channel_group_start_cosine_output(dac_channel_group_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Stop the DAC cosine wave generator output
|
||||
*
|
||||
* @param[in] handle DAC channel group handle
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG The input parameter is invalid
|
||||
* - ESP_ERR_INVALID_STATE The DAC channel group has not been enabled yet or stoppped already
|
||||
* - ESP_OK Success to stop cosine wave generator
|
||||
*/
|
||||
esp_err_t dac_channel_group_stop_cosine_output(dac_channel_group_handle_t handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
55
components/driver/include/driver/dac_types.h
Normal file
55
components/driver/include/driver/dac_types.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief DAC channel mask
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
DAC_CHANNEL_MASK_1 = BIT(0), /*!< DAC channel 1 is GPIO25(ESP32) / GPIO17(ESP32S2) */
|
||||
DAC_CHANNEL_MASK_2 = BIT(1), /*!< DAC channel 2 is GPIO26(ESP32) / GPIO18(ESP32S2) */
|
||||
DAC_CHANNEL_MASK_BOTH = BIT(0) | BIT(1), /*!< DAC channel 2 is GPIO26(ESP32) / GPIO18(ESP32S2) */
|
||||
} dac_channel_mask_t;
|
||||
|
||||
/**
|
||||
* @brief DAC channel work mode in dma mode
|
||||
* @note Only take effect when multiple channels enabled.
|
||||
*/
|
||||
typedef enum {
|
||||
DAC_CHANNEL_SIMULTANEOUS, /*!< The data in the DMA buffer is simultaneously output to the enable channel of the DAC. */
|
||||
DAC_CHANNEL_ALTERNATE, /*!< The data in the DMA buffer is alternately output to the enable channel of the DAC. */
|
||||
} dac_dma_channel_mode_t;
|
||||
|
||||
/**
|
||||
* @brief The multiple of the amplitude of the cosine wave generator. The max amplitude is VDD3P3_RTC.
|
||||
*/
|
||||
typedef enum {
|
||||
DAC_COSINE_SCALE_1 = 0x0, /*!< No scaling to the DAC cosine wave amplitude. Default. */
|
||||
DAC_COSINE_SCALE_2 = 0x1, /*!< 1/2 amplitude of the DAC cosine wave */
|
||||
DAC_COSINE_SCALE_4 = 0x2, /*!< 1/4 amplitude of the DAC cosine wave */
|
||||
DAC_COSINE_SCALE_8 = 0x3, /*!< 1/8 amplitude of the DAC cosine wave */
|
||||
} dac_cosine_scale_t;
|
||||
|
||||
/**
|
||||
* @brief Set the phase of the cosine wave generator output.
|
||||
*/
|
||||
typedef enum {
|
||||
DAC_COSINE_PHASE_0 = 0x2, /*!< Phase shift +0° */
|
||||
DAC_COSINE_PHASE_180 = 0x3, /*!< Phase shift +180° */
|
||||
} dac_cosine_phase_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
37
components/driver/include/esp_private/dac_dma.h
Normal file
37
components/driver/include/esp_private/dac_dma.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
esp_err_t dac_dma_periph_init(int chan_num, uint32_t freq_hz, bool is_alternate);
|
||||
|
||||
esp_err_t dac_dma_periph_deinit(void);
|
||||
|
||||
esp_err_t dac_dma_periph_register_intr(intr_handler_t intr_handler_func, void *user_ctx);
|
||||
|
||||
esp_err_t dac_dma_periph_deregister_intr(void);
|
||||
|
||||
void dac_dma_periph_enable(void);
|
||||
|
||||
void dac_dma_periph_disable(void);
|
||||
|
||||
bool dac_dma_periph_intr_is_triggered(void);
|
||||
|
||||
uint32_t dac_dma_periph_intr_get_eof_desc(void);
|
||||
|
||||
void dac_dma_periph_dma_trans_start(uint32_t desc_addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -125,7 +125,6 @@ if(NOT BOOTLOADER_BUILD)
|
||||
"esp32s2/brownout_hal.c"
|
||||
"esp32s2/cp_dma_hal.c"
|
||||
"esp32s2/touch_sensor_hal.c"
|
||||
"esp32s2/dac_hal.c"
|
||||
"usb_dwc_hal.c")
|
||||
endif()
|
||||
|
||||
|
@ -1,24 +1,16 @@
|
||||
// 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.
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "hal/dac_hal.h"
|
||||
// #include "hal/dac_hal.h"
|
||||
|
||||
void dac_hal_cw_generator_config(dac_cw_config_t *cw)
|
||||
{
|
||||
dac_ll_cw_set_freq(cw->freq);
|
||||
dac_ll_cw_set_scale(cw->en_ch, cw->scale);
|
||||
dac_ll_cw_set_phase(cw->en_ch, cw->phase);
|
||||
dac_ll_cw_set_dc_offset(cw->en_ch, cw->offset);
|
||||
dac_ll_cw_set_channel(cw->en_ch, true);
|
||||
}
|
||||
// void dac_hal_cw_generator_config(dac_cw_config_t *cw)
|
||||
// {
|
||||
// dac_ll_cw_set_freq(cw->freq);
|
||||
// dac_ll_cw_set_scale(cw->en_ch, cw->scale);
|
||||
// dac_ll_cw_set_phase(cw->en_ch, cw->phase);
|
||||
// dac_ll_cw_set_dc_offset(cw->en_ch, cw->offset);
|
||||
// dac_ll_cw_set_channel(cw->en_ch, true);
|
||||
// }
|
||||
|
@ -128,7 +128,7 @@ static inline void dac_ll_cw_set_freq(uint32_t freq)
|
||||
* @param channel DAC channel num.
|
||||
* @param scale The multiple of the amplitude. The max amplitude is VDD3P3_RTC.
|
||||
*/
|
||||
static inline void dac_ll_cw_set_scale(dac_channel_t channel, dac_cw_scale_t scale)
|
||||
static inline void dac_ll_cw_set_scale(dac_channel_t channel, uint32_t scale)
|
||||
{
|
||||
if (channel == DAC_CHANNEL_1) {
|
||||
SENS.sar_dac_ctrl2.dac_scale1 = scale;
|
||||
@ -143,7 +143,7 @@ static inline void dac_ll_cw_set_scale(dac_channel_t channel, dac_cw_scale_t sca
|
||||
* @param channel DAC channel num.
|
||||
* @param scale Phase value.
|
||||
*/
|
||||
static inline void dac_ll_cw_set_phase(dac_channel_t channel, dac_cw_phase_t phase)
|
||||
static inline void dac_ll_cw_set_phase(dac_channel_t channel, uint32_t phase)
|
||||
{
|
||||
if (channel == DAC_CHANNEL_1) {
|
||||
SENS.sar_dac_ctrl2.dac_inv1 = phase;
|
||||
|
@ -59,7 +59,7 @@ void dac_dma_hal_trans_start(dac_hal_context_t *hal, lldesc_t *desc)
|
||||
void dac_hal_digi_controller_configure(const dac_hal_ctrl_config_t *cfg)
|
||||
{
|
||||
dac_ll_digi_clk_inv(true);
|
||||
dac_ll_digi_set_convert_mode(cfg->mode);
|
||||
dac_ll_digi_set_convert_mode(cfg->mode == DAC_CONV_ALTER);
|
||||
dac_ll_digi_set_trigger_interval(cfg->interval);
|
||||
adc_ll_digi_controller_clk_div(cfg->dig_clk.div_num, cfg->dig_clk.div_b, cfg->dig_clk.div_a);
|
||||
adc_ll_digi_clk_sel(cfg->dig_clk.use_apll);
|
||||
@ -87,7 +87,7 @@ void __attribute__((deprecated)) dac_hal_digi_deinit(void)
|
||||
|
||||
void __attribute__((deprecated)) dac_hal_digi_controller_config(const dac_digi_config_t *cfg)
|
||||
{
|
||||
dac_ll_digi_set_convert_mode(cfg->mode);
|
||||
dac_ll_digi_set_convert_mode(cfg->mode == DAC_CONV_ALTER);
|
||||
dac_ll_digi_set_trigger_interval(cfg->interval);
|
||||
adc_ll_digi_controller_clk_div(cfg->dig_clk.div_num, cfg->dig_clk.div_b, cfg->dig_clk.div_a);
|
||||
adc_ll_digi_controller_clk_enable(cfg->dig_clk.use_apll);
|
||||
|
@ -83,8 +83,6 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph)
|
||||
return DPORT_CRYPTO_DMA_CLK_EN | DPORT_CRYPTO_SHA_CLK_EN;
|
||||
case PERIPH_AES_DMA_MODULE:
|
||||
return DPORT_CRYPTO_DMA_CLK_EN | DPORT_CRYPTO_AES_CLK_EN;
|
||||
case PERIPH_SARADC_MODULE:
|
||||
return DPORT_APB_SARADC_CLK_EN_M;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ static inline void dac_ll_cw_set_freq(uint32_t freq)
|
||||
* @param channel DAC channel num.
|
||||
* @param scale The multiple of the amplitude. The max amplitude is VDD3P3_RTC.
|
||||
*/
|
||||
static inline void dac_ll_cw_set_scale(dac_channel_t channel, dac_cw_scale_t scale)
|
||||
static inline void dac_ll_cw_set_scale(dac_channel_t channel, uint32_t scale)
|
||||
{
|
||||
if (channel == DAC_CHANNEL_1) {
|
||||
SENS.sar_dac_ctrl2.dac_scale1 = scale;
|
||||
@ -164,7 +164,7 @@ static inline void dac_ll_cw_set_scale(dac_channel_t channel, dac_cw_scale_t sca
|
||||
* @param channel DAC channel num.
|
||||
* @param scale Phase value.
|
||||
*/
|
||||
static inline void dac_ll_cw_set_phase(dac_channel_t channel, dac_cw_phase_t phase)
|
||||
static inline void dac_ll_cw_set_phase(dac_channel_t channel, uint32_t phase)
|
||||
{
|
||||
if (channel == DAC_CHANNEL_1) {
|
||||
SENS.sar_dac_ctrl2.dac_inv1 = phase;
|
||||
@ -251,13 +251,9 @@ static inline void dac_ll_digi_trigger_output(bool enable)
|
||||
*
|
||||
* @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)
|
||||
static inline void dac_ll_digi_set_convert_mode(bool is_alternate)
|
||||
{
|
||||
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;
|
||||
}
|
||||
APB_SARADC.apb_dac_ctrl.apb_dac_alter_mode = is_alternate;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -13,6 +13,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "hal/dac_ll.h"
|
||||
#include "hal/dac_types.h"
|
||||
|
||||
/**
|
||||
* Power on dac module and start output voltage.
|
||||
@ -62,7 +63,7 @@
|
||||
*
|
||||
* @param cw Configuration.
|
||||
*/
|
||||
void dac_hal_cw_generator_config(dac_cw_config_t *cw);
|
||||
// void dac_hal_cw_generator_config(dac_cw_config_t *cw);
|
||||
|
||||
/**
|
||||
* Enable/disable DAC output data from DMA.
|
||||
|
@ -28,18 +28,6 @@ typedef enum {
|
||||
DAC_CW_PHASE_180 = 0x3, /*!< Phase shift +180° */
|
||||
} dac_cw_phase_t;
|
||||
|
||||
/**
|
||||
* @brief Config the cosine wave generator function in DAC module.
|
||||
*/
|
||||
typedef struct {
|
||||
dac_channel_t en_ch; /*!< Enable the cosine wave generator of DAC channel. */
|
||||
dac_cw_scale_t scale; /*!< Set the amplitude of the cosine wave generator output. */
|
||||
dac_cw_phase_t phase; /*!< Set the phase of the cosine wave generator output. */
|
||||
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;
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
|
||||
/**
|
||||
@ -48,17 +36,8 @@ typedef struct {
|
||||
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 The type of the DAC DMA link.
|
||||
*/
|
||||
typedef enum {
|
||||
DAC_DMA_LINK_LINE = BIT(0), /*!< The link is Linear. */
|
||||
DAC_DMA_LINK_RECURSIVE = BIT(1), /*!< The link is recursive. */
|
||||
} dac_dma_link_type_t;
|
||||
|
||||
/**
|
||||
* @brief DAC digital controller (DMA mode) configuration parameters.
|
||||
*/
|
||||
@ -70,6 +49,6 @@ typedef struct {
|
||||
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 __attribute__((deprecated));
|
||||
} dac_digi_config_t;
|
||||
|
||||
#endif //CONFIG_IDF_TARGET_ESP32S2
|
||||
|
@ -688,7 +688,6 @@ components/freertos/FreeRTOS-Kernel-SMP/stream_buffer.c
|
||||
components/freertos/FreeRTOS-Kernel-SMP/tasks.c
|
||||
components/freertos/FreeRTOS-Kernel-SMP/timers.c
|
||||
components/hal/aes_hal.c
|
||||
components/hal/dac_hal.c
|
||||
components/hal/ds_hal.c
|
||||
components/hal/esp32/include/hal/aes_ll.h
|
||||
components/hal/esp32/include/hal/mpu_ll.h
|
||||
@ -717,7 +716,6 @@ components/hal/esp32h2/include/hal/uhci_ll.h
|
||||
components/hal/esp32h2/include/hal/uhci_types.h
|
||||
components/hal/esp32h2/include/hal/usb_serial_jtag_ll.h
|
||||
components/hal/esp32s2/include/hal/crypto_dma_ll.h
|
||||
components/hal/esp32s2/include/hal/dac_ll.h
|
||||
components/hal/esp32s2/include/hal/dedic_gpio_ll.h
|
||||
components/hal/esp32s2/include/hal/mpu_ll.h
|
||||
components/hal/esp32s2/include/hal/sha_ll.h
|
||||
|
Loading…
Reference in New Issue
Block a user