Dangerous DSO design introduction
Dangerous DSO part 1: There’s so much between 0 and 1
Dangerous DSO is a new logic analyzer/oscilloscope prototype we've been using in the lab. It combines a 16 channel logic analyzer and one 50MHz oscilloscope channel with +/-10volt DC range. The combined tool shows what your signal does between 0 and 1, which helps pinpoint noise and other electrical glitches.
Our goal with the D-DSO is to make the simplest possible oscilloscope reference design. It doesn't have range selection or AC coupling, it can't trigger based on analog voltage levels. It's a basic design with the bare minimum needed to capture an analog signal.
This screenshot shows the D-DSO view of a pulse-width modulator square wave. The analog view shows that the signal isn't perfectly square, it bounces around slightly. We haven't compared it to a real scope yet. There's no telling what noise is real, and what comes from our crappy analog design.
A general overview of the design follows the break. Daily articles will cover the ADC, the analog front-end, and simulating the circuit all week.
The Dangerous DSO uses a Xilinx Spartan XC3S250E-TQ144 FPGA. We got really comfortable working with this chip and supporting it on the Logic Sniffer. We could have used the 100pin package, but the pinout on the 144pin version is a lot easier to work with.
The FPGA has a basic support circuit with a 50MHz crystal and various pullup resistors. A 2Mbit flash ROM stores the firmware that the FPGA loads at start-up. We added a button for whatever.
Our favorite PIC 18F24J50 tends to the ROM programming and USB connection. This is one of Microchip's featured 3.3volt chips with extended support. It should have good availability for a long time. The PIC runs Honken's open source USB stack with only a couple issues.
ROM upgrade mode is based around the SUMP protocol. The metadata command 0x04 that returns the hardware description in normal mode also works in update mode. If you try to do a logic capture while the hardware is in update mode the descriptor is different and the client can warn the user. Similarly, the upgrade application understand the normal logic analyzer mode metadata and prompts the user to enter update mode and try again.
The upgrade application has raw access to the ROM chip using Bus Pirate SPI bulk read/write commands. This means new ROM chips can be supported by a software update alone, no firmware changes needed. Bulky chip ID and write algorithms are all in the computer app where they belong.
D-DSO has 16 digital IO channels. 8 are buffered and 5volt tolerant. The buffer is bi-directional, and the FPGA is wired to control the direction and output enable signals.
assign bufferOEOut=1'b0;//OE low for normal outputs<br> assign bufferDirectionOut=1'b0;//direction low for B->A (external to FPGA)
We modified the latest Demon Core Verilog logic analyzer engine to configure the buffer for input and enable it permanently.
//DSO LEDs<br> assign groupLEDs[2:0]=disabledGroups[2:0];<br> assign extClockLEDnn=!extClock_mode;
Each IO group and the DSO input have a LED that lights when they are selected. Group LEDs are controlled by wiring the output pins to the disabled group configuration bits in core.v.
The external clock LED is controlled by the external clock mode bit, also in core.v. We haven't figured out where to connect the external trigger LED, but that's ok because we never use it.
An ADS830 flash ADC measures a voltage and outputs the value on 8 parallel pins. A simple analog front-end with a single opamp gives the ADC a +/-10volts input range.
//DSO clock, range output<br> assign ADCClockOut=!clock;<br> assign ADCRangeOut=1'b1;
The ADC needs a clock, up to 60MHz. We make it simple and wired the ADC clock to the inverse of the system clock. A better method is probably needed.
Amazingly that's the only real change to support the ADC. 8bits from the ADC output pins connect to logic analyzer channel group 3. The FPGA doesn't care what the data is, it just passes it to the client. Luck for us, the client already has support for displaying a channel group as an analog signal.
USB and external power supplies are toggled with a switch. USB supplies are not guaranteed to be 5volts, and the fuse eats a little more too. An external supply is more reliable.
We haven't finished populating the power section, we've only used it with the USB supply.
SUMP clients, even the old ones, already support an oscilloscope mode. Choose scope mode for channel 3 under Diagram->mode settings.
We connected GROUP0 channel 0 and the DSO input to a 50kHz square wave generated by the Bus Pirate. Capture is configured for group 0 and group 3, group 3 is where the ADC data output is attached to the FPGA. Click capture.
There it is, the shades of gray we've been missing, our analog hello world. It's probably a horrible representation of the actual signal, but you gotta start somewhere.
Design files will be available later in the week under a CC BY-SA license. We'll release a patch against the Demon core eventually, but the snippets here give the general idea.
Dangerous DSO part 2: Feed and water your ADC
Analog to digital converters are common on small microcontrollers, they're handy for measuring voltage from a sensor. Top speeds are usually less than 1 million samples per second.
The Dangerous DSO oscilloscope also uses an ADC to measure voltage, but it's much faster. We'd like our ADC to work at the 100-200MSPS maximum rate of the logic analyzer part, but a professional DSO would be even faster.
At high-speeds things start to get complex. High-speed ADCs have a very narrow input range and other specific requirements. Today we'll look at the Dangerous DSO analog to digital converter. Tomorrow we cover our attempt to satiate the beast with an analog front-end.
To get respectable speed from a DSO we need an analog to digital converter with a parallel interface. The ADC measures voltage and puts the reading on 8 output pins. Fresh measurements pop out the ADC_Dx pins every time the clock pin (ADC_CLK) goes high to low.
Dangerous DSO uses a TI ADS830 analog to digital converter with a maximum speed of 60MHz. We run it at 50MHz for testing. The ADS830 is low cost, compared to some, but not exactly cheap.
Logic analyzer channel 3 is connected to the ADC output pins. During capture the FPGA stores the ADC output just like the logic analyzer channels. The SUMP clients already have a scope mode that displays the channel as an analog graph.
ADC input range pains
We're spoiled by microcontroller ADCs. They'll usually measure a voltage between ground and the supply. If your system is 5volts, the ADC will measure from 0volts to 5volts. An 8bit ADC reading of 254 (254/255*5volts) represents ~4.9volts, somewhere near the top of the range.
High-speed ADCs have a very limited measurement range, usually only 1 or 2volts. This is a pain, but easy enough to solve with a resistor divider. The swing is noted as Vp-p in datasheets, the voltage difference between the highest and lowest points of the signal.
The real bummer comes from the center or common mode voltage. Input can only swing one volt, and it has to be centered at 2.5volts. That means the lowest we can measure is 2volts, and the highest is 3volts. We can adjust the top and bottom references, but our ADC is optimized to work best in this range.
2volts to 3volts isn't a very useful measurement range for an oscilloscope. We need an analog front-end that divides the input voltage into the 1Vp-p range the ADC will accept, and then centers it at 2.5volts. This is where black art DSO design happens. It's a safe bet that our design is a dud.
For a 0-10volt DC input range we would need to:
- Divide the input by 10 to get a 1volt range between minimum and maximum values. 0volts/10=0volts, 10volts/10=1volt.
- Lift the input 2 volts so it swings between 2 and 3volts.
Depending on the input range there are a lot of different ways to do this. We'll explain our sucky front-end design and simulate the circuit later this week. Warning, there be op-amps in these woods.
Analog parts of the ADS830 run at 5volts, the digital pins run from a separate 3.3volt supply. There's lots of juicy decoupling capacitors for the various supply pins and references. Not all of them are actually needed, and a few cause problems like the extra 10uF on the CM pin.
Internal references are enabled by grounding the !INT/EXT pin. Each reference (REFT and REFB) pin gets a 2.2uF and 0.1uF decoupling capacitor. REFT is the top or high level reference for the ADC, the internal reference is 3.0volts. REFB is the bottom or low level reference, the internal reference is 2.0volts.
An internal connection between the top and bottom reference create a center reference on the CM pin. The 2volt and 3volt internal references have a 2.5volt center reference.
The ADC has differential inputs that we don't need, so we tied the inverting input to the 2.5volt center reference. Now the non-inverting input can be used like a normal single-ended ADC.
RSEL selects a 1Vp-p or 2Vp-p measurement range. Technically the ADS830 can measure 1.5volts to 3.5volts, but we don't think the internal reference configuration supports that. Rather, now we don't think that. Earlier we did, and we designed the analog front-end around a 2Vp-p range. More about that bug later.
Internally RSEL is pulled-up to 5volts, which would damage the 3.3volt FPGA pins. A small transistor circuit (cut off in the image above) grounds RSEL to enable 1Vp-p operation. This is can probably be tied to ground permanently instead.
The ADS831 is an 80MHz ADC with the same pinout, but it requires a 5volt clock signal. It won't work with the FPGAs 3.3volt output. Even if a faster ADC is used it wouldn't necessarily mean more speed. We haven't figured out how to use the full 60MHz of the current ADC, it's just tied to the inverse of the 50MHz system clock. A true 60/80/100MHz ADC sample rate will require some additional clock trickery.
Dangerous DSO part 3: Messing with the front-end
Lets set a +/-10volts DC input range goal for our feeble first attempt at a DSO. That's a 20volt swing from top to bottom(Vp-p). Input to the DSO will be divided by 20 so it has a 1Vp-p range. Then we need to lift it 2 volts into the 2-3volt measurement range of the ADC. Some gory details below.
The Bitscope logic analyzer/oscilloscope was originally an all through-hole project in Circuit Cellar magazine. A CPLD drives two 32Kx8 SRAM chips that store 8 channels of logic and 8bits from a flash ADC chip. Sound familiar? Top capture speed is 50million samples per second.
Fascination with the Bitscope is the reason Dangerous Prototypes exists today. Our first open source logic analyzers cloned the Bitscope protocol instead of SUMP. We've been building bits and pieces of it for years. In short, a Bitscope clone has been a long term goal. But enough gushing, more thieving.
We dug through the Bitscope design to see how they handled the ADC input. Just the minimum circuit to get a ground-centered voltage into the ADC. The Bitscope ADC buffer is exactly what we need. An op-amp lifts a 1.2Vp-p signal to a range the ADC can use. It's adjustable and works with different ADCs, including a few with the same specs as the ADS830 we're using. It has 1.667 gain by default, but we can deal with that later.
To get 1Vp-p from +/-10volt input, a swing of 20Vp-p, we need to divide the input by 20. We used a 1Mohm trimmer resistor (R12) so we can adjust the input range. 1Mohm places a very small load on the circuit it connects to, but shouldn't change the signal too much. Instrumentation quality isn't a goal, we're just prototyping.
We used a standard probe connector, but a banana plug might be better. Who has o-scope probe cables? Everyone has a multimeter cable, and it's cheaper. C44 and C33 are for filter caps, if we ever get around to trying them.
Now we've got a +/- 10 volt signal divided down to +/-0.5volts. We still need to move it up to the 2-3volt range the ADC measures. Next up, a trip to the op-amp.
There's no easy way around it, this project needs an op-amp. It's gonna be confusing, and probably expensive. Our understanding might even be wrong, don't use this to study for an exam.
An op-amp does two things we so desperately need. It can recenter the input signal from ground to 2.5volts. After the 1Mohm divider the signal is pretty weak, the op-amp adds some kick so it has enough power to drive the ADC.
We used the Bitscope ADC buffer verbatim, but removed the over-voltage protection diodes. The op-amp needs a +/-5volt supply. The negative voltage comes from a TCM828 inverter that just needs a few capacitors. USB isn't always 5volts, it's probably best to use the external power supply if a clean 5volt reference matters.
Input from voltage divider (R12) drives the op-amp's non-inverting input (+). The inverting input (-) connects to an adjustable negative voltage created by R8 and T1. C3,4,5,20 are filters.
An op-amp lives to keep the the voltage on both input pins equal, it tries to do this by changing the output voltage. If the input on the + pin goes up 0.1volts, the op-amp increases the output voltage until the other input (-) goes up 0.1volts too.
R33 and R44 are key. They form a voltage divider between the op-amp output and the - input. We can manipulate this divider to change the output. If the voltage on the - input is half the output, then the output has to increase twice as much to equalize the + and - pins when + changes. 0.1volts increase on the + pin causes a 0.2volts increase in output to compensate on the - pin. This is gain. Or at least how we understand it. The Bitscope circuit has 1.667 gain, but we'll play with that more tomorrow in simulations.
Back to the task at hand, shifting our ground to 2.5volt for the ADC. The adjustable negative supply connected to the inverting input forces the op-amp to shift the output to compensate. The center point can be set by changing the negative supply with R8. We used a single turn pot and it doesn't give nearly enough room for fine adjustment.
Choosing an op-amp
Not just any op-amp will do, it has to be high speed and low distortion. You might notice some flywire rework on the op-amp. We're testing lots of op-amps and they aren't all pin-compatible.
The MAX477 used in the Bitscope design is discontinued. We looked for op-amps in current production with similar values: 300MHz -3dB bandwidth (at 1Vp-p if specified) and 1100V/µs slew rate. There are other factors to consider, but this helps narrow down the candidates.
MAX4450 is a recommended replacement, but the specs aren't as nice (210MHz -3dB bandwidth, 485V/µs slew rate). An SOT-23 version is available at Digikey for $1.20, but we sampled the SOIC version for prototyping.
Summing it up
Now we have an analog front-end. A trimmer resistor divides the input signal down to 1Vp-p. The op-amp re-centers the signal at 2.5volts so we can measure it with the ADC. Both input range and the ground center can be adjusted.
Dangerous DSO part 4: Over simulated
This circuit divides our +/-10volt input to +/-0.5volts, and re-centers it between the 2volt and 3volt range the ADC can measure. Today we'll simulate the circuit to get a better feel for how it works.
LTspice has a crappy schematic editor, second only to the Xilinx Webpack schematic entry program in suckage. Seriously. We managed to enter our front-end design with the default values from the Bitscope schematic.
Remember this diagram. We want to divide the +/-10volt input down to +/-0.5volts, then offset it 2volts.
Right click->run to simulate the design. A pretty graph appears that shows the voltage at various points in the circuit as the DSO input goes from -10volts to +10volts.
Input (green) goes from -10v to +10v. This is a simulation of voltage coming into the scope probe.
After the voltage divider (red) the signal is reduced to -0.5v at -10volts input and +0.5v at +10volts input. Perfect.
Output voltage (blue) shows what the ADC gets from the op-amp. 2v at -10volts, to 3.7v at +10volts. No good! We need to be centered in the 2volt-3volt measurement range of the ADC.
Fixing the gain
What's going on? Gain. Remember from yesterday that the Bitscope ADC buffer stage multiplies the input by 1.667. Gain is determined by R1 and R2 in the simulated circuit.
- To solve for gain set Vin=1 and enter the resistor values
This is exactly what we got, ~1.7Vp-p from our 1Vp-p signal.
We can compensate for the gain by adjusting the input voltage divider. We can also reduce the gain by changing the value of R1 and R2, but we can't reduce it to 1 in the current circuit.
After a lot of experimenting we decided to increase the gain to 2x by setting R1 and R2 to the same value (220 ohms). The zero adjustment got really close to the edge of the pot with any 1.667 gain setup, 2x gain leaves lots of room to play.
A gain of 2 means we have to divide the input by an additional factor of 2. The 20Vp-p input is now divided to +/-0.25volts (0.5Vp-p). The op-amp then amplifies the signal by a factor of two and offsets it to the ADC measurement range. It probably does awful things to the signal, but we don't care at this point.
- 0.975M+0.025M=/40=+/- 10volt input
- 0.950M+0.050M=/20=+/- 5volt input
- 0.900M+0.100M=/10=+/- 2.5volt input
For +/-10volt input we're now using a .975M and .025M resistor divider. Most of the useful divider values are in the bottom 100K of the 1M resistor. It would be a lot easier to control the input range with a 900K fixed resistor and 100K trimmer.
Simulate the new values
This is a simulation of the front-end with the new values.
Input from the DSO probe (green) goes from -10v to +10v. Offset voltage (light blue) measured at R1 is constant at around 2.5v.
After the voltage divider (red) the signal is reduced to -0.25v at -10volts input and +0.25v at +10volts input. Perfect.
Output voltage (blue) from the op-amp is 2v at -10volts, to 3v at +10volts. Perfectly centered in the 2volt-3volt measurement range of the ADC.
Looks great, this will be the basis for tomorrow's test.
There's lots of other ways to handle the voltage offset. A second slow op-amp pair can first buffer, then invert, the 2.5volt common mode voltage from the ADC. That's something to try on a future revision.
Dangerous DSO part 5: Testing and conclusions
It's the last day of our week-long Dangerous DSO adventure. Yesterday we simulated the analog front-end and found a few changes to test. First, we're going to increase the ADC buffer gain to 2. That should make vertical offset adjustment easier. Second, we're going to try a more refined input range divider with a 900K fixed resistor and 100K trimmer resistor. For background on the front-end see the previous articles.
We hope you enjoyed this series, we had a blast designing the hardware and writing about it. Dangerous DSO v1 PCBs are in the free PCB drawer, if you are serious about building this board please let us know via the contact form. The Dangerous DSO source download includes the v1 design files, the current v1a update, and LTspice simulation files. Now on to the final day of testing!
A big thank you to everyone who helped realize this project. It would not have been possible without you.
This capture was done with the original circuit and an op-amp gain of 1.667.
Set gain to 2
Our LTspice simulations showed that it's easier to get a 2volt offset for the ADC when the op-amp gain is 2. The original Bitscope ADC buffer has a gain of 1.667.
- To solve for gain set Vin=1 and enter the resistor values
Gain is determined by R33 and R34. To set the gain at 2 we replaced the 330ohm op-amp feedback resistor with 220ohm. This forms a 1:2 divider between the inverting input and the the op-amp output. Now the output to responds double to changes of input.
Here's a capture with an op-amp gain of 2. The extra gain made the input adjustment really difficult. We couldn't calibrate it as well as before.
The transitions seem to over/undershoot a lot. We guess this is op-amp noise and not part of the actual signal. This looks too messy to believe it's representative of the PIC PWM output.
Mod input divider for better control
Double gain means we need to divide a +/-10volt input signal by 40 before feeding it to the op-amp.
- 0.975M+0.025M=/40=+/- 10volt input
- 0.950M+0.050M=/20=+/- 5volt input
- 0.900M+0.100M=/10=+/- 2.5volt input
Most usable input ranges are in the bottom 100K ohms of the trimmer. A single-turn trimmer resistor give us about 5degrees of usable adjustment room, that makes calibration a pain.
We removed the 1M trimmer and replaced it with a 100K trimmer. The extra 900K ohms comes from a fixed value resistor. We didn't have a 100K SMD trimmer, so this test was done with a breadboard and through-hole parts.
Here's a capture with an op-amp gain of 2 and the modified input divider. The input range was a lot easier to adjust, definitely a worthwhile update to the next revision. Noise and garbage from using a breadboard and fly-wires is obvious.
Between each circuit update we recalibrate the center offset and input divider. This is the basic procedure:
- Connect the oscilloscope input to ground
- Run a capture
- Adjust the offset with R8 a little each time and do another capture
- Repeat step 3 until the oscope line is in the middle of the graph
- Once centered, remove the ground connection
- Connect the input to a 50kHz square wave from the Bus Pirate (command g, then both default values)
- Perform captures and adjust the input divider with R12 until the signal fits in the limits of the display
Things don't look great for the double gain setup. Additional gain seems to magnify noise, moving back to 1.667 would probably be best. After Maker Faire we'll post a few comparisons against an actual o-scope.
Further discussion in the