espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
13.72k stars 7.43k forks source link

Frequency incorrect when using new style DAC dac_cosine libraries, also glitches on channel 1 #10192

Open Jay-esp opened 3 months ago

Jay-esp commented 3 months ago

Board

ESP32-WROOM-32

Device Description

devkit

Hardware Configuration

DAC output 1 (or 2) pins 25 or 26, tektronix oscilloscope for measurements

Version

v3.0.3

IDE Name

arduino 1.18.19

Operating System

windows 10

Flash frequency

80

PSRAM enabled

no

Upload speed

921600

Description

I generate a sine wave on one of the dac outputs, the old method with dac.h driver generates for a 500Hz setting a 520Hz signal, the new method with dac_cosine libraries generates 390Hz for the 500Hz setting, comparable errors on other frequencies. Plus there are spikes in the signal when using dac 1, not with dac2, actually on both old and new method, this is documented on the net and not resolved, the spikes are around the signal changes so at 90,180,270,360 degrees

Sketch

New code that generates 390Hz instead of 500

#include <driver/dac_cosine.h>
dac_cosine_handle_t dac_chan_handle;
void setup() {
  outputCW(500);
}

void loop() {
  delay(1000);
}

void outputCW( uint32_t freq ) {
  dac_cosine_config_t dac_cos_cfg = {
    .chan_id = DAC_CHAN_1, // GPIO25 pin on ESP32
    .freq_hz = freq,       // DAC frequency in Hz
    .clk_src = DAC_COSINE_CLK_SRC_DEFAULT, // RC_FAST
    .atten = DAC_COSINE_ATTEN_DEFAULT, // normal amplitude
    .phase = DAC_COSINE_PHASE_0, // phase value (0 or 180)
    .offset = 0,           // offset value -128 ~ +127
    .flags = { .force_set_freq = true }
  };

  if ( dac_chan_handle != NULL ) {
    dac_cosine_stop( dac_chan_handle );
    dac_cosine_del_channel( dac_chan_handle );
  }
  // Configure the DAC-CW channel
  dac_cosine_new_channel( &dac_cos_cfg, &dac_chan_handle );
  // Start te DAC-CW Generator on DAC channel
  dac_cosine_start( dac_chan_handle );
}

Old code that generates 520Hz

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

void setup() {
  DAC_Start();
  DAC_SetScale(0);
  DAC_SetFrequency(500);
}

void loop() {
  delay(2000);
}

void DAC_Start(void) {
  // Enable tone generator common to both channels
  SET_PERI_REG_MASK(SENS_SAR_DAC_CTRL1_REG, SENS_SW_TONE_EN);
  // 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);
  // enable channel
  dac_output_enable(DAC_CHANNEL_1);
}

void DAC_SetFrequency(double frequency)
{
  // f = s * 127 / v

  double f, delta, delta_min = 999999999.0;
  uint16_t divi = 0, step = 1, s;
  uint8_t clk_8m_div = 0; // 0 bis 7
  for (uint8_t div = 1; div < 9; div++)
  {
    s = round(frequency * div / 127);
    if ((s > 0) && ((div == 1) || (s < 1024)))
    {
      f = 127 * s / div;
      delta = abs(f - frequency);
      if (delta < delta_min)
      {
        step = s;
        divi = div - 1;
        delta_min = delta;
      }
    }
  }
  frequency = 127 * step / (divi + 1);
  REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, divi);
  SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL1_REG, SENS_SW_FSTEP, step, SENS_SW_FSTEP_S);
}

void DAC_SetScale(int scale) {
  /*
     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
  */
  SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_SCALE1, scale, SENS_DAC_SCALE1_S);
}

void DAC_Stop(void) {
  CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_CW_EN1_M);
  dac_output_disable(DAC_CHANNEL_1);
}

Debug Message

no errors are generated

Other Steps to Reproduce

its consistant using small demo code and minimal hardware

I have checked existing issues, online documentation and the Troubleshooting Guide

lbernstone commented 3 months ago

You will probably need to ask this at https://github.com/espressif/esp-idf/issues, since this is pure esp-idf code. First thing to check, however, is to collect the results of dac_cosine_new_channel and dac_cosine_start to make sure there are no errors there.

Jay-esp commented 3 months ago

You will probably need to ask this at https://github.com/espressif/esp-idf/issues, since this is pure esp-idf code. First thing to check, however, is to collect the results of dac_cosine_new_channel and dac_cosine_start to make sure there are no errors there.

I dont use the idf, just the arduino ide, tx for the tip but both functions return no error

lbernstone commented 3 months ago

The code comes from upstream, so it can't be fixed here.