How to change the frequency ?

Hi
This example is producing 440 Hz nice sine wave, how to modify the code to have nice 20kHz nice sine wave ? Just changing from 440 to 20000 does not producing any sine.

end of set up

  setAllFreq(440);
/*
 * https://diyelectromusic.com/2024/04/01/esp32-and-pwm-part-2/
 * https://github.com/diyelectromusic/sdemp/blob/main/src/SDEMP/ArduinoESP32PWM2/ArduinoESP32PWM2.ino
  /*
  // Simple DIY Electronic Music Projects
  //    diyelectromusic.wordpress.com
  //
  //  Arduino ESP32 PWM - Part 2
  //  https://diyelectromusic.wordpress.com/2024/04/01/esp32-and-pwm-part-2/
  
/*
  Using principles from the following Arduino tutorials:
    ESP32 for Arduino     - https://docs.espressif.com/projects/arduino-esp32/
    ESP32 Arduino LEDC    - https://espressif-docs.readthedocs-hosted.com/projects/arduino-esp32/en/latest/api/ledc.html
*/

//#define TIMING_PIN 12
#define NUM_PWM_PINS 4
int pwm_pins[NUM_PWM_PINS] = {13, 12, 14, 27};

// NB: Rely on fact we're using an 8-bit index to auto wrap for our 256 samples
#define NUM_SAMPLES   256
uint8_t sinedata[NUM_SAMPLES] = {
  128, 131, 134, 137, 140, 144, 147, 150, 153, 156, 159, 162, 165, 168, 171, 174,
  177, 179, 182, 185, 188, 191, 193, 196, 199, 201, 204, 206, 209, 211, 213, 216,
  218, 220, 222, 224, 226, 228, 230, 232, 234, 235, 237, 239, 240, 241, 243, 244,
  245, 246, 248, 249, 250, 250, 251, 252, 253, 253, 254, 254, 254, 255, 255, 255,
  255, 255, 255, 255, 254, 254, 254, 253, 253, 252, 251, 250, 250, 249, 248, 246,
  245, 244, 243, 241, 240, 239, 237, 235, 234, 232, 230, 228, 226, 224, 222, 220,
  218, 216, 213, 211, 209, 206, 204, 201, 199, 196, 193, 191, 188, 185, 182, 179,
  177, 174, 171, 168, 165, 162, 159, 156, 153, 150, 147, 144, 140, 137, 134, 131,
  128, 125, 122, 119, 116, 112, 109, 106, 103, 100,  97,  94,  91,  88,  85,  82,
  79,  77,  74,  71,  68,  65,  63,  60,  57,  55,  52,  50,  47,  45,  43,  40,
  38,  36,  34,  32,  30,  28,  26,  24,  22,  21,  19,  17,  16,  15,  13,  12,
  11,  10,   8,   7,   6,   6,   5,   4,   3,   3,   2,   2,   2,   1,   1,   1,
  1,   1,   1,   1,   2,   2,   2,   3,   3,   4,   5,   6,   6,   7,   8,  10,
  11,  12,  13,  15,  16,  17,  19,  21,  22,  24,  26,  28,  30,  32,  34,  36,
  38,  40,  43,  45,  47,  50,  52,  55,  57,  60,  63,  65,  68,  71,  74,  77,
  79,  82,  85,  88,  91,  94,  97, 100, 103, 106, 109, 112, 116, 119, 122, 125
};

// Following wavetables are calculated...
uint8_t sawdata[NUM_SAMPLES];
uint8_t tridata[NUM_SAMPLES];
uint8_t sqdata[NUM_SAMPLES];

// Use a SAMPLE_RATE that is a multiple of the basic wavetable
#define BASE_FREQ_MULT 128
#define SAMPLE_RATE (NUM_SAMPLES*BASE_FREQ_MULT)  // i.e. 256*128 = 32768 Hz

// 10 bit resoution for PWM will mean 78277 Hz PWM frequency
// 9 bit resoution for PWM will mean 156555 Hz PWM frequency
// 8 bit resoution for PWM will mean 313111 Hz PWM frequency
#define PWM_RESOLUTION 8
#define PWM_FREQUENCY  313111

// Timer configuration
// NB: CPU Freq = 80MHz so dividers used to get other
//     frequencies for syncing to other operations.
//
// For a timer frequency of 1000000Hz i.e. divider of 80,
// the Timer alarms would be configured in uS.
// So need to convert required sample rate into uS.
//    Period = 1 / Sample Rate = 1 / 32768 = 30.5uS
//
// However, if up the timer frequency to 10MHz then
// alarms will be set in 0.1uS.
//
#define TIMER_FREQ 10000000  // 1MHz * 10
#define TIMER_RATE 305       // 30.5uS * 10

// For direct digital synthesis from a wavetable
// we have an accumulator to store the index into
// the table and an increment based on the sample
// rate and frequency.
//    Increment = Frequency * (Number of Samples in wavetable / Sample Rate)
//    Increment = Frequency * (256 / 32768)
//    Increment = Frequency / 128
//
// But using a 8.8 fixed-point accumulator and increment:
//   Increment = 256 * Frequency / 128
//   Increment = Frequency * 2
//
#define FREQ2INC(f) (f*2)
uint16_t acc[NUM_PWM_PINS];
uint16_t inc[NUM_PWM_PINS];
#if 1
uint16_t mul[NUM_PWM_PINS] = {1,1,1,1};
uint8_t *pWT[NUM_PWM_PINS] = {sinedata, sawdata, tridata, sqdata};
#else
uint16_t mul[NUM_PWM_PINS] = {1,2,3,4}; // Optional frequency multipliers
uint8_t *pWT[NUM_PWM_PINS] = {sinedata, sinedata, sinedata, sinedata};
#endif
void setFreq (int ch, unsigned freq) {
  if (ch < NUM_PWM_PINS) {
    // First apply any optional frequency multipliers
    freq = freq * mul[ch];
    inc[ch] = FREQ2INC(freq);
    Serial.print(ch);
    Serial.print("\tFreq: ");
    Serial.print(freq);
    Serial.print("\tIncrement: ");
    Serial.println(inc[ch]);
  }
}

void setAllFreq (unsigned freq) {
  for (int i=0; i<NUM_PWM_PINS; i++) {
    setFreq(i, freq);
  }
}

// Assumed to be running at SAMPLE_RATE
void ddsUpdate (int ch) {
  if (ch < NUM_PWM_PINS) {
    acc[ch] += inc[ch];
    ledcWrite (pwm_pins[ch], pWT[ch][acc[ch] >> 8]);
  }
}

// Use the ESP32 timer routines
hw_timer_t *timer = NULL;

int toggle;
void ARDUINO_ISR_ATTR timerIsr (void) {
#ifdef TIMING_PIN
  toggle = !toggle;
  digitalWrite(TIMING_PIN, toggle);
#endif
  for (int i=0; i<NUM_PWM_PINS; i++) {
    ddsUpdate(i);
  }
}

void setupWavetables () {
  for (int i=0; i<NUM_SAMPLES; i++) {
    sawdata[i] = i;
    if (i<NUM_SAMPLES/2) {
      tridata[i] = i*2;
      sqdata[i] = 255;
    } else {
      tridata[i] = 255-(i-128)*2;
      sqdata[i] = 0;
    }
  }
}

void setup () {
  Serial.begin(115200);
  setupWavetables();
#ifdef TIMING_PIN
  pinMode(TIMING_PIN, OUTPUT);
  digitalWrite(TIMING_PIN, LOW);
#endif
  timer = timerBegin(TIMER_FREQ);
  timerAttachInterrupt(timer, &timerIsr);
  timerAlarm(timer, TIMER_RATE, true, 0);
  Serial.print("Timer frequency: ");
  Serial.println(timerGetFrequency(timer));
  for (int i=0; i<NUM_PWM_PINS; i++) {
    ledcAttach(pwm_pins[i], PWM_FREQUENCY, PWM_RESOLUTION);
  }
  setAllFreq(440);
}

void loop () {
//  Serial.println(acc>>8);
}

have a look at AD9833 Programmable Waveform Generator
e.g. signal-generator-with-esp32-and-ad9833-dds-module

1 Like

So why not change from 440 to 540 and see if you have a sin wave?

In other words see where it stops being able to produce a wave.
Basically you are asking too much of that code to go as fast as you want to.

At 20000 Hz you have 50 micros to write all 256 points. 8 or maybe 16 points might be more possible. At 440 Hz you have over 2272 micros, almost 10 micros per point.

1 Like

[quote="Grumpy_Mike, post:3, topic:1381335"]
see where it stops being able to produce a wave.
[/
4kHz

Thanks that feels about a correct answer.

If you go through the tables not one at a time, but two at a time does this double? I would suspect it will.

If you go through the table a fraction of time you will have more control over the frequency. This is done by incrementing an integer but only using the part of the integer over 256 and shifted to the right eight times as your pointer to the next sample to use.

As pointed out your processor is not fast enough to do exactly what you want to do.

Your data shows you are using an 8 bit conversion (256 possible values).
For a "reasonable" sine wave you then only need "about" 20 samples per period.

As you are using PWM to do the d-a conversion, you can also use a simple RC filter to reduce harmonics.

1 Like

What do you need the 20kHz waveform for?

Tom.... :smiley: :+1: :coffee: :australia:

How to do that ?

As your commented out code says:-

Not stable 10 kHz with distortions

I just want to have similar generator but using esp32

I have another code but is missing sine wave.


#include <driver/ledc.h>

void setup() {
    // Конфигурация таймера
    ledc_timer_config_t timerConfig = {
        .speed_mode = LEDC_LOW_SPEED_MODE, 
        .duty_resolution = LEDC_TIMER_10_BIT, 
        .timer_num = LEDC_TIMER_0, 
        .freq_hz = 10000, //
        .clk_cfg = LEDC_AUTO_CLK 
    };
    ledc_timer_config(&timerConfig);

    
    ledc_channel_config_t channelConfig1 = {
        .gpio_num = 12, 
        .speed_mode = LEDC_LOW_SPEED_MODE,
        .channel = LEDC_CHANNEL_0, 
        .timer_sel = LEDC_TIMER_0, 
        .duty = 512, 
        .hpoint = 0 
    };
    ledc_channel_config(&channelConfig1);

    
    ledc_channel_config_t channelConfig2 = {
        .gpio_num = 27, 
        .speed_mode = LEDC_LOW_SPEED_MODE,
        .channel = LEDC_CHANNEL_1, 
        .timer_sel = LEDC_TIMER_0, 
        .duty = 512, 
        .hpoint = 256 
    };
    ledc_channel_config(&channelConfig2);
}
void loop() {}

How to implement this function to it ?

/**
*
* Outputs a sine wave on the output pin
*
**/
void doSineWave()
{
  // This essentially works the same as the square wave function.
  // However, instead of creating a digital output, the counter
  // variable is as an angle and passed to the sine function.
  // Then, the counter is increased by a step until it reaches 360
 
  float rads = (angle * 71) / 4068;
  int val = 512 + (512.0 * sin(rads));
 
  analogWrite(OUT_PIN, val);
  angle = (angle + step);
 
  if(angle >= 360.0)
	angle = 0;
}

Never ever try something you have no knowledge about from an instructiables page. There is no quality control and they are often written by people with an inflated idea of there own knowledge. This is no exception to that rule and is littered with mistake after mistake.

You are compounding this by wanting to expand this pile of garbage in a direction you do not understand.

1 Like

I entirely agree Mike, the OP is trying to achieve something fairly trivial in an "old school", inefficient and un-necessarily complicated way. As @horace said, just do it this way

or if the OP REALLY Just wants to use an esp32 there is this - fully documented and sensible.

Every ESP32 is many times faster than an AVR.

Arduino Due has 2 DACs to do true audio quality analog-out.

Hi,
If you read at the end of that destructible;

You will notice that the pulse wave is the only wave which truly ranges from 1Hz to 50kHz. Since the sampling rate is 100kHz, the sine, triangle, and saw waves start to become somewhat unrecognizable at about 25kHz (they are only comprised of 4 samples per cycle- 100kHz/25kHz). The saw and triangle waves only go down to about 100Hz, this is because the values of triInc and sawInc get so low that they are rounded to zero below this frequency. The sine wave reaches all the way to 1 HZ but the resolution stays the same for anything under 5Hz, since the Arduino only has enough memory to store about 20 thousand samples.

Also the 200 replies....

Have you built this circuit?

Tom.... :smiley: :+1: :coffee: :australia:

I do not, I practicing ESP32

Can you post a schematic PLEASE.

Tom.... :smiley: :+1: :coffee: :australia:

I am using this board , pins are described in the sketch
https://pt.aliexpress.com/item/1005006259553219.html