Path: Home =>
R/2R-DAC => Sine wave generators
Diese Seite in Deutsch:
||Tutorial for learning avr assembler language of|
AVR-single-chip-processors AT90S, ATtiny, ATmega, ATxmega
of ATMEL using practical examples.
8-bit-digital-to-analog-converter using R/2R-networks
A R/2R network as Digital-to-Analog Converter (DAC)
If you need fixed or variable sine wave generators and if you do not
want to be limited to a maximum frequency and you do not need triangles such as in
generator, you can follow this page.
Accessing the sine wave table
This page provides a versatile algorithm to generate sine waves with a R/2R
network. It uses a 256 byte long sine wave table. Up to 3.676 kHz this table
is accessed byte by byte, above that every second/fourth/eigth/sixteenth/thirtysecond
byte is accessed to increase the generated frequency, but that reduces the resolution
of the network.
The algorithm works as follows. It requires two values, which can either be located
in a constant or, as double byte values, in two registers. Here the two values are
assumed to be in the 16-bit registers X and Y, but they can be as well be in other
registers or defined as constants (with slighlty differing code).
The whole algorithm does the following:
nop ; Short delay, +1 = 4 * cCnt + 8
ldi ZH,High(2*SineTable) ; Restart table, +1 = 4 * cCnt + 9
ldi ZL,Low(2*SineTable) ; +1 = 4 * cCnt + 10
; Next table value, 4 * Cnt + 10
lpm rmp,Z ; Read table value, +2 = 4 * cCnt + 11
out pR2RO,rmp ; 1 cycle = reference point, +1 = 1 or 4 * cCnt + 13
; Start delay loop
mov rCntH,YH ; Int delay counter, MSB, +1
mov rCntL,YL ; dto., LSB, +1
sbiw rCntL,1 ; Decrease counter, +1 = 2 delay loop
brne SineLoop2 ; +2 when jumping, +1 if not
; Loop delay = 1 + 1 + 4 * (cCnt - 1) + 3
; = 4 * cCnt + 1
add ZL,XL ; Next value address, +1 = 4 * cCnt + 3
adc ZH,XH ; +1 = 4 * cCnt + 4
cpi ZL,Low(2*SineTableEnd) ; +1 = 4 * cCnt + 5
breq SineLoop ; +2 when jumping = 4 * cCnt + 7
; +1 when not, = 4 * cCnt + 6
nop ; An additional delay, +1 = 4 * cCnt + 7
nop ; Two instructions delay, +1 = 4 * cCnt + 8
rjmp SineLoop1 ; +2 = 4 * cCnt + 10
The number of clock cycles for the whole loop is 4 * Counter value + 13. If
the counter value is one, the loop needs 17 cycles. The maximum delay is
4 * 65536 + 13 = 262,157 cycles, which prolongs the routine and reduces the
generated frequency by the 15,421-fold.
- First, the Z pointer is set to the start of the sine wave table.
- The table value is read with LPM and written to the R/2R port.
- Then a delay loop starts: a 16-bit counter in R25:R24 is loaded with
a start value from Y, then decreased until it reaches zero. That loop
requires (4 * Counter value) + 1 clock cycles.
- To the address in Z is then added a fixed displacement in X, which can
- If the end of the table has been reached, the loop restarts from the
- If not, there is some delay added to get a fixed loop time and the next
table value is issued.
The frequency generated is
fsine = clock / resolution / (4 * delay + 13)
the delay counter value can be calculated from
delay = (clock / resolution / fsine - 13) / 4
The algorithm can be used in every AVR that has ADIW implemented. If you need
X and Y for other purposes: these values can also be located in lower
registers or in constants (if you do not need to change them at runtime).
The reason, why the loop starts with a NOP, is: if you have to react on an
external interrupt, you'll have to have a mechanism that diverts out of that
routine. If you use the T flag in the status register for that purpose, the
NOP would change to BRTS ExtJmpLabel. As there is normally no jump,
this consumes one clock cycle. If you do not need that diversion routine,
just remove the NOP from line 1 and one NOP at the end, so that the time
comsumption is balanced. In the above formulas, the 13 changes to 12 then.
That is the case with the version described
The sheet Clocking in the LibreOffice Calc file
here shows the frequencies that can
be generated. First select the clock frequency of the controller: the
drop-down list offers all crystals that are available in the market. Select
one of these. Then select the cycle length of the algorithm to be used,
either 12 or 13 (+4 * Delay). The frequency ranges that can be generated
with the different resolutions of the sine table access appear.
The limitations of operational amplifiers
Operational amplifiers that work with 5V are only linear in certain voltage
areas. The design of the sine table has to account for that.
To measure linearity properties I have written fixed values to the R/2R
network with a ATmega324PA and measured the input and output voltages
of the opamp types 741 and CA3140.
The measured voltages of the 741 are listed on the sheet 741 in
the LibreOffice calc file here.
The voltage on the input (thick in red) in Volt differs only slightly from
the value that should occur (small in black), the difference is displayed
in the yellow curve in mV and is constant over the whole voltage range.
The 1% resistors work very linear.
The output of the 741 does not follow the input voltage below 2.0V: the
output always remains at 2.0V.
From 2.0V on the output follows the input (green curve in V). This only
changes at 4.3V, above the output goes into saturation. The difference
(violet curve in mV) gets negative.
This is the same curve for a CA3140. That already works linear from
0.0V on, but has its end of linearity already at 3.0V.
As it is unnecessary to use the whole voltage area from 0 to 5V, we can
simply create a sine table that respects the usable area. We then do not
need any special ICs (so-called rail-to-rail opamps).
The sine wave table
Due to the described linearity, the sine wave table used needs a little bit
attention. Depending from the type of operation amplifier to be used and
the desired amplitude of the sine the values have to be selected. The
LibreOffice document sinegenerator_table
provides a calculation scheme for that.
Select an opamp from the respective drop-down-list first. If your opamp is not
listed here, just add it, with its specific upper and lower usable voltage,
to the list and select it.
If considering smaller operating voltages than +5V, keep in mind that the operation
amplifier also works with this.
On the right side, the produced table values appear. Just select the cells F9 to
F42, copy those with Ctrl-C and paste this to your source code text file.
LC or RC filters for the output?
The 8-bit sine wave generator produces rectangles with 256 * fsine,
or the 128/64/32/16/8-fold, if so selected, with all uneven harmonics of that.
To filter those rectangles, an LC filter can be used, if the range of the
frequencies is limited. To calculate those LC filters you can use the sheet
"LCfilter" in the LibreOffice calc document referenced above. Just
input your selected parameters and see what is produced from that.
I additionally tested an RC filter for this purpose. See the sheet
RC_filter in the LibreOffice Calc file
here. The RC filter reduces the
output amplitude only slightly (88%), while it suppresses the R/2R
rectangles and their harmonics perfectly.
The same with the output capacitor that removes the DC from the sine wave.
This must be at least as large as the desired frequency and the impedance of
the following stage requires. Use the same calculation sheet to calculate
the minimum capacity.
A fixed sine wave generator
If you need a precise sine wave generator at a certain fixed frequency you
can use this
It works with an ATtiny24 in a small 14-pin DIL package. All you need for
that can be found on the referenced page.
Adjustable sine wave generator with LCD
If you rather want to have a Mercedes, which
then you have to have a slightly higher device and you come to that
- shows you the frequency on a small 1x8 character LCD in Hz,
- allows to adjust the resolution and the delay with two potentiometers,
- updates the frequency by pressing a key,
To the top of that page
©2020 by http://www.avr-asm-tutorial.net