The personal website of Scott W Harden
August 31st, 2016

ICS501 Simple Frequency Multiplier

Today I made a high frequency multiplier using a single component: the ICS501 PLL clock multiplier IC. This chip provides 2x, 5x, 8x (and more) clock multiplication using an internal phased-lock loop (PLL). At less than a dollar on eBay, $1.55 on mouser, and $0.67 on Digikey, they don't break the bank and I'm glad I have a few in my junk box! I have a 10MHz frequency standard which I want to use to measure some 1Hz (1pps) pulses with higher precision, so my general idea is to use a frequency multiplier circuit to increase the frequency (to 80 MHz) and use this to run a counter IC to measure the number of clock pulses between the PPS pulses. I spent a lot of time working with the CD4046 micro-power phased lock loop IC which has a phase comparator and a voltage controlled oscillator built in. It seemed this chip was the go-to for many years, but it requires external circuitry (ICs in my case) to divide by N and is intended to adjust a VCO output voltage based on the phase difference of two different inputs. Although I made some great progress using this chip, I found a few SMT ICS501 ICs in my junk box and decided to give them a try. I was impressed how easy it was to use! I just fed it 5V and my clock signal, and it output 8x my clock signal! Since I don't have my 10MHz reference frequency running at the moment, I tested it with a 1MHz canned oscillator. It worked great, and was so easy! I'll definitely be using this chip to multiply-up crystal oscillator frequencies to improve the precision of frequency counting.

The pin connections are straightforward: +5V and GND to pins 2 and 3, no connection for pins 7 and 8, clock goes in 1 and comes out on 5. Pins 4 and 6 are both set to +5V to yield a x8 multiplier, according to the chart. All of this is in the datasheet for the chip.

The IC I had on hand was SOIC. I don't think they make this IC in DIP. Luckily, I have breadboardable breakout boards on hand. These breakout boards are identical to those sold on dipmicro but I got mine from ebay and they're all over ebay!

I didn't feel like changing my soldering iron tip so I gave it a go with a huge wedge, and it worked pretty well! I first melted a little bit of solder on all the rails, waited until it cooled, pressed the IC into the solder, then re-melted it with the iron. It was relatively easy and I had no shorts. I do have a hot air gun (which I also didn't feel like setting up and waiting for to get warm) but this worked fine...

Here's the test circuit. I added a 100nF power decoupling capacitor and a SMT LED (with a 1 kOhm current limiting resistor) so I could tell when it was powered. I am using a 1MHz can oscillator at the input of the ICS501, and capturing both outputs through a 0.1uF capacitors terminating in a 50 ohm loads (at the oscilloscope, seen better in the next photo).

It worked immediately with no trouble! The top trace is the original 1MHz clock signal, and the bottom is the 8MHz trace.

The frequency isn't exactly 1MHz because the adjustment pin of the can oscillator has been left floating. Also, I recognize the power supply is noisy which is also getting noise in the signals. None of that matters, I'm just testing the concept here. The bottom line is that the ICS501 is an extremely easy way to multiply a clock frequency to beyond 100 MHz and it requires no external components! I will definitely be using this IC in some of my future designs. I'm glad I have it! I had to search my email to see when I ordered it because I had no memory of doing so. It looks like I got them in August 2013 (3 years ago!) and never used them. Regardless, I'm happy to have found them in my junk box, and will definitely be using them from now on.

Update: Cascading Two ICS501s for 10x Frequency Multiplication

My ultimate goal is to build a frequency counter using a 10 MHz frequency source, multiplied to a higher value for greater precision. Although I could achieve 8x frequency multiplication with a single ICS501, I didn't like the idea of frequency steps not being decimal. I decided to try to cascade two ICS501 chips configured to multiply by 2 then by 5 to yield 10. Supposedly this could work on a range of frequencies up through 64x multiplication, but for me generating 100 MHz from a 10 MHz reference is exactly what I need.

Here's my design. It's simple. I configure S0 or S1 as floating, grounded, or high to set the multiplication factor (see the chart above).

Here's my implementation. I didn't have enough space on the breakout board to fit the whole chip (I was missing a single row!). Luckily the SMT perf board is spaced perfectly for SOIC. I was surprised how easy this thing was to solder on the SMT perf board. I'm going to have to buy some more and try prototyping with it. It would be cool to get good at it. That's another story for another day though...

The breadboard design got way easier! This thing now just needs power (+5V and GND), an input signal (1 MHz in this demo), and the output signal is 10x the input (10 MHz).

This is what the output looks like. Signals terminate into a 10 ohm load at the level of the oscilloscope.

I had the USB drive in the thing so I went ahead and pushed the print button. Here's the actual screen capture.

Here it is converting 10 MHz into 100 MHz. The signals are a bit noisy, likely because both ICs are being powered together (behind the same inductor/capacitor). In a production device, each IC should have its own inductor/capacitor to isolate it from ripple on the power rail. Regardless, this works great in cascading arrangement to multiply HF frequencies to VHF frequencies. The 10MHz source is my oven controlled crystal oscillator (OCXO) which I haven't written about yet.

All in all, the ICS501 was an easy cheap single-component solution to frequency multiplication, and cascading two in series easily allows me to multiply the frequency of an incoming signal. I look forward to posting details of my frequency counter build soon!

Markdown source code last modified on January 18th, 2021
---
title: ICS501 Simple Frequency Multiplier
date: 2016-08-31 03:57:50
tags: circuit, old
---

# ICS501 Simple Frequency Multiplier

**Today I made a high frequency multiplier using a single component: the ICS501 PLL clock multiplier** **IC.** This chip provides 2x, 5x, 8x (and more) clock multiplication using an internal phased-lock loop (PLL). At less [than a dollar on eBay](http://www.ebay.com/sch/i.html?&_nkw=ICS501), [$1.55 on mouser](http://www.mouser.com/Search/Refine.aspx?Keyword=ics501&Ns=Pricing%7c0&FS=True), and [$0.67 on Digikey](http://www.digikey.com/product-search/en/integrated-circuits-ics/clock-timing-clock-generators-plls-frequency-synthesizers/2556421?FV=fff40027%2Cfff80205&mnonly=0&newproducts=0&ColumnSort=1000011&page=1&stock=0&pbfree=0&rohs=0&k=ics501&quantity=&ptm=0&fid=0&pageSize=25), they don't break the bank and I'm glad I have a few in my junk box! I have a 10MHz frequency standard which I want to use to measure some 1Hz (1pps) pulses with higher precision, so my general idea is to use a frequency multiplier circuit to increase the frequency (to 80 MHz) and use this to run a counter IC to measure the number of clock pulses between the PPS pulses. I spent a lot of time working with the [CD4046](http://www.ti.com/lit/ds/symlink/cd4046b.pdf) micro-power phased lock loop IC which has a [phase comparator](https://en.wikipedia.org/wiki/Phase_detector) and a voltage controlled oscillator built in. It seemed this chip was the go-to for many years, but it requires external circuitry (ICs in my case) to divide by N and is intended to adjust a [VCO](https://en.wikipedia.org/wiki/Voltage-controlled_oscillator) output voltage based on the phase difference of two different inputs. Although I made some great progress using this chip, I found a few SMT ICS501 ICs in my junk box and decided to give them a try. I was impressed how easy it was to use! **I just fed it 5V and my clock signal, and it output 8x my clock signal!** Since I don't have my 10MHz reference frequency running at the moment, I tested it with a 1MHz canned oscillator. It worked great, and was so easy! I'll definitely be using this chip to multiply-up crystal oscillator frequencies to improve the precision of frequency counting.

<div class="text-center img-medium">

[![](datasheet_thumb.jpg)](datasheet.jpg)

</div>

**The pin connections are straightforward:** +5V and GND to pins 2 and 3, no connection for pins 7 and 8, clock goes in 1 and comes out on 5. Pins 4 and 6 are both set to +5V to yield a x8 multiplier, according to the chart. All of this is in the datasheet for the chip.

<div class="text-center img-border">

[![](IMG_8104_thumb.jpg)](IMG_8104.jpg)

</div>

**The IC I had on hand was [SOIC](https://en.wikipedia.org/wiki/Small_Outline_Integrated_Circuit).** I don't think they make this IC in [DIP](https://en.wikipedia.org/wiki/Dual_in-line_package). Luckily, I have breadboardable breakout boards on hand. These breakout boards are identical to those sold on [dipmicro](https://www.dipmicro.com/store/PCB-SSOP-DIP28) but I got mine from ebay and they're [all over ebay](http://www.ebay.com/sch/sis.html?_nkw=SMD+SMT+IC+PCB+Adapter)!

<div class="text-center img-border">

[![](IMG_8111_thumb.jpg)](IMG_8111.jpg)

</div>

**I didn't feel like changing my soldering iron tip so I gave it a go with a huge wedge,** **and it worked pretty well!** I first melted a little bit of solder on all the rails, waited until it cooled, pressed the IC into the solder, then re-melted it with the iron. It was relatively easy and I had no shorts. I do have a hot air gun (which I also didn't feel like setting up and waiting for to get warm) but this worked fine...

<div class="text-center img-border">

[![](IMG_8113_thumb.jpg)](IMG_8113.jpg)

</div>

**Here's the test circuit.** I added a 100nF power [decoupling capacitor](https://en.wikipedia.org/wiki/Decoupling_capacitor) and a SMT LED (with a 1 kOhm current limiting resistor) so I could tell when it was powered. I am using a 1MHz can oscillator at the input of the ICS501, and capturing both outputs through a 0.1uF capacitors terminating in a 50 ohm loads (at the oscilloscope, seen better in the next photo).

<div class="text-center img-border">

[![](IMG_8121_thumb.jpg)](IMG_8121.jpg)

</div>

**It worked immediately with no trouble!** The top trace is the original 1MHz clock signal, and the bottom is the 8MHz trace.

<div class="text-center img-border">

[![](ics501-demo_thumb.jpg)](ics501-demo.png)

</div>

The frequency isn't exactly 1MHz because the adjustment pin of the can oscillator has been left floating. Also, I recognize the power supply is noisy which is also getting noise in the signals. **None of that matters, I'm just testing the concept here. The bottom line is that the ICS501 is an extremely easy way to multiply a clock frequency to beyond 100 MHz and it requires no external components!** I will definitely be using this IC in some of my future designs. I'm glad I have it! I had to search my email to see when I ordered it because I had no memory of doing so. It looks like I got them in August 2013 (3 years ago!) and never used them. Regardless, I'm happy to have found them in my junk box, and will definitely be using them from now on.

## Update: Cascading Two ICS501s for 10x Frequency Multiplication

**My ultimate goal is to build a frequency counter using a 10 MHz frequency source, multiplied to a higher value for greater precision.** Although I could achieve 8x frequency multiplication with a single ICS501, I didn't like the idea of frequency steps not being decimal. I decided to try to cascade two ICS501 chips configured to multiply by 2 then by 5 to yield 10. Supposedly this could work on a range of frequencies up through 64x multiplication, but for me generating 100 MHz from a 10 MHz reference is exactly what I need.

<div class="text-center img-border img-small">

[![](IMG_8179_thumb.jpg)](IMG_8179.jpg)

</div>

**Here's my design.** It's simple. I configure S0 or S1 as floating, grounded, or high to set the multiplication factor (see the chart above).

<div class="text-center img-border">

[![](IMG_8175_thumb.jpg)](IMG_8175.jpg)

</div>

**Here's my implementation.** I didn't have enough space on the breakout board to fit the whole chip (I was missing a single row!). Luckily the SMT perf board is spaced perfectly for SOIC. I was surprised how easy this thing was to solder on the SMT perf board. I'm going to have to buy some more and try prototyping with it. It would be cool to get good at it. That's another story for another day though...

<div class="text-center img-border">

[![](IMG_8162_thumb.jpg)](IMG_8162.jpg)

</div>

**The breadboard design got way easier!** This thing now just needs power (+5V and GND), an input signal (1 MHz in this demo), and the output signal is 10x the input (10 MHz).

<div class="text-center img-border">

[![](IMG_8161_thumb.jpg)](IMG_8161.jpg)

</div>

**This is what the output looks like.** Signals terminate into a 10 ohm load at the level of the oscilloscope.

<div class="text-center img-border">

![](SDS00018.jpg)

</div>

I had the USB drive in the thing so I went ahead and pushed the print button. Here's the actual screen capture.

<div class="text-center img-border">

![](SDS00005.jpg)

</div>

**Here it is converting 10 MHz into 100 MHz.** The signals are a bit noisy, likely because both ICs are being powered together (behind the same inductor/capacitor). In a production device, each IC should have its own inductor/capacitor to isolate it from ripple on the power rail. Regardless, this works great in cascading arrangement to multiply HF frequencies to VHF frequencies. The 10MHz source is my oven controlled crystal oscillator (OCXO) which I haven't written about yet.

<div class="text-center img-border">

[![](IMG_8166_thumb.jpg)](IMG_8166.jpg)

</div>

**All in all, the ICS501 was an easy cheap single-component solution to frequency multiplication**, **and cascading two in series** easily allows me to multiply the frequency of an incoming signal. I look forward to posting details of my frequency counter build soon!
August 20th, 2016

Breadboard Line Driver Module

Sometimes I rapidly want to amplify a signal, but building amplifiers, buffers, and line drivers can be a hassle, especially on a breadboard! It's important to know how to carefully design build tuned and untuned amplifier circuits, but sometimes you just want to analyze or work with a signal without modifying it by sinking too much current, so being able to rapidly drop in a buffer stage would be a great help. Sometimes I want to buffer a signal so I can analyze it (with an oscilloscope or frequency counter) or use use it (perhaps to drive or gate something), but the signal source is across the room, so I need a beefy amplifier to drive it into coax as I run it across my ceiling while I'm experimenting. A MOSFET voltage follower or a Darlington transistor may do the job, but I have to worry about input conditioning, biasing, output voltage limiting, class A, B, C, D, etc., RF vs DC, copying this circuit multiple times for multiple signals, and before you know it I'm sinking more time into my task than I need to.

Line driver chips are one of my go-tos for quickly amplifying digital signals because they're so fast to drop in a breadboard and they provide a strong output with very high impedance inputs and need no external components. Individual buffer of the integrated chip can be paralleled to multiply their current handling capabilities too. One of the common variants is the 74HC240. I don't know why it's so popular (I still find its pinout odd), but because it is popular it is cheap. They're $0.50 on Mouser.com (perhaps cheaper on ebay) and according to their datasheet they can be run up to 7V to deliver or sink 20mA/pin with a maximum dissipation of 500mW. With propagation, enable, and disable times of tens of nanoseconds, they're not awful for lower-range radio frequencies (HF RF). This specific chip (somewhat comically at the exclusion of almost all others) has been latched onto by amateur radio operators who use it as an amplifier stage of low power (QRP) Morse code radio transmitters often pushing it to achieve ~1 watt of power output. A quick google reveals thousands of web pages discussing this! This Portuguese site is one of the most thorough. Even if not used as the final amplifier, they're a convenient intermediate stage along an amplifier chain as they can directly drive FET final stages very well (probably best for class C operation). If you're interested, definitely check out The Handiman's Guide to MOSFET "Switched Mode" Amplifiers guide by Paul Harden (no relation). Also his part 2.

This is the circuit I commonly build. I have one variant on hand for RF (extremely fast oscillations which are continuously fed into the device and often decoupled through a series capacitor), and one for TTL signals (extremely fast). I find myself paralleling line driver outputs all the time. On a breadboard, this means tons of wires! It becomes repetitive and a pain. I've started pre-packaging highly parallel line drivers into little modules which I find really convenient. I have a half dozen of these soldered and ready to go, and I can use them by simply dropping them into a breadboard and applying ground, power (+5V), and input signal, and it amplifies it and returns an output signal. Note that in the "Case 2: RF input" example, the inverted output of the first stage is continuously fed back into the input. This will result in continuous oscillation and undesired output if no input is supplied. In case 2, RF must be continuously applied. The advantage is that the feedback network holds the input near the threshold voltage, so very little voltage swing through the decoupling capacitor is required to generate strong output.

Although I have made this entirely floating, I prefer using copper-clad board. Not only does it aid heat dissipation and provide better mechanical structure, but it also serves as a partial RF shield to minimize noise in the input and output signals. A Dremel with a diamond wheel does a good job at cutting out notches in the copper-clad board.

The best way to replicate this is to look at the picture. It's surprisingly difficult to get it right just by looking at the datasheet, because when it's upside down it's mirror-imaged and very easy to make mistakes. I just connect all inputs and all outputs in parallel, for 7 of 8 gates. For one gate, I connect its output to the parallel inputs. I added some passives (including a ferrite bead and decoupling capacitor on the VCC pin) and it's good to go. With only 4 pins (GND, +5V, IN, and OUT) this amplifier is easy to drop in a breadboard:

Although I often use it in a breadboard, it's easy to stick in a project. Since the back side is unpopulated, you can use a dot of super glue and stick it anywhere you want. In this example, I had a GPS receiver module which blinked a LED at exactly one pulse per second (1PPS) [check out why] and I wanted to do some measurements on its output. I couldn't send this line signal out a coax line because it was so low current (in reality, I didn't know what it could deliver). This is a perfect use for a buffer / line driver.

I glued this board inside my temporary project enclosure (which admittedly looks nicer and more permanent than it's actually intended to be) and set the output to deliver through 50 Ohm coax. It works beautifully!

Markdown source code last modified on January 18th, 2021
---
title: Breadboard Line Driver Module
date: 2016-08-20 19:16:27
tags: circuit, old
---

# Breadboard Line Driver Module

__Sometimes I rapidly want to amplify a signal, but building amplifiers, buffers, and line drivers can be a hassle, especially on a breadboard!__ It's important to know how to carefully design build [tuned and untuned amplifier circuits](https://en.wikibooks.org/wiki/Practical_Electronics/Amplifiers#Type_of_load), but sometimes you just want to analyze or work with a signal without modifying it by sinking too much current, so being able to rapidly drop in a buffer stage would be a great help. Sometimes I want to buffer a signal so I can analyze it (with an oscilloscope or frequency counter) or use use it (perhaps to drive or gate something), but the signal source is across the room, so I need a beefy amplifier to drive it into coax as I run it across my ceiling while I'm experimenting. A [MOSFET voltage follower](https://en.wikipedia.org/wiki/Buffer_amplifier#Impedance_transformation_using_the_MOSFET_voltage_follower) or a [Darlington transistor](https://en.wikipedia.org/wiki/Darlington_transistor) may do the job, but I have to worry about input conditioning, biasing, output voltage limiting, class A, B, C, D, etc., RF vs DC, copying this circuit multiple times for multiple signals, and before you know it I'm sinking more time into my task than I need to. 

__Line driver chips are one of my go-tos for quickly amplifying digital signals because they're so fast to drop in a breadboard and they provide a strong output with very high impedance inputs and need no external components.__ Individual buffer of the integrated chip can be paralleled to multiply their current handling capabilities too. One of the common variants is the 74HC240. I don't know why it's so popular (I still find its pinout odd), but because it is popular it is cheap. They're [$0.50 on Mouser.com](http://www.mouser.com/Semiconductors/Integrated-Circuits-ICs/Logic-ICs/Buffers-Line-Drivers/_/N-6j78c?P=1z0z63x&Keyword=74hc240&FS=True) (perhaps cheaper on ebay) and [according to their datasheet](http://www.nxp.com/documents/data_sheet/74HC_HCT240.pdf) they can be run up to 7V to deliver or sink 20mA/pin with a maximum dissipation of 500mW. With propagation, enable, and disable times of tens of nanoseconds, they're not awful for lower-range radio frequencies (HF RF). This specific chip (somewhat comically at the exclusion of almost all others) has been latched onto by amateur radio operators who use it as an amplifier stage of low power (QRP) Morse code radio transmitters often pushing it to achieve ~1 watt of power output. A quick google [reveals](https://www.google.com/search?q=74hc240+transmitter) thousands of web pages discussing this! This [Portuguese site](http://py2ohh.w2c.com.br/trx/digital/rfdigital.htm) is one of the most thorough. Even if not used as the final amplifier, they're a convenient intermediate stage along an amplifier chain as they can directly drive FET final stages very well (probably best for class C operation). If you're interested, definitely check out [The Handiman's Guide to MOSFET "Switched Mode" Amplifiers guide by Paul Harden](http://www.aoc.nrao.edu/~pharden/hobby/_ClassDEF1.pdf) (no relation). Also his [part 2](http://www.aoc.nrao.edu/~pharden/hobby/_ClassDEF2.pdf).

<div class="text-center img-medium">

[![](schematic_thumb.jpg)](schematic.jpg)

</div>

This is the circuit I commonly build. I have one variant on hand for RF (extremely fast oscillations which are continuously fed into the device and often decoupled through a series capacitor), and one for TTL signals (extremely fast). __I find myself paralleling line driver outputs all the time. On a breadboard, this means tons of wires!__ __It becomes repetitive and a pain. I've started pre-packaging highly parallel line drivers into little modules which I find really convenient.__ I have a half dozen of these soldered and ready to go, and I can use them by simply dropping them into a breadboard and applying ground, power (+5V), and input signal, and it amplifies it and returns an output signal. Note that in the "Case 2: RF input" example, the inverted output of the first stage is continuously fed back into the input. This will result in continuous oscillation and undesired output if no input is supplied. In case 2, RF must be continuously applied. The advantage is that the feedback network holds the input near the threshold voltage, so very little voltage swing through the decoupling capacitor is required to generate strong output.

<div class="text-center img-border img-small">

[![](IMG_7890_thumb.jpg)](IMG_7890.jpg)
[![](IMG_7894_thumb.jpg)](IMG_7894.jpg)
[![](IMG_7897_thumb.jpg)](IMG_7897.jpg)

</div>

__Although I have made this entirely floating, I prefer using copper-clad board.__ Not only does it aid heat dissipation and provide better mechanical structure, but it also serves as a partial RF shield to minimize noise in the input and output signals. A Dremel with a diamond wheel does a good job at cutting out notches in the copper-clad board.

<div class="text-center img-border img-small">

[![](IMG_7898_thumb.jpg)](IMG_7898.jpg)
[![](IMG_7900_thumb.jpg)](IMG_7900.jpg)
[![](IMG_7909_thumb.jpg)](IMG_7909.jpg)

</div>

__The best way to replicate this is to look at the picture.__ It's surprisingly difficult to get it right just by looking at the datasheet, because when it's upside down it's mirror-imaged and very easy to make mistakes. I just connect all inputs and all outputs in parallel, for 7 of 8 gates. For one gate, I connect its output to the parallel inputs. I added some passives (including a [ferrite bead](https://en.wikipedia.org/wiki/Ferrite_bead) and decoupling capacitor on the VCC pin) and it's good to go. With only 4 pins (GND, +5V, IN, and OUT) this amplifier is easy to drop in a breadboard:

<div class="text-center img-border">

[![](IMG_7904_thumb.jpg)](IMG_7904.jpg)

</div>

__Although I often use it in a breadboard, it's easy to stick in a project.__ Since the back side is unpopulated, you can use a dot of super glue and stick it anywhere you want. In this example, I had a GPS receiver module which blinked a LED at exactly one pulse per second (1PPS) [[check out why](http://electronics.stackexchange.com/questions/30750/why-do-gps-receivers-have-a-1-pps-output)] and I wanted to do some measurements on its output. I couldn't send this line signal out a coax line because it was so low current (in reality, I didn't know what it could deliver). This is a perfect use for a buffer / line driver. 

<div class="text-center img-border">

[![](IMG_7912_thumb.jpg)](IMG_7912.jpg)

</div>

I glued this board inside my temporary project enclosure (which admittedly looks nicer and more permanent than it's actually intended to be) and set the output to deliver through 50 Ohm coax. It works beautifully!

<div class="text-center img-border img-small">

[![](IMG_7943_thumb.jpg)](IMG_7943.jpg)
[![](IMG_7948_thumb.jpg)](IMG_7948.jpg)

</div>
August 8th, 2016

DIY ECG with 1 op-amp

⚠️ Check out my newer ECG design:

I made surprisingly good ECG from a single op-amp and 5 resistors! An ECG (electrocardiograph, sometimes called EKG) is a graph of the electrical potential your heart produces as it beats. Seven years ago I posted DIY ECG Machine on the Cheap which showed a discernible ECG I obtained using an op-amp, two resistors, and a capacitor outputting to a PC sound card's microphone input. It didn't work well, but the fact that it worked at all was impressive! It has been one of the most popular posts of my website ever since, and I get 1-2 emails a month from people trying to recreate these results (some of them are during the last week of a college design course and sound pretty desperate). Sometimes people get good results with that old circuit, but more often than not the output isn't what people expected. I decided to revisit this project (with more patience and experience under my belt) and see if I could improve it. My goal was not to create the highest quality ECG machine I could, but rather to create the simplest one I could with emphasis on predictable and reproducible results. The finished project is a blend of improved hardware and custom cross-platform open-source software (which runs on Windows, Linux, and MacOS), and an impressively good ECG considering the circuit is so simple and runs on a breadboard! Furthermore, the schematics and custom software are all open-sourced on my github!

Here's a video demonstrating how the output is shown in real time with custom Python software. The video is quite long, but you can see the device in action immediately, so even if you only watch the first few seconds you will see this circuit in action with the custom software. In short, the amplifier circuit (described in detail below) outputs to the computer's microphone and a Python script I wrote analyzes the audio data, performs low-pass filtering, and graphs the output in real time. The result is a live electrocardiograph!

ECG Circuit

The circuit is simple, but a lot of time and thought and experimentation went into it. I settled on this design because it produced the best and most reliable results, and it has a few nuances which might not be obvious at first. Although I discuss it in detail in the video, here are the highlights:

  • The output goes to the microphone jack of your computer.

  • There's nothing special about the op-amp I used (LM741). A single unit of an LM324 (or any general purpose op-amp) should work just as well.

  • Resistor values were chosen because I had them on hand. You can probably change them a lot as long as they're in the same ballpark of the values shown here. Just make sure R1 and R2 are matched, and R3 should be at least 10MOhm.

  • Do not use a bench power supply! "BAT+" and "BAT-" are the leads of a single 9V battery.

  • Note that the leg electrode is ground (same ground as the computer's microphone ground)

  • R5 and R4 form a traditional voltage divider like you'd expect for an op-amp with a gain of about 50.

    • You'd expect R4 to connect to ground, but since your body is grounded, chest 2 is essentially the same

    • R3 must be extremely high value, but it pulls your body potential near the optimal input voltage for amplification by the op-amp.

    • R1 and R2 split the 9V battery's voltage in half and center it at ground, creating -4.5V and +4.5V.

  • altogether, your body stays grounded, and the op-amp becomes powered by -4.5V and +4.5V, and your body is conveniently near the middle and ready to have small signals from CHEST1 amplified. Amplification is with respect to CHEST2 (roughly ground), rather than actual ground, so that a lot of noise (with respect to ground) is eliminated.

For those of you who would rather see a picture than a schematic, here's a diagram of how to assemble it graphically. This should be very easy to reproduce. Although breadboards are typically not recommended for small signal amplification projects, there is so much noise already in these signals that it doesn't really matter much either way. Check out how good the signals look in my video, and consider that I use a breadboard the entire time.

The most comfortable electrodes I used were made for muscle simulators. A friend of mine showed me some muscle stimulator pads he got for a back pain relief device he uses. As soon as I saw those pads, I immediately thought they would be perfect for building an ECG! They're a little bit expensive, but very comfortable, reusable, last a long time, and produce brilliant results. They also have 3.5 mm (headphone jack) connectors which is perfect for DIY projects. On Amazon.com you can get 16 pads for $11 with free shipping. I decided not to include links, because sometimes the pads and cords are sold separately, and sometimes they have barrel connectors and sometimes they have snap connectors. Just get any adhesive reusable electrodes intended for transcutaneous electrical nerve stimulation (TENS) that you can find! They should all work fine.

Pennies as Electrodes

You can make your own electrodes for $0.03! Okay that's a terrible joke, but it's true. I made not-awful electrodes by soldering wires to copper pennies, adding strength by super-gluing the wire to the penny, and using electrical tape to attach them to my chest. Unless you want a tattoo of an old guy's face on your torso, wait until they cool sufficiently after soldering before proceeding to the adhesion step. I suspect that super gluing the penny to your chest would also work, but please do not do this. Ironically, because the adhesive pads of the TENS electrodes wear away over time, the penny solution is probably "more reusable" than the commercial electrode option.

This ECG was recorded using pennies as electrodes:

Notes on filtering: Why didn't I just use a hardware low-pass filter?

  1. It would have required extra components, which goes against the theme of this project
  2. It would require specific value components, which is also undesirable for a junkbox project
  3. I'm partial to the Chebyshev filter, but getting an extremely sharp roll-off a few Hz shy of 50Hz would take multiple poles (of closely matched passive components) and not be as trivial as it sounds.

Notes on software: This a really cool use of Python! I lean on some of my favorite packages numpy, scipy, matplotlib, pyqrgraph, and PyQt4. I've recently made posts describing how to perform real-time data graphing in Python using these libraries, so I won't go into that here. If you're interested, check out my real-time audio monitor, notes on using PlotWidget, and notes on using MatPlotLib widget. I tried using PyInstaller to package this project into a single .EXE for all my windows readers who might want to recreate this project, but the resulting EXE was over 160MB! That's crazy! It makes sense considering packagers like PyInstaller and Py2EXE work by building your entire python interpreter and all imported libraries. With all those fun libraries I listed above, it's no wonder it came out so huge. It may be convenient for local quick-fixes, but not a good way to distribute code over the internet. To use this software, just run it in Python. It was tested to work with out-of-the-box WinPython-64bit-3.5.2.1 (not the Qt5 version), so if you want to run it yourself start there.

Notes on safety. How safe is this project? I'm conflicted on this subject. I want to be as conservative as I can (leaning on the side of caution), but I also want to be as realistic as possible. I'm going to play it safe and say "this may not be safe, so don't build or use it". As an exercise, let's consider the pros and cons:

  • PROS:

    • It's powered from a 9V battery which is safer than a bench power supply (but see the matching con).

    • The only connections to your body are:

      • leg - ground. you ground yourself all the time. using a wrist grounding strap is the same thing.
      • chest 1 - extremely high impedance. You're attaching your chest to the high impedance input of an op-amp (which I feel fine with), and also to a floating battery through a 10MOhm resistor (which also I feel fine with)
      • chest 2 - raises an eyebrow. In addition to a high impedance input, you're connected to an op-amp through a 100k resistor. Even if the op-amp were putting out a full 4.5V, that's 0.045mA (which doesn't concern me a whole lot).
    • I don't know where to stick this, but I wonder what type of voltages / currents TENS actually provide.

  • CONS / WARNINGS:

    • It's powered from a 9V battery. So are many stun guns.
    • If the op-amp oscillates, oscillations may enter your body. Personally I feel this may be the most concerning issue.
    • Small currents can kill. I found a curiously colored website that describes this. It seems like the most dangerous potential effect is induction of cardiac fibrillation, which can occur around 100mA.

Improving safety through optical isolation: The safety of this device may be improved (albeit with increased complexity) through the implementation of opto-isolators. I may consider a follow-up post demonstrating how I do this. Unlike digital signals which I've optically isolated before, I've never personally isolated analog signals. Although I'm sure there are fully analog means to do this, I suspect I'd accomplish it by turning it into a digital signal (with a voltage-to-frequency converter), pulsing the output across the optoisolator, and turning it back into voltage with a frequency-to-voltage converter or perhaps even a passive low-pass filter. Analog Devices has a good write-up about optical isolation techniques.

Do you have comments regarding the safety of this device? Write your thoughts concisely and send them to me in an email! I'd be happy to share your knowledge with everyone by posting it here.

Did you build this or a device similar to it? Send me some pictures! I'll post them here.

Source code and project files: https://github.com/swharden/diyECG-1opAmp/

LEGAL: This website is for educational purposes only. Do not build or use any electrical devices shown. Attaching non-compliant electronic devices to your body may be dangerous. Consult a physician regarding proper usage of medical equipment.

Markdown source code last modified on January 18th, 2021
---
title: DIY ECG with 1 op-amp
date: 2016-08-08 01:49:24
tags: diyECG, python, circuit
---

# DIY ECG with 1 op-amp

> **⚠️ Check out my newer ECG design:** 
* [**Sound Card ECG with AD8232**](https://swharden.com/blog/2019-03-15-sound-card-ecg-with-ad8232/)

__I made surprisingly good ECG from a single op-amp and 5 resistors! __An ECG (electrocardiograph, sometimes called EKG) is a graph of the electrical potential your heart produces as it beats. Seven years ago I posted _[DIY ECG Machine on the Cheap](https://www.swharden.com/wp/2009-08-14-diy-ecg-machine-on-the-cheap/)_ which showed a discernible ECG I obtained using an op-amp, two resistors, and a capacitor outputting to a PC sound card's microphone input. It didn't work well, but the fact that it worked at all was impressive! It has been one of the most popular posts of my website ever since, and I get 1-2 emails a month from people trying to recreate these results (some of them are during the last week of a college design course and sound pretty desperate). Sometimes people get good results with that old circuit, but more often than not the output isn't what people expected. I decided to revisit this project (with more patience and experience under my belt) and see if I could improve it. My goal was not to create the highest quality ECG machine I could, but rather to create the _simplest_ one I could with emphasis on predictable and reproducible results. The finished project is a blend of improved hardware and custom cross-platform open-source software (which runs on Windows, Linux, and MacOS), and an impressively good ECG considering the circuit is so simple and runs on a breadboard! Furthermore, the schematics and custom software are all [open-sourced on my github](https://github.com/swharden/diyECG-1opAmp/)!

![](https://www.youtube.com/embed/AfirWls9Sys)

__Here's a video demonstrating how the output is shown in real time with custom Python software.__ The video is quite long, but you can see the device in action immediately, so even if you only watch the first few seconds you will see this circuit in action with the custom software. In short, the amplifier circuit (described in detail below) outputs to the computer's microphone and a Python script I wrote analyzes the audio data, performs low-pass filtering, and graphs the output in real time. The result is a live electrocardiograph!

<div class="text-center">

[![](ECG_1470609065_thumb.jpg)](ECG_1470609065.png)

</div>

### ECG Circuit

<div class="text-center">

[![](circuit_thumb.jpg)](circuit.jpg)

</div>

__The circuit is simple, but a lot of time and thought and experimentation went into it.__ I settled on this design because it produced the best and most reliable results, and it has a few nuances which might not be obvious at first. Although I discuss it in detail in the video, here are the highlights:

*   The output goes to the microphone jack of your computer.
*   There's nothing special about the op-amp I used ([LM741](http://www.ti.com/lit/ds/symlink/lm741.pdf)). A single unit of an [LM324](http://www.ti.com.cn/cn/lit/ds/symlink/lm2902-n.pdf) (or any general purpose op-amp) should work just as well.
*   Resistor values were chosen because I had them on hand. You can probably change them a lot as long as they're in the same ballpark of the values shown here. Just make sure R1 and R2 are matched, and R3 should be at least 10MOhm.
*   <span style="color: #ff0000;">Do not use a bench power supply!</span> "BAT+" and "BAT-" are the leads of a single 9V battery.
*   Note that the leg electrode is ground (same ground as the computer's microphone ground)
*   R5 and R4 form a traditional voltage divider like you'd expect for an op-amp with a gain of about 50.

    *   You'd expect R4 to connect to ground, but since your body is grounded, chest 2 is essentially the same

    *   R3 must be extremely high value, but it pulls your body potential near the optimal input voltage for amplification by the op-amp.

    *   R1 and R2 split the 9V battery's voltage in half and center it at ground, creating -4.5V and +4.5V.

*   altogether, your body stays grounded, and the op-amp becomes powered by -4.5V and +4.5V, and your body is conveniently near the middle and ready to have small signals from CHEST1 amplified. Amplification is with respect to CHEST2 (roughly ground), rather than actual ground, so that a lot of noise (with respect to ground) is eliminated.

<div class="text-center img-border">

[![](IMG_7574_thumb.jpg)](IMG_7574.jpg)

</div>

__For those of you who would rather see a picture than a schematic__, here's a diagram of how to assemble it graphically. This should be very easy to reproduce. Although breadboards are typically not recommended for small signal amplification projects, there is so much noise already in these signals that it doesn't really matter much either way. Check out how good the signals look in my video, and consider that I use a breadboard the entire time.

<div class="text-center">

[![](design_thumb.jpg)](design.jpg)

</div>

__The most comfortable electrodes I used were made for muscle simulators.__ A friend of mine showed me some muscle stimulator pads he got for a back pain relief device he uses. As soon as I saw those pads, I immediately thought they would be perfect for building an ECG! They're a little bit expensive, but very comfortable, reusable, last a long time, and produce brilliant results. They also have 3.5 mm (headphone jack) connectors which is perfect for DIY projects. On Amazon.com you can get 16 pads for $11 with free shipping. I decided not to include links, because sometimes the pads and cords are sold separately, and sometimes they have barrel connectors and sometimes they have snap connectors. Just get any adhesive reusable electrodes intended for [transcutaneous electrical nerve stimulation (TENS)](https://en.wikipedia.org/wiki/Transcutaneous_electrical_nerve_stimulation) that you can find! They should all work fine.

<div class="text-center img-border">

[![](IMG_7576_thumb.jpg)](IMG_7576.jpg)

</div>

### Pennies as Electrodes

__You can make your own electrodes for $0.03!__ Okay that's a terrible joke, but it's true. I made not-awful electrodes by soldering wires to copper pennies, adding strength by super-gluing the wire to the penny, and using electrical tape to attach them to my chest. Unless you want a tattoo of an old guy's face on your torso, wait until they cool sufficiently after soldering before proceeding to the adhesion step. I suspect that super gluing the penny to your chest would also work, but please do not do this. Ironically, because the adhesive pads of the TENS electrodes wear away over time, the penny solution is probably "more reusable" than the commercial electrode option.

<div class="text-center img-border img-small">

[![](IMG_7527_thumb.jpg)](IMG_7527.jpg)
[![](IMG_7570-1_thumb.jpg)](IMG_7570-1.jpg)

</div>

This ECG was recorded using pennies as electrodes:

<div class="text-center">

[![](ECG_1470611901_thumb.jpg)](ECG_1470611901.png)

</div>

__Notes on filtering:__ Why didn't I just use a [hardware low-pass filter](https://en.wikipedia.org/wiki/Low-pass_filter)?

1.   It would have required extra components, which goes against the theme of this project
2.   It would require _specific value_ components, which is also undesirable for a junkbox project
3.   I'm partial to the [Chebyshev filter](https://en.wikipedia.org/wiki/Chebyshev_filter), but getting an extremely sharp roll-off a few Hz shy of 50Hz would take multiple poles (of closely matched passive components) and [not be as trivial as it sounds](http://www.analog.com/library/analogDialogue/archives/43-09/EDCh%208%20filter.pdf?doc=ADA4661-2.pdf).

__Notes on software:__ This a really cool use of Python! I lean on some of my favorite packages [numpy](http://www.numpy.org/), [scipy](https://www.scipy.org/), [matplotlib](http://matplotlib.org/), [pyqrgraph](http://www.pyqtgraph.org/), and [PyQt4](https://wiki.python.org/moin/PyQt4). I've recently made posts describing how to perform real-time data graphing in Python using these libraries, so I won't go into that here. If you're interested, check out my [real-time audio monitor](https://www.swharden.com/wp/2016-07-31-real-time-audio-monitor-with-pyqt/), notes on using [PlotWidget](https://www.swharden.com/wp/2016-07-31-live-data-in-pyqt4-with-plotwidget/), and notes on using [MatPlotLib widget](https://www.swharden.com/wp/2016-07-30-live-data-in-pyqt4-with-matplotlibwidget/). I tried using [PyInstaller](http://www.pyinstaller.org/) to package this project into a single .EXE for all my windows readers who might want to recreate this project, but the resulting EXE was over 160MB! That's crazy! It makes sense considering packagers like PyInstaller and Py2EXE work by building your entire python interpreter and all imported libraries. With all those fun libraries I listed above, it's no wonder it came out so huge. It may be convenient for local quick-fixes, but not a good way to distribute code over the internet. To use this software, just run it in Python. It was tested to work with out-of-the-box [WinPython-64bit-3.5.2.1](https://sourceforge.net/projects/winpython/files/) (not the Qt5 version), so if you want to run it yourself start there.

__Notes on safety.__ How safe is this project? I'm conflicted on this subject. I want to be as conservative as I can (leaning on the side of caution), but I also want to be as realistic as possible. I'm going to play it safe and say "this may not be safe, so don't build or use it". As an exercise, let's consider the pros and cons:

*   __PROS:__

    *   It's powered from a 9V battery which is safer than a bench power supply (but see the matching con).
    *   The only connections to your body are:

        *   leg - ground. you ground yourself all the time. using a wrist grounding strap is the same thing.
        *   chest 1 - extremely high impedance. You're attaching your chest to the high impedance input of an op-amp (which I feel fine with), and also to a floating battery through a 10MOhm resistor (which also I feel fine with)
        *   chest 2 - raises an eyebrow. In addition to a high impedance input, you're connected to an op-amp through a 100k resistor. Even if the op-amp were putting out a full 4.5V, that's 0.045mA (which doesn't concern me a whole lot).

    *   I don't know where to stick this, but I wonder what type of voltages / currents [TENS](https://en.wikipedia.org/wiki/Transcutaneous_electrical_nerve_stimulation) actually provide.

*   __CONS / WARNINGS:__

    *   It's powered from a 9V battery. So are many stun guns.
    *   If the op-amp oscillates, oscillations may enter your body. Personally I feel this may be the most concerning issue.
    *   Small currents can kill. I found a [curiously colored website](https://www.physics.ohio-state.edu/~p616/safety/fatal_current.html) that describes this. It seems like the most dangerous potential effect is induction of cardiac fibrillation, which can occur around 100mA.

__Improving safety through optical isolation:__ The safety of this device may be improved (albeit with increased complexity) through the implementation of [opto-isolators](https://en.wikipedia.org/wiki/Opto-isolator). I may consider a follow-up post demonstrating how I do this. Unlike digital signals which I've [optically isolated before](https://www.swharden.com/wp/2016-07-28-opto-isolated-laser-controller-build/), I've never personally isolated analog signals. Although I'm sure there are fully analog means to do this, I suspect I'd accomplish it by turning it into a digital signal (with a voltage-to-frequency converter), pulsing the output across the optoisolator, and turning it back into voltage with a frequency-to-voltage converter or perhaps even a passive low-pass filter. Analog Devices has a good write-up about [optical isolation techniques](http://www.analog.com/media/en/training-seminars/tutorials/MT-071.pdf).

__Do you have comments regarding the safety of this device?__ Write your thoughts concisely and send them to me in an email! I'd be happy to share your knowledge with everyone by posting it here.

__Did you build this or a device similar to it?__ Send me some pictures! I'll post them here.

__Source code and project files:__ <https://github.com/swharden/diyECG-1opAmp/>

___LEGAL__: This website is for educational purposes only. Do not build or use any electrical devices shown. Attaching non-compliant electronic devices to your body may be dangerous. Consult a physician regarding proper usage of medical equipment._
July 28th, 2016

Opto-Isolated Laser Controller Build

This page documents the design and build of a small device to interface a modern fiber-coupled DPSS laser with old scientific hardware designed to control mechanical relays. This project involves analog and digital circuitry, microcontrollers, and lasers, and it turned out to be a pretty cool build so I'm sharing the design and construction process online in case it will be helpful for others or even my future self.

The existing hardware I must interface is made by Coulbourn Instruments and is essentially just a large multi-channel computer-controlled DAC/ADC. It does its job well (turning lights on and off, recording button presses, etc.), but this new task requires millisecond resolution and modulation patterns which lies outside the specs of this system and software. My goal is to interface a free output line of this old hardware and use it to signal to a new device I build to activate the laser to produce a pulsed pattern. This way there would be no modification to any existing equipment, and no software to install. Further, since this hardware isn't mine, I don't like the idea of permanently modifying it (or even risking breaking it by designing something which could damage it by connecting to it). The specific goal is to allow the existing software to cause the laser to fire 20 ms pulses at 15 Hz for a few dozen cycles of 5s on, 5s off. It's also important to have some flexibility to reprogram the high speed laser stimulation pattern in the future. Experiments are already underway and I need this device to be complete within a couple of days! As much as I'd love to go to the internet and order the perfect cheap components, make a proper PCB, and have a beautiful build completed in a month, my goal is to build this over a weekend using only using parts I already have at my home.

Probing the existing hardware revealed many surprises. After inspecting the existing hardware setup I found an auxiliary output which could be controlled by software. This AUX port has a frustratingly rare connector 1mm dual keyhole touchproof connector which I couldn't buy in bulk on eBay or Amazon, and couldn't figure out the part numbers of on Mouser or Digikey. The manual even says "you may find it convenient to fit them with CI-type connectors" which makes me wonder why it wasn't designed this way in the first place! Luckily the laboratory had an old (broken) device with that connector on it they said I could use for this build. After plugging in the connector, I used a volt meter to measure the output. To my surprise, it wasn't a TTL signal! I expected to see my volt meter read 5V, but it read 28V! After consulting the manual I found mention of this: "Graphic State Notation software is designed for use with our Habitest animal-behavior-analysis environments or any other animal-behavior-testing apparatus that operates on the industry-standard 28-Volt control voltage." I was surprised that 28V signals is a standard for any industry.

Control voltages are negative! Elsewhere in the manual I found the phrase "The power base is capable of delivering 8 Amps of -28 VDC" which made me question the voltage reading I took earlier. The voltmeter showed 28V, but that's the difference between one keyhole connector output and the other. It became apparent that it really may be 0V (GND) and -28mV (an even more curious "industry standard"). I wondered if connecting the negative terminal to ground would destroy the unit (think about how easy this would be to do! If it were a TTL signal, the first thing you would do is connect the negative terminal to ground and start sampling the positive terminal). There was even talk of me interfacing with a different output port (which I hadn't probed, so I didn't know the voltage). Moving forward, I realized I had to tread very carefully. Doing something like connecting two grounds together could permanently damage this system!

Optical isolation should be used as a caution. Not really knowing if I should design to expect a TTL signal, a +28V signal, or a -28V signal, I decided to design a circuit to accommodate all of the above, while achieving total electrical discontinuity from whatever circuit I develop. I'm going to accomplish this using an opto-isolator on the input. I drew the schematic using KiCad as I built the board manually using through-hole construction. I considered laying-out a PCB (I have most of these components in SMT form factors too) but I knew I wouldn't manage a one-weekend turnaround if I went that direction.

Design Notes

  • The input should be able to accomodate any signal (TTL, CMOS, 28V, etc)
  • The input is totally isolated electrically, so this should be very safe on the hardware
  • The microcontroller is a socketed ATTiny85 which I programmed with a Bus Pirate.
  • I decided to rely on a crystal rather than the internal RC clock to improve temporal precision of the output signal. A 11.0592 MHz crystal was chosen because I already had an abundance of them (they're perfect for serial communication at all common baud rates). Any crystal could be used, as long as its frequency is defined in software.
  • Capacitors were added more to ensure oscillation initiates than to bring down the oscillation frequency. (I'm told that omitting them may cause a case where the crystal doesn't resonate as well, but I've never found this in my personal experience.) A good note on microcontroller clocks is in a Microchip PIC application note.
  • I included a "test" button (momentary switch) to simulate having an input signal.
  • Note that R1 must be able to handle the current applied to it. It was mistakenly designed as 1k, and later replaced with 10k. See the bodge note at the bottom of this post for details.

Potential Improvements

  • Forward protection diodes on the input could protect accidental reverse polarity
  • Adding an ICSP header would prevent de-socketing of the MCU if reprogramming is desired
  • The BNC output is directly from a MCU pin. A transistor-buffered output design could be considered to deliver higher current for more confident control of the laser input.

Because there is a possibility that a different output (laser control) pattern may be desired in the future, I considered whether or not I should make the output pattern user-configurable. Adding buttons, a display, and designing a menu system in software would be a lot of work and it's unclear if a protocol change will ever actually be required, so I concluded that I'm going to build this device to the specific task at hand and extended it later if/when needed. If the end user eventually wants the ability to modulate the pattern on their own, the device they ask for would be a very different one than the one I was tasked to create. Since the current pattern is burned into a microchip, a compromise is that I could have new patterns burned into new microchips, and the end-user could change the chip (as long as it's an infrequent occurrence).

EDIT: About a year later a modification was indeed required (something like changing 15 Hz to 40 Hz), and the solution was to burn these two patterns into two microchips. Since they're socketed, they're swappable (albiet a limited number of times). This design worked-out well.

Is a microcontroller/crystal overkill for a system which could be accomplished using an analog circuit? Generating 20 ms pulses at 15 Hz sounds like an easy task for a 555 timer without the need for digital circuitry. I considered this for a while, but concluded that the advantage of the MCU (crystal-disciplined time precision) outweighed the convenience of a purely analog circuit. A 555 timer in astable / multi-vibrator configuration would mostly get the job done, but you would either (1) only allow one output pattern and rely on precision passive components (which I don't have on hand), or (2) allow the end-user to adjust duty/frequency with potentiometers (which would require the output to be quantitatively monitored on an oscilloscope). There's also the issue where RC oscillators can be highly temperature sensitive, so the microcontroller/crystal design seemed like a more robust solution for reliable and defined behavior.

I started the build by measuring/marking drill points. I used a Dremel drill press to make the holes, then smoothed them with a deburring tool. I also drilled holes in the base of the enclosure.

I had an enclosure ready to go. I always buy enclosures in bulk, and even though nice ones tend to be expensive, having them on hand encourages me to build devices as I think of them, rather than making flaky hardware which I have a history of doing which sometimes borders on ridiculousness. I usually stock unfinished Hammond diecast aluminum enclosures for making quick RF projects, and boxes with feet and side vents for fancier projects, but for this task I decided to enclose everything inside a typical (but a little more costly) aluminum enclosure ordered in bulk from eBay. I love using low current LEDs, and I started going with frosted instead of clear LEDs because they're easier on the eyes. Also, I switched to mostly 3mm LEDs instead of 5MM because they look a little nicer in these small enclosures with small black bezels.

I used nicer perfboard with plated holes to build this circuit. Normally I use cheap perfboard with little copper rings glued to one side because it's faster to solder (the copper is so thin it heats quickly), but it's not always a good long-term solution because the copper pads have a tendency to un-stick. I rarely use this nicer perfboard (it is more expensive), but it's nice to have for more reliable builds.

I marked areas of optical isolation with a black marker. This makes it obvious where the potentially dangerous, potentially high-voltage (well, higher than TTL), potentially negative input comes in. No wires or connections should invade this space on the board. The special connector which will connect this device to the scientific hardware is on-site, and I'll have to solder it at the time of delivery/installation. I left an extra hole in the back to accommodate this wire. I didn't have any rubber grommets, but I suspect this build may have benefitted from one.

Once it was all together, the device seemed to perform well. The test button on the back made it easy to inspect the output. I build so many RF circuits that I instinctively reached for a 50-ohm terminator, but the square wave quickly transformed into shark fins (RC curves) reminding me that and I realized 50 ohms is far too low impedance. If it's a TTL signal, let's assume it's virtually infinite impedance. I was uncertain whether or not I should drive the output directly with a microcontroller pin. There may be a need for a buffered output. The microcontroller's datasheet suggests limiting its current to 20 mA per pin (requiring termination of no less than 250 Ohms at 5V), and I'm going to move forward assuming the laser TTL input doesn't sink much current.

How should TTL timing be controlled in software? I want this device to perform identically over long periods of time, favoring reliability and consistency over microsecond time precision. To achieve 15 Hz of 20ms pulses I need 20ms on and 46.666667 ms off. I could probably get pretty close if I wanted to, but I rounded it to 20 ms on and 46 ms off. This gives time for the instruction cycles toggling the output pins to occur (although it's on an order of magnitude faster time scale), which slightly biases the time in the right direction. I considered adding a _delay_us(666) after the _delay_ms(46) but I'm satisfied with it this knowing it's within 1% accuracy of 15 Hz and that precision is locked to that of the crystal (around 10 ppm, or 0.001%).

Hard-coded _delay_ms() is somewhat inelegant. The use of AVR timers should probably be considered as an alternative strategy. Here's an awesome guide on the topic, and here's another. Timers would be preferred if I wanted the program code of the microcontroller to be free to do other things like drive menus or multiplex a display. Since this task is simply required generation of a TTL output pattern (and nothing more), the hard-coded delay method met this need, but I found it useful to consider the asynchronous strategies:

  • Timers: Set the timer to overflow every 1 ms. On overflow, a counting variable would be incremented and a function would be called to determine what to do. At pre-programmed time points (with respect to the counting variable), the output pin would be toggled, or the counting variable would be reset.

  • Output compare registers: Utilize the built-in OCR (output compare register) to turn the output signal on and off. Set the timer to overflow at 15 Hz, turning the output on. Set the OCR (to the fractional point between 0 and the maximum timer value) such that when it is passed, the output is turned off. This way 15 Hz, 20 ms pulses would be continuously running without any code being executed. Input sensing could simply enable and disable the timer.

  • Input interrupts: Why stop at timers? Polling the input pin for a TTL signal puts the chip in an infinite loop. Relying on the AVR's external (pin change) hardware interrupts could eliminate this as well. I always rely heavily on the datasheet when setting these interrupts.

These alternative implementations will be useful in the future if a more accurate time source is desired, an advanced display is added, or menus are implemented which would benefit from letting the pulsing output operate in the background while accepting user input. For now, I'm happy with the blocking delay strategy.

After I was satisfied with construction, I started labeling the enclosure. I want to tip my hat to Onno Hoekstra on this one, as his webpage and some email correspondence helped me realize how good clear labels look when outlined and applied to aluminum enclosures. I'm using a DYMO LetraTag LT-100T Plus label maker and clear tape. It's important to enable the black outline around the text, then I cut carefully slightly outside the outline with regular scissors, and apply the labels with a hobby knife or razor blade.

The morning I delivered the product and added the final proprietary connector which I didn't have at home. It's an inelegant knot-retained configuration, but I think it'll get the job done! It was a surprisingly rare, fully shielded, keyhole-shaped touchproof connector apparently used only in medical applications. At this point, I'm thinking this connector was chosen to (A) protect the user from accidentally shorting a 28V 8A power source (that's over 200 watts!), (B) to prevent you from damaging the equipment by plugging in something that doesn't belong (could you imagine what would happen if this -28V high current source had a BNC connector and you plugged this into something expecting a 5V TTL input?), and (C) prevent you from plugging in anything that wasn't made by this company. The last option is most likely a well-intentioned attempt by the manufacturer to prevent customers from damaging their product rather than the company trying to maintain its status as a sole distributor of accessories, but it makes me wonder. I would have preferred power pole sockets, molded power connectors like those on motherboards, or even barrel connectors! Surely there's a more standard touchproof connector for moderate voltage/currents than this bizarre keyhole connector.

I plugged the device in to the computer, attached the laser, and it worked immediately! I wasn't really surprised that it worked (I tested it extensively at home), but it still felt good to watch the blue laser trigger as it was supposed to. Another interesting one-off project is complete, and have some interesting photos and notes about the build to share on this website. I hope this little device continues to do its job well for many years in its new laboratory home.

Microcontroller Code

#define F_CPU 11059200UL
#include <avr/io.h>
#include <util/delay.h>

int main (void){
    DDRB=(1<<PB0); // set port B pin 0 as an output
    PORTB=0;       // pull all pins low
    while(1){
        while((PINB&(1<<PB2))==0){} // do nothing while the input is low
        PORTB=(1<<PB0);   // TTL ON
        _delay_ms(20);    // stay on for 20ms
        PORTB&=~(1<<PB0); // TTL OFF
        _delay_ms(46);    // stay off for 46ms
    }
}

Here's the batch script I used to compile and load the code onto the microcontroller. I compiled the code with AVR-GCC and copied it onto the microcontroller with a Bus Pirate. Note also that I'm setting the fuses to respect an external oscillator.

@echo off
del *.elf
del *.hex
avr-gcc -mmcu=attiny85 -Wall -Os -o main.elf main.c
avr-objcopy -j .text -j .data -O ihex main.elf main.hex
avrdude -c buspirate -p attiny85 -P com3 -e -U flash:w:main.hex
avrdude -c buspirate -p attiny85 -P com3 -U lfuse:w:0xff:m -U hfuse:w:0xdf:m -U efuse:w:0xff:m
pause

Final Design

Update: Improve Current Handling

After a few days I got an email from someone concerned about the current handling capability of the front-end of the circuit. It was noted that a standard 1/4 watt resistor may not be suitable for R1, as a 28V potential would stress it beyond its specs. With 28V applied, R1 (a quarter-watt resistor) would experience P=IE=28mA*28V=784mW of current! It might last (especially if pulsed), but it also might fail with time. The advantage of the R1/D1/R2 system is that the output current will be identical across a wide range of input voltages. The disadvantage is that it's hard to predict how much current R1 needs to be expected to tolerate. I could have placed five 4.7k resistors in parallel to replace R1 (this would let me handle over 1 watt of input power), but I instead simply upped it from 1kOhm to 10kOhm. This further reduced the current that the opto-isolator sees (now only about 0.2 mA) but it seems to work still. I'm satisfied with this modification, but a little disappointed I didn't catch it sooner. Note that the new input resistor (a 10k R1) should now only have to dissipate about 80mW, well within its specs.

Update: H11B1 minimum current and AC noise

What is the minimum current required to confidently activate the optoisolator? I considered that a 10K input resistor on 28V would only allow 2.8 mA to pass, and I was unsure if this would reliably activate the optocoupler. Considering only 3.3V will persist after the zener (a ~11.7% current retaining ratio, if that's valid), I figured that a best 330µA were passing through the opto-isolator. That seems outside of the specs of the device, because their datasheet graphs always start at 1mA. I decided to run some tests at my home to see how this device performed with lower input currents. I determined that a 10k resistor still works with 5V (500 µA into the device), but checking the output on the oscilloscope I realized that the device operates only partially, and slowly at that low voltage/current. The darlington transistor configuration is very high gain, which is the only reason this works at all, but such low currents are sensitive to parasitic capacitance and infiltrating RF currents. Because of this it seems the chip takes a few ms to activate and deactivate. Since this application only uses 5s on and 5s off inputs, it's fine for this application, but I wouldn't expect high speed pulsing of the input signal to work well. Furthermore, in my breadboard I realized I was getting funny output currents oscillating around 60Hz, which made me suspicious that the device was picking up AC somehow. I realized it was from pin 6 (the exposed darlington base). Normally the LED is so strong is blasts the device fully on or off, but hovering on the edge like this, that pin is picking up signals that influence the open state of the transistor inside. Since it's not connected to anything anyway, I cut the pin off as close to the microchip as I could, and noticed an instant improvement in 60Hz rejection. In conclusion, I wouldn't try to reliably drive an opto-isolator with a complex pattern using less than 1 mA, but it seems to work well for simple on/off control.

This is the output of the unmodified H11B1:

This is the output of the H11B1 with the base pin removed:

Conclusion: This was an interesting build! I'm satisfied with the use of optical isolation here to adapt two incompatible systems with unknown/unspecified input/output properties, and the lack of electrical connections between the inputs and outputs gave me high confidence to experiment along the way.

Markdown source code last modified on May 4th, 2021
---
title: Opto-Isolated Laser Controller Build
date: 2016-07-28 02:33:12
tags: microcontroller, circuit, old
---

# Opto-Isolated Laser Controller Build

**This page documents the design and build of a small device to interface a [modern fiber-coupled DPSS laser](http://www.lasercentury.com/product.asp?id=612) with [old scientific hardware](http://www.coulbourn.com/product_p/h02-08.htm) designed to control mechanical relays.** This project involves analog and digital circuitry, microcontrollers, and lasers, and it turned out to be a pretty cool build so I'm sharing the design and construction process online in case it will be helpful for others or even my future self.

<div class="text-center img-border">

[![](IMG_7304_thumb.jpg)](IMG_7304.jpg)

</div>

**The existing hardware I must interface is made by [Coulbourn Instruments](http://www.coulbourn.com/) and is essentially just a large multi-channel computer-controlled DAC/ADC**. It does its job well (turning lights on and off, recording button presses, etc.), but this new task requires millisecond resolution and modulation patterns which lies outside the specs of this system and software. **My goal is to interface a free output line of this old hardware and use it to signal to a new device I build to activate the laser to produce a pulsed pattern.** This way there would be no modification to any existing equipment, and no software to install. Further, since this hardware isn't mine, I don't like the idea of permanently modifying it (or even risking breaking it by designing something which could damage it by connecting to it). The specific goal is to allow the existing software to cause the laser to fire 20 ms pulses at 15 Hz for a few dozen cycles of 5s on, 5s off. **It's also important to have some flexibility to reprogram the high speed laser stimulation pattern in the future.** Experiments are already underway and I need this device to be complete within a couple of days! As much as I'd love to go to the internet and order the perfect cheap components, make a proper PCB, and have a beautiful build completed in a month, my goal is to build this over a weekend using only using parts I already have at my home.

<div class="text-center img-micro">

[![](hardware-stack_thumb.jpg)](hardware-stack.jpg)
![](hardware-stack2.jpg)
[![](hardware-pci_thumb.jpg)](hardware-pci.jpg)

</div>

**Probing the existing hardware revealed many surprises.** After inspecting the existing hardware setup I found an auxiliary output which could be controlled by software. This AUX port has a [frustratingly rare connector 1mm dual keyhole touchproof connector](http://shop.cephalon.eu/Braebon,-Keyhole-to-two-touchproof-(1,5mm)-connect/ItemDetails.aspx?9=GB&5=0574&11=1531) which I couldn't buy in bulk on eBay or Amazon, and couldn't figure out the part numbers of on Mouser or Digikey. The manual even says "_you may find it convenient to fit them with CI-type connectors_" which makes me wonder why it wasn't designed this way in the first place! Luckily the laboratory had an old (broken) device with that connector on it they said I could use for this build. After plugging in the connector, I used a volt meter to measure the output. To my surprise, it wasn't a [TTL signal](https://en.wikipedia.org/wiki/Transistor%E2%80%93transistor_logic)! I expected to see my volt meter read 5V, but it read 28V! [After consulting the manual](http://www.coulbourn.com/v/vspfiles/assets/manuals/GraphicStateNotation2-101SoftwareUserGuide.pdf) I found mention of this: "_Graphic State Notation software is designed for use with our Habitest animal-behavior-analysis environments or any other animal-behavior-testing apparatus that operates on the industry-standard 28-Volt control voltage._" I was surprised that 28V signals is a standard for any industry. 

**Control voltages are negative!** Elsewhere in the manual I found the phrase "_The power base is capable of delivering 8 Amps of -28 VDC_" which made me question the voltage reading I took earlier. The voltmeter showed 28V, but that's the difference between one keyhole connector output and the other. It became apparent that it really may be 0V (GND) and -28mV (an even more curious "industry standard"). I wondered if connecting the negative terminal to ground would destroy the unit (think about how easy this would be to do! If it were a TTL signal, the first thing you would do is connect the negative terminal to ground and start sampling the positive terminal). There was even talk of me interfacing with a different output port (which I hadn't probed, so I didn't know the voltage). _Moving forward, I realized I had to tread very carefully. Doing something like connecting two grounds together could permanently damage this system!_ 

**Optical isolation should be used as a caution.** Not really knowing if I should design to expect a TTL signal, a +28V signal, or a -28V signal, I decided to design a circuit to accommodate all of the above, while achieving _total electrical discontinuity_ from whatever circuit I develop. I'm going to accomplish this using an [opto-isolator on the input](https://en.wikipedia.org/wiki/Opto-isolator). I drew the schematic using [KiCad](http://kicad-pcb.org/) as I built the board manually using through-hole construction. I considered laying-out a PCB (I have most of these components in SMT form factors too) but I knew I wouldn't manage a one-weekend turnaround if I went that direction.

<div class="text-center">

[![](schematic-4_thumb.jpg)](schematic-4.png)

</div>

### Design Notes

*   The input should be able to accomodate any signal (TTL, CMOS, 28V, etc)
*   The input is _totally_ isolated electrically, so this should be very safe on the hardware
*   The microcontroller is a socketed [ATTiny85](http://www.atmel.com/images/atmel-2586-avr-8-bit-microcontroller-attiny25-attiny45-attiny85_datasheet.pdf) which I programmed with a [Bus Pirate](https://www.swharden.com/wp/2016-07-14-controlling-bus-pirate-with-python/).
*   I decided to rely on a [crystal rather than the internal RC clock](http://www.electroschematics.com/9481/avr-clock-source-fuse-bits/) to improve temporal precision of the output signal. A 11.0592 MHz crystal was chosen because I already had an abundance of them (they're [perfect for serial communication at all common baud rates](http://wormfood.net/avrbaudcalc.php)). Any crystal could be used, as long as its frequency is defined in software.
*   Capacitors were added more to ensure oscillation initiates than to bring down the oscillation frequency. (I'm told that omitting them may cause a case where the crystal doesn't resonate as well, but I've never found this in my personal experience.) A good note on microcontroller clocks is in a [Microchip PIC application note](http://ww1.microchip.com/downloads/en/appnotes/00826a.pdf).
*   I included a "test" button (momentary switch) to simulate having an input signal.
*   Note that R1 must be able to handle the current applied to it. It was mistakenly designed as 1k, and later replaced with 10k. See the bodge note at the bottom of this post for details.

### Potential Improvements

*   Forward protection diodes on the input could protect accidental reverse polarity
*   Adding an [ICSP](http://www.ladyada.net/learn/avr/programming.html) header would prevent de-socketing of the MCU if reprogramming is desired
*   The BNC output is directly from a MCU pin. A [transistor-buffered](https://en.wikipedia.org/wiki/Buffer_amplifier#Single-transistor_circuits) output design could be considered to deliver higher current for more confident control of the laser input.

**Because there is a possibility that a different output (laser control) pattern may be desired in the future, I considered whether or not I should make the output pattern user-configurable.** Adding buttons, a display, and designing a menu system in software would be a lot of work and it's unclear if a protocol change will ever actually be required, so I concluded that I'm going to build this device to the specific task at hand and extended it later if/when needed. If the end user eventually wants the ability to modulate the pattern on their own, the device they ask for would be a very different one than the one I was tasked to create. Since the current pattern is burned into a microchip, a compromise is that I could have new patterns burned into new microchips, and the end-user could change the chip (as long as it's an infrequent occurrence).

_EDIT: About a year later a modification was indeed required (something like changing 15 Hz to 40 Hz), and the solution was to burn these two patterns into two microchips. Since they're socketed, they're swappable (albiet a limited number of times). This design worked-out well._

**Is a microcontroller/crystal overkill for a system which could be accomplished using an analog circuit?** Generating 20 ms pulses at 15 Hz sounds like an easy task for a [555 timer](https://en.wikipedia.org/wiki/555_timer_IC) without the need for digital circuitry. I considered this for a while, but concluded that the advantage of the MCU (crystal-disciplined time precision) outweighed the convenience of  a purely analog circuit. A 555 timer in [astable / multi-vibrator configuration](http://www.circuitbasics.com/555-timer-basics-astable-mode/) would mostly get the job done, but you would either (1) only allow one output pattern and rely on precision passive components (which I don't have on hand), or (2) allow the end-user to adjust duty/frequency with potentiometers (which would require the output to be quantitatively monitored on an oscilloscope). There's also the issue where RC oscillators can be highly temperature sensitive, so the microcontroller/crystal design seemed like a more robust solution for reliable and defined behavior.

**I started the build** by measuring/marking drill points. I used a Dremel drill press to make the holes, then smoothed them with a deburring tool. I also drilled holes in the base of the enclosure.

<div class="text-center img-small img-border">

[![](IMG_7186_thumb.jpg)](IMG_7186.jpg)
[![](IMG_7188_thumb.jpg)](IMG_7188.jpg)
[![](IMG_7191_thumb.jpg)](IMG_7191.jpg)
[![](IMG_7192_thumb.jpg)](IMG_7192.jpg)
[![](IMG_7203_thumb.jpg)](IMG_7203.jpg)

</div>

**I had an enclosure ready to go.** I always buy enclosures in bulk, and even though nice ones tend to be expensive, having them on hand encourages me to build devices as I think of them, rather than making flaky hardware which I [have a history of doing](https://www.swharden.com/wp/2011-01-16-first-homebrew-qso-ever/) which sometimes [borders on ridiculousness](https://www.swharden.com/wp/2010-06-03-aj4vd-qrss-vd-mept/). I usually stock [unfinished Hammond diecast aluminum enclosures](http://www.alliedelec.com/hammond-manufacturing-1590g/70165610/) for making quick RF projects, and [boxes with feet and side vents](https://www.amazon.com/s/ref=nb_sb_noss?url=search-alias%3Daps&field-keywords=aluminum+electronic+project+enclosure+box) for fancier projects, but for this task I decided to enclose everything inside a typical (but a little more costly) aluminum enclosure ordered in bulk from eBay. I love using low current LEDs, and I started going with frosted instead of clear LEDs because they're easier on the eyes. Also, I switched to mostly 3mm LEDs instead of 5MM because they look a little nicer in these small enclosures with small black bezels.

<div class="text-center img-small img-border">

[![](IMG_7191_thumb.jpg)](IMG_7191.jpg)
[![](IMG_7206_thumb.jpg)](IMG_7206.jpg)
[![](IMG_7204_thumb.jpg)](IMG_7204.jpg)
[![](IMG_7208_thumb.jpg)](IMG_7208.jpg)

</div>

**I used nicer perfboard with plated holes to build this circuit.** Normally I use [cheap perfboard](https://www.circuitspecialists.com/solderable-perf-boards) with little copper rings glued to one side because it's faster to solder (the copper is so thin it heats quickly), but it's not always a good long-term solution because the copper pads have a tendency to un-stick. I rarely use this nicer perfboard (it is more expensive), but it's nice to have for more reliable builds.

<div class="text-center img-small img-border">

[![](IMG_7258_thumb.jpg)](IMG_7258.jpg)
[![](IMG_7215_thumb.jpg)](IMG_7215.jpg)
[![](IMG_7216_thumb.jpg)](IMG_7216.jpg)
[![](IMG_7252_thumb.jpg)](IMG_7252.jpg)
[![](IMG_7259_thumb.jpg)](IMG_7259.jpg)

</div>

**I marked areas of optical isolation with a black marker.** This makes it obvious where the potentially dangerous, potentially high-voltage (well, higher than TTL), potentially negative input comes in. No wires or connections should invade this space on the board. The special connector which will connect this device to the scientific hardware is on-site, and I'll have to solder it at the time of delivery/installation. I left an extra hole in the back to accommodate this wire. I didn't have any [rubber grommets](http://www.ebay.com/sch/i.html?_from=R40&_trksid=p2050601.m570.l1313.TR0.TRC0.H0.Xrubber+grommets.TRS0&_nkw=rubber+grommets&_sacat=0), but I suspect this build may have benefitted from one.

<div class="text-center img-border">

[![](IMG_7232_thumb.jpg)](IMG_7232.jpg)

</div>

**Once it was all together, the device seemed to perform well.** The test button on the back made it easy to inspect the output. I build so many RF circuits that I instinctively reached for a 50-ohm terminator, but the square wave quickly transformed into shark fins (RC curves) reminding me that and I realized 50 ohms is far too low impedance. If it's a TTL signal, let's assume it's virtually infinite impedance. I was uncertain whether or not I should drive the output directly with a microcontroller pin. There may be a need for a buffered output. The microcontroller's datasheet suggests limiting its current to 20 mA per pin (requiring termination of no less than 250 Ohms at 5V), and I'm going to move forward assuming the laser TTL input doesn't sink much current.

<div class="text-center img-border img-medium">

[![](IMG_7284_thumb.jpg)](IMG_7284.jpg)
[![](scope_thumb.jpg)](scope.jpg)

</div>

**How should TTL timing be controlled in software?** I want this device to perform identically over long periods of time, favoring reliability and consistency over microsecond time precision. To achieve 15 Hz of 20ms pulses I need 20ms on and 46.666667 ms off. I could probably get pretty close if I wanted to, but I rounded it to 20 ms on and 46 ms off. This gives time for the instruction cycles toggling the output pins to occur (although it's on an order of magnitude faster time scale), which slightly biases the time in the right direction. I considered adding a _delay_us(666) after the _delay_ms(46) but I'm satisfied with it this knowing it's within 1% accuracy of 15 Hz and that precision is locked to that of the crystal (around 10 ppm, or 0.001%).

**Hard-coded \_delay\_ms() is somewhat inelegant.** The use of [AVR timers](http://www.atmel.com/Images/Atmel-2505-Setup-and-Use-of-AVR-Timers_ApplicationNote_AVR130.pdf) should probably be considered as an alternative strategy. Here's an [awesome guide on the topic](http://maxembedded.com/2011/06/introduction-to-avr-timers/), and [here's another](http://www.avrfreaks.net/forum/tut-c-newbies-guide-avr-timers?page=all). Timers would be preferred if I wanted the program code of the microcontroller to be free to do other things like drive menus or multiplex a display. Since this task is simply required generation of a TTL output pattern (and nothing more), the hard-coded delay method met this need, but I found it useful to consider the asynchronous strategies:

*   **Timers**: [Set the timer](http://eleccelerator.com/avr-timer-calculator/) to overflow every 1 ms. On overflow, a counting variable would be incremented and a function would be called to determine what to do. At pre-programmed time points (with respect to the counting variable), the output pin would be toggled, or the counting variable would be reset.

*   **Output compare registers:** Utilize the built-in OCR (output compare register) to turn the output signal on and off. [Set the timer](http://eleccelerator.com/avr-timer-calculator/) to overflow at 15 Hz, turning the output on. Set the OCR (to the fractional point between 0 and the maximum timer value) such that when it is passed, the output is turned off. This way 15 Hz, 20 ms pulses _would be continuously running without any code being executed_. Input sensing could simply enable and disable the timer.

*   **Input interrupts:** Why stop at timers? Polling the input pin for a TTL signal puts the chip in an infinite loop. Relying on the AVR's external (pin change) hardware interrupts could eliminate this as well. I always [rely heavily on the datasheet](http://www.atmel.com/images/atmel-2586-avr-8-bit-microcontroller-attiny25-attiny45-attiny85_datasheet.pdf) when setting these interrupts.

**These alternative implementations will be useful in the future** if a more accurate time source is desired, an advanced display is added, or menus are implemented which would benefit from letting the pulsing output operate in the background while accepting user input. For now, I'm happy with the blocking delay strategy.

<div class="text-center img-border img-small">

[![](IMG_7265_thumb.jpg)](IMG_7265.jpg)
[![](IMG_7262_thumb.jpg)](IMG_7262.jpg)
[![](IMG_7301_thumb.jpg)](IMG_7301.jpg)
[![](IMG_7300_thumb.jpg)](IMG_7300.jpg)

</div>

**After I was satisfied with construction, I started labeling the enclosure.** I want to tip my hat to [Onno Hoekstra](http://www.qsl.net/pa2ohh/) on this one, as [his webpage](http://www.qsl.net/pa2ohh/tlabels.htm) and some email correspondence helped me realize how good clear labels look when outlined and applied to aluminum enclosures. I'm using a [DYMO LetraTag LT-100T Plus](https://www.amazon.com/DYMO-LetraTag-Personal-Hand-Held-1733013/dp/B001B1FIW2/) label maker and [clear tape](https://www.amazon.com/DYMO-Labeling-LetraTag-Labelers-Black/dp/B00006B8FA). It's important to enable the black outline around the text, then I cut carefully slightly outside the outline with regular scissors, and apply the labels with a hobby knife or razor blade.

<div class="text-center img-border img-small">

[![](IMG_7310_thumb.jpg)](IMG_7310.jpg)
[![](IMG_7308_thumb.jpg)](IMG_7308.jpg)
[![](IMG_7307_thumb.jpg)](IMG_7307.jpg)
[![](IMG_7305_thumb.jpg)](IMG_7305.jpg)

</div>

**The morning I delivered the product** and added the final proprietary connector which I didn't have at home. It's an inelegant knot-retained configuration, but I think it'll get the job done! It was a [surprisingly rare, fully shielded, keyhole-shaped touchproof connector](http://shop.cephalon.eu/Braebon,-Keyhole-to-two-touchproof-(1,5mm)-connect/ItemDetails.aspx?9=GB&5=0574&11=1531) apparently used only in medical applications. At this point, I'm thinking this connector was chosen to (A) protect the user from accidentally shorting a 28V 8A power source (that's over 200 watts!), (B) to prevent you from damaging the equipment by plugging in something that doesn't belong (could you imagine what would happen if this -28V high current source had a BNC connector and you plugged this into something expecting a 5V TTL input?), and (C) prevent you from plugging in anything that wasn't made by this company. The last option is most likely a well-intentioned attempt by the manufacturer to prevent customers from damaging their product rather than the company trying to maintain its status as a sole distributor of accessories, but it makes me wonder. I would have preferred power pole sockets, molded power connectors like those on motherboards, or even barrel connectors! Surely there's a more standard touchproof connector for moderate voltage/currents than this bizarre keyhole connector.

**I plugged the device in to the computer, attached the laser, and it worked immediately!** I wasn't really surprised that it worked (I tested it extensively at home), but it still felt good to watch the blue laser trigger as it was supposed to. Another interesting one-off project is complete, and have some interesting photos and notes about the build to share on this website. I hope this little device continues to do its job well for many years in its new laboratory home.

<div class="text-center img-border">

[![](IMG_7316_thumb.jpg)](IMG_7316.jpg)

</div>

### Microcontroller Code

```c
#define F_CPU 11059200UL
#include <avr/io.h>
#include <util/delay.h>

int main (void){
    DDRB=(1<<PB0); // set port B pin 0 as an output
    PORTB=0;       // pull all pins low
    while(1){
        while((PINB&(1<<PB2))==0){} // do nothing while the input is low
        PORTB=(1<<PB0);   // TTL ON
        _delay_ms(20);    // stay on for 20ms
        PORTB&=~(1<<PB0); // TTL OFF
        _delay_ms(46);    // stay off for 46ms
    }
}
```

**Here's the batch script I used to compile and load the code onto the microcontroller.** I compiled the code with AVR-GCC and copied it onto the microcontroller with a [Bus Pirate](https://www.swharden.com/wp/2016-07-14-controlling-bus-pirate-with-python/). Note also that I'm [setting the fuses to respect an external oscillator](http://www.engbedded.com/fusecalc/).

```bash
@echo off
del *.elf
del *.hex
avr-gcc -mmcu=attiny85 -Wall -Os -o main.elf main.c
avr-objcopy -j .text -j .data -O ihex main.elf main.hex
avrdude -c buspirate -p attiny85 -P com3 -e -U flash:w:main.hex
avrdude -c buspirate -p attiny85 -P com3 -U lfuse:w:0xff:m -U hfuse:w:0xdf:m -U efuse:w:0xff:m
pause
```

### Final Design

<div class="text-center img-border">

[![](IMG_7304_thumb.jpg)](IMG_7304.jpg)

</div>

### Update: Improve Current Handling

**After a few days I got an email from someone concerned about the current handling capability of the front-end of the circuit.** It was noted that a standard 1/4 watt resistor may not be suitable for R1, as a 28V potential would stress it beyond its specs. With 28V applied, R1 (a quarter-watt resistor) would experience P=IE=28mA*28V=784mW of current! It might last (especially if pulsed), but it also might fail with time. The advantage of the R1/D1/R2 system is that the output current will be identical across a wide range of input voltages. The disadvantage is that it's hard to predict how much current R1 needs to be expected to tolerate. I could have placed five 4.7k resistors in parallel to replace R1 (this would let me handle over 1 watt of input power), but I instead simply upped it from 1kOhm to 10kOhm. This further reduced the current that the opto-isolator sees (now only about 0.2 mA) but it seems to work still. I'm satisfied with this modification, but a little disappointed I didn't catch it sooner. Note that the new input resistor (a 10k R1) should now only have to dissipate about 80mW, well within its specs.

<div class="text-center img-border">

[![](IMG_7368_thumb.jpg)](IMG_7368.jpg)

</div>

### Update: H11B1 minimum current and AC noise

**What is the minimum current required to confidently activate the optoisolator?** I considered that a 10K input resistor on 28V would only allow 2.8 mA to pass, and I was unsure if this would reliably activate the optocoupler. Considering only 3.3V will persist after the zener (a ~11.7% current retaining ratio, if that's valid), I figured that a best 330µA were passing through the opto-isolator. That seems outside of the specs of the device, because their datasheet graphs always start at 1mA. I decided to run some tests at my home to see how this device performed with lower input currents. I determined that a 10k resistor still works with 5V (500 µA into the device), but checking the output on the oscilloscope I realized that the device operates only partially, and slowly at that low voltage/current. The darlington transistor configuration is very high gain, which is the only reason this works at all, but such low currents are sensitive to parasitic capacitance and infiltrating RF currents. Because of this it seems the chip takes a few ms to activate and deactivate. Since this application only uses 5s on and 5s off inputs, it's fine for this application, but I wouldn't expect high speed pulsing of the input signal to work well. Furthermore, in my breadboard I realized I was getting funny output currents oscillating around 60Hz, which made me suspicious that the device was picking up AC somehow. I realized it was from pin 6 (the exposed darlington base). Normally the LED is so strong is blasts the device fully on or off, but hovering on the edge like this, that pin is picking up signals that influence the open state of the transistor inside. Since it's not connected to anything anyway, I cut the pin off as close to the microchip as I could, and noticed an instant improvement in 60Hz rejection. In conclusion, I wouldn't try to reliably drive an opto-isolator with a complex pattern using less than 1 mA, but it seems to work well for simple on/off control.

This is the output of the unmodified H11B1:

<div class="text-center img-border img-small">

[![](IMG_7495_thumb.jpg)](IMG_7495.jpg)
![](SDS00008.bmp)

</div>

This is the output of the H11B1 with the base pin removed:

<div class="text-center img-border img-small">

[![](IMG_7497_thumb.jpg)](IMG_7497.jpg)
![](SDS00010.bmp)

</div>

**Conclusion:** This was an interesting build! I'm satisfied with the use of optical isolation here to adapt two incompatible systems with unknown/unspecified input/output properties, and the lack of electrical connections between the inputs and outputs gave me high confidence to experiment along the way.
July 14th, 2016

Controlling Bus Pirate with Python

After using the AVR-ISP mkII for years (actually the cheap eBay knock-offs) to program ATMEL AVR microcontrollers, today I gave the Bus Pirate a shot. Far more than just a microcontroller programmer, this little board is basically a serial interface to basic microcontroller peripherals. In a nutshell, you plug it in via USB and it looks like a serial port which has a command-line interface that lets you do things like turn pins on and off, perform voltage measurements, and it naively supports bidirectional use of common protocols like I2C, SPI, UART, and even HD44780 series LCDs. Note that although you could directly interface with the Bus Pirate using HyperTerminal, I recommend using TeraTerm. It can supply voltages (3.3V and 5V) to power small circuits, and if current draw is too high (indicating something is hooked-up wrong) it automatically turns the supply off. So clever! At <$30, it's a cool tool to have around. In addition, it's naively supported as an AVR programmer by AVRDUDE. Although I could write assembly to perform tasks, I almost always write in C for the convenience. For my reference (and that of anyone who may want to do something similar), I'm posting the simplest-case method I use to program AVR microcontrollers with the Bus Pirate on Windows (noting that Linux would be nearly identical). I also wrote a Python script to connect with the Bus Pirate and run simple commands (which turns the power supply on and report the voltage of the VCC line immediately after programming completes). Yes, there are fancy packages that allow you to interact with Bus Pirate from Python, but the advantage of my method is that it runs from native Python libraries! To get this all up and running for yourself, just install WinAVR (which supplies AVRDUDE and AVR-GCC) and Python 3. I assume this code will work just as well on Python 2, but haven't tried.

To ensure my Bus Pirate is working properly, I start off by running the Bus Pirate's built-in test routine. For full details read the guide. It just involves connecting two pairs of pins together as shown in the picture here, connecting to the Bus Pirate with the serial terminal, and running the command "~". It will output all sorts of useful information. Once I know my hardware is up and running, I'm good to continue.

Here's the code which runs on the microcontroller to twiddle all the pins (saved as main.c). Note that my MCU is an ATTiny85. I'm using standard clock settings (internal RC clock, 8MHz), but if I wanted to modify fuses to do things like use an external clock source or crystal, I'd calculate them with engbedded's handy dandy fuse calculator (which also shows AVRdude arguments needed to make the change!).

#define F_CPU (8000000UL)
#include <avr/io.h>
#include <util/delay.h>

int main (void)
{
    DDRB = 255;
    while(1)
    {
        PORTB ^= 255;
        _delay_ms(500);
    }
}

To compile the code and program the MCU with it, I always have a bash script in the same folder that I can double-click on to delete old compiled files (so we don't accidentally re-program our MCU with old code), compile main.c, and load it onto the MCU using the Bus Pirate. You may have to change COM3 to reflect the com port of your Bus Pirate. Note that it is required that you disconnect other terminals from the Bus Pirate before doing this, otherwise you'll get an "access denied" error.

@echo off
del *.elf
del *.hex
avr-gcc -mmcu=attiny85 -Wall -Os -o main.elf main.c
avr-objcopy -j .text -j .data -O ihex main.elf main.hex
avrdude -c buspirate -p attiny85 -P com3 -e -U flash:w:main.hex
python up.py

Although the programmer briefly supplies my MCU with power from the +5V pin, it's cut after programming completes. Rather than manually re-opening my terminal program, re-connecting with the bus pirate, re-setting the mode (command "m") to something random (DIO, command "9"), and re-enableing voltage output (command "W") just to see my LED blink, I want all that to be automated. Thanks python for making this easy. The last line calls "up.py". This fancy script even outputs the voltage of the VCC line after it's turned on!

Python3 Control of Bus Pirate

import serial

BUSPIRATE_PORT = 'com3' #customize this! Find it in device manager.

def send(ser,cmd):
    """send the command and listen to the response."""
    ser.write(str(cmd+'\n').encode('ascii')) # send our command
    for line in ser.readlines(): # while there's a response
        print(line.decode('utf-8').strip()) # show it

ser=serial.Serial(BUSPIRATE_PORT, 115200, timeout=1) # is com free?
assert ser.isOpen() #throw an exception if we aren't connected
send(ser,'#') # reset bus pirate (slow, maybe not needed)
send(ser,'m') # change mode (goal is to get away from HiZ)
send(ser,'9') # mode 9 is DIO
send(ser,'W') # turn power supply to ON. Lowercase w for OFF.
send(ser,'v') # show current voltages
ser.close() # disconnect so we can access it from another app
print("disconnected!") # let the user know we're done.

When "burn.cmd" is run, the code is compiled and loaded, the power supply is turned on (and killed if too much current is drawn!), and the voltage on VCC is reported. The output is:

C:\Users\scott\Documents\important\AVR\2016-07-13 ATTiny85 LEDblink>burn.cmd

Detecting BusPirate...
**
**  Bus Pirate v3a
**  Firmware v5.10 (r559)  Bootloader v4.4
**  DEVID:0x0447 REVID:0x3046 (24FJ64GA002 B8)
**  http://dangerousprototypes.com
**
BusPirate: using BINARY mode
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.12s

avrdude: Device signature = 0x1e930b
avrdude: erasing chip
avrdude: reading input file "main.hex"
avrdude: input file main.hex auto detected as Intel Hex
avrdude: writing flash (84 bytes):

Writing | ################################################## | 100% 3.12s

avrdude: 84 bytes of flash written
avrdude: verifying flash memory against main.hex:
avrdude: load data flash data from input file main.hex:
avrdude: input file main.hex auto detected as Intel Hex
avrdude: input file main.hex contains 84 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 2.72s

avrdude: verifying ...
avrdude: 84 bytes of flash verified

avrdude: safemode: Fuses OK

avrdude done.  Thank you.
#
RESET

Bus Pirate v3a
Firmware v5.10 (r559)  Bootloader v4.4
DEVID:0x0447 REVID:0x3046 (24FJ64GA002 B8)
http://dangerousprototypes.com

HiZ>
m
1. HiZ
2. 1-WIRE
3. UART
4. I2C
5. SPI
6. 2WIRE
7. 3WIRE
8. LCD
9. DIO
x. exit(without change)

(1)>
9
Ready
DIO>
W
Power supplies ON
DIO>
v
Pinstates:
1.(BR)  2.(RD)  3.(OR)  4.(YW)  5.(GN)  6.(BL)  7.(PU)  8.(GR)  9.(WT)  0.(Blk)
GND     3.3V    5.0V    ADC     VPU     AUX     CLK     MOSI    CS      MISO
P       P       P       I       I       I       I       I       I       I
GND     3.17V   5.00V   0.00V   0.00V   L       L       L       H       L
DIO>
disconnected!

This is a minimal-case scenario, but can be obviously expanded to perform some complicated tasks! For example, all commands could be run from a single python program. Considering the Bus Pirate's ability to communicate with so many different protocols (I2C, 2-write, etc.), being able to naively control it from Python without having to install special additional libraries will certainly prove to be convenient.

PS: I noted there is a surprising delay when initializing programming the AVR with the bus pirate. The process hangs for about 10 seconds after the bus pirate introduces itself with the welcome message, then seems to resume at full speed writing to the flash of the microchip. After a bit of Googling, I believe the delay is due to the Bus Pirate slowly bit-banging SPI to initialize the programming sequence. The AVR has rich SPI functionality, some of which involves its own programming. Satisfied with this answer for now, I'm not going to try to speed it up. It's a little annoying, but not too bad that I won't use this to program my AVRs.

Markdown source code last modified on January 18th, 2021
---
title: Controlling Bus Pirate with Python
date: 2016-07-14 00:15:31
tags: microcontroller, circuit, old
---

# Controlling Bus Pirate with Python

__After using the [AVR-ISP mkII](http://www.atmel.com/Images/Atmel-42093-AVR-ISP-mkII_UserGuide.pdf) for years (actually the [cheap eBay knock-offs](http://www.ebay.com/sch/i.html?_nkw=avr+isp+mkii)) to program [ATMEL AVR microcontrollers](https://en.wikipedia.org/wiki/Atmel_AVR), today I gave the [Bus Pirate ](http://dangerousprototypes.com/docs/Bus_Pirate)a shot.__ Far more than just a microcontroller programmer, this little board is basically a serial interface to basic microcontroller peripherals. In a nutshell, you plug it in via USB and it looks like a serial port which has a command-line interface that lets you do things like turn pins on and off, perform voltage measurements, and it naively supports bidirectional use of common protocols like I2C, SPI, UART, and even HD44780 series LCDs. Note that although you could directly interface with the Bus Pirate using HyperTerminal, I recommend using [TeraTerm](https://ttssh2.osdn.jp/index.html.en). It can supply voltages (3.3V and 5V) to power small circuits, and if current draw is too high (indicating something is hooked-up wrong) it automatically turns the supply off. So clever! At <$30, it's a cool tool to have around. In addition, it's naively supported as an AVR programmer by [AVRDUDE](http://www.nongnu.org/avrdude/). Although I could write assembly to perform tasks, I almost always write in C for the convenience. For my reference (and that of anyone who may want to do something similar), I'm posting the simplest-case method I use to program AVR microcontrollers with the Bus Pirate on Windows (noting that Linux would be nearly identical). ___I also wrote a Python script to connect with the Bus Pirate and run simple commands___ (which turns the power supply on and report the voltage of the VCC line immediately after programming completes).  Yes, there are [fancy packages](http://dangerousprototypes.com/docs/Bus_Pirate_Scripting_in_Python) that allow you to interact with Bus Pirate from Python, but ___the advantage of my method is that it runs from native Python libraries! ___To get this all up and running for yourself, just install [WinAVR ](http://winavr.sourceforge.net/)(which supplies AVRDUDE and AVR-GCC) and Python 3. I assume this code will work just as well on Python 2, but haven't tried.

<div class="text-center img-border">

[![](IMG_7092-1_thumb.jpg)](IMG_7092-1.jpg)

</div>

__To ensure my Bus Pirate is working properly, I start off by running the Bus Pirate's built-in test routine.__ For full details read the [guide](http://dangerousprototypes.com/docs/Bus_Pirate_self-test_guide). It just involves connecting two pairs of pins together as shown in the picture here, connecting to the Bus Pirate with the serial terminal, and running the command "~". It will output all sorts of useful information. Once I know my hardware is up and running, I'm good to continue.

<div class="text-center">

[![](Bpv3v2go-pinout_thumb.jpg)](Bpv3v2go-pinout.png)

</div>

__Here's the code which runs on the microcontroller to twiddle all the pins (saved as main.c).__ Note that my MCU is an [ATTiny85](http://www.atmel.com/images/atmel-2586-avr-8-bit-microcontroller-attiny25-attiny45-attiny85_datasheet.pdf). I'm using standard clock settings (internal RC clock, 8MHz), but if I wanted to modify fuses to do things like use an external clock source or crystal, I'd calculate them with [engbedded's handy dandy fuse calculator](http://www.engbedded.com/fusecalc/) (which also shows AVRdude arguments needed to make the change!).

```c
#define F_CPU (8000000UL)
#include <avr/io.h>
#include <util/delay.h>

int main (void)
{
    DDRB = 255;
    while(1)
    {
        PORTB ^= 255;
        _delay_ms(500);
    }
}
```

__To compile the code and program the MCU with it__, I always have a bash script in the same folder that I can double-click on to delete old compiled files (so we don't accidentally re-program our MCU with old code), compile main.c, and load it onto the MCU using the Bus Pirate. You may have to change COM3 to reflect the com port of your Bus Pirate. Note that it is required that you disconnect other terminals from the Bus Pirate before doing this, otherwise you'll get an "access denied" error.

```bash
@echo off
del *.elf
del *.hex
avr-gcc -mmcu=attiny85 -Wall -Os -o main.elf main.c
avr-objcopy -j .text -j .data -O ihex main.elf main.hex
avrdude -c buspirate -p attiny85 -P com3 -e -U flash:w:main.hex
python up.py
```

Although the programmer briefly supplies my MCU with power from the +5V pin, it's cut after programming completes. Rather than manually re-opening my terminal program, re-connecting with the bus pirate, re-setting the mode (command "m") to something random (DIO, command "9"), and re-enableing voltage output (command "W") just to see my LED blink, I want all that to be automated. Thanks python for making this easy. The last line calls "up.py". This fancy script even outputs the voltage of the VCC line after it's turned on!

### Python3 Control of Bus Pirate

```python
import serial

BUSPIRATE_PORT = 'com3' #customize this! Find it in device manager.

def send(ser,cmd):
    """send the command and listen to the response."""
    ser.write(str(cmd+'\n').encode('ascii')) # send our command
    for line in ser.readlines(): # while there's a response
        print(line.decode('utf-8').strip()) # show it

ser=serial.Serial(BUSPIRATE_PORT, 115200, timeout=1) # is com free?
assert ser.isOpen() #throw an exception if we aren't connected
send(ser,'#') # reset bus pirate (slow, maybe not needed)
send(ser,'m') # change mode (goal is to get away from HiZ)
send(ser,'9') # mode 9 is DIO
send(ser,'W') # turn power supply to ON. Lowercase w for OFF.
send(ser,'v') # show current voltages
ser.close() # disconnect so we can access it from another app
print("disconnected!") # let the user know we're done.

```

When "burn.cmd" is run, the code is compiled and loaded, the power supply is turned on (and killed if too much current is drawn!), and the voltage on VCC is reported. The output is:

```
C:\Users\scott\Documents\important\AVR\2016-07-13 ATTiny85 LEDblink>burn.cmd

Detecting BusPirate...
**
**  Bus Pirate v3a
**  Firmware v5.10 (r559)  Bootloader v4.4
**  DEVID:0x0447 REVID:0x3046 (24FJ64GA002 B8)
**  http://dangerousprototypes.com
**
BusPirate: using BINARY mode
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.12s

avrdude: Device signature = 0x1e930b
avrdude: erasing chip
avrdude: reading input file "main.hex"
avrdude: input file main.hex auto detected as Intel Hex
avrdude: writing flash (84 bytes):

Writing | ################################################## | 100% 3.12s

avrdude: 84 bytes of flash written
avrdude: verifying flash memory against main.hex:
avrdude: load data flash data from input file main.hex:
avrdude: input file main.hex auto detected as Intel Hex
avrdude: input file main.hex contains 84 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 2.72s

avrdude: verifying ...
avrdude: 84 bytes of flash verified

avrdude: safemode: Fuses OK

avrdude done.  Thank you.
```

```
#
RESET

Bus Pirate v3a
Firmware v5.10 (r559)  Bootloader v4.4
DEVID:0x0447 REVID:0x3046 (24FJ64GA002 B8)
http://dangerousprototypes.com

HiZ>
m
1. HiZ
2. 1-WIRE
3. UART
4. I2C
5. SPI
6. 2WIRE
7. 3WIRE
8. LCD
9. DIO
x. exit(without change)

(1)>
9
Ready
DIO>
W
Power supplies ON
DIO>
v
Pinstates:
1.(BR)  2.(RD)  3.(OR)  4.(YW)  5.(GN)  6.(BL)  7.(PU)  8.(GR)  9.(WT)  0.(Blk)
GND     3.3V    5.0V    ADC     VPU     AUX     CLK     MOSI    CS      MISO
P       P       P       I       I       I       I       I       I       I
GND     3.17V   5.00V   0.00V   0.00V   L       L       L       H       L
DIO>
disconnected!
```

__This is a minimal-case scenario, but can be obviously expanded to perform some complicated tasks!__ For example, all commands could be run from a single python program. Considering the Bus Pirate's ability to communicate with so many different protocols (I2C, 2-write, etc.), being able to naively control it from Python without having to install special additional libraries will certainly prove to be convenient.

_PS: I noted there is a surprising delay when initializing programming the AVR with the bus pirate. The process hangs for about 10 seconds after the bus pirate introduces itself with the welcome message, then seems to resume at full speed writing to the flash of the microchip. After a bit of Googling, I believe the delay is due to the Bus Pirate slowly bit-banging SPI to initialize the programming sequence. The AVR has [rich SPI functionality](http://maxembedded.com/2013/11/the-spi-of-the-avr/), some of which involves its own programming. Satisfied with this answer for now, I'm not going to try to speed it up. It's a little annoying, but not too bad that I won't use this to program my AVRs._
Pages