Simple way to code sine frequency decreases, while amplitude increases?

Is there an easier way to make a esp32 DAC output a sine wave that decreases in frequency AND increases in amplitude?

For example, DAC starts off at 5 hertz at 50% amplitude and over the next 5 seconds the frequency gradually drops down from 5hz-->2hz and the amplitude gradually goes up from 50%-->100%

Writing this like a newbe that I am bit by bit would take forever

dacWrite(DAC_CH1, value);
  delay(value);

You need to come up with a formula for value which produces a sine wave which changes in frequency and amplitude over time. Time to build up your coding skills!

Start simpler by creating a sine wave which has a fixed frequency and amplitude, and build from there.

I would also recommend not getting used to using delay(). It will cause problems as your code gets more sophisticated, and it will never be very accurate.

1 Like

I would use timer interrupts to generate sine wave DAC output on an ESP32
have a look at esp32-dac-audio-arduino-examples

This should get you started...

const unsigned long int interval = 5 * 60 * 1000;
const int freqDelay = 5Hz delay (you calculate this)
const float freqIncrement = (2Hz delay - 5Hz delay)/(float)(interval);

int amplitudeStart = 255 * 0.5;
float amplitude = amplitudeStart;
const float ampIncrement = (255 - amplitudeStart)/(float)(interval);

for (float i = interval; i > 0; i-= freqIncrement)
{
  dacWrite(DAC_CH1, amplitude); // Final product would call sine wave generator function here
  delayMicroseconds(freqDelay);
  // Decrease frequency
  freqDelay += freqIncrement);
  // Increase amplitude
  amplitude += ampIncrement;  
}

Now, this should produce a ramp not a sine but with the addition of a sine wave table and a generator to read that table, that should be easy to accomplish. I'm only trying to show the technique of what you want to do, not the final solution (too much work!).

1 Like

Also bear in mind that 5 seconds of a 5Hz sine wave is only 25 complete cycles. What's this for?

One more thing: it occurs to me that an envelope generator might be a useful solution.

have a look at the following code
using an ESP32 DAC and timer it generates 5Hz enter < and > to change amplitude

// ESP32 DAQ
// ESP32 timer interrupts 5Hz sine wave using 100 sample lookup table
// enter < and > to change amplitude

// from ESP32 Sine Wave Example https://deepbluembedded.com/esp32-dac-audio-arduino-examples/

/*
* LAB Name: ESP32 Sine Wave Generation Example
* Author: Khaled Magdy
* DeepBlueMbedded 2023
* For More Info Visit: www.DeepBlueMbedded.com
*/

#include <driver/dac.h>

// Timer0 Configuration Pointer (Handle)
hw_timer_t *Timer0_Cfg = NULL;

// Sine LookUpTable & Index Variable
uint8_t SampleIdx = 0;
const uint8_t sineLookupTable[] = {
  128, 136, 143, 151, 159, 167, 174, 182,
  189, 196, 202, 209, 215, 220, 226, 231,
  235, 239, 243, 246, 249, 251, 253, 254,
  255, 255, 255, 254, 253, 251, 249, 246,
  243, 239, 235, 231, 226, 220, 215, 209,
  202, 196, 189, 182, 174, 167, 159, 151,
  143, 136, 128, 119, 112, 104, 96, 88,
  81, 73, 66, 59, 53, 46, 40, 35,
  29, 24, 20, 16, 12, 9, 6, 4,
  2, 1, 0, 0, 0, 1, 2, 4,
  6, 9, 12, 16, 20, 24, 29, 35,
  40, 46, 53, 59, 66, 73, 81, 88,
  96, 104, 112, 119
};

volatile int counter = 0, amplitude = 10;  // amplitude 0 to 10 in steps of 1

// The Timer0 ISR Function (Executes Every Timer0 Interrupt Interval)
void IRAM_ATTR Timer0_ISR() {
  // Send SineTable Values To DAC One By One
  dac_output_voltage(DAC_CHANNEL_1, sineLookupTable[SampleIdx++] * amplitude / 10);
  if (SampleIdx == 100) {
    SampleIdx = 0;
  }
  counter++;
}

void setup() {
  Serial.begin(115200);
  Serial.println("\nESP32 DAC sine wave");
  // Configure Timer0 Interrupt
  Timer0_Cfg = timerBegin(0, 80, true);
  timerAttachInterrupt(Timer0_Cfg, &Timer0_ISR, true);
  timerAlarmWrite(Timer0_Cfg, 2000, true);
  timerAlarmEnable(Timer0_Cfg);
  // Enable DAC1 Channel's Output
  dac_output_enable(DAC_CHANNEL_1);
}

void loop() {
  // every second print interrupt counter
  static long timer = millis();
  if (millis() - timer > 1000) {
    Serial.println(counter);
    counter = 0;
    timer = millis();
  }
  // check if < (decrease amplitude) or > (increase amplitude) entered
  if (Serial.available()) {
    char ch = Serial.read();
    if (ch == '<')
      if (amplitude == 0) return;  // range is 0 to 10
      else amplitude -= 1;
    if (ch == '>')
      if (amplitude == 10) return;  // range is 0 to 10
      else amplitude += 1;
  }
}

output
image

by pressing < the amplitude reduces to 0 pressing > increases it (maximum is approx 3.2V)

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