Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
273 views

Arduino Waveform Generator: Step 1: Technical Considerations

This document describes an Arduino-based waveform generator with the following features: - It uses an 8-bit R2R DAC and 256 sample waveforms to generate analog signals up to 381 kHz sampling rate. - Waveform shape and frequency can be set using a single rotary encoder. It supports 20 predefined waveforms that are stored as 256-sample arrays. - An op-amp circuit buffers and optionally amplifies the DAC output, allowing voltages from millivolts to 20V. - The frequency is set precisely using a 32-bit phase accumulator, with a resolution of 1 mHz. - An Arduino sketch controls the waveform generation through direct port

Uploaded by

dheenadayalan
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
273 views

Arduino Waveform Generator: Step 1: Technical Considerations

This document describes an Arduino-based waveform generator with the following features: - It uses an 8-bit R2R DAC and 256 sample waveforms to generate analog signals up to 381 kHz sampling rate. - Waveform shape and frequency can be set using a single rotary encoder. It supports 20 predefined waveforms that are stored as 256-sample arrays. - An op-amp circuit buffers and optionally amplifies the DAC output, allowing voltages from millivolts to 20V. - The frequency is set precisely using a 32-bit phase accumulator, with a resolution of 1 mHz. - An Arduino sketch controls the waveform generation through direct port

Uploaded by

dheenadayalan
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 11

instructables

Arduino Waveform Generator

by rgco

In the lab, one often needs a repetitive signal of a * Fast: 381 kHz sampling rate
certain frequency, shape and amplitude. It may be to
test an amplifier, check out a circuit, a component or * Precise: 1mHz steps frequency range. As accurate
an actuator. Powerful waveform generators are as the Arduino crystal.
available commercially, but it is relatively easily to
make a useful one yourself with an Arduino Uno or * Easy operation: waveform and frequency settable
Arduino Nano, see for example: with single rotary encoder

https://www.instructables.com/id/Arduino-Waveform- * Wide range of amplitudes: millivolts to 20V


...
* 20 pre-defined waveforms. Straightforward to add
https://www.instructables.com/id/10-Resister-Ardui... more.

Here is the description of another one with the * Easy to make: Arduino Uno or Nano plus standard
following features: components

* Accurate waveforms: 8-bit output using R2R DAC,


256-sample shape

Step 1: Technical Considerations

Making an analog signal One shortcoming of the Arduino Uno and Nano is that
it does not have a digital-to-analog (DAC) converter,

Arduino Waveform Generator: Page 1


so it is not possible to make it output an analog sampled each period. For waveforms where the
voltage directly on the pins. One solution is the R2R signal changes smoothly, for example the sine wave,
ladder: 8 digital pins are connected to a resistor skipping samples is no problem. But for waveforms
network so that 256 levels of output can be reached. with narrow spikes, for example a square wave with a
Through direct port access, the Arduino can set 8 small duty cycle, there is the danger that for
pins simultaneously with a single command. For the frequencies above 1.5 kHz missing a single sample
resistor network, 9 resistors with value R are needed can result in a the waveform not behaving as
and 8 with value 2R. I used 10kOhm as a value for R, expected
that keeps the current from the pins to 0.5mA or less.
I guess R=1kOhm could work as well, since the Accuracy of the frequency
Arduino can easily deliver 5mA per pin, 40mA per
port. It is important that the ratio between the R and The number by which the phase is incremented at
the 2R resistors is really 2. That is most easily each sample is proportional to the frequency. The
achieved by putting 2 resistors of value R in series, frequency can thus be set to an accuracy of
for a total of 25 resistors. 381kHz/2^32=0.089mHz. In practice such accuracy is
hardly ever needed, so the interface limits to set the
Phase accumulator frequency in steps of 1mHz. The absolute precision of
the frequency is determined by the precision of the
Generating a waveform then comes down to Arduino clock frequency. This depends on the
repetitively sending a sequence of 8-bit numbers to Arduino type but most specify a frequency of
the Arduino pins. The waveform is stored in an array 16.000MHz, so a precision of ~10^-4. The code
of 256 bytes and this array is sampled and sent to the allows to modify the ratio of the frequency and the
pins. The frequency of the output signal is determined phase increment to correct for small deviations of the
by how fast one advances through the array. A 16MHz assumption.
robust, precise and elegant way to do that is with a
phase accumulator: a 32-bit number gets Buffering and amplification
incremented at regular intervals, and we use the 8
most significant bits as the index of the array. The resistor network has a high output impedance, so
its output voltage quickly drops if a load is attached.
Fast sampling That can be solved by buffering or amplifying the
output. Here, the buffering and amplification is done
Interrupts allow to sample at well-defined times, but with an opamp. I used the LM358 because I had
the overhead of interrupts limit the sampling some. It is a slow opamp (slew rate 0.5V per
frequency to ~100kHz. An infinite loop to update the microsecond) so at high frequency and high
phase, sample the waveform and set the pins takes amplitude the signal gets distorted. A good thing is
42 clock cycles, thus achieving a sampling rate of that it can handle voltages very close to 0V. The
16MHz/42=381kHz. Rotating or pushing the rotary output voltage is however limited to ~2V below the
encoder causes a pin change and an interrupt that rail, so using +5V power limits the output voltage to
gets out of the loop to change the setting (waveform 3V. Step-up modules are compact and cheap.
or frequency). At this stage the 256 numbers in the Feeding +20V to the opamp, it can generate signals
array are recalculated so that no actual calculations with voltage up to 18V. (NB, the schematic says
of the waveform need to be performed in the main LTC3105 because that was the only step-up I found
loop. The absolute maximum frequency that can be in Fritzing. In reality I used an MT3608 module, see
generated is 190kHz (half of the sampling rate) but pictures in the next steps). I choose to apply a
then there are only two samples per period, so not variable attenuation to the output of the R2R DAC
much control of the shape. The interface thus doesn't then use one of the opamps to buffer the signal
allow to set the frequency above 100kHz. At 50kHz, without amplification and the other to amplify by 5.7,
there are 7-8 samples per period and at 1.5 kHz and so that the signal can reach a maximum output of
below all 256 numbers stored in the array get about 20V. The output current is rather limited,

Arduino Waveform Generator: Page 2


~10mA, so a stronger amplifier may be needed if the
signal is to drive a large speaker or electromagnet.
Download
https://www.instructables.com/ORIG/F4X/N6E7/JN3HUGRN/F4XN6E7JN3HUGRN.pdf

Download
https://www.instructables.com/ORIG/FCX/6Q5E/JN3HUGRL/FCX6Q5EJN3HUGRL.pdf

Download
https://www.instructables.com/ORIG/F2B/XUAM/JP2XYEF8/F2BXUAMJP2XYEF8.fzz

Step 2: Required Components

For the core waveform generator LM358 or other dual opamp

Arduino Uno or Nano step-up module based on the MT3608

16x2 LCD display + 20kOhm trimmer and 100Ohm 50kOhm variable resistor
series resistor for backlight
10kOhm resistor
5-pin rotary encoder (with integrated pushbutton)
47kOhm resistor
25 resistors of 10kOhm
1muF capacitor
For the buffer/amplifier

Step 3: Construction

Arduino Waveform Generator: Page 3


I soldered everything on a 7x9cm prototype board, as the display are attached with pin-headers. I wouldn't
shown in the picture. Since it got a bit messy with all do that again if I'd build a new one. I did not put
the wires I tried to colour the leads that carry positive connectors on the board to pick up the signals.
voltage red and those that carry ground black. Instead, I pick them up with crocodile leads from
protruding pieces of copper wire, labelled as follows:
The encoder I used has 5 pins, 3 on one side, 2 on
the other side. The side with 3 pins is the actual R - raw signal from the R2R DAC
encoder, the side with 2 pins is the integrated
pushbutton. On the 3-pin side, the central pin should B - buffered signal
be connected to ground, the other two pins to D10
and D11. On the 2-pin side, one pin should be A - amplified signal
connected to ground and the other to D12.
T - timer signal from pin 9
It's the ugliest thing I've ever made but it works. It'd
be nice to put in an enclosure, but for now the extra G - ground
work and cost doesn't really justify it. The Nano and

+ - positive 'high' voltage from the step-up module

Step 4: The Code


Arduino Waveform Generator: Page 4
The code, an Arduino sketch, is attached and should perfectly.
be uploaded to the Arduino.
Normally, the Arduino interrupts every millisecond to
20 waveforms have been pre-defined. It should be keep track of time with the millis() function. This
straightforward to add any other wave. Note that the would disturb the accurate signal generation, so the
random waves fill up the 256-value array with random particular interrupt is disabled.
values, but the same pattern gets repeated every
period. True random signals sound like noise, but this The compiler says: "Sketch uses 7254 bytes (23%) of
waveform sounds much more like a whistle. program storage space. Maximum is 30720 bytes.
Global variables use 483 bytes (23%) of dynamic
The code sets a 1kHz signal on pin D9 with TIMER1. memory, leaving 1565 bytes for local variables.
This is useful to check the timing of the analog signal. Maximum is 2048 bytes." So there is ample space for
That is how I figured out that the number of clock more sophisticated code. Beware that you may have
cycles is 42: If I assume either 41 or 43, and generate to choose "ATmega328P (old bootloader)" to upload
a 1kHz signal, it clearly has a different frequency from successfully to the Nano.
the signal on pin D9. With the value 42 they match

Download
https://www.instructables.com/ORIG/FZ1/VHTG/JN3HUGRJ/FZ1VHTGJN3HUGRJ.ino

Step 5: Usage

The signal generator can be powered simply through signal can be used.
the mini-USB cable of the Arduino Nano. It is best
done with a power bank, so that there is no accidental It is really helpful to use an oscilloscope to check the
ground loop with the apparatus that it may be signal amplitude, in particular when the signal
connected with. supplies current to another device. If too much current
is drawn, the signal will clip and the signal is heavily
When switched on it will generate a 100Hz sine distorted
wave. By rotating the knob, one of the other 20 wave
types can be chosen. By rotating while pushed, the For very low frequencies, the output can be visualised
cursor can be set to any of the digits of the frequency, with an LED in series with a 10kOhm resistor. Audio
which can then be changed to the desired value. frequencies can be heard with a speaker. Make sure
to set the signal very small ~0.5V, otherwise the
The amplitude can be regulated with the current gets too high and the signal starts clipping.
potentiometer and either the buffered or the amplified

https://www.youtube.com/watch?v=Y5Rsz057c-E

Now the two waveform generators are nearly finshed.

I have overclocked the MapleMini (normal: 72 MHz, overclocked : 128 MHz).

The signal a better at higher frequencies and also the signal at higher frequencys at the Osci is
better.
Arduino Waveform Generator: Page 5
The video shows the signals generated with the LGT8F328p(32MHz) on the MapleMini Dual-Osci
(I have here switched off the secon channel).

https://youtu.be/qg0Yn3Hg5r4

Hi, now I have 2 waveform generators,


one with a LGT8F328p processor instead of ATMega328P and 1602 LCD running at 32 Mhz
and one with a MapleMini (STM32F103 ) and ILI9341 2.8" Touch-Display, running with 72 Mhz.

In the MapleMini I have integrate a Dual-Channel Oscilloscope with about 1 MSPS.


I can choose over a touch-menu
- normal WaveForm Generator
- sweep WaveForm Generator or
- Dual Channel Oscilloscope.

You can see it here in action:

/assets/img/pixel.png

Merhaba

4 Hz e kadar düşürmek mümkünmüdür ?


4Hz is no problem. It goes down to 1mHz

Teşekkür ederim

bilgim az ama en kısa zamanda uygulayacağım.


The A-Star 328PB Micro (Pololu) was a litlle bit better or quicker than the original NANO with 16
MHz, but the Sinus-signal at about 20 kHz was not nice. Therefore I tried to port the software to
STM32 MapleMini, running with 72 MHz.
After some time I had succes:

https://www.youtube.com/watch?v=tasBP7qpmMM&feature=youtu.be
Wow, good work, that looks like a big jump in sample rate, even more than the factor 3.6 from the
clock frequency, it looks like the sampling loop takes fewer cycles thanks to the intrinsic 32 bit
calculations! The scope trace seems to have at least 30 points per cycle, so that would be 3Msps.
You should really publish this as a separate instructable! I once tried but failed to program the
STM32F103C8T6, and would be quite interested to see a reliable instructable on that.
One follow-up idea I had but never came to was to make the function shape more flexible: fewer
shapes, but each shape with additional parameters e.g. duty cycle, rise-time, fall time for block,
amplitude, phase and frequency for double-sine.
Also, if the STM has more RAM and it can search it fast, there is real gain from having a larger
signal array (e.g. 4096samples) : square waves with very low duty cycles or pulse trains would
Arduino Waveform Generator: Page 6
then be possible.
The triangle and sawtooth have a little bump halfway the range, it looks as if your DAC is not
perfectly monotonic, you may want to test that at lower speeds.
I had some problems to migrate Your code, to set the Port (like PORTD = ...) is different .
Therefore I tried it at first with a special "digitalWriteFaster" to the eight Pins, but now I use the
ODR command , it's for all 32 bits of the port ! It's quicker.

I programmed it with the Arduino IDE (STM32DUINO from Roger Clark Melbourne).
On the STM32F103CB (MapleMini / BluePill) is also more space for programming (128k) and
nearly each pin you can use for ext. interrupts .

But if i measure the frequency at 1 kHz , it is ok (because I have adjusted it there!).


But if adjust my LCD to 100 kHz, the real frequency is about 3% higher.
Because of the time for the ODR command in the loop.
Hi,
I have found the error in my curves, I had reversed some pins!
Now the curves are o.k. and the frequencyon the display is near the frequency of the counter.
I made some pictures f:
Sinus at 100 kHz, Sinus at 200 kHz, Sinus at 300 kHz, Sinus at 400 kHz.
At 400 kHz it looks like a triangle wave !

Because there is enough space for programming, I tested it as simple Sweep - Generator:

https://www.youtube.com/watch?v=UVS4idJIxCA&feature=youtu.be
Hi, it says "Video unavailable. This video is private."
A sweep is interesting. I did not consider it since I had no need for it and the update of the phase
increment inside the core loop would slow things down, or is it not too bad?
Your scope pictures seem to show wiggles that probably correspond to the sampling frequency, I
would guess they come either from the amplification step or from the scope (which scope is that by
the way, it looks like a budget scope but it has a much better bandwidth than my 1Msps DSO138).
An RC filter could be used to filter out the frequencies above the sampling rate. The output
impedance of the DAC already provides the R, so it would just be a matter of adding a capacitor to
ground at the exit of the R2R DAC. The value of C should be or order
1/(fR)=1/(1MHz*10kOhm)=100pF.
Hi, yes I have to insert a RC filter, but I think its good for sine, but perhaps a problem for square
and other waveforms. I will test it , perhaps I make it switchable.
Last week I made some changes with the menu on the ILI9341 display and integrate a little touch-
menu for changing the frequency ...
I used for the touch-screen 2 interrupt-routines (on TOUCH_IRQ), the normal to
change the input and the second only for stop the loop.
On maplemini it's possible to save up to 14 waveforms in separate arrays.
It's quicker if you change the waveform while sweeping ...

Here a small video from the touch:

https://www.youtube.com/watch?v=2DBm2Bz4bVM

Arduino Waveform Generator: Page 7


Hi,
now I made something for the eyes:

I changed the LCD-Display with a TFT ILI9341 SPI 2.8" and


integrate a small graphic from the curves.
It was a little bit difficult, because I have to use there SPI1 (PIN PA4 ... PA7) for the display in
conflict with the DAC on the same Port. The other Port on MaspleMini with seven Pins is Port B,
but B1 is connected with the Board-LED ( similar Arduino D13). But PB1 is not on the headers,
therfore I had eliminate the led and fixed a thin wire on the board with the iron...

https://www.youtube.com/watch?v=Za_ELC_1gVQ&feature=youtu.be
I made some changes, a small menu for sweep and other ? functions..
I use now ttwo encoder and two normal push-buttons.

The video is here:

/assets/img/pixel.png

Super project !
I have expand it with a second rotary encoder .

The second encoder is only for switching between the waveforms.

The first encoder is now on Pin 10 and 11,


the switch (for changing between 0..9 and other decimal-positions) is on Pin 8,
the second encoder on Pin 12 and 13.
To use Pin 13 , I had to remove the internal resistance (330 Ohm) on Pin13 at the Nano-Board.
The R2R network I made with compared 5k and 10k resistors.
Instead of the MT3608 I used a RECOM DC/DC converter from 5v to +-12V (or better +-15v) and a
quicker OPamp (NE5532). The first works as non-inverting with possibility to change the zero-level
with a poti, the second works as inverter( see on Videos):

https://www.youtube.com/watch?v=3FNXE9sXheA

/assets/img/pixel.png

https://www.youtube.com/watch?v=RQ3Ek9W75dM&feature=youtu.be

Arduino Waveform Generator: Page 8


hei. ...what is the max frequency of this setup ? can the frequency be increased only from code? if
yes can you please show me how?
And thank you for posting such a great project :)
max 100kHz. There is no point to go higher since the sampling rate is 381kHz, so already at
100kHz it only takes 3 to 4 out of the 256 samples.
The sampling rate could be increased slightly by using a 16 or 24 bit phase accumulator, but it
would be at the cost of a lot of precision, it'd be better to go to different hardware for the MHz
range.
ok thanks for your answer.... can you tell me if the output of this generator can can drive a larger
mosfet (irfp250)? i started building the generator but I still have a little work to do.
Hmm I have little experience with mosfets. I have used the IRLZ44N
(in https://www.instructables.com/id/Portable-Precision-Stroboscope/ )
The 'L' in IRLZ44N indicates it becomes fully conducting at logic levels (i.e. +5V)
Yours has the 'F' so it may not fully conduct at 5V.

Moreover, this generator has an analog output, you can't just connect it to a MOSFET and expect a
high-current analog output. The MOSFETs are great for digital switching, analog DC amplification
is a lot more involved!
ok thanks ..but can you give me an idea how to make this work ....perhaps using some transistors
for boosting the signal?(i am new to electronics and i am just trying to learn)Thanks
The simplest circuit is a power-transistor inside an op-amp feedback loop, see
https://www.allaboutcircuits.com/technical-articles/how-to-buffer-an-op-amp-output-for-higher-
current-part-1/

However, it's hard to make it work in practice. I tried and failed. Beware that the buffer needs to
dissipate a lot of power.
Do you really need true analog signals? If you manage with PWM it'll be much easier. If it's for
audio, it's better to get an off-the-shelf audio amplifier.
This presents an oversimplification of the R2R network requirements for accuracy. The pin outputs
need to be well matched, which is
best done a light loads, so stick with the 10K values. To achieve 8-bit DAC accuracy and be
monotonic (google it), the resistors' should be accurate to 1/512 or about 0.2%, so that makes
them expensive.
However, typical 1% or even 2% resistors have a resistor-to-resistor matching within a
single batch that can be much better than their absolute accuracy. It’s also possible to “hand
select” resistors using a DVM. Note that DVM accuracy is not as important as
its repeatability and resolution, since it’s their ratios that is important here,
but ALL resistors should be within 0.2% of each other! See: "resistor ladder" in Wikipedia. DACs
need to be to monotonic to accurately reproduce signals without distortion.
Just a quick update on my purchase of a DSO138 oscilloscope. The eBay seller, cinnamon 1956-
5, refunded me the cost of the case (look out for that misleading practice where the Selection box
has more than one price, although it didn't when I placed my order, it did later, I'm taking screen
Arduino Waveform Generator: Page 9
prints from now on). The agreement was that I would buy the o'scope from him/her again (at a
higher price for certain), which I've done. So I'm now waiting for another 16 days for the scope to
get here (USA). I guess the case will serve as compensation for the time lost, but all is well.
Nice job! I have a need for something portable that generates more-complex waveforms at low
frequencies, and this may well be the basis for it.

One suggestion: you can buy R2R ladders as SIPs or DIPs, and will probably get a closer match
by using one. Plus you save a bunch of board space and soldering. I found the Bourns 4610X-
R2R-103LF (10K SIP) for a buck at Mouser, and it's probably available at about the same price
from Digi-Key, Farnell, etc.

Thanks for sharing this.

Thanks for the tip! I must say I was surprised how well the R2R DAC works even without any
special measures: I had started to make a list of resistor values to make matched pairs, but then
got bored and thought I could adjust afterwards if needed. Instead there is no sign of any steps in
going e.g. from 127 to 128. Also the soldering wasn't too bad since the schematics almost matches
the pin layout, so there is no need for bridges, and resistors are easy anyway since they are
symmetric and temperature-resistant. But I'll definitively consider for future projects!

If you don't need the highest frequencies, the waveform array can indeed be extended to e.g. 1024
bytes using a 16-bit integer as index. The number of clock cycles will need to be redetermined
(easiest by trial and error) but I suppose it won't add more than 10 cycles.

Ugly? Heck no, that’s the coolest thing I’ve seen in a while. I like it! I could use a little frequency
generator to set up the IF stages of antique radios I’ve been restoring and I think this would work. I
Like the way you can just set it to sine wave and set a frequency. Like I said, that’s cool! :-)

i have a quick question... going back and reviewing everything, the schematic and breadboard
show you using a “LTC3105” module which goes for $26 on eBay. In the photograph you use a
“MT3608” module which is a much more affordable $3 on eBay but you didn’t show the
connections. Does it make any difference what you use? And Is there any way you might just edit
this to show which connections are used to connect the “MT3608” buck boost module?

I think i understood everything else... love the code!!!!! The way it is written, it is really easy to
understand what’s being done and I’m sure glad I didn’t have to figure out the math.

This is a really great instructable! Thank you for posting it!

Buddy
I used an MT3608, which cost 30euro cents on Aliexpress. The LTC3105 was the only step-up
module that I could find on Fritzing (the text has been updated to make it more clear). I don't think
it's critical, it only needs to power 20mA or so for the opamp.
Glad you like it. Let me know in case you make it!
Ok I understand now, thanks.
€ 0.30 I need to be shopping on Alienxpress!
I’m going to see what I have, I think I have almost everything to do it but no matter, if I move
forward, I will certainly let you know!
One other thing, when I look at this, it looks almost ready to build on a PC board, Do you have a
Gerber file for it?
I was just thinking if you didn’t, I don’t think it would take too much to make one and get some
Arduino Waveform Generator: Page 10
boards built.
I think this is such a great idea, an Nano, a bunch of resistors, and a few other parts, you toss in a
board and you have a great kit you could sell. (If you wanted to)
Thanks to all who responded regarding the oscilloscope. I see several vendors on eBay, Amazon,
and the like. Excellent price, I'm ordering one. I also built a probe for zelscope but never got it to
work (other than seeing my voice while using the XP computer's internal mic). There is also
soundcard scope (free) software but I'm not about to build another probe. The ready made scope
shown may only be single-trace but there is no danger of bricking a computer or microprocessor.
Thanks again. (Let's hope we don't alienate China)
Interesting project, I liked it, thanks a lot.

Glad you like it. Let me know in case you make it!

Sure I will.

Very interesting and well written instructable, and I appreciate the well laid out and easy to follow
code to run the device. I'm looking for just such a device but hope to get it to give at least 500 KHz
of undistorted sine wave so I can use it to generate IF frequencies for radio repair work. I wonder if
there'd be any benefit to using two Arduinos instead of one, one for frequency generation and the
other for interrupt handling? Could the output frequency be increased using such a scheme?
500kHz undistorted sine wave with Arduino would be hard. The interrupt handling does not cost
any time, so a second Arduino would not help. One thing that comes to mind is to use the timers to
generate a fast block wave and then use an analog filter to turn it into sine. But the frequency can't
be tuned precisely. There are other instructables out here that describe how to use an external
chip, e.g MAX038 and control it with an Arduino. That'd probably give a much more performing
device
This was a fantastic instructable. I was just looking for a little frequency generator build and then
that fantastic demo of the little oscilloscope was exactly what I was looking for. Did you assemble
your oscilloscope. Now they have them completely assembled at Amazon for less than $26
(https://amzn.to/2CUdSbb). Thanks for writing this one up.
Great project that I will be building soon.
Thanks! let me know in case you manage to build it or find a mistake somewhere. The scope was
bought pre-assembled for 13EUR. There are videos on youtube on how to assemble them, which
easily convinced me not to.
Fantastic project! Thank you for sharing it :-)

Glad you like it. Let me know in case you make it!

Cool!!!

Arduino Waveform Generator: Page 11

You might also like