# Digital To Analog Converter (DAC)

[中文]

## Overview

ESP32 has two 8-bit DAC (digital to analog converter) channels respectively connected to GPIO25 (Channel 1) and GPIO26 (Channel 2). Each DAC channel can convert the digital value 0~255 to the analog voltage 0~Vref (The reference voltage 'Vref' here is input from the pin VDD3P3_RTC, which ideally equals to the power supply VDD). The output voltage can be calculated as the following:

    out_voltage = Vref * digi_val / 255

The DAC peripheral supports outputting analog signal in the following ways:

1. Outputting a voltage directly. The DAC channel keeps outputting a specified voltage.

2. Outputting continuous analog signal by DMA. The DAC converts the data in a buffer at a specified frequency.

3. Outputting a cosine wave by the cosine wave generator. The DAC channel can output a cosine wave with specified frequency and amplitude.

For other analog output options, see Sigma-Delta Modulation and LED Control. Both modules produce high-frequency PWM/PDM output, which can be hardware low-pass filtered in order to generate a lower frequency analog output.

## Functional Overview

### Resources Management

The DAC on ESP32 has two channels. The channels have separate software resources and can be managed by `dac_oneshot_handle_t`, `dac_cosine_handle_t`, or `dac_continuous_handle_t` according to the usage. Registering different modes on a same DAC channel is not allowed.

### Direct Voltage Output (One-shot/Direct Mode)

The DAC channels in the group can convert an 8-bit digital value into the analog when `dac_oneshot_output_voltage()` is called (it can be called in ISR). The analog voltage is kept on the DAC channel until the next conversion starts. To start the voltage conversion, the DAC channels need to be enabled first through registering by `dac_oneshot_new_channel()`.

### Continuous Wave Output (Continuous/DMA Mode)

DAC channels can convert digital data continuously via the DMA. There are three ways to write the DAC data:

> 1. Normal writing (synchronous): Data can be transmitted at one time and kept blocked until all the data has been loaded into the DMA buffer, and the voltage is kept as the last conversion value while no more data is inputted. It is usually used to transport a long signal like an audio. To convert data continuously, the continuous channel handle need to be allocated by calling `dac_continuous_new_channels()` and the DMA conversion should be enabled by calling `dac_continuous_enable()`. Then data can be written by `dac_continuous_write()` synchronously. Refer to peripherals/dac/dac_continuous/dac_audio for examples.

> 2. Cyclical writing: A piece of data can be converted cyclically without blocking, and no more operation is needed after the data are loaded into the DMA buffer. But note that the inputted buffer size is limited by the number of descriptors and the DMA buffer size. It is usually used to transport short signals that need to be repeated, e.g., a sine wave. To achieve cyclical writing, call `dac_continuous_write_cyclically()` after the DAC continuous mode is enabled. Refer to peripherals/dac/dac_continuous/signal_generator for examples.

> 3. Asynchronous writing: Data can be transmitted asynchronously based on the event callback. `dac_event_callbacks_t::on_convert_done` must be registered to use asynchronous mode. Users can get the `dac_event_data_t` in the callback which contains the DMA buffer address and length, allowing them to load the data into the buffer directly. To use the asynchronous writing, call `dac_continuous_register_event_callback()` to register the `dac_event_callbacks_t::on_convert_done` before enabling, and then `dac_continuous_start_async_writing()` to start the asynchronous writing. Note that once the asynchronous writing is started, the callback function will be triggered continuously. Call `dac_continuous_write_asynchronously()` to load the data either in a separate task or in the callback directly. Refer to peripherals/dac/dac_continuous/dac_audio for examples.

The following diagram illustrates the life cycle of the DAC continuous driver and the state transitions associated with each API:

            flowchart TD
        NC(["Idle (Initial State)"]) -->|"new_channels()"| REG[Registered]
        REG -->|"del_channels()"| NC
        REG -->|"enable()"| EN[Enabled]
        EN -->|"disable()"| REG

        EN -->|"start_async_writing()"| ASYNC[Async Writing]
        ASYNC -->|"stop_async_writing()"| EN

        EN -->|"write_cyclically()"| CYCLIC[Cyclic Writing]
        CYCLIC -->|"stop_cyclically()"| EN

        EN -->|"write()"| SYNC[Sync Writing]
        SYNC -->|"write()"| SYNC
        SYNC -->|"on transmission complete"| EN

        subgraph REG_APIS [Registered State APIs]
            REGCB["register_event_callbacks()"]
        end

        subgraph ASYNC_APIS [Async Writing State APIs]
            AWRITE["write_asynchronously()"]
        end

        REG -. can call .-> REGCB
        ASYNC -. when receiving a callback .-> AWRITE

Note

- For brevity, the prefix `dac_continuous_` is omitted from all function names in the diagram.

- For backward compatibility, calling `dac_continuous_stop_cyclically()` to exit cyclic writing is optional — any API that transitions away from the Enabled state will automatically stop an ongoing cyclic conversion. However, explicitly calling `dac_continuous_stop_cyclically()` is recommended.

- Sync writing requires no explicit exit — any API that transitions away from the Enabled state will automatically stop the ongoing sync writing immediately (the data not yet converted is discarded).

On ESP32, the DAC digital controller can be connected internally to the I2S0 and use its DMA for continuous conversion. Although the DAC only needs 8-bit data for conversion, it has to be the left-shifted 8 bits (i.e., the high 8 bits in a 16-bit slot) to satisfy the I2S communication format. By default, the driver helps to expand the data to 16-bit wide automatically. To expand manually, please disable CONFIG_DAC_DMA_AUTO_16BIT_ALIGN in the menuconfig.

The clock of the DAC digital controller comes from I2S0 as well, so there are two clock sources for selection:

- `dac_continuous_digi_clk_src_t::DAC_DIGI_CLK_SRC_PLL_D2` supports frequency between 19.6 KHz to several MHz. It is the default clock which can also be selected by `dac_continuous_digi_clk_src_t::DAC_DIGI_CLK_SRC_DEFAULT`.

- `dac_continuous_digi_clk_src_t::DAC_DIGI_CLK_SRC_APLL` supports frequency between 648 Hz to several MHz. However, it might be occupied by other peripherals, thus not providing the required frequency. In such case, this clock source is available only if APLL still can be correctly divided into the target DAC DMA frequency.

### Cosine Wave Output (Cosine Mode)

The DAC peripheral has a cosine wave generator, which can generate cosine wave on the channels. Users can specify the frequency, amplitude, and phase of the cosine wave. To output the cosine wave, please acquire the DAC to cosine mode using `dac_cosine_new_channel()`, and then start the cosine wave generator by `dac_cosine_start()`.

Currently, the clock source of the cosine wave generator only comes from `RTC_FAST` which can be selected by `dac_cosine_clk_src_t::DAC_COSINE_CLK_SRC_RTC_FAST`. It is also the default clock source which is the same as `dac_cosine_clk_src_t::DAC_COSINE_CLK_SRC_RTC_DEFAULT`.

### Power Management

When the power management is enabled (i.e., CONFIG_PM_ENABLE is on), the system will adjust or stop the clock source of DAC before entering Light-sleep mode, thus potential influence to the DAC signals may lead to false data conversion.

When using DAC driver in continuous mode, it can prevent the system from changing or stopping the clock source in DMA or cosine mode by acquiring a power management lock. When the clock source is generated from APB, the lock type will be set to `esp_pm_lock_type_t::ESP_PM_APB_FREQ_MAX`. When the clock source is APLL (only in DMA mode), it will be set to `esp_pm_lock_type_t::ESP_PM_NO_LIGHT_SLEEP`. Whenever the DAC is converting (i.e., DMA or cosine wave generator is working), the driver guarantees that the power management lock is acquired after calling `dac_continuous_enable()`. Likewise, the driver will release the lock when `dac_continuous_disable()` is called.

### IRAM Safe

By default, the DAC DMA interrupt will be deferred when the cache is disabled for reasons like writing/erasing Flash. Thus the DMA EOF interrupt will not get executed in time.

To avoid such case in real-time applications, you can enable the Kconfig option CONFIG_DAC_ISR_IRAM_SAFE which:

1. Enables the interrupt being serviced even when cache is disabled;

2. Places driver object into DRAM (in case it is linked to PSRAM by accident).

This allows the interrupt to run while the cache is disabled but comes at the cost of increased IRAM consumption.

### Thread Safety

All the public DAC APIs are guaranteed to be thread safe by the driver, which means users can call them from different RTOS tasks without protection by extra locks. Notice that the DAC driver uses mutex lock to ensure the thread safety, thus the APIs except `dac_oneshot_output_voltage()` are not allowed to be used in ISR.

### Kconfig Options

- CONFIG_DAC_ISR_IRAM_SAFE controls whether the default ISR handler can work when cache is disabled. See IRAM Safe for more information.

- CONFIG_DAC_ENABLE_DEBUG_LOG is used to enable the debug log output. Enable this option increases the firmware binary size.

- CONFIG_DAC_DMA_AUTO_16BIT_ALIGN auto expands the 8-bit data to 16-bit data in the driver to satisfy the I2S DMA format.

## Application Example

- peripherals/dac/dac_continuous/signal_generator demonstrates how to use the DAC driver on ESP32 to output continuous voltage in two ways: by DMA transmission and by timer interrupt, generating different waveforms such as sine, triangle, saw tooth and square wave.

- peripherals/dac/dac_continuous/dac_audio demonstrates how to use the DAC driver on ESP32 to play a piece of audio stored in a buffer, with the audio being played every one second from a speaker or earphone.

- peripherals/dac/dac_cosine_wave demonstrates how to use the DAC driver on an ESP32 board to output a cosine wave on both channels, which can be monitored using an oscilloscope or the ADC channels internally.

- peripherals/dac/dac_oneshot demonstrates how to use the DAC driver on ESP32 to output a voltage that increases stepwise every 500 ms and resets to 0 periodically, with the output monitored via ADC or an optional oscilloscope.

## API Reference

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

  Note

  The channel will be enabled as well when the channel allocated

  Parameters:

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

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

  Returns:

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

  Note

  The channel will be disabled as well when the channel deleted

  Parameters:

    handle -- [in] The DAC oneshot channel handle

  Returns:

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

  Note

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

  Parameters:

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

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

  Returns:

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

  Note

  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.

  Parameters:

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

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

  Returns:

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

  Parameters:

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

  Returns:

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

  Parameters:

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

  Returns:

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

  Parameters:

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

  Returns:

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

  Note

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

  Parameters:

    - cont_cfg -- [in] Continuous mode configuration

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

  Returns:

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

  Parameters:

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

  Returns:

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

  Note

  Must enable the channels before

  Parameters:

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

  Returns:

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

  Parameters:

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

  Returns:

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

  Note

  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

  Note

  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.

  Parameters:

    - 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

  Returns:

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

  Note

  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.

  Note

  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`

  Note

  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.

  Parameters:

    - 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

  Returns:

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

  Note

  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.

  Parameters:

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

  Returns:

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

  Note

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

  Note

  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.

  Parameters:

    - 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

  Returns:

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

  Note

  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

  Parameters:

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

  Returns:

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

  Parameters:

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

  Returns:

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

  Note

  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`

  Parameters:

    - 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

  Returns:

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

  Note

  The callbacks are all running under ISR environment

  Note

  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.

  Note

  Only take effect when multiple channels enabled.

  Note

  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)

  Note

  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.

  Note

  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°

Was this page helpful?

- Thank you! We received your feedback.
- If you have any comments, fill in Espressif Documentation Feedback Form.

- We value your feedback.
- Let us know how we can improve this page by filling in Espressif Documentation Feedback Form.