Compact PWM Test Oscillator
tiny 8-pin Atmel ATtiny15 microcontroller generates a wide range of
pulse-width modulated (PWM) waveforms. A compact battery-powered unit,
this versatile PWM oscillator also includes a sweep frequency
capability. It can also output a 1kHz sinusoidal audio test tone.
My 8051 chips were just too slow. Snail-pace, really.
This was the conclusion I reached when I was looking for a suitable
microcontroller for some new projects. I had noticed that competing PIC
and Atmel chips were easily able to outperform any of the 8051 devices
I was using at that stage although, for the most part, the limited
performance of the 8051 had not previously prevented me achieving any
of my design goals.
All of that changed when I started to look at projects requiring generating high speed and high quality digital audio waveforms.
order to assess the relative merits of these other microprocessors, I
decided to try designing a simple project with a low cost device from
each of these two microcontroller families. That way, I could evaluate
one of the devices in each family at minimal cost, I hoped, and try out
the respective programming tools. This way, I could get a first-hand
opinion on some of the claimed benefits of each processor as well as
This project was the one I used to build to test the AVR family. It
uses a low cost ATtiny15 8-pin chip. This device has just 1k of flash
memory for programming, 32 8-bit registers, and 64 bytes of EEPROM.
This tiny device package was another reason for my search for a new
microprocessor – I could not find any 8051 devices in an 8-pin package.
I should warn you right now that the ATtiny15 is no longer a current
device in Atmel’s AVR family. It’s been superseded by a variety of
other chips, such as the ATtiny25 and ATtiny13. However, this chip is
actually still readily available from many suppliers, so I felt it was
worthwhile describing this design here. Also, if necessary, the
software can be easily adapted to suit, say, the ATtiny25.
from using this design to look more closely at the AVR family, I only
had a few objectives in mind at first for this PWM test generator. I
had been experimenting with some simple switch-mode power supplies, and
testing some circuits would be much easier if I had a basic square-wave
generator, something that could generate a TTL-like 5VDC square-wave
frequency from a few hundred Hertz up to perhaps 500 kHz. I also wanted
to be able to adjust the duty cycle of the waveform.
wasn’t too concerned about the exact frequency – I didn’t need a
digital readout to the nearest Hz, for example – nor was I particularly
interested in the exact duty cycle. Again, just having a continuous
adjustment range, ideally from 0 to 100%, I thought would be sufficient.
PWM generator to be used on my test bench. I don’t know about your
situation, but I find I never have enough power supplies for
everything. So, from the outset, I wanted this to be battery powered,
and as compact as I could reasonably make it.
The Design Goals Expand
project developed, and as I became more familiar with writing assembly
code for the ATtiny15, I started to add a few more features. I began by
just getting the generator to output a simple 1000 Hz square-wave. I
then got the duty cycle code working.
Once I got that initial software working correctly, I decided to add a
series of frequency ranges. To do that, I needed a switch to select a
number of ranges. It had to be compact, however. I happened to have a
thin BCD switch in my box of parts and so that got used. This provides
a binary coded output on four pins, or five if you include the common
Once I had the generator operating over a series of ranges, I still had
some positions free on the switch. The next feature I decided to try to
add was a frequency sweep where the generator would automatically step
(or “sweep") across a range of frequencies, and then repeat this sweep
of frequencies until another range was selected. I couldn’t think of an
application for it at the time, but I thought it was a feature worth
Finally, and just before calling a halt to all of this, I
decided to try to generate a sine wave using a much higher PWM
waveform. The addition of a very simple RC filtr will remove the much
higher PWM “carrier” frequency, leaving the much lower audio frequency
At that point, I stopped writing more code. The range selection switch
actually has ten positions (0 - 9) so the last two are free for any
extra features you'd like to add. Of course, you'll have to write the
code. I'm too busy with my day job, and my other projects in the
evening and weekends.
the end, what I had developed in a compact box was a simple variable
PWM test generator with an audio tone and sweep frequency generator
The diagram below shows the final circuit. As you can see, there are very few parts.
Figure 1 : The circuit diagram of the ATtiny15 PWM test generator
Three AAA cells provide a nominal 4.5V supply for the oscillator. A
small yellow LED is used to remind me that the power is turned on. (I
could have added a power-down feature, I guess…) The current drain of
the ATtiny15 is very low, about 3mA, and the entire generator draws
less than 15 mA in use. I’ve had it on my bench for over three years
and I’ve still not needed to change the batteries.
Two potentiometers are used to input the required frequency and duty
cycle. The resulting variable DC voltage on each pot's wiper ranges
from zero to the supply rail. These voltages go into two of the
ATtiny15’s 10-bit analog to decimal converter (ADC) inputs. Just note
for the moment that one pot is a LOG (logarithmic) type while the other
is a LIN (linear) type. I’ll come back to that in a moment.
The PWM generator’s output comes from a pin which is connected to the
ATtiny15’s internal PWM generator. This feeds a pair of small signal
transistors which buffer this before the signal is fed to the generator
output connector via a switch.
resistor and capacitor (R3 and C4) is also connected to the output of
the buffer and is connected to the other side of the output switch.
This RC pair forms a very simple RC PWM filter used with the range #7
to give the 1kHz sine-wave audio output. IThe output switch is just a
PCB jumper in my prototype because at the time, I didn’t have a
suitable switch at the time. I’ve never got around to changing it.
If you look really carefully at the board in this photo, you may see a
small diode next to the yellow LED that is not shown on the schematic.
This is a 5.6V zener diode that was used to limit the voltage from a
DC-DC inverter generating 5V from a single AA cell. I didn't like the
final result, so the inverter was removed, but that diode, which serves
no purpose now (but affects nothing either) was left in place.
features of the ATtiny15 used in this design are the ADC inputs, which
allow the analog values of the variable control pots to be determined
with 10-bit accuracy, and the powerful high speed PWM oscillator.
The main core of the software simply reads the value of the control
pots and uses them to program the PWM oscillator registers. The
required tuning range is determined by reading the value of the three
pins connected to the BCD switch.
The PWM oscillator response is near-logarithmic for a linear selection
of PWM register settings. Using a log pot for the frequency control
gives a roughly linear frequency output from the generator. This is the
reason behind the log and linear potentiometers.
The fully commented source code, for those wanting to change or add
features, and the hex file, generated by the assembler for programming
the ATtiny15, are both provided for download further down this page.
photos here show, the generator was built on a small prototyping board.
The battery holder was hot-glued to the underside of the board.
A small wooden box was made from a thin strip of hard wood, and
threaded nylon spacers were glued with epoxy into each inner corner.
Top and bottom covers were then made for the box, and these are screwed
into place using bolts on each corner screwed into the threaded
spacers. The entire enclosure measures about 80(w) x 50(d) x 25mm(h).
LED power indicator is mounted down on the board. In order to see it
with the covers in place, a 3mm hole was drilled in the top cover, and
a 10mm length of 3mm diameter clear plastic rod was pushed into the
hole, the top flush with the top of the lid. This sits directly over
the power LED. Its yellow glow shows clearly on the top cover.
The range selector switch fits through a hole in the woodwork on one
side, and the power switch and output connect fit through other similar
holes. A label showing the details of each range (See one of the photos
towards the top of this page) was covered in clear plastic and glued to
the bottom cover. Another label was made for the controls on another
side of the box.
While these labels may be of limited use, I have provided the artwork in the download section below.
- Source code and programmer-ready Hex file : pwmgen2.zip
(Fuse settings are documented in the source code file)
Some Thoughts about the AVR Family
much of this design was done in order to see if the AVR family would
work for me, I guess I should add just a few thoughts about that here.
If it's a topic of little interest, feel free to stop reading here.
In practice, I found the ATtiny15 microcontroller was generally easy to
program and it was certainly fast, as promised. That's also proven to
be true as I've gone on to use other devices in the family. (I began
programming the ATtiny15 with a homemade programmer, and then moved on
later to PonyProg which uses an RS232 interface with the PC. More recently, I've made this USB programmer
which works very well) It was also very nice not to have to worry about
adding a crystal to the ATtiny microprocessor to get it to run, as you
must with every 8051 chip even when the application doesn't need that
level of clock accuracy. So, the internal Atmel clock is a nice feature.
The software provided by Atmel was also easy to install, and it worked
much as expected. The datasheet was clear and, once I read it carefully
in a few areas, the operation of the chip became clear. I tend to print
out a copy of the datasheet and put it into a ring binder. It makes it
easier for me to add notes on specific features as I go, or add
highlights and underlining to remind myself about certain issues.
However, now that I’m using some of the current 8-pin chips, like the
ATtiny85, I do find it amusing to find the printed datasheet, which
runs to hundreds of pages in length, weight hundred of time the weight
of the chip itself. As I glance across at my bench on one side today, I
see the tiny chip over there, and the huge pile of datasheet paper in
the folder on the shelf opposite. Huh.
I did find some odd things about a few AVR instructions, and a few
basic instructions missing. Why can’t you invert a bit in one
instruction anywhere in memory or on an output pin? Weird. Also, coming
from the 8051 background where flags can be set and tested so easily,
yet doing the same with the AVR chips is just a continual pain in the,
I also encountered a few issues initially with the programmable fuses –
These are some internal separately programmed settings which provide
some basic operating settings for the chip. I just had to think some
more about these factors, and documenting these is also important.
Generally, however, I don’t see any reason to go back to using the 8051
family, especially now I’ve got some higher level compliers for the AVR
family. That eases my complaints about missing instructions, and speeds
up my programming.
The PIC tests? Well, I did build a little binary clock
designed by Roman Black to test one of the current PIC chips. Of
course, I designed my own tiny PCB for it and made a very compact
hardwood box for it. Then I messed about with the software to add
automatic nighttime dimming. Despite this limited exposure to PICs, I
found the entire PIC experience at assembly code level so primitive,
and just so awful, that I’ve never bothered with a PIC chip again.
Using high level compilers (and I don’t include C in that category!)
would protect you from such things, of course. However, for me, my
periodic descent into assembly code on a number of my projects, in some
cases just for one or two critical routines, makes it impossible to
consider the PIC family.
"Your mileage may vary", as they say. But one day, that PIC chip is
going to be ripped out of that clock and replaced with something more
modern. Maybe an Intel 4040.
Want to go back to the main page? Click