# 数模转换器 (DAC)

[English]

## 概况

ESP32 有两个 8 位数模转换器 (DAC) 通道，分别连接到 GPIO25（通道 1）和 GPIO26（通道 2）。每个 DAC 通道可以将数字值 0 ~ 255 转换成模拟电压 0 ~ Vref（此处的 Vref 为 VDD3P3_RTC 引脚输入的参考电压，一般来说其输入的电压值应等于电源电压 VDD）。输出电压可按以下方式计算:

    out_voltage = Vref * digi_val / 255

DAC 外设支持以下列方式输出模拟信号：

1. 直接输出电压。DAC 通道持续输出某一指定电压。

2. 通过 DMA 输出连续模拟信号。DAC 以某一特定频率转换缓冲器中的数据。

3. 通过余弦波发生器输出余弦波。DAC 通道可以输出特定频率和振幅的余弦波。

其他模拟输出选项可参考 Sigma-Delta 调制 和 LED PWM 控制器。这两个模块均输出高频的 PWM/PDM 信号，也可借助硬件低通滤波输出较低频率的模拟信号。

## 功能概览

### 资源管理

ESP32 有两个 DAC 通道。通道的软件资源互相独立，用户可以根据具体情况调用 `dac_oneshot_handle_t`、 `dac_cosine_handle_t` 或 `dac_continuous_handle_t` 来管理不同通道，但不支持在同一个通道上注册不同模式。

### 电压直接输出（单次/直接模式）

在这种模式下，DAC 通道每次调用 `dac_oneshot_output_voltage()` （可在 ISR 中调用）时都可以将一个 8 位数字转换为模拟值。直至下一次转换开始前，DAC 通道上都将维持该模拟电压。开始转换电压前，需要首先调用 `dac_oneshot_new_channel()` 来启用该 DAC 通道。

### 连续波输出（连续/DMA 模式）

DAC 通道可以通过 DMA 连续转换数字信号，这种模式下有三种写入 DAC 数据的方法：

> 1. 常规写入（同步）：一次性传输所有数据并在所有数据均已载入 DMA 缓冲区前保持阻塞状态。如果不再继续输入数据，电压将维持在最后的转换值。该模式通常用于传输音频等长信号。要连续转换数据，需要调用 `dac_continuous_new_channels()` 来分配连续通道句柄，调用 `dac_continuous_enable()` 来启用 DMA 转换，然后调用 `dac_continuous_write()` 来同步写入数据。示例可参考 peripherals/dac/dac_continuous/dac_audio。

> 2. 循环写入：在数据载入 DMA 缓冲区后，缓冲区中的数据将以非阻塞的方式被循环转换。但要注意，输入的缓冲区大小受 DMA 描述符数量和 DMA 缓冲区大小的限制。该模式通常用于传输如正弦波等需要重复的短信号。为了启用循环写入，需要在启用 DAC 连续模式后调用 `dac_continuous_write_cyclically()`。示例可参考 peripherals/dac/dac_continuous/signal_generator。

> 3. 异步写入。可根据事件回调异步传输数据。需要调用 `dac_event_callbacks_t::on_convert_done` 以启用异步模式。用户在回调中可得到 `dac_event_data_t`，其中包含 DMA 缓冲区的地址和长度，即允许用户直接将数据载入 DMA 缓冲区。启用异步写入前需要调用 `dac_continuous_register_event_callback()`、 `dac_event_callbacks_t::on_convert_done` 和 `dac_continuous_start_async_writing()`。注意，异步写入一旦开始，回调函数将被持续触发。调用 `dac_continuous_write_asynchronously()` 可以在某个单独任务中或直接在回调函数中载入数据。示例可参考 peripherals/dac/dac_continuous/dac_audio。

下图展示了连续模式驱动的生命周期，以及各 API 对应的状态转移：

            flowchart TD
        NC([空闲（初始状态）]) -->|"new_channels()"| REG[已注册]
        REG -->|"del_channels()"| NC
        REG -->|"enable()"| EN[已启用]
        EN -->|"disable()"| REG

        EN -->|"start_async_writing()"| ASYNC[异步写入]
        ASYNC -->|"stop_async_writing()"| EN

        EN -->|"write_cyclically()"| CYCLIC[循环写入]
        CYCLIC -->|"stop_cyclically()"| EN

        EN -->|"write()"| SYNC[同步写入]
        SYNC -->|"write()"| SYNC
        SYNC -->|"传输完成后"| EN

        subgraph REG_APIS [已注册状态可用 API]
            REGCB["register_event_callbacks()"]
        end

        subgraph ASYNC_APIS [异步写入可用 API]
            AWRITE["write_asynchronously()"]
        end

        REG -. 可调用 .-> REGCB
        ASYNC -. 收到回调通知后调用 .-> AWRITE

备注

- 为了简洁，图中省略了各函数名的前缀 `dac_continuous_`。

- 为了向后兼容，循环写入的退出函数 `dac_continuous_stop_cyclically()` 是可选的，所有从已启用状态出发的函数会自动检查并停止任何正在进行的循环写入。推荐显式调用 `dac_continuous_stop_cyclically()` 来停止循环写入。

- 同步写入无需显式退出，所有从已启用状态出发的函数会自动立即停止任何正在进行的同步写入（尚未转换的数据将被丢弃）。

在 ESP32 上，DAC 的数字控制器可以在内部连接到 I2S0，并借用其 DMA 进行连续转换。虽然 DAC 转换仅需 8 位数据，但它必须是左移的 8 位（即 16 位中的高 8 位），以满足 I2S 通信格式。默认状态下驱动程序将自动扩充数据至 16 位，如需手动扩充，请在 menuconfig 中禁用 CONFIG_DAC_DMA_AUTO_16BIT_ALIGN。

DAC 的数字控制器的时钟也来自 I2S0，有以下两种时钟源可选：

- `dac_continuous_digi_clk_src_t::DAC_DIGI_CLK_SRC_PLL_D2` 支持 19.6 KHz 到若干 MHz 之间的频率。该时钟源为默认时钟源，也可通过选择 `dac_continuous_digi_clk_src_t::DAC_DIGI_CLK_SRC_DEFAULT` 来启用该时钟源。

- `dac_continuous_digi_clk_src_t::DAC_DIGI_CLK_SRC_APLL` 支持 648 Hz 到若干 MHz 之间的频率。该时钟源可能会被其他外设占用而导致频率无法更改，此时除非 APLL 仍能准确分频得到 DAC DMA 的目标频率，否则将无法使用该时钟源。

### 余弦波输出（余弦模式）

DAC 外设中包含一个余弦波发生器，可以在通道上产生余弦波。用户可以配置余弦波的频率、振幅和相位。启用该模式需要先调用 `dac_cosine_new_channel()` 将 DAC 转换成余弦模式，然后调用 `dac_cosine_start()` 启动余弦波发生器。

目前，余弦波发生器仅有 `RTC_FAST` 一个时钟源，可通过选择 `dac_cosine_clk_src_t::DAC_COSINE_CLK_SRC_RTC_FAST` 来启用该时钟源。该时钟源为默认时钟源，与 `dac_cosine_clk_src_t::DAC_COSINE_CLK_SRC_RTC_DEFAULT` 相同。

### 电源管理

启用电源管理时（即开启 CONFIG_PM_ENABLE），系统会在进入 Light-sleep 模式前调整或停止 DAC 时钟源，这可能会影响 DAC 信号，从而导致数据无法正确转换。

在连续模式下使用 DAC 驱动时，可以通过获取电源管理锁来防止系统在 DMA 或余弦波模式下改变或停止时钟源。时钟源为 APB 时，锁的类型将被设置为 `esp_pm_lock_type_t::ESP_PM_APB_FREQ_MAX`。时钟源为 APLL 时（仅在 DMA 模式下），锁的类型将被设置为 `esp_pm_lock_type_t::ESP_PM_NO_LIGHT_SLEEP`。在进行 DAC 转换时（即 DMA 或余弦波发生器运行时），驱动程序会保证在调用 `dac_continuous_enable()` 后获取电源管理锁。同样地，在调用 `dac_continuous_disable()` 时，驱动程序会释放锁。

### IRAM 安全

默认情况下，由于写入或擦除 flash 等原因导致 cache 被禁用时，DAC 的 DMA 中断将产生延迟，无法及时执行 DMA EOF 中断。

在实时应用中，可通过启用 Kconfig 选项 CONFIG_DAC_ISR_IRAM_SAFE 来避免此种情况发生，启用后：

1. 即使在 cache 被禁用的情况下，也可以启用中断服务。

2. 驱动对象会被放入 DRAM（以防其被意外链接到 PSRAM）。

此时在 cache 被禁用时仍可以运行中断，但会增加 IRAM 内存消耗。

### 线程安全

驱动程序可保证所有公共 DAC API 的线程安全，用户可以从不同的 RTOS 任务中调用这些 API，而不需要额外的锁来保护。注意，DAC 驱动使用 mutex 锁来保证线程安全，因此不允许在 ISR 中使用除了 `dac_oneshot_output_voltage()` 之外的 API。

### Kconfig 选项

- CONFIG_DAC_ISR_IRAM_SAFE 控制默认 ISR 处理程序在 cache 被禁用时能否继续运行。更多信息可参考 线程安全。

- CONFIG_DAC_ENABLE_DEBUG_LOG 用于启用调试日志输出。启用该选项将增加固件的二进制文件大小。

- CONFIG_DAC_DMA_AUTO_16BIT_ALIGN 会在驱动中自动将 8 位数据扩展为 16 位数据，以满足 I2S DMA 格式。

## 应用示例

- peripherals/dac/dac_continuous/signal_generator 演示了在 ESP32 上使用 DAC 驱动程序输出连续电压的两种方式：通过 DMA 传输、以及通过定时器中断。两种方式可以生成不同的波形，如正弦波、三角波、锯齿波和方波。

- peripherals/dac/dac_continuous/dac_audio 演示了如何在 ESP32 上使用 DAC 驱动程序播放存储在 buffer 中的音频，每秒钟通过扬声器或耳机播放一次。

- peripherals/dac/dac_cosine_wave 演示了如何在 ESP32 开发板上使用 DAC 驱动程序在两个通道上输出余弦波，并且可以通过示波器或内部的 ADC 通道进行监控。

- peripherals/dac/dac_oneshot 演示了如何在 ESP32 上使用 DAC 驱动程序输出每 500 毫秒阶跃增加一次的电压，并且会定期复位为 0。输出的电压可通过 ADC 或可选的示波器进行监测。

## API 参考

### Header File

- components/esp_driver_dac/include/driver/dac_oneshot.h

- This header file can be included with:

  >     #include "driver/dac_oneshot.h"

- This header file is a part of the API provided by the `esp_driver_dac` component. To declare that your component depends on `esp_driver_dac`, add the following to your CMakeLists.txt:

  >     REQUIRES esp_driver_dac

  > or

  >     PRIV_REQUIRES esp_driver_dac

### Functions

esp_err_t dac_oneshot_new_channel(const dac_oneshot_config_t *oneshot_cfg, dac_oneshot_handle_t *ret_handle)

  Allocate a new DAC oneshot channel.

  备注

  The channel will be enabled as well when the channel allocated

  参数:

    - oneshot_cfg -- [in] The configuration for the oneshot channel

    - ret_handle -- [out] The returned oneshot channel handle

  返回:

    - ESP_ERR_INVALID_ARG The input parameter is invalid

    - ESP_ERR_INVALID_STATE The DAC channel has been registered already

    - ESP_ERR_NO_MEM No memory for the DAC oneshot channel resources

    - ESP_OK Allocate the new DAC oneshot channel success

esp_err_t dac_oneshot_del_channel(dac_oneshot_handle_t handle)

  Delete the DAC oneshot channel.

  备注

  The channel will be disabled as well when the channel deleted

  参数:

    handle -- [in] The DAC oneshot channel handle

  返回:

    - ESP_ERR_INVALID_ARG The input parameter is invalid

    - ESP_ERR_INVALID_STATE The channel has already been de-registered

    - ESP_OK Delete the oneshot channel success

esp_err_t dac_oneshot_output_voltage(dac_oneshot_handle_t handle, uint8_t digi_value)

  Output the voltage.

  备注

  Generally it'll take 7~11 us on ESP32 and 10~21 us on ESP32-S2

  参数:

    - handle -- [in] The DAC oneshot channel handle

    - digi_value -- [in] The digital value that need to be converted

  返回:

    - ESP_ERR_INVALID_ARG The input parameter is invalid

    - ESP_OK Convert the digital value success

### Structures

struct dac_oneshot_config_t

  DAC oneshot channel configuration.

  Public Members

  dac_channel_t chan_id

    DAC channel id

### Type Definitions

typedef struct dac_oneshot_s *dac_oneshot_handle_t

  DAC oneshot channel handle

### Header File

- components/esp_driver_dac/include/driver/dac_cosine.h

- This header file can be included with:

  >     #include "driver/dac_cosine.h"

- This header file is a part of the API provided by the `esp_driver_dac` component. To declare that your component depends on `esp_driver_dac`, add the following to your CMakeLists.txt:

  >     REQUIRES esp_driver_dac

  > or

  >     PRIV_REQUIRES esp_driver_dac

### Functions

esp_err_t dac_cosine_new_channel(const dac_cosine_config_t *cos_cfg, dac_cosine_handle_t *ret_handle)

  Allocate a new DAC cosine wave channel.

  备注

  Since there is only one cosine wave generator, only the first channel can set the frequency of the cosine wave. Normally, the latter one is not allowed to set a different frequency, but the it can be forced to set by setting the bit `force_set_freq` in the configuration, notice that another channel will be affected as well when the frequency is updated.

  参数:

    - cos_cfg -- [in] The configuration of cosine wave channel

    - ret_handle -- [out] The returned cosine wave channel handle

  返回:

    - ESP_ERR_INVALID_ARG The input parameter is invalid

    - ESP_ERR_INVALID_STATE The DAC channel has been registered already

    - ESP_ERR_NO_MEM No memory for the DAC cosine wave channel resources

    - ESP_OK Allocate the new DAC cosine wave channel success

esp_err_t dac_cosine_del_channel(dac_cosine_handle_t handle)

  Delete the DAC cosine wave channel.

  参数:

    handle -- [in] The DAC cosine wave channel handle

  返回:

    - ESP_ERR_INVALID_ARG The input parameter is invalid

    - ESP_ERR_INVALID_STATE The channel has already been deregistered

    - ESP_OK Delete the cosine wave channel success

esp_err_t dac_cosine_start(dac_cosine_handle_t handle)

  Start outputting the cosine wave on the channel.

  参数:

    handle -- [in] The DAC cosine wave channel handle

  返回:

    - ESP_ERR_INVALID_ARG The input parameter is invalid

    - ESP_ERR_INVALID_STATE The channel has been started already

    - ESP_OK Start the cosine wave success

esp_err_t dac_cosine_stop(dac_cosine_handle_t handle)

  Stop outputting the cosine wave on the channel.

  参数:

    handle -- [in] The DAC cosine wave channel handle

  返回:

    - ESP_ERR_INVALID_ARG The input parameter is invalid

    - ESP_ERR_INVALID_STATE The channel has been stopped already

    - ESP_OK Stop the cosine wave success

### Structures

struct dac_cosine_config_t

  DAC cosine channel configurations.

  Public Members

  dac_channel_t chan_id

    The cosine wave channel id

  uint32_t freq_hz

    The frequency of cosine wave, unit: Hz. The cosine wave generator is driven by RTC_FAST clock which is divide from RC_FAST, With the default RTC clock, the minimum frequency of cosine wave is about 130 Hz, Although it can support up to several MHz frequency theoretically, the waveform will distort at high frequency due to the hardware limitation. Typically not suggest to set the frequency higher than 200 KHz

  dac_cosine_clk_src_t clk_src

    The clock source of the cosine wave generator, currently only support `DAC_COSINE_CLK_SRC_DEFAULT`

  dac_cosine_atten_t atten

    The attenuation of cosine wave amplitude

  dac_cosine_phase_t phase

    The phase of cosine wave, can only support DAC_COSINE_PHASE_0 or DAC_COSINE_PHASE_180, default as 0 while setting an unsupported phase

  int8_t offset

    The DC offset of cosine wave

  bool force_set_freq

    Force to set the cosine wave frequency

  struct dac_cosine_config_t flags

    Flags of cosine mode

### Type Definitions

typedef struct dac_cosine_s *dac_cosine_handle_t

  DAC cosine wave channel handle

### Header File

- components/esp_driver_dac/include/driver/dac_continuous.h

- This header file can be included with:

  >     #include "driver/dac_continuous.h"

- This header file is a part of the API provided by the `esp_driver_dac` component. To declare that your component depends on `esp_driver_dac`, add the following to your CMakeLists.txt:

  >     REQUIRES esp_driver_dac

  > or

  >     PRIV_REQUIRES esp_driver_dac

### Functions

esp_err_t dac_continuous_new_channels(const dac_continuous_config_t *cont_cfg, dac_continuous_handle_t *ret_handle)

  Allocate new DAC channels in continuous mode.

  备注

  The DAC channels can't be registered to continuous mode separately

  参数:

    - cont_cfg -- [in] Continuous mode configuration

    - ret_handle -- [out] The returned continuous mode handle

  返回:

    - ESP_ERR_INVALID_ARG The input parameter is invalid

    - ESP_ERR_INVALID_STATE The DAC channel has been registered already

    - ESP_ERR_NOT_FOUND Not found the available dma peripheral, might be occupied

    - ESP_ERR_NO_MEM No memory for the DAC continuous mode resources

    - ESP_OK Allocate the new DAC continuous mode success

esp_err_t dac_continuous_del_channels(dac_continuous_handle_t handle)

  Delete the DAC continuous handle.

  参数:

    handle -- [in] The DAC continuous channel handle that obtained from 'dac_continuous_new_channels'

  返回:

    - ESP_ERR_INVALID_ARG The input parameter is invalid

    - ESP_ERR_INVALID_STATE The channels have already been deregistered or not disabled

    - ESP_OK Delete the continuous channels success

esp_err_t dac_continuous_enable(dac_continuous_handle_t handle)

  Enabled the DAC continuous mode.

  备注

  Must enable the channels before

  参数:

    handle -- [in] The DAC continuous channel handle that obtained from 'dac_continuous_new_channels'

  返回:

    - ESP_ERR_INVALID_ARG The input parameter is invalid

    - ESP_ERR_INVALID_STATE The channels have been enabled already

    - ESP_OK Enable the continuous output success

esp_err_t dac_continuous_disable(dac_continuous_handle_t handle)

  Disable the DAC continuous mode.

  参数:

    handle -- [in] The DAC continuous channel handle that obtained from 'dac_continuous_new_channels'

  返回:

    - ESP_ERR_INVALID_ARG The input parameter is invalid

    - ESP_ERR_INVALID_STATE The channels are not enabled, or a write operation is still ongoing

    - ESP_OK Disable the continuous output success

esp_err_t dac_continuous_write(dac_continuous_handle_t handle, uint8_t *buf, size_t buf_size, size_t *bytes_loaded, int timeout_ms)

  Write DAC data continuously.

  备注

  The data in buffer will only be converted one time, This function will be blocked until all data loaded or timeout then the DAC output will keep outputting the voltage of the last data in the buffer

  备注

  Specially, on ESP32, the data bit width of DAC continuous data is fixed to 16 bits while only the high 8 bits are available, The driver will help to expand the inputted buffer automatically by default, you can also align the data to 16 bits manually by clearing `CONFIG_DAC_DMA_AUTO_16BIT_ALIGN` in menuconfig.

  参数:

    - handle -- [in] The DAC continuous channel handle that obtained from 'dac_continuous_new_channels'

    - buf -- [in] The digital data buffer to convert

    - buf_size -- [in] The buffer size of digital data buffer

    - bytes_loaded -- [out] The bytes that has been loaded into DMA buffer, can be NULL if don't need it

    - timeout_ms -- [in] The timeout time in millisecond, set a minus value means will block forever

  返回:

    - ESP_ERR_INVALID_ARG The input parameter is invalid

    - ESP_ERR_INVALID_STATE The DAC continuous mode has not been enabled yet

    - ESP_ERR_TIMEOUT Waiting for semaphore or message queue timeout

    - ESP_OK Success to output the acyclic DAC data

esp_err_t dac_continuous_write_cyclically(dac_continuous_handle_t handle, uint8_t *buf, size_t buf_size, size_t *bytes_loaded)

  Write DAC continuous data cyclically.

  备注

  The data in buffer will be converted cyclically using DMA once this function is called, This function will return once the data loaded into DMA buffers.

  备注

  The buffer size of cyclically output is limited by the descriptor number and dma buffer size while initializing the continuous mode. Concretely, in order to load all the data into descriptors, the cyclic buffer size is not supposed to be greater than `desc_num * buf_size`

  备注

  Specially, on ESP32, the data bit width of DAC continuous data is fixed to 16 bits while only the high 8 bits are available, The driver will help to expand the inputted buffer automatically by default, you can also align the data to 16 bits manually by clearing `CONFIG_DAC_DMA_AUTO_16BIT_ALIGN` in menuconfig.

  参数:

    - handle -- [in] The DAC continuous channel handle that obtained from 'dac_continuous_new_channels'

    - buf -- [in] The digital data buffer to convert

    - buf_size -- [in] The buffer size of digital data buffer

    - bytes_loaded -- [out] The bytes that has been loaded into DMA buffer, can be NULL if don't need it

  返回:

    - ESP_ERR_INVALID_ARG The input parameter is invalid

    - ESP_ERR_INVALID_STATE The DAC continuous mode has not been enabled yet

    - ESP_OK Success to output the cyclic DAC data

esp_err_t dac_continuous_stop_cyclically(dac_continuous_handle_t handle)

  Stop the cyclical conversion triggered by 'dac_continuous_write_cyclically'.

  备注

  For backward compatibility, calling this function is optional. That is, after a cyclic write (conversion) has started, users can directly call 'dac_continuous_disable', 'dac_continuous_write_cyclically', 'dac_continuous_start_async_writing', or 'dac_continuous_write'. These functions will automatically check for and stop any ongoing cyclic conversion. However, this behavior is NOT recommended.

  参数:

    handle -- [in] The DAC continuous channel handle that obtained from 'dac_continuous_new_channels'

  返回:

    - ESP_ERR_INVALID_ARG The input parameter is invalid

    - ESP_ERR_INVALID_STATE The DAC continuous is not in cyclic writing mode

    - ESP_OK Success to stop the cyclic conversion

esp_err_t dac_continuous_register_event_callback(dac_continuous_handle_t handle, const dac_event_callbacks_t *callbacks, void *user_data)

  Set event callbacks for DAC continuous mode.

  备注

  User can deregister a previously registered callback by calling this function and setting the callback member in the `callbacks` structure to NULL.

  备注

  When CONFIG_DAC_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM. The variables used in this function, including the `user_data`, should be in the internal RAM as well.

  参数:

    - handle -- [in] The DAC continuous channel handle that obtained from 'dac_continuous_new_channels'

    - callbacks -- [in] Group of callback functions, input NULL to clear the former callbacks

    - user_data -- [in] User data, which will be passed to callback functions directly

  返回:

    - ESP_OK Set event callbacks successfully

    - ESP_ERR_INVALID_ARG Set event callbacks failed because of invalid argument

esp_err_t dac_continuous_start_async_writing(dac_continuous_handle_t handle)

  Start the async writing.

  备注

  When the asynchronous writing start, the DAC will keep outputting '0' until the data are loaded into the DMA buffer. To loaded the data into DMA buffer, 'on_convert_done' callback is required, which can be registered by 'dac_continuous_register_event_callback' before enabling

  参数:

    handle -- [in] The DAC continuous channel handle that obtained from 'dac_continuous_new_channels'

  返回:

    - ESP_OK Start asynchronous writing successfully

    - ESP_ERR_INVALID_ARG The handle is NULL

    - ESP_ERR_INVALID_STATE The channel is not enabled or the 'on_convert_done' callback is not registered

esp_err_t dac_continuous_stop_async_writing(dac_continuous_handle_t handle)

  Stop the async writing.

  参数:

    handle -- [in] The DAC continuous channel handle that obtained from 'dac_continuous_new_channels'

  返回:

    - ESP_OK Stop asynchronous writing successfully

    - ESP_ERR_INVALID_ARG The handle is NULL

    - ESP_ERR_INVALID_STATE Asynchronous writing has not started

esp_err_t dac_continuous_write_asynchronously(dac_continuous_handle_t handle, uint8_t *dma_buf, size_t dma_buf_len, const uint8_t *data, size_t data_len, size_t *bytes_loaded)

  Write DAC data asynchronously.

  备注

  This function can be called when the asynchronous writing started, and it can be called in the callback directly but recommend to writing data in a task, referring to :example:`peripherals/dac/dac_continuous/dac_audio`

  参数:

    - handle -- [in] The DAC continuous channel handle that obtained from 'dac_continuous_new_channels'

    - dma_buf -- [in] The DMA buffer address, it can be acquired from 'dac_event_data_t' in the 'on_convert_done' callback

    - dma_buf_len -- [in] The DMA buffer length, it can be acquired from 'dac_event_data_t' in the 'on_convert_done' callback. It should always be equal to the buffer size of descriptors. This parameter is kept for compatibility and ignored by the driver.

    - data -- [in] The data that need to be written

    - data_len -- [in] The data length the need to be written

    - bytes_loaded -- [out] The bytes number that has been loaded/written into the DMA buffer

  返回:

    - ESP_OK Write the data into DMA buffer successfully

    - ESP_ERR_INVALID_ARG NULL pointer

    - ESP_ERR_INVALID_STATE The channels haven't start the asynchronous writing

    - ESP_ERR_NOT_FOUND The param 'dam_buf' not match any existed DMA buffer

### Structures

struct dac_continuous_config_t

  DAC continuous channels' configurations.

  Public Members

  dac_channel_mask_t chan_mask

    DAC channels' mask for selecting which channels are used

  uint32_t desc_num

    The number of DMA descriptor, at least 2 descriptors are required The number of descriptors is directly proportional to the max data buffer size while converting in cyclic output but only need to ensure it is greater than '1' in acyclic output Typically, suggest to set the number bigger than 5, in case the DMA stopped while sending a short buffer

  size_t buf_size

    The DMA buffer size, should be within 32~4092 bytes. Each DMA buffer will be attached to a DMA descriptor, i.e. the number of DMA buffer will be equal to the DMA descriptor number The DMA buffer size is not allowed to be greater than 4092 bytes The total DMA buffer size equal to `desc_num * buf_size` Typically, suggest to set the size to the multiple of 4

  uint32_t freq_hz

    The frequency of DAC conversion in continuous mode, unit: Hz The supported range is related to the target and the clock source. For the clock `DAC_DIGI_CLK_SRC_DEFAULT`: the range is 19.6 KHz to several MHz on ESP32 and 77 Hz to several MHz on ESP32-S2. For the clock `DAC_DIGI_CLK_SRC_APLL`: the range is 648 Hz to several MHz on ESP32 and 6 Hz to several MHz on ESP32-S2. Typically not suggest to set the frequency higher than 2 MHz, otherwise the severe distortion will appear

  int8_t offset

    The offset of the DAC digital data. Range -128~127

  dac_continuous_digi_clk_src_t clk_src

    The clock source of digital controller, which can affect the range of supported frequency Currently `DAC_DIGI_CLK_SRC_DEFAULT` and `DAC_DIGI_CLK_SRC_APLL` are available

  dac_continuous_channel_mode_t chan_mode

    The channel mode of continuous mode, only take effect when multiple channels enabled, depends converting the buffer alternately or simultaneously

struct dac_event_data_t

  Event structure used in DAC event queue.

  Public Members

  void *buf

    The pointer of DMA buffer that just finished sending

  size_t buf_size

    The writable buffer size of the DMA buffer, equal to 'dac_continuous_config_t::buf_size'

  size_t write_bytes

    The number of bytes that be written successfully

struct dac_event_callbacks_t

  Group of DAC callbacks.

  备注

  The callbacks are all running under ISR environment

  备注

  When CONFIG_DAC_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM. The variables used in the function should be in the SRAM as well.

  Public Members

  dac_isr_callback_t on_convert_done

    Callback of data conversion done event An event data buffer previously loaded to the driver has been output and converted. The event data includes DMA buffer address and size that just finished converting.

  dac_isr_callback_t on_stop

    Callback of finished sending all the data. All loaded event data buffers are converted. Driver is pending for new data buffers to be loaded. The event data will be NULL in this callback.

### Type Definitions

typedef struct dac_continuous_s *dac_continuous_handle_t

  DAC continuous channel handle

typedef bool (*dac_isr_callback_t)(dac_continuous_handle_t handle, const dac_event_data_t *event, void *user_data)

  DAC event callback.

  Param handle:

    [in] DAC channel handle, created from `dac_continuous_new_channels()`

  Param event:

    [in] DAC event data

  Param user_data:

    [in] User registered context, passed from `dac_continuous_register_event_callback()`

  Return:

    Whether a high priority task has been waken up by this callback function

### Header File

- components/esp_driver_dac/include/driver/dac_types.h

- This header file can be included with:

  >     #include "driver/dac_types.h"

- This header file is a part of the API provided by the `esp_driver_dac` component. To declare that your component depends on `esp_driver_dac`, add the following to your CMakeLists.txt:

  >     REQUIRES esp_driver_dac

  > or

  >     PRIV_REQUIRES esp_driver_dac

### Type Definitions

typedef soc_periph_dac_digi_clk_src_t dac_continuous_digi_clk_src_t

  DAC DMA (digital controller) clock source.

typedef soc_periph_dac_cosine_clk_src_t dac_cosine_clk_src_t

  DAC cosine wave generator clock source.

### Enumerations

enum dac_continuous_channel_mode_t

  DAC channel work mode in dma mode.

  备注

  Only take effect when multiple channels enabled.

  备注

  Assume the data in buffer is 'A B C D E F' DAC_CHANNEL_MODE_SIMUL:

  - channel 0: A B C D E F

  - channel 1: A B C D E F DAC_CHANNEL_MODE_ALTER:

  - channel 0: A C E

  - channel 1: B D F

  Values:

  enumerator DAC_CHANNEL_MODE_SIMUL

    The data in the DMA buffer is simultaneously output to the enable channel of the DAC.

  enumerator DAC_CHANNEL_MODE_ALTER

    The data in the DMA buffer is alternately output to the enable channel of the DAC.

### Header File

- components/esp_hal_ana_conv/include/hal/dac_types.h

- This header file can be included with:

  >     #include "hal/dac_types.h"

- This header file is a part of the API provided by the `esp_hal_ana_conv` component. To declare that your component depends on `esp_hal_ana_conv`, add the following to your CMakeLists.txt:

  >     REQUIRES esp_hal_ana_conv

  > or

  >     PRIV_REQUIRES esp_hal_ana_conv

### Macros

IS_VALID_DAC_CHANNEL(channel)

DAC_CHANNEL_MASK_CH0

  DAC channel 0 mask

DAC_CHANNEL_MASK_CH1

  DAC channel 1 mask

DAC_CHANNEL_MASK_ALL

  Bitwise OR of all valid channel masks

IS_VALID_DAC_CHANNEL_MASK(mask)

  备注

  0 is valid

DAC_CHANNEL_MASK_FOREACH(channel, mask)

  Use a loop to extract every channel (dac_channel_t) from the mask (dac_channel_mask_t).

### Type Definitions

typedef uint32_t dac_channel_mask_t

### Enumerations

enum dac_channel_t

  ESP32:

  - DAC channel 0: GPIO25

  - DAC channel 1: GPIO26 ESP32S2:

  - DAC channel 0: GPIO17

  - DAC channel 1: GPIO18

  Values:

  enumerator DAC_CHAN_0
  enumerator DAC_CHAN_1
  enumerator DAC_CHAN_MAX

    For checking purpose

enum dac_cosine_atten_t

  The attenuation of the amplitude of the cosine wave generator. The max amplitude is VDD3P3_RTC.

  Values:

  enumerator DAC_COSINE_ATTEN_DEFAULT

    No attenuation to the DAC cosine wave amplitude. Default.

  enumerator DAC_COSINE_ATTEN_DB_0

    Original amplitude of the DAC cosine wave, equals to DAC_COSINE_ATTEN_DEFAULT

  enumerator DAC_COSINE_ATTEN_DB_6

    1/2 amplitude of the DAC cosine wave

  enumerator DAC_COSINE_ATTEN_DB_12

    1/4 amplitude of the DAC cosine wave

  enumerator DAC_COSINE_ATTEN_DB_18

    1/8 amplitude of the DAC cosine wave

enum dac_cosine_phase_t

  Set the phase of the cosine wave generator output.

  备注

  Only 0 or 180 are supported, it will be set to 0 as default if configured to an unsupported phase.

  Values:

  enumerator DAC_COSINE_PHASE_0

    Phase shift +0°

  enumerator DAC_COSINE_PHASE_180

    Phase shift +180°

此文档对您有帮助吗？

- 反馈已收到，谢谢！
- 如果您有其他意见，欢迎填写乐鑫文档反馈表。

- 我们重视您的反馈。
- 您可以填写乐鑫文档反馈表告诉我们如何改进该文档。