Stuck creating an accurate, flexible waveform in the kHz range on the arduino uno r4 minuma

Hey everyone, thank you for your help! I'm an absolute arduino beginner trying to use the arduino Uno R4s DAC pin to output a modulated sine wave that goes to a nice amplifier that drives a piezo. Im trying to get to a frequency range of between 1 and 10 kHz and want the waves to be as smooth as possible. My first attempt was using the analogWave library, but it uses a quantization that I can't seem to be able to turn up enought to work for my purpose. This library also has a buffer function, but since no documentation seems to exists and the C code itself is (so far) baffeling me, I havent been able to get it to work. My second attemt was to compute the function values live using the device time in the loop. However, millis() and micros() is too imprecise for me. I then read the excellent discusssions in this thread (Hairy output on R4 DAC), but using the chips oscillators directly for timing is way too advanced for me and all my attempts to date failed. I will probably continue to bang my head against this approach, but before I do I wanted to know if I am missing something obvious or if anyone had any good reading recommendations to help with this kind of issue. All the best and thank you!

are you saying that something like this does not work ? (I don't own that board so can't test)

#include "analogWave.h"
 analogWave wave(DAC); 
 int freq = 10000; // 10 kHz
 
void setup()  {
  wave.sine(freq); // Generate a sine wave with the chosen frequency
}
 
void loop()  {}
1 Like

Have you seen this video?

You can access the software from there as well.
The trick here is that rather than calculate the waveform as you need each sample, it uses a pre-calculated look up table and then reads the appropriate point in the look up table.

The resolution of the waveform is governed by how many points are in your lookup. So if you want more resolution then just generate a bigger look up table. This example waveform is enough for any quantization noise to be in the ultrasonic frequency range. But you can go much faster than you can with the analogWave library because that tries to fit everything into one buffer and it can't work as fast.

All digital waveforms use quantization.

This code can run much much faster. Note that it has a ramp at the end of each waveform to reduce the audio pop you would otherwise get, but if this not what you want you can simply miss out this section.

I think from memory this technique could go at a sample rate of 360K samples per second, enough for any resolution you might need in practice for a 1 and 10 Khz wave.

1 Like

@J-M-L , yes! Or at least not precise enough for me, and not with the capabilities that I need. Thank you!

@Grumpy_Mike Thank you for your reply! As i said, I have been reading through your discussion with susan parker about that project and it has been super helpfull in understanding what the problem is. Unfortunatly, neither my C++ nor my microcontroler knowledge (X-ray/Image proccessing guy here) are up to the task of translating it to what I need, but that might need to change. I was hoping there was a more noob friendly solution that I was simply missing, but if not, I will try again using your approach and maybe post here again if I get stuck on something. Thank you both for taking the time!

In amplitude and in time.

Audio DACs have a low-pass "smoothing" filter but for the highest frequencies or wave shapes with fast rise or fall times, you may not want that.

1 Like

@DVDdoug Yes! In principle the arduino should be fast enough and the DAC high resolution enough for that not to be an issue in my case though. For posterities sake, what I wanted to do was this:

  int freq = 10000;
  int AMP = 4096/2;

void setup() {
  pinMode(DAC, OUTPUT);
  analogWriteResolution(12);  
  Serial.begin(9600); // open the serial port at 9600 bps: 
}

void loop() {
  /works for low freqs, higher ones not so much
  unsigned long time = micros();
  analogWrite(DAC,AMP+AMP*(sin(2*PI*time/1000000*freq)));
  Serial.print(AMP+AMP*(sin(2*PI*time/1000000*freq)));  
}

Just with a higher time resolution. But @Grumpy_Mikes approach is probably better and will definetly teach me something, so on to that

You could also consider to use the AD9833 function generator board. It's cheap and easy to use:

image

Another approach if the frequency range is not too wide, would be to output a PWM signal and then filter it strongly with low pass filters to get the sine wave.

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