This page is still in progress!

Analog to Digital Conversion

So far, we've been focused solely on analog electronics. Being alive in the 21st century, you've no doubt noticed that there are a whole lot of digital electronic devices around. You can't just jam a wire from your circuit board into a computer and have it transmit data, so we sometimes need a way to map a range of analog values into discrete digitized values. Digital devices also tend to react poorly to being subjected to voltages higher or lower than their design mandates.

You've actually already done a sort of digital conversion! If you think about it, a comparator circuit essentially has a one-bit output, so you've already used them to distinguish between voltages above and below a threshold. We're going to continue the trend throughout today's lab.

Digital Logic Signals:

When working with digital circuits, voltages are essentially mapped to binary values of either High (1) or Low (0).  There are quite a few different standards out there for what voltages are mapped to which, but we'll work with a 5V standard:

  • 5V standard (Used by Transistor Transistor Logic (TTL) and some Complementary Metal Oxide Semiconductor (CMOS))
    • Above 2V is HIGH
    • Below 0.8V is LOW
    • Between 0.8V and 2V is UNDEFINED (Don't do this!)
What about other logic families?

3.3V is the other dominant logic family used by modern devices, but there are other standards for even lower power consumption.  The trade off is that they are much less tolerant of any noise

Image courtesy of a Texas Implements application report

Analog to Unary

To start off, let's not worry about how to encode data into bits, but instead how we can discriminate between a range of values. Consider the circuit on the left below:

Our first step in analog to digital conversion. Note that we'll be using our friend the TL074CN for this for simplicity. You'll want to use your function generator for the 3V connection here.

This is just a series of three comparators, tied to an increasing set of thresholds.

$V_{in}$ $V_{out}$
>3V 111
2V - 3V 011
1V - 2V 001
< 1 V 000

Don't forget to power your op-amps!

Build the circuit and test its behavior. You'll want to use one channel of your function generator on DC mode for the +3V, and the other channel as $V_{in}$. It's probably wise to start testing with DC voltages, or very low frequency sine waves.


This is all well and good for breaking up a range of values coarsely, but what if we want more precision? To divide the same voltage range into 0.5V increments would take the following circuit:

Four more op-amps to double our precision. Ouch! Don't build this!

We've slightly more than doubled the number of comparators needed to double our resolution here. Since getting up to 8 bits would take 255 comparators, this is obviously not something we want to build by hand! Furthermore, we don't want to have to run a cable with that many wires to our computer. You can use some digital logic to condense your outputs, but thankfully there are other options too.

Successive Approximation

What if we were willing to trade a bit of time to make it so we had to use fewer parts? This is the idea behind a Successive Approximation SA approach. The general setup is as follows:

  1. Make a voltage divider that successively halves the reference voltage
    1. e.g. if we have a maximum of 16 volts, make a voltage divider with outputs of 8V, 4V, and 2V
  2. Hook up these outputs to a summing amplifier with switches that can toggle the connections on and off.
  3. Add an inverting amplifier to flip the sign of the output
  4. Feed that signal into one half of a comparator
  5. Feed your analog signal to the other half of a comparator

To start off, we'll build make a set of reference voltages with a voltage divider circuit. You can just use the V+ power for your op-amp for this; it can handle being powered off of 16V just fine.

Note technically we have a 40.2k resistor as straight up 40k's aren't made.

Build the circuit, and test that the reference voltages are what you'd expect. You should use your handheld DMM for this, as the resolution on the scope can make for misleading readings.

Now to build the second stage, a summing amplifier. The schematic is using 1M resistors to try and avoid loading our reference too much, but it will happen a bit. In practice you'd probably want a buffer circuit or a more robust way of generating reference values.

Our summing amplifier circuit, with manual toggles. The switches are labeled for the voltage they control Our slide switches for use in this part of the lab. This will go across the middle channel of the breadboard, and makes connections across the sides when switched to ON.

Add the summing amplifier and test what outputs it can create for different permutations of switches.

Now there's a slight problem here; our output is negated. We'll solve that by slapping in an inverting amplifier

Adding an inverting amplifier with a gain of 1 fixes our sign problem.

Lastly, we can add in an input for us to make a comparison to. We'll use our function generator's DC mode for this. You can also slap an LED in there as a visual indicator.

Our fully functional Successive Approximation circuit. You'd better be quick with the switches if you want to measure an AC value!

Usually, this design would have some logic circuits in it to toggle the switches (or more realistically, switch some transistors). For practice, you will be doing the logic yourself. Begin with all the switches toggled off. You'll start by flipping the first (S8) switch. If the comparator output goes high, it means that the input is less than 8V. In that case, flip the switch off again. Otherwise, repeat the process for each successively lower voltage. When you're done, the state of your switches IS the digital conversion of your input. So if you've got switches S2 and S4 flipped, your input is between 6 and 8 V.

Build the circuit, and test a few different inputs.

Sure, we used three op-amps/comparators. But, we don't need any more to scale up the precision! All we need is to keep splitting our reference voltage into smaller increments, add a few switches, and take more time.


Dedicated ADCs

Nowadays, you can find a ridiculous variety of chips dedicated to converting analog signals to digital ones. At the time of writing this, Digikey has 14,210 parts listed. Some microcontrollers (e.g. an Arduino) have ADCs built into the chip along with the rest of the device, but others (like Raspberry Pis) will need you to supply your own.

On interfaces

One of the first questions you'll need to ask yourself when choosing an ADC is how you want your digital data presented. The versions we built essentially had parallel outputs: all outputs can be measured at the same time. The downside is that you need one wire for each bit, which you'll find can eat up a lot of the input/output pins on a microcontroller. The upside is that it can update quickly.

The other option is some form of serial output: you have a single connection for data from your ADC to your device. Now, you have the downside that your signal is stretched out in time. In practice, you'll usually need to have both a data connection and a clock connection to let the receiving device know when you're sending it a new bit. On the upside, you need only a pair of wires to convey the output.

As a rule of thumb, you should use an ADC with a serial output as the default. Parallel outputs are good for either higher speed readouts or ease of implementation. The latter is because you don't need to do any work with clock interfaces or communication protocols; you can just connect your outputs to a bunch of pins and read the values when you want.


Our ADC: The ADC0804

We've chosen an 8-bit ADC with parallel outputs for this lab. The pin labels and the basic setup of our circuit are shown below:



(top) The ADC's pinout. The nomenclature is a little opaque, but we'll explain below. \\(bottom) Our chip on a breakout board, which makes the Surface Mount Technology(SMT) chip compatible with our breadboards. (top) Our basic analog to digital converter. Don't panic, it isn't as bad as it looks at first. We've set up a module with the resistors and LEDs for you. NC on pin 9 indicates that it shouldn't connect to anything. Modified from the Texas Instruments datasheet.
(bottom) A photo of the LED module. The pins on the left side line up with pins 11-18 of the ADC. The black wire should connect to ground.

There are a few things to note here:

  1. Lots of pins are grounded. Most of them do have functionality, but we just aren't using it right now.
    1. For instance, pin 1 is the Chip Select input, which is basically an on-off switch. The bar over the top means the logic is inverted; ground means the chip is selected.
    2. ReaD updates the digital output pins. Grounding it just makes it so that they're constantly being updated.
  2. The digital outputs (DB0-DB7) run from pins 11 to 18. However, pin 11 is the Most Significant Bit MSB (i.e. it doesn't toggle until halfway though the analog range) and pin 18 is the Least Significant Bit LSB.
    1. This isn't likely to be problematic here, but when working with an ADC with a serial output you'll need to check the order that bits are sent in.
  3. Pins 19 and 4 are used as part of a Schmitt Trigger clock.
    1. This is why we teach you about analog circuits first. They can (and will) show up when working with digital devices.
    2. We manually toggle a pin in order to start a measurement (or WRite the output).
      1. After the ADC has finished measuring, it will change the INTrRrupt from high to low.
      2. Often you'd connect both of these to a microcontroller.
      3. By connecting the two together, we're basically making our chip start a new measurement every time the last one finishes.

Keep you inputs between 0 and 5V. By default, the function generator's sine and square waves oscillate between -2.5 and 2.5 V. You'll need to add a 2.5V offset to make them compatible with your chip.

Build the circuit and test its behavior. Specifically, check that

  • The Schmitt trigger clock is in the 100kHz range,
  • that the outputs change as the input changes, and
  • that holding the start button freezes the output.

You can, of course, use things other than the function generator here, as long as the output is between 0 and 5V. Potentiometers, light-dependent resistors, thermistors, whatever you can hook up.


Not doing this because the Pico 2040 isn't 5V tolerant. Sigh.

Microcontroller Inputs

Now we get to the point of all of this, actually reading the digital values with a device. For this, we're going to use a Raspberry Pi Pico running MicroPython. This isn't a course on coding, so we've got a basic program already in place. If you know Python, you'll be able to dig through what it is doing a bit.

Connect the pins of your Pico to the digital outputs of your ADC as shown below

After connecting the device, plug the Pico's USB cable into the lab computer. Open the Thonny application, and click on the hamburger menu in the lower right corner. Select MicroPython (Generic). Use the menu to open a new file, selecting the This Computer option. Open the Readout.py file that's on the desktop, or download a new copy below. Finally, run the script by pushing the green button (or pushing F5)

FILE DOWNLOAD

With this, the Pico will start printing out what the individual bits are, and then what the Analog equivalent is. Congratulations! You've digitized a signal. You can log it, plot it, whatever your heart desires.