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() endif()
if(CONFIG_SOC_TOUCH_SENSOR_SUPPORTED) 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() endif()
if(CONFIG_SOC_SDIO_SLAVE_SUPPORTED) if(CONFIG_SOC_SDIO_SLAVE_SUPPORTED)
@@ -107,14 +114,12 @@ if(CONFIG_SOC_SDIO_SLAVE_SUPPORTED)
endif() endif()
if(${target} STREQUAL "esp32") if(${target} STREQUAL "esp32")
list(APPEND srcs "dac_common.c" list(APPEND srcs "deprecated/adc_i2s_deprecated.c"
"deprecated/adc_i2s_deprecated.c" "deprecated/esp32/dac_legacy.c")
"esp32/dac.c")
endif() endif()
if(${target} STREQUAL "esp32s2") if(${target} STREQUAL "esp32s2")
list(APPEND srcs "dac_common.c" list(APPEND srcs "deprecated/esp32s2/dac_legacy.c")
"esp32s2/dac.c")
endif() endif()
if(BOOTLOADER_BUILD) 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. Note that, this option only controls the I2S driver log, will not affect other drivers.
endmenu # I2S Configuration 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 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 "driver/dac.h"
#include "soc/dac_periph.h" #include "soc/dac_periph.h"
#include "hal/dac_hal.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. 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"); ESP_RETURN_ON_FALSE(cw, ESP_ERR_INVALID_ARG, TAG, "invalid clock configuration");
portENTER_CRITICAL(&rtc_spinlock); 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); portEXIT_CRITICAL(&rtc_spinlock);
return ESP_OK; return ESP_OK;

View File

@@ -13,7 +13,7 @@ extern "C" {
#include <stdint.h> #include <stdint.h>
#include "esp_err.h" #include "esp_err.h"
#include "driver/gpio.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. * @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/brownout_hal.c"
"esp32s2/cp_dma_hal.c" "esp32s2/cp_dma_hal.c"
"esp32s2/touch_sensor_hal.c" "esp32s2/touch_sensor_hal.c"
"esp32s2/dac_hal.c"
"usb_dwc_hal.c") "usb_dwc_hal.c")
endif() endif()

View File

@@ -1,24 +1,16 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD /*
// * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
// Licensed under the Apache License, Version 2.0 (the "License"); *
// you may not use this file except in compliance with the License. * SPDX-License-Identifier: Apache-2.0
// You may obtain a copy of the License at */
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "hal/dac_hal.h" // #include "hal/dac_hal.h"
void dac_hal_cw_generator_config(dac_cw_config_t *cw) // void dac_hal_cw_generator_config(dac_cw_config_t *cw)
{ // {
dac_ll_cw_set_freq(cw->freq); // dac_ll_cw_set_freq(cw->freq);
dac_ll_cw_set_scale(cw->en_ch, cw->scale); // dac_ll_cw_set_scale(cw->en_ch, cw->scale);
dac_ll_cw_set_phase(cw->en_ch, cw->phase); // 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_dc_offset(cw->en_ch, cw->offset);
dac_ll_cw_set_channel(cw->en_ch, true); // 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 channel DAC channel num.
* @param scale The multiple of the amplitude. The max amplitude is VDD3P3_RTC. * @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) { if (channel == DAC_CHANNEL_1) {
SENS.sar_dac_ctrl2.dac_scale1 = scale; 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 channel DAC channel num.
* @param scale Phase value. * @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) { if (channel == DAC_CHANNEL_1) {
SENS.sar_dac_ctrl2.dac_inv1 = phase; 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) void dac_hal_digi_controller_configure(const dac_hal_ctrl_config_t *cfg)
{ {
dac_ll_digi_clk_inv(true); 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); 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_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); 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) 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); 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_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); 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; return DPORT_CRYPTO_DMA_CLK_EN | DPORT_CRYPTO_SHA_CLK_EN;
case PERIPH_AES_DMA_MODULE: case PERIPH_AES_DMA_MODULE:
return DPORT_CRYPTO_DMA_CLK_EN | DPORT_CRYPTO_AES_CLK_EN; return DPORT_CRYPTO_DMA_CLK_EN | DPORT_CRYPTO_AES_CLK_EN;
case PERIPH_SARADC_MODULE:
return DPORT_APB_SARADC_CLK_EN_M;
default: default:
return 0; 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 channel DAC channel num.
* @param scale The multiple of the amplitude. The max amplitude is VDD3P3_RTC. * @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) { if (channel == DAC_CHANNEL_1) {
SENS.sar_dac_ctrl2.dac_scale1 = scale; 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 channel DAC channel num.
* @param scale Phase value. * @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) { if (channel == DAC_CHANNEL_1) {
SENS.sar_dac_ctrl2.dac_inv1 = phase; 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``. * @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 = is_alternate;
APB_SARADC.apb_dac_ctrl.apb_dac_alter_mode = 0;
} else {
APB_SARADC.apb_dac_ctrl.apb_dac_alter_mode = 1;
}
} }
/** /**

View File

@@ -13,6 +13,7 @@
#pragma once #pragma once
#include "hal/dac_ll.h" #include "hal/dac_ll.h"
#include "hal/dac_types.h"
/** /**
* Power on dac module and start output voltage. * Power on dac module and start output voltage.
@@ -62,7 +63,7 @@
* *
* @param cw Configuration. * @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. * 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_180 = 0x3, /*!< Phase shift +180° */
} dac_cw_phase_t; } 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 #if CONFIG_IDF_TARGET_ESP32S2
/** /**
@@ -48,17 +36,8 @@ typedef struct {
typedef enum { typedef enum {
DAC_CONV_NORMAL, /*!< The data in the DMA buffer is simultaneously output to the enable channel of the DAC. */ 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_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; } 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. * @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. */ 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``. 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. */ 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 #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/tasks.c
components/freertos/FreeRTOS-Kernel-SMP/timers.c components/freertos/FreeRTOS-Kernel-SMP/timers.c
components/hal/aes_hal.c components/hal/aes_hal.c
components/hal/dac_hal.c
components/hal/ds_hal.c components/hal/ds_hal.c
components/hal/esp32/include/hal/aes_ll.h components/hal/esp32/include/hal/aes_ll.h
components/hal/esp32/include/hal/mpu_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/uhci_types.h
components/hal/esp32h2/include/hal/usb_serial_jtag_ll.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/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/dedic_gpio_ll.h
components/hal/esp32s2/include/hal/mpu_ll.h components/hal/esp32s2/include/hal/mpu_ll.h
components/hal/esp32s2/include/hal/sha_ll.h components/hal/esp32s2/include/hal/sha_ll.h