espressif / arduino-esp32

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

Cosine generator offset = 0 produces error output #6265

Open palmerr23 opened 2 years ago

palmerr23 commented 2 years ago

Board

ESP32 DevkitC WROOM-32D

Device Description

Plain Devkit module

Hardware Configuration

No

Version

v2.0.2

IDE Name

Arduino 1.8.13

Operating System

Win 11

Flash frequency

80MHz

PSRAM enabled

no

Upload speed

921600

Description

Cosine generator.

When dac_cw_config_t cosineConf.offset == 0 the output is as if a value of -127 has been input (i.e. cuts off the bottom half of the waveform).

The issue is only visible for cosineConf.offset == 1 (full-scale output).

Offset values of +1 or -1 produce the desired small offset from half VDD.

The issue appears to be in the DAC driver library, in dac_cw_generator_config().

Sketch

// DAC Cosine Generator  - offset error  
#include "driver/dac.h"
#include <driver/dac_common.h>
#include "esp_err.h"

int8_t cw_offset = 0;

// only scale and freqency should be changed be code
dac_cw_config_t cosineConf = {DAC_CHANNEL_2, DAC_CW_SCALE_1, DAC_CW_PHASE_0, 5000, cw_offset};

void setup()
{ 
  Serial.begin(115200);
  delay(2000);  
  Serial.println("Cosine test DAC channel 2.");

  Serial.printf("Config %s\n", (dac_cw_generator_config(&cosineConf) == ESP_OK)? "OK" : "BAD");
  Serial.printf("Co Enable %s\n", (dac_cw_generator_enable()== ESP_OK)? "OK" : "BAD");
  Serial.printf("DAC Enable %s\n", (dac_output_enable(DAC_CHANNEL_2) == ESP_OK)? "OK" : "BAD");
  printSineConfig();
  Serial.println("Setup done");
}

void loop()
{
    cosineConf.offset = -1;
    dac_cw_generator_config(&cosineConf);
    printSineConfig(); 
    delay(5000); 

    cosineConf.offset = 0;
    dac_cw_generator_config(&cosineConf);
    printSineConfig(); 
    delay(5000); 

    cosineConf.offset = 1;
    dac_cw_generator_config(&cosineConf);
    printSineConfig(); 
    delay(5000); 
}
void printSineConfig()
{
  Serial.printf("Cosine: Chan =: %i, ", cosineConf.en_ch);
  Serial.printf("Scale = %i, ", cosineConf.scale);
 // Serial.printf("Phase = %i, ",cosineConf.phase);
  //Serial.printf("Freq = %i, ",cosineConf.freq);
  Serial.printf("Offset = %i\n",cosineConf.offset);  
}

Debug Message

No debug messages

Other Steps to Reproduce

Should not need any other steps to reproduce issue

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

kseungjin commented 2 years ago

Hello.

Firstly, thank you for the information about DAC.

Nothing but, I want to conduct above code but, I cannot find library.

So can you share it? If it is possible please share through the email. (ksjpcad@gmail.com)

Thank you. Best regards.

palmerr23 commented 2 years ago

The library is dac_hal.h

In my installation it's at C:\Users\XXXXX\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.2\tools\sdk\esp32\include\hal\esp32\include\hal\dac_ha.h

BTW, there's probably nothing you can do to simply resolve the issue, as it appears to be the inbuilt hardware cosine generator that's causing the issue. In fancy cosine generators, they use a complex algorithms for interpolation, and write the result into a buffer, which is replayed endlessly. In the hardware implementation there's (probably) no buffer, so I suspect that they use a simple interpolation method to minimise the CPU load.

Here's a good article on the subject: https://www.analog.com/en/technical-articles/an-almost-pure-dds-sine-wave-tone-generator.html

I've found that a Sallen-Key filter with a knee at around 75kHz works pretty well to smooth and buffer the output: http://sim.okawa-denshi.jp/en/OPseikiLowkeisan.htm

I've got N&D down to around 1%, with such a filter, which is close to the 48dB theoretical limit for an 8-bit implementation.

If you care about a rally good sine wave, then you'll need to use one an external DAC with of the many available DDS libraries.

VojtechBartoska commented 2 years ago

Hello, can you please retest this on v2.0.3-rc1?

palmerr23 commented 2 years ago

Issue is still present on v2.0.3-rc1 - this appears to be an issue with the cosine generator itself, rather than code.