mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
Merge branch 'refactor/dac_ll_sintx' into 'master'
refactor(dac): rename LL APIs and introduce sintx manager See merge request espressif/esp-idf!51995
This commit is contained in:
@@ -36,7 +36,7 @@ static _Atomic dac_channel_fsm_t s_dac_chan_fsm[SOC_DAC_CHAN_NUM] = {
|
||||
[0 ... SOC_DAC_CHAN_NUM - 1] = DAC_CHAN_FSM_IDLE,
|
||||
};
|
||||
|
||||
esp_err_t dac_priv_register_channel(dac_channel_t chan_id)
|
||||
esp_err_t dac_priv_channel_register(dac_channel_t chan_id)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(IS_VALID_DAC_CHANNEL(chan_id), ESP_ERR_INVALID_ARG, TAG, "channel id is invalid");
|
||||
|
||||
@@ -49,7 +49,7 @@ esp_err_t dac_priv_register_channel(dac_channel_t chan_id)
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t dac_priv_deregister_channel(dac_channel_t chan_id)
|
||||
esp_err_t dac_priv_channel_deregister(dac_channel_t chan_id)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(IS_VALID_DAC_CHANNEL(chan_id), ESP_ERR_INVALID_ARG, TAG, "channel id is invalid");
|
||||
|
||||
@@ -62,7 +62,7 @@ esp_err_t dac_priv_deregister_channel(dac_channel_t chan_id)
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t dac_priv_enable_channel(dac_channel_t chan_id)
|
||||
esp_err_t dac_priv_channel_enable(dac_channel_t chan_id, dac_data_source_t source)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(IS_VALID_DAC_CHANNEL(chan_id), ESP_ERR_INVALID_ARG, TAG, "channel id is invalid");
|
||||
|
||||
@@ -71,8 +71,9 @@ esp_err_t dac_priv_enable_channel(dac_channel_t chan_id)
|
||||
gpio_num_t gpio_num = (gpio_num_t)dac_periph_signal.dac_channel_io_num[chan_id];
|
||||
gpio_config_as_analog(gpio_num);
|
||||
DAC_ENTER_CRITICAL();
|
||||
dac_ll_power_on(chan_id);
|
||||
dac_ll_rtc_sync_by_adc(false);
|
||||
dac_ll_pad_set_data_source(chan_id, source);
|
||||
dac_ll_sync_by_adc(false);
|
||||
dac_ll_pad_power_on(chan_id);
|
||||
DAC_EXIT_CRITICAL();
|
||||
atomic_store(&s_dac_chan_fsm[chan_id], DAC_CHAN_FSM_ENABLED);
|
||||
return ESP_OK;
|
||||
@@ -82,14 +83,14 @@ esp_err_t dac_priv_enable_channel(dac_channel_t chan_id)
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t dac_priv_disable_channel(dac_channel_t chan_id)
|
||||
esp_err_t dac_priv_channel_disable(dac_channel_t chan_id)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(IS_VALID_DAC_CHANNEL(chan_id), ESP_ERR_INVALID_ARG, TAG, "channel id is invalid");
|
||||
|
||||
dac_channel_fsm_t expected_fsm = DAC_CHAN_FSM_ENABLED;
|
||||
if (atomic_compare_exchange_strong(&s_dac_chan_fsm[chan_id], &expected_fsm, DAC_CHAN_FSM_WAIT)) {
|
||||
DAC_ENTER_CRITICAL();
|
||||
dac_ll_power_down(chan_id);
|
||||
dac_ll_pad_power_down(chan_id);
|
||||
DAC_EXIT_CRITICAL();
|
||||
atomic_store(&s_dac_chan_fsm[chan_id], DAC_CHAN_FSM_REGISTERED);
|
||||
return ESP_OK;
|
||||
@@ -99,6 +100,141 @@ esp_err_t dac_priv_disable_channel(dac_channel_t chan_id)
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Cosine (Sintx) generator management
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* The cosine wave generator is a single shared resource: every channel that outputs a cosine wave
|
||||
* uses the same generator, and therefore the same frequency. On some targets, the same Sintx generator
|
||||
* also serves the direct (DC) software output. The tone and DC modes are mutually exclusive there.
|
||||
* This manager reference counts the generator, enforces the mode exclusion and the single shared
|
||||
* frequency.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
DAC_SINTX_MODE_TONE = 0, /* cosine wave output */
|
||||
#if SOC_DAC_DC_VIA_SINTX
|
||||
DAC_SINTX_MODE_DC, /* direct (DC) software output */
|
||||
#endif
|
||||
} dac_sintx_mode_t;
|
||||
|
||||
typedef struct {
|
||||
dac_sintx_mode_t mode;
|
||||
uint32_t ref_cnt;
|
||||
uint32_t freq;
|
||||
} dac_sintx_state_t;
|
||||
|
||||
static dac_sintx_state_t s_dac_sintx_state;
|
||||
|
||||
typedef struct {
|
||||
#if SOC_DAC_SINTX_HAS_TIMER_TARGET
|
||||
uint32_t timer_target;
|
||||
#endif
|
||||
uint32_t fstep;
|
||||
} dac_sintx_freq_hw_t;
|
||||
|
||||
/* Due to frequency aliasing, fstep values above the Nyquist limit (2^16)/2, are effectively invalid */
|
||||
#define DAC_SINTX_FSTEP_MAX 0x8000
|
||||
|
||||
/**
|
||||
* @brief Compute Sintx hardware frequency parameters from the requested tone frequency.
|
||||
*/
|
||||
static __attribute__((const)) dac_sintx_freq_hw_t dac_priv_sintx_calc_freq(uint32_t freq_hz, uint32_t clk_freq_hz)
|
||||
{
|
||||
#if SOC_DAC_SINTX_HAS_TIMER_TARGET
|
||||
#error "Not implemented"
|
||||
#else
|
||||
/* freq = clk * fstep / 2^16 */
|
||||
uint64_t fstep = DAC_DIV_ROUND((uint64_t)freq_hz << 16, clk_freq_hz);
|
||||
return (dac_sintx_freq_hw_t) {
|
||||
.fstep = DAC_CLAMP(fstep, 1, DAC_SINTX_FSTEP_MAX),
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void dac_priv_sintx_apply_freq(dac_sintx_freq_hw_t hw)
|
||||
{
|
||||
#if SOC_DAC_SINTX_HAS_TIMER_TARGET
|
||||
dac_ll_cw_set_timer_target(hw.timer_target);
|
||||
#endif
|
||||
dac_ll_cw_set_fstep(hw.fstep);
|
||||
}
|
||||
|
||||
esp_err_t dac_priv_sintx_acquire_tone(uint32_t freq_hz, uint32_t clk_freq_hz, bool force_set_freq)
|
||||
{
|
||||
dac_sintx_freq_hw_t hw_freq = dac_priv_sintx_calc_freq(freq_hz, clk_freq_hz);
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
DAC_ENTER_CRITICAL();
|
||||
if (s_dac_sintx_state.ref_cnt == 0) {
|
||||
// We are the first user. Lock the generator in tone mode and start the generator.
|
||||
s_dac_sintx_state.ref_cnt = 1;
|
||||
s_dac_sintx_state.mode = DAC_SINTX_MODE_TONE;
|
||||
s_dac_sintx_state.freq = freq_hz;
|
||||
|
||||
dac_priv_sintx_apply_freq(hw_freq);
|
||||
dac_ll_cw_enable_tone();
|
||||
} else if (s_dac_sintx_state.mode != DAC_SINTX_MODE_TONE) {
|
||||
// The generator is busy in other mode. Conflict.
|
||||
ret = ESP_ERR_INVALID_STATE;
|
||||
} else if (s_dac_sintx_state.freq == freq_hz) {
|
||||
// Other users already requested the same frequency. Just ride it.
|
||||
s_dac_sintx_state.ref_cnt++;
|
||||
} else if (force_set_freq) {
|
||||
// Re-program the frequency.
|
||||
s_dac_sintx_state.ref_cnt++;
|
||||
s_dac_sintx_state.freq = freq_hz;
|
||||
|
||||
dac_ll_cw_disable();
|
||||
dac_priv_sintx_apply_freq(hw_freq);
|
||||
dac_ll_cw_enable_tone();
|
||||
} else {
|
||||
// Other users already requested a different frequency. Conflict.
|
||||
ret = ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
DAC_EXIT_CRITICAL();
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if SOC_DAC_DC_VIA_SINTX
|
||||
esp_err_t dac_priv_sintx_acquire_dc(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
DAC_ENTER_CRITICAL();
|
||||
if (s_dac_sintx_state.ref_cnt == 0) {
|
||||
// We are the first user. Lock the generator in DC mode and start the generator.
|
||||
s_dac_sintx_state.ref_cnt = 1;
|
||||
s_dac_sintx_state.mode = DAC_SINTX_MODE_DC;
|
||||
dac_ll_cw_enable_dc();
|
||||
} else if (s_dac_sintx_state.mode == DAC_SINTX_MODE_DC) {
|
||||
// Other users already requested the DC mode. Just ride it.
|
||||
s_dac_sintx_state.ref_cnt++;
|
||||
} else {
|
||||
// Other users already requested the cosine mode. Conflict.
|
||||
ret = ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
DAC_EXIT_CRITICAL();
|
||||
return ret;
|
||||
}
|
||||
#endif // SOC_DAC_DC_VIA_SINTX
|
||||
|
||||
esp_err_t dac_priv_sintx_release(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
DAC_ENTER_CRITICAL();
|
||||
if (s_dac_sintx_state.ref_cnt > 0) {
|
||||
s_dac_sintx_state.ref_cnt--;
|
||||
if (s_dac_sintx_state.ref_cnt == 0) {
|
||||
// We are the last user. Stop the generator.
|
||||
dac_ll_cw_disable();
|
||||
}
|
||||
} else {
|
||||
ret = ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
DAC_EXIT_CRITICAL();
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if CONFIG_DAC_ENABLE_DEBUG_LOG
|
||||
__attribute__((constructor))
|
||||
static void dac_override_default_log_level(void)
|
||||
|
||||
@@ -219,7 +219,7 @@ esp_err_t dac_continuous_new_channels(const dac_continuous_config_t *cont_cfg, d
|
||||
/* Register the channels */
|
||||
dac_channel_mask_t registered_chan_mask = 0;
|
||||
DAC_CHANNEL_MASK_FOREACH(chan, cont_cfg->chan_mask) {
|
||||
ESP_GOTO_ON_ERROR(dac_priv_register_channel(chan), err_dereg, TAG, "register dac channel %"PRIu32" failed", chan);
|
||||
ESP_GOTO_ON_ERROR(dac_priv_channel_register(chan), err_dereg, TAG, "register dac channel %"PRIu32" failed", chan);
|
||||
registered_chan_mask |= BIT(chan);
|
||||
}
|
||||
|
||||
@@ -258,11 +258,6 @@ esp_err_t dac_continuous_new_channels(const dac_continuous_config_t *cont_cfg, d
|
||||
ESP_GOTO_ON_ERROR(dac_priv_dma_init(handle->cfg.clk_src, handle->cfg.freq_hz, handle->cfg.chan_mode == DAC_CHANNEL_MODE_ALTER, &cbs, handle),
|
||||
err_desc, TAG, "Failed to initialize DAC DMA peripheral");
|
||||
|
||||
/* Connect DAC module to the DMA peripheral */
|
||||
DAC_ENTER_CRITICAL();
|
||||
dac_ll_digi_enable_dma(true);
|
||||
DAC_EXIT_CRITICAL();
|
||||
|
||||
/* FSM: WAIT -> REGISTERED */
|
||||
atomic_store(&s_dac_cont_fsm, DAC_CONT_FSM_REGISTERED);
|
||||
|
||||
@@ -287,7 +282,7 @@ err_free:
|
||||
err_dereg:
|
||||
/* Deregister registered channels */
|
||||
DAC_CHANNEL_MASK_FOREACH(chan, registered_chan_mask) {
|
||||
dac_priv_deregister_channel(chan);
|
||||
dac_priv_channel_deregister(chan);
|
||||
}
|
||||
/* FSM: WAIT -> IDLE */
|
||||
atomic_store(&s_dac_cont_fsm, DAC_CONT_FSM_IDLE);
|
||||
@@ -308,11 +303,6 @@ esp_err_t dac_continuous_del_channels(dac_continuous_handle_t handle)
|
||||
/* Deinitialize DMA peripheral */
|
||||
ESP_RETURN_ON_ERROR(dac_priv_dma_deinit(), TAG, "Failed to deinitialize DAC DMA peripheral");
|
||||
|
||||
/* Disconnect DAC module from the DMA peripheral */
|
||||
DAC_ENTER_CRITICAL();
|
||||
dac_ll_digi_enable_dma(false);
|
||||
DAC_EXIT_CRITICAL();
|
||||
|
||||
/* Free allocated resources */
|
||||
s_dac_free_dma_desc(handle);
|
||||
|
||||
@@ -334,7 +324,7 @@ esp_err_t dac_continuous_del_channels(dac_continuous_handle_t handle)
|
||||
|
||||
/* Deregister the channels */
|
||||
DAC_CHANNEL_MASK_FOREACH(chan, handle->cfg.chan_mask) {
|
||||
dac_priv_deregister_channel(chan);
|
||||
dac_priv_channel_deregister(chan);
|
||||
}
|
||||
|
||||
free(handle);
|
||||
@@ -386,14 +376,10 @@ esp_err_t dac_continuous_enable(dac_continuous_handle_t handle)
|
||||
#endif
|
||||
|
||||
DAC_CHANNEL_MASK_FOREACH(chan, handle->cfg.chan_mask) {
|
||||
dac_priv_enable_channel(chan);
|
||||
dac_priv_channel_enable(chan, DAC_DATA_SOURCE_DMA);
|
||||
}
|
||||
dac_priv_dma_enable();
|
||||
|
||||
DAC_ENTER_CRITICAL();
|
||||
dac_ll_digi_enable_dma(true);
|
||||
DAC_EXIT_CRITICAL();
|
||||
|
||||
/* FSM: WAIT -> ENABLED */
|
||||
atomic_store(&s_dac_cont_fsm, DAC_CONT_FSM_ENABLED);
|
||||
return ESP_OK;
|
||||
@@ -421,12 +407,8 @@ esp_err_t dac_continuous_disable(dac_continuous_handle_t handle)
|
||||
|
||||
dac_priv_dma_disable();
|
||||
|
||||
DAC_ENTER_CRITICAL();
|
||||
dac_ll_digi_enable_dma(false);
|
||||
DAC_EXIT_CRITICAL();
|
||||
|
||||
DAC_CHANNEL_MASK_FOREACH(chan, handle->cfg.chan_mask) {
|
||||
dac_priv_disable_channel(chan);
|
||||
dac_priv_channel_disable(chan);
|
||||
}
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_release(handle->pm_lock);
|
||||
|
||||
@@ -4,26 +4,36 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <string.h>
|
||||
#include "dac_priv_common.h"
|
||||
#include "driver/dac_cosine.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "hal/dac_ll.h"
|
||||
#include "esp_clk_tree.h"
|
||||
#include "esp_private/esp_clk_tree_common.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
typedef enum {
|
||||
DAC_COS_FSM_REGISTERED,
|
||||
DAC_COS_FSM_ENABLED,
|
||||
DAC_COS_FSM_WAIT,
|
||||
} dac_cosine_fsm_t;
|
||||
|
||||
struct dac_cosine_s {
|
||||
dac_cosine_config_t cfg; /*!< Cosine mode configurations */
|
||||
bool is_started; /*!< Flag: is the channel started(not cosine wave generator) */
|
||||
dac_cosine_config_t cfg; /*!< Cosine mode configurations */
|
||||
_Atomic dac_cosine_fsm_t fsm; /*!< FSM state */
|
||||
};
|
||||
|
||||
/* Cosine wave generator reference count
|
||||
* The cosine wave generator is shared by dac channels */
|
||||
static uint32_t s_cwg_refer_cnt = 0;
|
||||
|
||||
/* The frequency of cosine wave generator */
|
||||
static uint32_t s_cwg_freq = 0;
|
||||
static bool dac_cosine_clk_src_is_supported(dac_cosine_clk_src_t clk_src)
|
||||
{
|
||||
const dac_cosine_clk_src_t supported[] = SOC_DAC_COSINE_CLKS;
|
||||
for (size_t i = 0; i < sizeof(supported) / sizeof(supported[0]); i++) {
|
||||
if (clk_src == supported[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
esp_err_t dac_cosine_new_channel(const dac_cosine_config_t *cos_cfg, dac_cosine_handle_t *ret_handle)
|
||||
{
|
||||
@@ -31,45 +41,68 @@ esp_err_t dac_cosine_new_channel(const dac_cosine_config_t *cos_cfg, dac_cosine_
|
||||
DAC_NULL_POINTER_CHECK(cos_cfg);
|
||||
DAC_NULL_POINTER_CHECK(ret_handle);
|
||||
ESP_RETURN_ON_FALSE(IS_VALID_DAC_CHANNEL(cos_cfg->chan_id), ESP_ERR_INVALID_ARG, TAG, "invalid dac channel id");
|
||||
ESP_RETURN_ON_FALSE(cos_cfg->freq_hz >= (130 / clk_ll_rc_fast_get_divider()), ESP_ERR_NOT_SUPPORTED, TAG, "The cosine wave frequency is too low");
|
||||
ESP_RETURN_ON_FALSE((!s_cwg_freq) || cos_cfg->flags.force_set_freq || (cos_cfg->freq_hz == s_cwg_freq),
|
||||
ESP_ERR_INVALID_STATE, TAG, "The cosine wave frequency has set already, not allowed to update unless `force_set_freq` is set");
|
||||
ESP_RETURN_ON_FALSE(cos_cfg->freq_hz > 0, ESP_ERR_INVALID_ARG, TAG, "invalid cosine wave frequency");
|
||||
|
||||
dac_cosine_clk_src_t clk_src = cos_cfg->clk_src ? : DAC_COSINE_CLK_SRC_DEFAULT;
|
||||
ESP_RETURN_ON_FALSE(dac_cosine_clk_src_is_supported(clk_src), ESP_ERR_INVALID_ARG, TAG, "invalid DAC cosine clock source");
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
/* Allocate cosine handle */
|
||||
dac_cosine_handle_t handle = heap_caps_calloc(1, sizeof(struct dac_cosine_s), DAC_MEM_ALLOC_CAPS);
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_NO_MEM, TAG, "no memory for the dac cosine handle");
|
||||
/* Assign configurations */
|
||||
handle->cfg = *cos_cfg;
|
||||
if (handle->cfg.clk_src == 0) {
|
||||
handle->cfg.clk_src = DAC_COSINE_CLK_SRC_DEFAULT;
|
||||
}
|
||||
/* Register the handle */
|
||||
ESP_GOTO_ON_ERROR(dac_priv_register_channel(handle->cfg.chan_id), err1, TAG, "register dac channel %d failed", handle->cfg.chan_id);
|
||||
handle->cfg.clk_src = clk_src;
|
||||
atomic_store(&handle->fsm, DAC_COS_FSM_REGISTERED);
|
||||
|
||||
/* Get the cosine wave generator clock frequency */
|
||||
uint32_t rtc_clk_freq = 0;
|
||||
esp_clk_tree_src_get_freq_hz((soc_module_clk_t)handle->cfg.clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &rtc_clk_freq);
|
||||
/* Acquire the generator clock and resolve its frequency */
|
||||
uint32_t clk_freq = 0;
|
||||
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)handle->cfg.clk_src, true), err_handle, TAG, "enable clock failed");
|
||||
ESP_GOTO_ON_ERROR(esp_clk_tree_src_get_freq_hz((soc_module_clk_t)handle->cfg.clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_freq),
|
||||
err_clk, TAG, "get clock frequency failed");
|
||||
|
||||
if (rtc_clk_freq == 0) {
|
||||
ESP_LOGW(TAG, "RTC clock calibration failed, using the approximate value as default");
|
||||
rtc_clk_freq = SOC_CLK_RC_FAST_FREQ_APPROX;
|
||||
ESP_GOTO_ON_ERROR(dac_priv_channel_register(cos_cfg->chan_id), err_clk, TAG, "register dac channel %d failed", cos_cfg->chan_id);
|
||||
|
||||
/* Claim the shared cosine wave generator in tone mode and program the wave frequency (this also
|
||||
* starts the generator). Rejected if the direct-output path is in use or a different frequency
|
||||
* is already set. */
|
||||
ESP_GOTO_ON_ERROR(dac_priv_sintx_acquire_tone(cos_cfg->freq_hz, clk_freq, cos_cfg->flags.force_set_freq), err_dereg, TAG, "acquire cosine wave generator failed");
|
||||
|
||||
int16_t offset = cos_cfg->offset;
|
||||
if (cos_cfg->phase == DAC_COSINE_PHASE_180) {
|
||||
offset = -offset;
|
||||
}
|
||||
#if SOC_DAC_SINTX_LUT_SIGNED
|
||||
#error "not implemented"
|
||||
#else
|
||||
const int16_t base_offset = 0;
|
||||
/* Hardware DC register is signed: -128~127 */
|
||||
const int16_t min_offset = -128, max_offset = 127;
|
||||
#endif
|
||||
if (offset < min_offset || offset > max_offset) {
|
||||
/* User-facing range: phase 0° → [min-B, max-B]; phase 180° → [B-max, B-min] */
|
||||
const int16_t min_user = (cos_cfg->phase == DAC_COSINE_PHASE_0) ? (min_offset - base_offset) : (base_offset - max_offset);
|
||||
const int16_t max_user = min_user + (max_offset - min_offset);
|
||||
ESP_LOGW(TAG, "DAC cosine DC offset %d out of range [%d, %d], saturating",
|
||||
cos_cfg->offset, min_user, max_user);
|
||||
offset = (offset < min_offset) ? min_offset : max_offset;
|
||||
}
|
||||
|
||||
/* Set the per-channel cosine wave parameters. */
|
||||
DAC_ENTER_CRITICAL();
|
||||
/* Set coefficients for cosine wave generator */
|
||||
if ((!s_cwg_freq) || handle->cfg.flags.force_set_freq) {
|
||||
dac_ll_cw_set_freq(handle->cfg.freq_hz, rtc_clk_freq);
|
||||
s_cwg_freq = handle->cfg.freq_hz;
|
||||
}
|
||||
dac_ll_cw_set_atten(handle->cfg.chan_id, handle->cfg.atten);
|
||||
dac_ll_cw_set_phase(handle->cfg.chan_id, handle->cfg.phase);
|
||||
dac_ll_cw_set_dc_offset(handle->cfg.chan_id, handle->cfg.offset);
|
||||
dac_ll_cw_set_offset(handle->cfg.chan_id, offset);
|
||||
DAC_EXIT_CRITICAL();
|
||||
|
||||
*ret_handle = handle;
|
||||
return ret;
|
||||
return ESP_OK;
|
||||
|
||||
err1:
|
||||
err_dereg:
|
||||
dac_priv_channel_deregister(cos_cfg->chan_id);
|
||||
err_clk:
|
||||
esp_clk_tree_enable_src((soc_module_clk_t)handle->cfg.clk_src, false);
|
||||
err_handle:
|
||||
free(handle);
|
||||
return ret;
|
||||
}
|
||||
@@ -77,15 +110,15 @@ err1:
|
||||
esp_err_t dac_cosine_del_channel(dac_cosine_handle_t handle)
|
||||
{
|
||||
DAC_NULL_POINTER_CHECK(handle);
|
||||
ESP_RETURN_ON_FALSE(!handle->is_started, ESP_ERR_INVALID_STATE, TAG,
|
||||
"the dac cosine generator is not stopped yet");
|
||||
|
||||
ESP_RETURN_ON_ERROR(dac_priv_deregister_channel(handle->cfg.chan_id), TAG,
|
||||
dac_cosine_fsm_t expected_fsm = DAC_COS_FSM_REGISTERED;
|
||||
ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&handle->fsm, &expected_fsm, DAC_COS_FSM_WAIT),
|
||||
ESP_ERR_INVALID_STATE, TAG, "dac cosine is running");
|
||||
|
||||
ESP_RETURN_ON_ERROR(dac_priv_channel_deregister(handle->cfg.chan_id), TAG,
|
||||
"deregister dac channel %d failed", handle->cfg.chan_id);
|
||||
/* Clear the frequency if no channel using it */
|
||||
if (!s_cwg_refer_cnt) {
|
||||
s_cwg_freq = 0;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(dac_priv_sintx_release(), TAG, "release dac sintx generator failed");
|
||||
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)handle->cfg.clk_src, false), TAG, "disable clock failed");
|
||||
free(handle);
|
||||
|
||||
return ESP_OK;
|
||||
@@ -93,56 +126,42 @@ esp_err_t dac_cosine_del_channel(dac_cosine_handle_t handle)
|
||||
|
||||
esp_err_t dac_cosine_start(dac_cosine_handle_t handle)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
DAC_NULL_POINTER_CHECK(handle);
|
||||
ESP_RETURN_ON_FALSE(!handle->is_started, ESP_ERR_INVALID_STATE, TAG,
|
||||
"the dac channel has already started");
|
||||
/* Acquire the cosine wave generator clock */
|
||||
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)handle->cfg.clk_src, true), TAG, "cosine clock enable failed");
|
||||
/* Enabled DAC channel */
|
||||
ESP_GOTO_ON_ERROR(dac_priv_enable_channel(handle->cfg.chan_id), err, TAG,
|
||||
"enable dac channel %d failed", handle->cfg.chan_id);
|
||||
/* Enabled the cosine wave generator if no channel using it before */
|
||||
DAC_ENTER_CRITICAL();
|
||||
if (s_cwg_refer_cnt == 0) {
|
||||
dac_ll_cw_generator_enable();
|
||||
}
|
||||
/* Connect the DAC channel to the cosine wave generator */
|
||||
dac_ll_cw_enable_channel(handle->cfg.chan_id, true);
|
||||
s_cwg_refer_cnt++;
|
||||
handle->is_started = true;
|
||||
DAC_EXIT_CRITICAL();
|
||||
|
||||
dac_cosine_fsm_t expected_fsm = DAC_COS_FSM_REGISTERED;
|
||||
ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&handle->fsm, &expected_fsm, DAC_COS_FSM_WAIT),
|
||||
ESP_ERR_INVALID_STATE, TAG, "dac cosine already started");
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
/* The generator is already running; starting only powers on the pad so the wave reaches the output. */
|
||||
ESP_GOTO_ON_ERROR(dac_priv_channel_enable(handle->cfg.chan_id, DAC_DATA_SOURCE_COSINE), err,
|
||||
TAG, "enable dac channel %d failed", handle->cfg.chan_id);
|
||||
|
||||
atomic_store(&handle->fsm, DAC_COS_FSM_ENABLED);
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
esp_clk_tree_enable_src((soc_module_clk_t)handle->cfg.clk_src, false);
|
||||
atomic_store(&handle->fsm, DAC_COS_FSM_REGISTERED);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t dac_cosine_stop(dac_cosine_handle_t handle)
|
||||
{
|
||||
DAC_NULL_POINTER_CHECK(handle);
|
||||
ESP_RETURN_ON_FALSE(handle->is_started, ESP_ERR_INVALID_STATE, TAG,
|
||||
"the dac channel has already stopped");
|
||||
|
||||
/* Enabled DAC channel */
|
||||
ESP_RETURN_ON_ERROR(dac_priv_disable_channel(handle->cfg.chan_id), TAG,
|
||||
"disable dac channel %d failed", handle->cfg.chan_id);
|
||||
DAC_ENTER_CRITICAL();
|
||||
/* Disconnect the DAC channel from the cosine wave generator */
|
||||
dac_ll_cw_enable_channel(handle->cfg.chan_id, false);
|
||||
s_cwg_refer_cnt--;
|
||||
/* Disable the cosine wave generator if no channel using it */
|
||||
if (s_cwg_refer_cnt == 0) {
|
||||
dac_ll_cw_generator_disable();
|
||||
}
|
||||
handle->is_started = false;
|
||||
DAC_EXIT_CRITICAL();
|
||||
/* Release the cosine wave generator clock */
|
||||
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)handle->cfg.clk_src, false), TAG, "cosine clock disable failed");
|
||||
dac_cosine_fsm_t expected_fsm = DAC_COS_FSM_ENABLED;
|
||||
ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&handle->fsm, &expected_fsm, DAC_COS_FSM_WAIT),
|
||||
ESP_ERR_INVALID_STATE, TAG, "dac cosine already stopped");
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
/* Power off the pad; the generator keeps running */
|
||||
ESP_GOTO_ON_ERROR(dac_priv_channel_disable(handle->cfg.chan_id), err,
|
||||
TAG, "disable dac channel %d failed", handle->cfg.chan_id);
|
||||
|
||||
atomic_store(&handle->fsm, DAC_COS_FSM_REGISTERED);
|
||||
return ESP_OK;
|
||||
err:
|
||||
atomic_store(&handle->fsm, DAC_COS_FSM_ENABLED);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t dac_cosine_get_bitwidth(dac_cosine_handle_t handle)
|
||||
|
||||
@@ -29,14 +29,14 @@ esp_err_t dac_oneshot_new_channel(const dac_oneshot_config_t *oneshot_cfg, dac_o
|
||||
handle->cfg = *oneshot_cfg;
|
||||
|
||||
/* Register and enable the dac channel */
|
||||
ESP_GOTO_ON_ERROR(dac_priv_register_channel(oneshot_cfg->chan_id), err2, TAG, "register dac channel %d failed", oneshot_cfg->chan_id);
|
||||
ESP_GOTO_ON_ERROR(dac_priv_enable_channel(oneshot_cfg->chan_id), err1, TAG, "enable dac channel %d failed", oneshot_cfg->chan_id);
|
||||
ESP_GOTO_ON_ERROR(dac_priv_channel_register(oneshot_cfg->chan_id), err2, TAG, "register dac channel %d failed", oneshot_cfg->chan_id);
|
||||
ESP_GOTO_ON_ERROR(dac_priv_channel_enable(oneshot_cfg->chan_id, DAC_DATA_SOURCE_DIRECT), err1, TAG, "enable dac channel %d failed", oneshot_cfg->chan_id);
|
||||
|
||||
*ret_handle = handle;
|
||||
return ret;
|
||||
|
||||
err1:
|
||||
dac_priv_deregister_channel(oneshot_cfg->chan_id);
|
||||
dac_priv_channel_deregister(oneshot_cfg->chan_id);
|
||||
err2:
|
||||
free(handle);
|
||||
return ret;
|
||||
@@ -47,8 +47,8 @@ esp_err_t dac_oneshot_del_channel(dac_oneshot_handle_t handle)
|
||||
DAC_NULL_POINTER_CHECK(handle);
|
||||
|
||||
/* Disable and deregister the channel */
|
||||
ESP_RETURN_ON_ERROR(dac_priv_disable_channel(handle->cfg.chan_id), TAG, "disable dac channel %d failed", handle->cfg.chan_id);
|
||||
ESP_RETURN_ON_ERROR(dac_priv_deregister_channel(handle->cfg.chan_id), TAG, "deregister dac channel %d failed", handle->cfg.chan_id);
|
||||
ESP_RETURN_ON_ERROR(dac_priv_channel_disable(handle->cfg.chan_id), TAG, "disable dac channel %d failed", handle->cfg.chan_id);
|
||||
ESP_RETURN_ON_ERROR(dac_priv_channel_deregister(handle->cfg.chan_id), TAG, "deregister dac channel %d failed", handle->cfg.chan_id);
|
||||
|
||||
/* Free resources */
|
||||
free(handle);
|
||||
@@ -64,7 +64,7 @@ esp_err_t dac_oneshot_output_voltage(dac_oneshot_handle_t handle, uint8_t digi_v
|
||||
|
||||
/* Set the voltage by the digital value */
|
||||
DAC_ENTER_CRITICAL_SAFE();
|
||||
dac_ll_update_output_value(handle->cfg.chan_id, digi_value);
|
||||
dac_ll_pad_set_output_code(handle->cfg.chan_id, digi_value);
|
||||
DAC_EXIT_CRITICAL_SAFE();
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#endif
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "hal/dac_types.h"
|
||||
#include "hal/dac_types_private.h"
|
||||
#include "hal/dac_ll.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_err.h"
|
||||
@@ -56,6 +58,11 @@ extern portMUX_TYPE dac_priv_spinlock;
|
||||
#define DAC_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
||||
#endif
|
||||
|
||||
#define DAC_DIV_ROUND(n, d) (((n) + (d) / 2) / (d))
|
||||
#define DAC_DIV_CEIL(n, d) (((n) + (d) - 1) / (d))
|
||||
#define DAC_MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define DAC_CLAMP(x, min, max) ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x)))
|
||||
|
||||
/**
|
||||
* @brief Register dac channel in the driver, in case a same channel is reused by different modes
|
||||
*
|
||||
@@ -65,7 +72,7 @@ extern portMUX_TYPE dac_priv_spinlock;
|
||||
* - ESP_ERR_INVALID_ARG The channel id is incorrect
|
||||
* - ESP_OK Register the channel success
|
||||
*/
|
||||
esp_err_t dac_priv_register_channel(dac_channel_t chan_id);
|
||||
esp_err_t dac_priv_channel_register(dac_channel_t chan_id);
|
||||
|
||||
/**
|
||||
* @brief Deregister dac channel in the driver
|
||||
@@ -76,18 +83,19 @@ esp_err_t dac_priv_register_channel(dac_channel_t chan_id);
|
||||
* - ESP_ERR_INVALID_ARG The channel id is incorrect
|
||||
* - ESP_OK Deregister the channel success
|
||||
*/
|
||||
esp_err_t dac_priv_deregister_channel(dac_channel_t chan_id);
|
||||
esp_err_t dac_priv_channel_deregister(dac_channel_t chan_id);
|
||||
|
||||
/**
|
||||
* @brief Enable the DAC channel and turn on its power
|
||||
*
|
||||
* @param chan_id DAC channel id
|
||||
* @param source Channel data source
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_STATE The channel has not been registered or already enabled
|
||||
* - ESP_ERR_INVALID_ARG The channel id is incorrect
|
||||
* - ESP_OK Enable the channel success
|
||||
*/
|
||||
esp_err_t dac_priv_enable_channel(dac_channel_t chan_id);
|
||||
esp_err_t dac_priv_channel_enable(dac_channel_t chan_id, dac_data_source_t source);
|
||||
|
||||
/**
|
||||
* @brief Disable the DAC channel and turn off its power
|
||||
@@ -98,7 +106,56 @@ esp_err_t dac_priv_enable_channel(dac_channel_t chan_id);
|
||||
* - ESP_ERR_INVALID_ARG The channel id is incorrect
|
||||
* - ESP_OK Disable the channel success
|
||||
*/
|
||||
esp_err_t dac_priv_disable_channel(dac_channel_t chan_id);
|
||||
esp_err_t dac_priv_channel_disable(dac_channel_t chan_id);
|
||||
|
||||
/**
|
||||
* @brief Acquire the shared cosine wave (Sintx/tone) generator (reference counted)
|
||||
*
|
||||
* @note The cosine wave generator is a single shared resource: all DAC channels that output a
|
||||
* cosine wave share one generator (and thus one frequency). This claims the generator in tone
|
||||
* mode, programs the wave frequency, and starts the generator on the first acquire. The first
|
||||
* acquirer (or any acquirer passing `force_set_freq`) programs the frequency; a later acquirer
|
||||
* requesting a different frequency without `force_set_freq` is rejected. On targets where the
|
||||
* tone generator and the direct (DC) output share one Sintx generator, a tone acquire is also
|
||||
* rejected while the DC path is in use.
|
||||
*
|
||||
* @param[in] freq_hz The cosine wave frequency in Hz
|
||||
* @param[in] clk_freq_hz The clock frequency that drives the generator in Hz
|
||||
* @param[in] force_set_freq Force (re)programming the frequency even if the generator is in use
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_STATE The generator is busy on a conflicting mode or frequency
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t dac_priv_sintx_acquire_tone(uint32_t freq_hz, uint32_t clk_freq_hz, bool force_set_freq);
|
||||
|
||||
#if SOC_DAC_DC_VIA_SINTX
|
||||
/**
|
||||
* @brief Acquire the shared Sintx generator for the direct (DC) software output (reference counted)
|
||||
*
|
||||
* @note On some targets, the direct (DC) software output runs through the same Sintx generator as
|
||||
* the cosine wave output, so the two are mutually exclusive. This claims the generator in DC
|
||||
* mode and, on the first acquire, starts the Sintx timer that pushes the written DC value to
|
||||
* the pad.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_STATE The generator is busy on the cosine path
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t dac_priv_sintx_acquire_dc(void);
|
||||
#endif // SOC_DAC_DC_VIA_SINTX
|
||||
|
||||
/**
|
||||
* @brief Release the shared Sintx generator (reference counted)
|
||||
*
|
||||
* @note Releases one reference acquired by `dac_priv_sintx_acquire_tone()` or
|
||||
* `dac_priv_sintx_acquire_dc()`. The generator is stopped once the last reference is
|
||||
* released.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_STATE The generator is not in use
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t dac_priv_sintx_release(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "hal/adc_ll.h"
|
||||
#include "hal/dac_ll.h"
|
||||
#include "hal/i2s_hal.h"
|
||||
#include "hal/i2s_types.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
@@ -148,6 +149,7 @@ esp_err_t dac_priv_dma_init(soc_periph_dac_digi_clk_src_t clk_src, uint32_t freq
|
||||
|
||||
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true), err, TAG, "enable DAC digital clock source failed");
|
||||
s_ddp->clk_src = clk_src;
|
||||
dac_ll_dma_clk_inv(true);
|
||||
ESP_GOTO_ON_ERROR(s_dac_priv_dma_set_clock(clk_src, freq_hz), err, TAG, "Failed to set clock of DMA peripheral");
|
||||
|
||||
i2s_ll_enable_builtin_adc_dac(s_ddp->periph_dev, true);
|
||||
@@ -188,6 +190,7 @@ esp_err_t dac_priv_dma_deinit(void)
|
||||
}
|
||||
|
||||
if (s_ddp->clk_src) {
|
||||
dac_ll_dma_clk_inv(false);
|
||||
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)s_ddp->clk_src, false), TAG, "disable DAC digital clock source failed");
|
||||
s_ddp->clk_src = 0;
|
||||
}
|
||||
|
||||
@@ -139,8 +139,8 @@ static esp_err_t s_dac_priv_dma_set_clock(soc_periph_dac_digi_clk_src_t clk_src,
|
||||
hal_utils_calc_clk_div_frac_accurate(&adc_clk_info, &adc_clk_div);
|
||||
|
||||
/* Step 4: Set the clock coefficients */
|
||||
dac_ll_digi_clk_inv(true);
|
||||
dac_ll_digi_set_trigger_interval(interval); // secondary clock division
|
||||
dac_ll_dma_clk_inv(true);
|
||||
dac_ll_dma_set_timer_target(interval); // secondary clock division
|
||||
adc_ll_digi_controller_clk_div(adc_clk_div.integer - 1, adc_clk_div.denominator, adc_clk_div.numerator);
|
||||
adc_ll_digi_clk_sel((adc_continuous_clk_src_t)clk_src);
|
||||
return ESP_OK;
|
||||
@@ -174,7 +174,7 @@ esp_err_t dac_priv_dma_init(soc_periph_dac_digi_clk_src_t clk_src, uint32_t freq
|
||||
err, TAG, "Failed to allocate dma peripheral channel");
|
||||
s_ddp->dma_chan = spi_bus_get_dma_ctx(DAC_DMA_PERIPH_SPI_HOST)->rx_dma_chan.chan_id;
|
||||
spi_ll_enable_intr(s_ddp->periph_dev, SPI_LL_INTR_OUT_DONE | SPI_LL_INTR_OUT_TOTAL_EOF);
|
||||
dac_ll_digi_set_convert_mode(is_alternate);
|
||||
dac_ll_dma_enable_alternate_mode(is_alternate);
|
||||
|
||||
s_ddp->cbs = *cbs;
|
||||
s_ddp->ctx = ctx;
|
||||
@@ -211,6 +211,7 @@ esp_err_t dac_priv_dma_deinit(void)
|
||||
}
|
||||
|
||||
if (s_ddp->clk_src) {
|
||||
dac_ll_dma_clk_inv(false);
|
||||
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)s_ddp->clk_src, false), TAG, "disable DAC digital clock source failed");
|
||||
s_ddp->clk_src = 0;
|
||||
}
|
||||
@@ -224,12 +225,14 @@ static void s_dac_priv_dma_reset(void)
|
||||
{
|
||||
spi_ll_dma_tx_reset(s_ddp->periph_dev, s_ddp->dma_chan);
|
||||
spi_ll_dma_tx_fifo_reset(s_ddp->periph_dev);
|
||||
dac_ll_dma_reset_fifo();
|
||||
dac_ll_dma_reset_fsm();
|
||||
}
|
||||
|
||||
void dac_priv_dma_enable(void)
|
||||
{
|
||||
s_dac_priv_dma_reset();
|
||||
dac_ll_digi_trigger_output(true);
|
||||
dac_ll_dma_enable_timer(true);
|
||||
esp_intr_enable(s_ddp->intr_handle);
|
||||
}
|
||||
|
||||
@@ -237,7 +240,7 @@ void dac_priv_dma_disable(void)
|
||||
{
|
||||
s_dac_priv_dma_reset();
|
||||
spi_ll_dma_tx_stop(s_ddp->periph_dev, s_ddp->dma_chan);
|
||||
dac_ll_digi_trigger_output(false);
|
||||
dac_ll_dma_enable_timer(false);
|
||||
esp_intr_disable(s_ddp->intr_handle);
|
||||
}
|
||||
|
||||
@@ -245,6 +248,7 @@ void dac_priv_dma_trans_start(uintptr_t desc_addr)
|
||||
{
|
||||
spi_ll_dma_tx_reset(s_ddp->periph_dev, s_ddp->dma_chan);
|
||||
spi_ll_dma_tx_fifo_reset(s_ddp->periph_dev);
|
||||
dac_ll_dma_reset_fifo();
|
||||
spi_ll_dma_tx_start(s_ddp->periph_dev, s_ddp->dma_chan, (lldesc_t *)desc_addr);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2019-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -181,25 +181,25 @@ static void s_disable_dac(adc_oneshot_hal_ctx_t *hal, adc_channel_t channel)
|
||||
* If enabled(default), ADC RTC controller sampling will cause the DAC channel output voltage.
|
||||
*/
|
||||
if (hal->unit == ADC_UNIT_1) {
|
||||
dac_ll_rtc_sync_by_adc(false);
|
||||
dac_ll_sync_by_adc(false);
|
||||
}
|
||||
|
||||
#if SOC_IS(ESP32)
|
||||
if (hal->unit == ADC_UNIT_2) {
|
||||
if (channel == ADC_CHANNEL_8) {
|
||||
dac_ll_power_down(DAC_CHAN_0); // the same as DAC channel 0
|
||||
dac_ll_pad_power_down(DAC_CHAN_0); // the same as DAC channel 0
|
||||
}
|
||||
if (channel == ADC_CHANNEL_9) {
|
||||
dac_ll_power_down(DAC_CHAN_1);
|
||||
dac_ll_pad_power_down(DAC_CHAN_1);
|
||||
}
|
||||
}
|
||||
#elif SOC_IS(ESP32S2)
|
||||
if (hal->unit == ADC_UNIT_2) {
|
||||
if (channel == ADC_CHANNEL_6) {
|
||||
dac_ll_power_down(DAC_CHAN_0); // the same as DAC channel 0
|
||||
dac_ll_pad_power_down(DAC_CHAN_0); // the same as DAC channel 0
|
||||
}
|
||||
if (channel == ADC_CHANNEL_7) {
|
||||
dac_ll_power_down(DAC_CHAN_1);
|
||||
dac_ll_pad_power_down(DAC_CHAN_1);
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2019-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -19,56 +19,84 @@
|
||||
#include "soc/rtc_io_struct.h"
|
||||
#include "soc/sens_struct.h"
|
||||
#include "hal/dac_types.h"
|
||||
#include "hal/dac_types_private.h"
|
||||
|
||||
#define SOC_DAC_DC_VIA_SINTX 0
|
||||
#define SOC_DAC_SINTX_HAS_TIMER_TARGET 0
|
||||
#define SOC_DAC_SINTX_LUT_SIGNED 0
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define DAC_LL_CW_PHASE_0 0x02
|
||||
#define DAC_LL_CW_PHASE_180 0x03
|
||||
/*---------------------------------------------------------------
|
||||
DAC pad setting
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Power on dac module and start output voltage.
|
||||
* @brief Power on the DAC pad and start outputting voltage.
|
||||
*
|
||||
* @note Before powering up, make sure the DAC PAD is set to RTC PAD and floating status.
|
||||
* @param channel DAC channel num.
|
||||
*/
|
||||
static inline void dac_ll_power_on(dac_channel_t channel)
|
||||
static inline void dac_ll_pad_power_on(dac_channel_t channel)
|
||||
{
|
||||
RTCIO.pad_dac[channel].dac_xpd_force = 1;
|
||||
RTCIO.pad_dac[channel].xpd_dac = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Power done dac module and stop output voltage.
|
||||
* @brief Power down the DAC pad and stop outputting voltage.
|
||||
*
|
||||
* @param channel DAC channel num.
|
||||
*/
|
||||
static inline void dac_ll_power_down(dac_channel_t channel)
|
||||
static inline void dac_ll_pad_power_down(dac_channel_t channel)
|
||||
{
|
||||
RTCIO.pad_dac[channel].dac_xpd_force = 0;
|
||||
RTCIO.pad_dac[channel].xpd_dac = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output voltage with value (8 bit).
|
||||
* @brief Select the internal data source that drives a DAC channel output.
|
||||
*
|
||||
* @note Since dac_dig_force is shared between the two channels, either both channels must use DMA as their data source, or neither can.
|
||||
* @note When selecting the DMA source, the DAC output data comes from the I2S DMA.
|
||||
*
|
||||
* @param channel DAC channel num.
|
||||
* @param value Output value. Value range: 0 ~ 255.
|
||||
* The corresponding range of voltage is 0v ~ VDD3P3_RTC.
|
||||
* @param source Data source, see `dac_data_source_t`
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void dac_ll_update_output_value(dac_channel_t channel, uint8_t value)
|
||||
static inline void dac_ll_pad_set_data_source(dac_channel_t channel, dac_data_source_t source)
|
||||
{
|
||||
if (channel == DAC_CHAN_0) {
|
||||
SENS.sar_dac_ctrl2.dac_cw_en1 = 0;
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(RTCIO.pad_dac[channel], dac, value);
|
||||
} else if (channel == DAC_CHAN_1) {
|
||||
SENS.sar_dac_ctrl2.dac_cw_en2 = 0;
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(RTCIO.pad_dac[channel], dac, value);
|
||||
if (source == DAC_DATA_SOURCE_DMA) {
|
||||
SENS.sar_dac_ctrl1.dac_dig_force = true;
|
||||
} else {
|
||||
bool cw_en = (source == DAC_DATA_SOURCE_COSINE);
|
||||
if (channel == DAC_CHAN_0) {
|
||||
SENS.sar_dac_ctrl2.dac_cw_en1 = cw_en;
|
||||
} else if (channel == DAC_CHAN_1) {
|
||||
SENS.sar_dac_ctrl2.dac_cw_en2 = cw_en;
|
||||
}
|
||||
SENS.sar_dac_ctrl1.dac_dig_force = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the DAC output code (8 bit).
|
||||
*
|
||||
* @param channel DAC channel num.
|
||||
* @param code Output code. Range: 0 ~ 255.
|
||||
* The corresponding voltage range is 0 V ~ VDD3P3_RTC.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void dac_ll_pad_set_output_code(dac_channel_t channel, uint8_t code)
|
||||
{
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(RTCIO.pad_dac[channel], dac, code);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
DAC controller setting
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Enable/disable the synchronization operation function of ADC1 and DAC.
|
||||
*
|
||||
@@ -76,56 +104,39 @@ static inline void dac_ll_update_output_value(dac_channel_t channel, uint8_t val
|
||||
*
|
||||
* @param enable Enable or disable adc and dac synchronization function.
|
||||
*/
|
||||
static inline void dac_ll_rtc_sync_by_adc(bool enable)
|
||||
static inline void dac_ll_sync_by_adc(bool enable)
|
||||
{
|
||||
SENS.sar_meas_ctrl2.sar1_dac_xpd_fsm = enable;
|
||||
}
|
||||
|
||||
/************************************/
|
||||
/* DAC cosine wave generator API's */
|
||||
/************************************/
|
||||
/*---------------------------------------------------------------
|
||||
Cosine wave generator setting
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Enable cosine wave generator output.
|
||||
* @brief Enable the cosine wave generator phase accumulator.
|
||||
*/
|
||||
static inline void dac_ll_cw_generator_enable(void)
|
||||
static inline void dac_ll_cw_enable_tone(void)
|
||||
{
|
||||
SENS.sar_dac_ctrl1.sw_tone_en = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable cosine wave generator output.
|
||||
* @brief Disable the cosine wave generator
|
||||
*/
|
||||
static inline void dac_ll_cw_generator_disable(void)
|
||||
static inline void dac_ll_cw_disable(void)
|
||||
{
|
||||
SENS.sar_dac_ctrl1.sw_tone_en = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the cosine wave generator of DAC channel.
|
||||
* Set the step increment of the cosine wave generator.
|
||||
*
|
||||
* @param channel DAC channel num.
|
||||
* @param enable
|
||||
* @note cosine wave frequency = (dig_clk_rtc_freq * fstep) / 2^16
|
||||
*/
|
||||
static inline void dac_ll_cw_enable_channel(dac_channel_t channel, bool enable)
|
||||
static inline void dac_ll_cw_set_fstep(uint16_t fstep)
|
||||
{
|
||||
if (channel == DAC_CHAN_0) {
|
||||
SENS.sar_dac_ctrl2.dac_cw_en1 = enable;
|
||||
} else if (channel == DAC_CHAN_1) {
|
||||
SENS.sar_dac_ctrl2.dac_cw_en2 = enable;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set frequency of cosine wave generator output.
|
||||
*
|
||||
* @note We know that CLK8M is about 8M, but don't know the actual value. so this freq have limited error.
|
||||
* @param freq_hz CW generator frequency. Range: >= 130Hz, no exact ceiling limitation, but will distort when reach several MHz
|
||||
* @param rtc8m_freq the calibrated RTC 8M clock frequency
|
||||
*/
|
||||
static inline void dac_ll_cw_set_freq(uint32_t freq, uint32_t rtc8m_freq)
|
||||
{
|
||||
uint32_t sw_freq = (uint32_t)(((uint64_t)freq << 16) / rtc8m_freq);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(SENS.sar_dac_ctrl1, sw_fstep, (sw_freq > 0xFFFF) ? 0xFFFF : sw_freq);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(SENS.sar_dac_ctrl1, sw_fstep, fstep);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,38 +174,33 @@ static inline void dac_ll_cw_set_phase(dac_channel_t channel, dac_cosine_phase_t
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the voltage value of the DC component of the cosine wave generator output.
|
||||
* @brief Set the DC offset of the cosine wave generator output.
|
||||
*
|
||||
* @note The DC offset setting should be after phase setting.
|
||||
* @note Unreasonable settings can cause the signal to be oversaturated.
|
||||
* @note On ESP32, dac_inv also inverts the DC component. The caller must
|
||||
* compensate (e.g. negate) the offset for 180° phase before calling this.
|
||||
* @param channel DAC channel num.
|
||||
* @param offset DC value. Range: -128 ~ 127.
|
||||
* @param offset DC offset. Range: -128 ~ 127.
|
||||
*/
|
||||
static inline void dac_ll_cw_set_dc_offset(dac_channel_t channel, int8_t offset)
|
||||
static inline void dac_ll_cw_set_offset(dac_channel_t channel, int8_t offset)
|
||||
{
|
||||
if (channel == DAC_CHAN_0) {
|
||||
if (SENS.sar_dac_ctrl2.dac_inv1 == DAC_LL_CW_PHASE_180) {
|
||||
offset = -offset;
|
||||
}
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(SENS.sar_dac_ctrl2, dac_dc1, offset);
|
||||
} else if (channel == DAC_CHAN_1) {
|
||||
if (SENS.sar_dac_ctrl2.dac_inv2 == DAC_LL_CW_PHASE_180) {
|
||||
offset = -offset;
|
||||
}
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(SENS.sar_dac_ctrl2, dac_dc2, offset);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************/
|
||||
/* DAC DMA API's */
|
||||
/************************************/
|
||||
/*---------------------------------------------------------------
|
||||
DAC DMA setting
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* Enable/disable DAC output data from I2S DMA.
|
||||
* I2S_CLK connect to DAC_CLK, I2S_DATA_OUT connect to DAC_DATA.
|
||||
* @brief Enable/disable invert the DAC DMA clock signal.
|
||||
*
|
||||
* @param enable true to invert, false otherwise
|
||||
*/
|
||||
static inline void dac_ll_digi_enable_dma(bool enable)
|
||||
static inline void dac_ll_dma_clk_inv(bool enable)
|
||||
{
|
||||
SENS.sar_dac_ctrl1.dac_dig_force = enable;
|
||||
SENS.sar_dac_ctrl1.dac_clk_inv = enable;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2019-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -17,28 +17,30 @@
|
||||
#include "hal/misc.h"
|
||||
#include "hal/dac_periph.h"
|
||||
#include "hal/dac_types.h"
|
||||
#include "hal/dac_types_private.h"
|
||||
#include "soc/apb_saradc_struct.h"
|
||||
#include "soc/sens_struct.h"
|
||||
#include "soc/rtc_io_struct.h"
|
||||
#include "soc/apb_saradc_reg.h"
|
||||
|
||||
#define SOC_DAC_DC_VIA_SINTX 0
|
||||
#define SOC_DAC_SINTX_HAS_TIMER_TARGET 0
|
||||
#define SOC_DAC_SINTX_LUT_SIGNED 0
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define DAC_LL_CW_PHASE_0 0x02
|
||||
#define DAC_LL_CW_PHASE_180 0x03
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
DAC common setting
|
||||
DAC pad setting
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* Power on dac module and start output voltage.
|
||||
* @brief Power on the DAC pad and start outputting voltage.
|
||||
*
|
||||
* @note Before powering up, make sure the DAC PAD is set to RTC PAD and floating status.
|
||||
* @param channel DAC channel num.
|
||||
*/
|
||||
static inline void dac_ll_power_on(dac_channel_t channel)
|
||||
static inline void dac_ll_pad_power_on(dac_channel_t channel)
|
||||
{
|
||||
SENS.sar_dac_ctrl1.dac_clkgate_en = 1;
|
||||
RTCIO.pad_dac[channel].dac_xpd_force = 1;
|
||||
@@ -46,11 +48,11 @@ static inline void dac_ll_power_on(dac_channel_t channel)
|
||||
}
|
||||
|
||||
/**
|
||||
* Power done dac module and stop output voltage.
|
||||
* @brief Power down the DAC pad and stop outputting voltage.
|
||||
*
|
||||
* @param channel DAC channel num.
|
||||
*/
|
||||
static inline void dac_ll_power_down(dac_channel_t channel)
|
||||
static inline void dac_ll_pad_power_down(dac_channel_t channel)
|
||||
{
|
||||
RTCIO.pad_dac[channel].dac_xpd_force = 0;
|
||||
RTCIO.pad_dac[channel].xpd_dac = 0;
|
||||
@@ -59,32 +61,51 @@ static inline void dac_ll_power_down(dac_channel_t channel)
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
RTC controller setting
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* Output voltage with value (8 bit).
|
||||
* @brief Select the internal data source that drives a DAC channel output.
|
||||
*
|
||||
* @note Since dac_dig_force is shared between the two channels, either both channels must use DMA as their data source, or neither can.
|
||||
*
|
||||
* @param channel DAC channel num.
|
||||
* @param value Output value. Value range: 0 ~ 255.
|
||||
* The corresponding range of voltage is 0v ~ VDD3P3_RTC.
|
||||
* @param source Data source, see `dac_data_source_t`
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void dac_ll_update_output_value(dac_channel_t channel, uint8_t value)
|
||||
static inline void dac_ll_pad_set_data_source(dac_channel_t channel, dac_data_source_t source)
|
||||
{
|
||||
if (channel == DAC_CHAN_0) {
|
||||
SENS.sar_dac_ctrl2.dac_cw_en1 = 0;
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(RTCIO.pad_dac[channel], dac, value);
|
||||
} else if (channel == DAC_CHAN_1) {
|
||||
SENS.sar_dac_ctrl2.dac_cw_en2 = 0;
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(RTCIO.pad_dac[channel], dac, value);
|
||||
if (source == DAC_DATA_SOURCE_DMA) {
|
||||
SENS.sar_dac_ctrl1.dac_dig_force = true;
|
||||
APB_SARADC.apb_dac_ctrl.apb_dac_trans = true;
|
||||
} else {
|
||||
bool cw_en = (source == DAC_DATA_SOURCE_COSINE);
|
||||
if (channel == DAC_CHAN_0) {
|
||||
SENS.sar_dac_ctrl2.dac_cw_en1 = cw_en;
|
||||
} else if (channel == DAC_CHAN_1) {
|
||||
SENS.sar_dac_ctrl2.dac_cw_en2 = cw_en;
|
||||
}
|
||||
SENS.sar_dac_ctrl1.dac_dig_force = false;
|
||||
APB_SARADC.apb_dac_ctrl.apb_dac_trans = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the DAC output code (8 bit).
|
||||
*
|
||||
* @param channel DAC channel num.
|
||||
* @param code Output code. Range: 0 ~ 255.
|
||||
* The corresponding voltage range is 0 V ~ VDD3P3_RTC.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void dac_ll_pad_set_output_code(dac_channel_t channel, uint8_t code)
|
||||
{
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(RTCIO.pad_dac[channel], dac, code);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
DAC controller setting
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* Reset dac by software.
|
||||
*/
|
||||
static inline void dac_ll_rtc_reset(void)
|
||||
static inline void dac_ll_reset(void)
|
||||
{
|
||||
SENS.sar_dac_ctrl1.dac_reset = 1;
|
||||
SENS.sar_dac_ctrl1.dac_reset = 0;
|
||||
@@ -97,56 +118,38 @@ static inline void dac_ll_rtc_reset(void)
|
||||
*
|
||||
* @param enable Enable or disable adc and dac synchronization function.
|
||||
*/
|
||||
static inline void dac_ll_rtc_sync_by_adc(bool enable)
|
||||
static inline void dac_ll_sync_by_adc(bool enable)
|
||||
{
|
||||
SENS.sar_amp_ctrl3.sar1_dac_xpd_fsm = enable;
|
||||
}
|
||||
|
||||
/************************************/
|
||||
/* DAC cosine wave generator API's */
|
||||
/************************************/
|
||||
/*---------------------------------------------------------------
|
||||
DAC cosine wave generator setting
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* Enable cosine wave generator output.
|
||||
* @brief Enable the cosine wave generator phase accumulator.
|
||||
*/
|
||||
static inline void dac_ll_cw_generator_enable(void)
|
||||
static inline void dac_ll_cw_enable_tone(void)
|
||||
{
|
||||
SENS.sar_dac_ctrl1.sw_tone_en = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable cosine wave generator output.
|
||||
* @brief Disable the cosine wave generator
|
||||
*/
|
||||
static inline void dac_ll_cw_generator_disable(void)
|
||||
static inline void dac_ll_cw_disable(void)
|
||||
{
|
||||
SENS.sar_dac_ctrl1.sw_tone_en = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the cosine wave generator of DAC channel.
|
||||
* Set the step increment of the cosine wave generator.
|
||||
*
|
||||
* @param channel DAC channel num.
|
||||
* @param enable
|
||||
* @note cosine wave frequency = (dig_clk_rtc_freq * fstep) / 2^16
|
||||
*/
|
||||
static inline void dac_ll_cw_enable_channel(dac_channel_t channel, bool enable)
|
||||
static inline void dac_ll_cw_set_fstep(uint16_t fstep)
|
||||
{
|
||||
if (channel == DAC_CHAN_0) {
|
||||
SENS.sar_dac_ctrl2.dac_cw_en1 = enable;
|
||||
} else if (channel == DAC_CHAN_1) {
|
||||
SENS.sar_dac_ctrl2.dac_cw_en2 = enable;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set frequency of cosine wave generator output.
|
||||
*
|
||||
* @note We know that CLK8M is about 8M, but don't know the actual value. so this freq have limited error.
|
||||
* @param freq_hz CW generator frequency. Range: >= 130Hz, no exact ceiling limitation, but will distort when reach several MHz
|
||||
* @param rtc8m_freq the calibrated RTC 8M clock frequency
|
||||
*/
|
||||
static inline void dac_ll_cw_set_freq(uint32_t freq, uint32_t rtc8m_freq)
|
||||
{
|
||||
uint32_t sw_freq = (uint32_t)(((uint64_t)freq << 16) / rtc8m_freq);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(SENS.sar_dac_ctrl1, sw_fstep, (sw_freq > 0xFFFF) ? 0xFFFF : sw_freq);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(SENS.sar_dac_ctrl1, sw_fstep, fstep);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,101 +187,84 @@ static inline void dac_ll_cw_set_phase(dac_channel_t channel, dac_cosine_phase_t
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the voltage value of the DC component of the cosine wave generator output.
|
||||
* @brief Set the DC offset of the cosine wave generator output.
|
||||
*
|
||||
* @note The DC offset setting should be after phase setting.
|
||||
* @note Unreasonable settings can cause the signal to be oversaturated.
|
||||
* @note On ESP32-S2, dac_inv also inverts the DC component. The caller must
|
||||
* compensate (e.g. negate) the offset for 180° phase before calling this.
|
||||
* @param channel DAC channel num.
|
||||
* @param offset DC value. Range: -128 ~ 127.
|
||||
* @param offset DC offset. Range: -128 ~ 127.
|
||||
*/
|
||||
static inline void dac_ll_cw_set_dc_offset(dac_channel_t channel, int8_t offset)
|
||||
static inline void dac_ll_cw_set_offset(dac_channel_t channel, int8_t offset)
|
||||
{
|
||||
if (channel == DAC_CHAN_0) {
|
||||
if (SENS.sar_dac_ctrl2.dac_inv1 == DAC_LL_CW_PHASE_180) {
|
||||
offset = -offset;
|
||||
}
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(SENS.sar_dac_ctrl2, dac_dc1, offset);
|
||||
} else if (channel == DAC_CHAN_1) {
|
||||
if (SENS.sar_dac_ctrl2.dac_inv2 == DAC_LL_CW_PHASE_180) {
|
||||
offset = -offset;
|
||||
}
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(SENS.sar_dac_ctrl2, dac_dc2, offset);
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Digital controller setting
|
||||
DAC DMA setting
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
/************************************/
|
||||
/* DAC DMA API's */
|
||||
/************************************/
|
||||
|
||||
/**
|
||||
* Enable/disable invert the DAC digital controller clock signal.
|
||||
* @brief Enable/disable invert the DAC DMA clock signal.
|
||||
*
|
||||
* @param enable true or false.
|
||||
* @param enable true to invert, false otherwise
|
||||
*
|
||||
* @note On ESP32-S2, when the DAC is driven through DMA, enabling inv_clk is necessary to avoid glitches in the output waveform.
|
||||
*/
|
||||
static inline void dac_ll_digi_clk_inv(bool enable)
|
||||
static inline void dac_ll_dma_clk_inv(bool enable)
|
||||
{
|
||||
SENS.sar_dac_ctrl1.dac_clk_inv = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable DAC-DMA mode for dac digital controller.
|
||||
* @brief Set the DMA path timer target.
|
||||
*
|
||||
* @note The clocks of the DAC digital controller use the ADC digital controller clock divider.
|
||||
* @note DMA output frequency = controller_clk / timer_target.
|
||||
*
|
||||
* @param timer_target Number of divided-clock cycles between DAC outputs.
|
||||
*/
|
||||
static inline void dac_ll_digi_enable_dma(bool enable)
|
||||
static inline void dac_ll_dma_set_timer_target(uint32_t timer_target)
|
||||
{
|
||||
SENS.sar_dac_ctrl1.dac_dig_force = enable;
|
||||
APB_SARADC.apb_dac_ctrl.apb_dac_trans = enable;
|
||||
APB_SARADC.apb_dac_ctrl.dac_timer_target = timer_target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of interval clock cycles for the digital controller to trigger the DAC output.
|
||||
* Expression: `dac_output_freq` = `controller_clk` / interval.
|
||||
* @brief Enable/disable the DAC DMA output timer.
|
||||
*
|
||||
* @note The clocks of the DAC digital controller use the ADC digital controller clock divider.
|
||||
*
|
||||
* @param cycle The number of clock cycles for the trigger output interval. The unit is the divided clock.
|
||||
* @param enable true to enable, false to disable
|
||||
*/
|
||||
static inline void dac_ll_digi_set_trigger_interval(uint32_t cycle)
|
||||
{
|
||||
APB_SARADC.apb_dac_ctrl.dac_timer_target = cycle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable DAC digital controller to trigger the DAC output.
|
||||
*
|
||||
* @param enable true or false.
|
||||
*/
|
||||
static inline void dac_ll_digi_trigger_output(bool enable)
|
||||
static inline void dac_ll_dma_enable_timer(bool enable)
|
||||
{
|
||||
APB_SARADC.apb_dac_ctrl.dac_timer_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set DAC conversion mode for digital controller.
|
||||
* @brief Enable/disable the alternate (ping-pong) output mode of the DMA path.
|
||||
*
|
||||
* @param mode Conversion mode select. See ``dac_digi_convert_mode_t``.
|
||||
* @param enable true to route consecutive samples alternately to the two channels
|
||||
*/
|
||||
static inline void dac_ll_digi_set_convert_mode(bool is_alternate)
|
||||
static inline void dac_ll_dma_enable_alternate_mode(bool enable)
|
||||
{
|
||||
APB_SARADC.apb_dac_ctrl.apb_dac_alter_mode = is_alternate;
|
||||
APB_SARADC.apb_dac_ctrl.apb_dac_alter_mode = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset FIFO of DAC digital controller.
|
||||
* @brief Reset the DAC DMA FIFO.
|
||||
*/
|
||||
static inline void dac_ll_digi_fifo_reset(void)
|
||||
static inline void dac_ll_dma_reset_fifo(void)
|
||||
{
|
||||
APB_SARADC.apb_dac_ctrl.dac_reset_fifo = 1;
|
||||
APB_SARADC.apb_dac_ctrl.dac_reset_fifo = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset DAC digital controller.
|
||||
* @brief Reset the DAC DMA FSM, i.e. the DAC-side consumer of DMA samples (timer, alter-mode demux).
|
||||
*/
|
||||
static inline void dac_ll_digi_reset(void)
|
||||
static inline void dac_ll_dma_reset_fsm(void)
|
||||
{
|
||||
APB_SARADC.apb_dac_ctrl.apb_dac_rst = 1;
|
||||
APB_SARADC.apb_dac_ctrl.apb_dac_rst = 0;
|
||||
|
||||
@@ -15,15 +15,6 @@ extern "C" {
|
||||
|
||||
#if SOC_DAC_SUPPORTED
|
||||
|
||||
/**
|
||||
* ESP32:
|
||||
* - DAC channel 0: GPIO25
|
||||
* - DAC channel 1: GPIO26
|
||||
* ESP32S2:
|
||||
* - DAC channel 0: GPIO17
|
||||
* - DAC channel 1: GPIO18
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
DAC_CHAN_0 = 0,
|
||||
DAC_CHAN_1 = 1,
|
||||
|
||||
33
components/esp_hal_ana_conv/include/hal/dac_types_private.h
Normal file
33
components/esp_hal_ana_conv/include/hal/dac_types_private.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if SOC_DAC_SUPPORTED
|
||||
|
||||
/**
|
||||
* @brief The internal data source that drives a DAC channel output
|
||||
*
|
||||
* @note The number of distinct sources differs per chip:
|
||||
* - ESP32/ESP32-S2: cosine generator, DMA, and direct register output are three separate states.
|
||||
* - ESP32-S31: the Sintx path serves both the cosine generator and the direct software output.
|
||||
*/
|
||||
typedef enum {
|
||||
DAC_DATA_SOURCE_COSINE = 0, /*!< Channel output driven by the on-chip cosine wave generator (Sintx) */
|
||||
DAC_DATA_SOURCE_DMA = 1, /*!< Channel output driven by the digital DMA path */
|
||||
DAC_DATA_SOURCE_DIRECT = 2, /*!< Channel output driven by the direct register value */
|
||||
} dac_data_source_t;
|
||||
|
||||
#endif // SOC_DAC_SUPPORTED
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user