dac: driver-ng framework

This commit is contained in:
laokaiyao 2022-05-09 17:33:51 +08:00
parent 9777c9d5b1
commit 351a18415c
26 changed files with 1684 additions and 614 deletions

View File

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

View File

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

View File

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

View File

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

View 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

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

View 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

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

View File

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

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

View File

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

View 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

View 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

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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