Audio Circuit: Single Frequency Output Selection

Audio Circuit Driven by Op Amp, GY-9833 frequency synthesizer, and Arduino

Above is the circuit I mentioned earlier had been intending to design with a small 3W speaker driven by an LM386 op amp driven by an AD9833 frequency synthesizer chip, driven by SPI (sourced in the schematic from an Arduino Uno).

I thought designing and testing this simple circuit would only take an hour or two. But I got hung up for a lot of hours because, in the breadboard, I was getting weird spurious signals in the output when I had the the circuit set to certain volume levels, and I couldn’t figure out what the problem was. In the end, the problem was fixed by putting a large capacitor across +5V and AGND. After that, this output sounded pure and pleasant, testing with 1000Hz, 1500Hz, and 2000Hz signals. I do not know if it is really necessary to use a capacitor quite that big, but I didn’t feel like doing additional testing.

I had thoughts to turn the circuit into a PCB, though it would be through-hole (easier to assemble) and not a miniature surface-mount design like would be seen in a commercial application. This would be around 6cm x 5cm, with the speaker plugging in on the right pins and the Arduino plugging in on the left header. The GY-9833 module would slide onto the center pins and could be soldered on to them.

I can provide design files later after I finish laying out the traces. I can also post some FlashForth code later.

LM386 Audio Amplifier

Learning how to use the LM386 Audio Amplifier IC — a “minimum parts” circuit.

I was pondering how I was going to amplify the signal coming out of my AD9833 signal generator module, to drive my MakerHawk 3 watt, 8 ohm speaker. Then I found an LM386 IC in my box of assorted op-amps. I found this amplifier to be easy to use, especial with the example “minimum parts” circuit in the data sheet:

Minimum parts circuit from LM386 data sheet. Pins 1, 7, and 8 can be left open if you are okay with the default gain setting of 20.
The LM386 pinout

In the picture at the top of this post, you can see the AD9833 module, but I’m actually trying out the amplifier chip by driving it with a desktop signal generator, which is connected to the leads on the left. With the signal generator set to as little as 100mV p-p, I had no trouble hearing the sound on the speaker with 1khz, 1.5 khz, and 2 khz tones. The sound was quiet and distorted at 500 Hz and lower, but that would be expected of such a small speaker.

The Uno in the picture is not providing the LM386 input signal in this test, but is simply providing the 5V supply voltage.

Some caveats; the LM386 requires at least 4V supply voltage, which is a problem for folks who want to use their microcontrollers with a lower 3.3 V supply only. Also, I think the AD9833 generated a 700 mV p-p signal when I tried it last week, which I believe fits just inside the LM386’s range of minimum -4V and maximum +4V input signal — probably you will want a voltage divider or volume control to attenuate the signal some.

AD9833 Signal Driven by Flash Forth

400 Hz signal from an AD9833 module, initialized by 328P MC running FlashForth

Having figured out how to configure the parameters of the SPI bus, and transmit bytes, I wanted then drive my AD9833 module, which is a frequency generator.

Arduino Uno running FlashForth connected to a GY-9833 module, which is a dev module for the AD9833 signal generator chip

I determined from the datasheet that I would need the SCLK signal to be high on idle, and to sample on the leading edge. Also, fsync needs to go low before the data is transmitted.

Timing Diagrams for AD9833 chip

Here are the FSYNC, SCK, and data signals on a scope:

FSYNC signal is yellow, SCK signal is green, and data signal is purple

I actually had to study these signals for a few minutes because at first the initialization code was not working. I released that there was a bug in my code such that the fsync signal was inverted. That was easy to fix.

The above data translates to this example initialization data from the programmer’s guide:

Zooming in, you can see the first byte, 0x21:

First byte’s worth of signals

With sampling on leading edge of SCK (green signal) we have 00100001, i.e., 0x21.

Here is the code so far:

\ ad9833.fs

\ Copyright 2021 Christopher Howard

\ Licensed under the Apache License, Version 2.0 (the "License");
\ you may not use this file except in compliance with the License.
\ You may obtain a copy of the License at

\     http://www.apache.org/licenses/LICENSE-2.0

\ Unless required by applicable law or agreed to in writing, software
\ distributed under the License is distributed on an "AS IS" BASIS,
\ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\ See the License for the specific language governing permissions and
\ limitations under the License.

ad9833
marker ad9833

: init-spi ( -- )
    \ set data direction bits
    DD_OUT DD_MOSI lshift
    DD_OUT DD_SCK  lshift or
    DD_OUT DD_SS   lshift or DDR_SPI mset
    \ Setup control register
    1           SPR0 lshift
    0           SPR1 lshift or \ fck/16
    CPHA_SMPLED CPHA lshift or
    CPOL_HIDLE  CPOL lshift or
    MSTR_MSTR   MSTR lshift or 
    DORD_MSB    DORD lshift or
    SPE_ENAB    SPE  lshift or
    SPIE_DISAB  SPIE lshift or SPCR c!
;

: init-fsync [ DD_OUT #4 lshift ] literal DDRD mset ;

: fsync-low [ 1 #4 lshift ] literal PORTD mclr ;

: fsync-high [ 1 #4 lshift ] literal PORTD mset ;

: demo-400hz
    init-spi
    init-fsync
    fsync-low
    $21 tx-spi $00 tx-spi
    $50 tx-spi $c7 tx-spi 
    $40 tx-spi $00 tx-spi 
    $c0 tx-spi $00 tx-spi 
    $20 tx-spi $00 tx-spi
    fsync-high
;

\ Only for viewing the SPI signals
: test-demo begin demo-400hz 1 ms again ;

First you have to load this ad9833 code:

\ ff-328p.fs

\ Copyright 2021 Christopher Howard

\ Licensed under the Apache License, Version 2.0 (the "License");
\ you may not use this file except in compliance with the License.
\ You may obtain a copy of the License at

\     http://www.apache.org/licenses/LICENSE-2.0

\ Unless required by applicable law or agreed to in writing, software
\ distributed under the License is distributed on an "AS IS" BASIS,
\ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\ See the License for the specific language governing permissions and
\ limitations under the License.

ff-328p
marker ff-328p

\ General I/O port addresses

$25 constant PORTB
$28 constant PORTC
$2b constant PORTD

\ Data Direction Registers

$24 constant DDRB
  1 constant DD_OUT
  0 constant DD_IN
$2a constant DDRD

\ DDR for SPI comms

$24 constant DDR_SPI
$2 constant DD_SS
$3 constant DD_MOSI
$5 constant DD_SCK

\ SPI control register

$4c constant SPCR
$0 constant SPR0 \ SPI Clock Rate Selector bits
$1 constant SPR1 \ (see table 18-5 in 328P datasheet)
$2 constant CPHA \ Clock Phase bit
  1 constant CPHA_SMPTRL \ sample on trailing edge of SCK
  0 constant CPHA_SMPLED \ sample on leading edge of SCK
$3 constant CPOL \ Clock Polarity bit
  1 constant CPOL_HIDLE \ SCK high when idle
  0 constant CPOL_LIDLE \ SCK low when idle
$4 constant MSTR \ Master/Slave Select bit
  1 constant MSTR_MSTR \ master mode
  0 constant MSTR_SLAVE \ slave mode
$5 constant DORD \ Data Order bit
  1 constant DORD_LSB \ LSB transmitter first
  0 constant DORD_MSB \ MSB transmitted first
$6 constant SPE \ SPI Enable bit
  1 constant SPE_ENAB \ SPI enabled
  0 constant SPE_DISAB \ SPI disabled
$7 constant SPIE \ SPI Interrupt Enable bit
  1 constant SPIE_ENAB \ SPI Interrupt Enabled
  0 constant SPIE_DISAB \ SPI Interrupt Disabled

\ SPI status register

$4d constant SPSR 
$0 constant SPI2X \ Double SPI Speed Bit
$6 constant WCOL \ Write COLlision Flag
$7 constant SPIF \ SPI Interrupt Flag

\ SPI Data Register (i/o port)

$4e constant SPDR

: tx-spi ( c -- )
    SPDR c! begin SPSR c@ 1 SPIF lshift and until
;

First Foray into KiCad

KiCad is a free software tool for designing Printed Circuit Boards, and can generate files to use with services like PCBWay. PCB manufacturing is getting so cheap now that it is hard to justify all the time and bother of old-fashioned soldering in a project with more than a dozen traces.

KiCad is a bit intimidating at first because of the many pages of the manual and tutorials, and a large forest of minor details. But I think it is not so scary once you understand the basic workflow:

1 – Put together a schematic. This shows the basic types of components (“symbols”) in your circuit and how they interconnect.

Somewhat embarrassing first schematic using KiCad.

2 – Assign “footprints” to your symbols. Footprints basically are the actual hardware you want to match to the component type.

3 – Use the new PCB tool to generate a PCB based on your schematic. You need (in a simple design) to lay out the traces and ground plane on your front and back copper layers, and then lay out the shape of your board in the edge cut layer.

Simple PCB design in KiCad

You can then view the PCB in 3D view if you wish.

Simple PCB design in 3D View

One hundred dollars in Monopoly money to the first person who can figure out what that circuit does!

And finally you generate Gerber files, which can be submitted to a service like PCBWay. You pay for the service, and they send the board with traces, holes, pads, labeling, and artwork as specified. You get the components separately and solder those on yourself.

XL6009 Voltage Boost Converters

XL6009 Boost Converter in NPN Transistor Switch

The large module is the the XL6009 Boost Converter, which is boosting a 5 V source to 21 V. There is a small screw on it that you can turn to select other voltages (i think it goes up to 35 V).

It is tied into an NPN transistor, set up for switching. The base of the switch is driven by a 5 V signal from the Uno, with a 10k resistor, which turns on the collector-emitter path, which being driven by the 21 V source, with a 1k resistor, and providing current for the LED.

I needed a 21 V source for my EPROM programming project, but needed it to be controlled by a 5 V AVR pin.

A pack of XL6009 Boost Converters is available for about $12 from Amazon.