ESP32 DAC cosine generator

In the ESP32 manual at page 629 I read:

29.5.4 Cosine Waveform Generator
The cosine waveform (CW) generator can be used to generate a cosine / sine tone.

I wonder how to use this feature from an Arduino code. I find a lot of examples the uses the dacWrite() function with a LUT of even with trigonometric functions to generate a sine tone.

How to use this specific DAC feature?

may be a good starting point to study this is the following function code. The readme is pretty informative

1 Like

for accurate frequency generation I would use a DDS device, e.g.how-to-use-arduino-dds-frequency-signal-generator-ad9850

Here's a working example to get you started - this will compile in PlatformIO but should compile in the Arduino IDE just as easily provided the relevant tool chains are there. This is essentially the same as shown above but modified to suit the Arduino platform from FreeRTOS.

#include "arduino.h"
#include "soc/sens_reg.h"
#include "soc/rtc.h"
#include "driver/dac.h"

int clk_8m_div = 7;      // RTC 8M clock divider (division is by clk_8m_div+1, i.e. 0 means 8MHz frequency)
int frequency_step = 8;  // Frequency step for CW generator
int scale = 0;           // 50% of the full scale
int offset;              // leave it default / 0 = no any offset
int invert =2;          // invert MSB to get sine waveform

/*
 * Enable cosine waveform generator on a DAC channel
 */
void dac_cosine_enable(dac_channel_t channel)
{
  // Enable tone generator common to both channels
  SET_PERI_REG_MASK(SENS_SAR_DAC_CTRL1_REG, SENS_SW_TONE_EN);
  switch(channel) 
  {
      case DAC_CHANNEL_1:
          // Enable / connect tone tone generator on / to this channel
          SET_PERI_REG_MASK(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_CW_EN1_M);
          // Invert MSB, otherwise part of waveform will have inverted
          SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_INV1, 2, SENS_DAC_INV1_S);
          break;
      case DAC_CHANNEL_2:
          SET_PERI_REG_MASK(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_CW_EN2_M);
          SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_INV2, 2, SENS_DAC_INV2_S);
          break;
  }
}


/*
 * Set frequency of internal CW generator common to both DAC channels
 *
 * clk_8m_div: 0b000 - 0b111
 * frequency_step: range 0x0001 - 0xFFFF
 *
 */
void dac_frequency_set(int clk_8m_div, int frequency_step)
{
    REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, clk_8m_div);
    SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL1_REG, SENS_SW_FSTEP, frequency_step, SENS_SW_FSTEP_S);
}

/*
 * Scale output of a DAC channel using two bit pattern:
 *
 * - 00: no scale
 * - 01: scale to 1/2
 * - 10: scale to 1/4
 * - 11: scale to 1/8
 *
 */
void dac_scale_set(dac_channel_t channel, int scale)
{
  switch(channel) 
  {
      case DAC_CHANNEL_1:
          SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_SCALE1, scale, SENS_DAC_SCALE1_S);
          break;
      case DAC_CHANNEL_2:
          SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_SCALE2, scale, SENS_DAC_SCALE2_S);
          break;
  }
}


/*
 * Offset output of a DAC channel
 *
 * Range 0x00 - 0xFF
 *
 */
void dac_offset_set(dac_channel_t channel, int offset)
{
  switch(channel) 
  {
      case DAC_CHANNEL_1:
          SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_DC1, offset, SENS_DAC_DC1_S);
          break;
      case DAC_CHANNEL_2:
          SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_DC2, offset, SENS_DAC_DC2_S);
          break;
  }
}


/*
 * Invert output pattern of a DAC channel
 *
 * - 00: does not invert any bits,
 * - 01: inverts all bits,
 * - 10: inverts MSB,
 * - 11: inverts all bits except for MSB
 *
 */
void dac_invert_set(dac_channel_t channel, int invert)
{
    switch(channel) 
    {
        case DAC_CHANNEL_1:
            SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_INV1, invert, SENS_DAC_INV1_S);
            break;
        case DAC_CHANNEL_2:
            SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_INV2, invert, SENS_DAC_INV2_S);
            break;
    }
}


void setup(void)
{
  Serial.begin(9600);
  Serial.println("Cosine Generator Test starting");
  dac_frequency_set(clk_8m_div, 2);

  dac_cosine_enable(DAC_CHANNEL_1);
  dac_cosine_enable(DAC_CHANNEL_2);

  dac_output_enable(DAC_CHANNEL_1);
  dac_output_enable(DAC_CHANNEL_2);
}

void loop(void)
{
  static  int f = 1; // 750 = 100Khz, 1000 = 132Khz,  (Much higher and it starts to distort)
  dac_frequency_set(clk_8m_div, f);
  delay(500);
  f += 10;

}
1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.