One of the best ways to learn how to use a new piece of test equipment is to use it. Sounds easy, right? The problem is, sometimes when you are in the middle of troubleshooting your circuit, figuring out what the knobs on your scope do is an immense frustration. Use these 6 oscilloscope measurements, and just an Arduino Uno, to learn how to use a new or unfamiliar digital scope. This tutorial is not a step-by-step guide on how to make each of these measurements on a particular scope. Instead, it is a general explanation on how to setup the Arduino and a screenshot to help identify if you set up your scope correctly. I reference the R&S RTM3004. However, practically any two (or more) digital channel oscilloscope should work. Between each measurement, I highly recommend using your scope’s default setup (or autoscale) before proceeding to the next one!
Special thanks to Rohde and Schwarz for the RTM3004 featured in this post. Go here to learn more about Rohde & Schwarz Oscilloscopes.

#1 Measure Auto-RESET

This tip applies to Arduino boards with a separate USB-to-Serial chip. Boards such as the Uno, Nano, and Mega2560 have a separate chip. (This measurement does not work with Leondardo, Zero, Teensy, or the boards based on their processors.)
Auto Reset Capactior Probing
Auto Reset Capactior Probing
The computer needs to be able to reset the processor to initiate the bootloader. This reset happens with the serial-to-USB adapter’s DTR or RTS signal. A capacitor between the processor’s reset pin and RTS enables this automatic reset. When RTS goes low, the capacitor suddenly sees 0 V on one side and 5 V on the other, which causes it to start charging. The amount of time depends on the capacitor value and amount of pull-tip resistance. On my Uno R3 board, this process takes about 2 ms. Place your probes on either side of the reset capacitor to see both the RTS signal and the Arduino RESET signal.
Arduino Auto Reset with Annotations
Auto Reset with Annotations
To capture this signal, make use of the oscilloscope’s negative edge or pulse width trigger. Change the sweep mode or trigger mode from “automatic” to “normal” or “single.” The scope’s screen only updates when the serial port opens. Open it using the IDE’s serial monitor.

Reader Exercise: Measure Auto RESET

Use your scope’s cursors to measure the auto-reset signal’s length. Bonus points, you need to lookup the logic levels for RESET. They are different from GPIO pins!

#2 Capture and Decode TX/RX

Connect a probe to Arduino Uno pin 0. Either use an upside down header pin to clip onto, or, try sticking your probes directly into the hole.
RTM3004 UART Probing RX
RTM3004 UART Probing RX
Using this simple code, you can capture serial data between the Arduino and PC.

void setup() {
   Serial.begin(9600);
}

void loop() {
   if (Serial.available())
      Serial.write(Serial.read());
   }
This measurement lets you practice triggering or decoding UART data. For example, here I am looking at the Uno’s RX signal.
Trigger on ASCII 5 with Annotation on RTM3004
Trigger on ASCII ‘5’ with touch-screen Annotation
Using the scope’s serial trigger, I set up the trigger for when the PC sends the character ‘5’ to the Arduino. In the serial monitor, I typed “01234569” and clicked “send.” On the scope, you see characters 0,1,2,3,4 before the trigger point and 6,7,8,9 afterward. The RTM3004 can both trigger and decode serial signals. It is convenient. In this case, I am displaying the ASCII values. In the image below, I show the same sequence in binary, hex, and ASCII.
04-serial-decode-sequence
(Animates through the different decode types)

Reader Exercise: UART turn-around-time

Connect probes to both pins 0 and 1 and then load my multiple digits over serial example. Measure how long it takes to capture a sequence and then send it back out.

#3 Zoom in on DC Voltage Rail.

Let’s move on to one of the most popular osciloscope measurements: voltage rails. First, restore your scope’s default setup. Then, move your probe over to the 3.3 volt pin. This point should be the output of the onboard 3.3 volt low drop out (LDO) linear regulator. To see noise on this line, you could decrease the volts/division on the channel to “zoom in” to the DC voltage. However.
DC Offset Goes Off Screen
DC Offset Goes Off Screen
For DC signals, eventually, the scope’s pre-amplifier runs out of voltage offset. Meaning, the scope cannot display the signal on the screen. When this scope reaches 200 mV/div, the signal goes “off screen.” There is a solution! Since we are only interested in the AC portion of this signal, we can remove the DC component by AC coupling the channel. Head into your channel settings and switch it to AC coupling.
Selecting AC or DC Coupling on RTM3004
Selecting AC or DC Coupling on RTM3004
This feature puts a series coupling capacitor between the input BNC and the amplifier stage. Like any capacitor, it blocks the signal’s DC component.
Note, not all scopes support AC coupling. Also, if it does, it may not be available in both 50 ohm and high-impedance termination.
Now with AC coupling on, we can increase the volts per division and see more of the noise on the rail.
Arduino 3v3 Rail at 20mVdiv on RTM3004
Arduino 3v3 Rail at 20mVdiv on RTM3004

Bonus Tip: Infinite Persistence

Usually, the oscilloscope clears trace data between each acquisition. If your scope supports infinite persistence, you can stop this clearing. Infinite persistence builds up all the waveform data. Heads-up, certain actions clear the screen. Now is a good time to see if changing the volts per division or horizontal scale, or on some particularly poorly programmed scopes, screenshots clear the screen data.
RTM3004 Infinite Persistance 3.3 Volt Rail
RTM3004 Infinite Persistance 3.3 Volt Rail
For this screenshot, I turned on the Rhode RTM3004’s temperature grading for the channel. White areas are “hotter” than other colors, meaning more hits.

Reader Exercise: USB is clean, right?

Want to see something crazy? Move your probe over to the 5 V pin. USB is not as clean as you think! Is it?

#4 See Probe Loading Effects

Previously I talked about different oscilloscope probe types. This oscilloscope measurement demonstrates how you can use two passive probes to see “probe loading” in action. Probe loading means the change a probe causes to the signal under test. For this measurement, you need to locate the ceramic resonator near the ATmega328p.
Probe Loading Ceramic Resonator
Probe Loading on the Ceramic Resonator
Before adding probes, the scope needs a few setup steps. Turn on a “peak-to-peak” voltage measurement for Channel 1. If statistics are available, enable those as well. You need two channels. In my setup, I am using Channels 1 and 3. Turn on both channels even though we are starting with just Channel 1.
Arduino 16 MHz Ceramic Resonator on RTM3004
Arduino 16 MHz Ceramic Resonator on RTM3004
Measuring one side of the resonator’s output, I see 1.1 volts on my Arduino. At this point, carefully, touch your other channel’s probe to the same point. To make it easier, touch the other probe’s tip.
RTM3004 Passive Probe Loading - Arduino Resonator
RTM3004 Passive Probe Loading – Arduino Resonator
Check that out! Channel 1 dropped. Depending on your scope, the signals may appear directly on top of each other. On the Rohde and Schwarz oscilloscope, I can tell by the colors of the front panel’s knobs which channel is on top. The key is the peak-to-peak voltage change on channel 1. Now the scope is only measuring about 1.0 volts. For this measurement, that difference is pretty small. However, it does illustrate a fundamental aspect of electronics measurements. Adding test equipment changes the circuit under test!

#5 Measure PWM Duty Cycle

Okay, let’s go back to the time domain and make some automated measurements. You might notice in my screenshots, there is only a very faint grid or graticule. In the old days, that grid is how you’d measure a signal.
Measure Arduino PWM on R&S RTM3004
Measure Arduino PWM on R&S RTM3004
Here I’m running analogWrite(3, 128). Ideally, this means the pin should be on 50% of the time and off 50% of the time. One option is to count the grids. But why? Your scope can measure that time for you. So in the image above, I turned on two measurements: Frequency and +Width. A frequency of about 490 HZ sounds right, as well as, a 50% duty cycle. But, a 50% signal is boring. So I changed the code to 64 instead. Notice how the measurement changed.
analogWrite(3, 64);
analogWrite(3, 64);
As you would expect on a PWM signal, the frequency stays the same. The duty cycle, however, changed. Now it is down to 25%. Which works out because 64 is about 25% of 255.

Reader Exercise: Loops and Persistence

You could take this a step further, and I suggest you do, to create a loop that increments the PWM value. Try combining it with infinite persistence!

#6 Difference between digitalWrite and port manipulation

In the past, I benchmarked digitalWrite() using a logic analyzer. Logic analyzers do not have either the vertical or horizontal resolution of an oscilloscope. They do, however, often support many more channels. Use this measurement to compare the amount of time it takes to turn on two Arduino Uno pins. The first time uses digitalWrite() and the second uses direct port manipulation.
digitalWrite() vs. Direct Port scope measurement
digitalWrite() vs. Direct Port scope measurement
The setup for this measurement is a bit more involved than the others. However, it does make use of a lot of cool digital oscilloscope features. Connect two scope channels to pins 1 and 3 on the Arduino. (It can be any two pins, I just picked those to match my scope’s channels.) Turn on the channels and make sure volts/div are the same. In my setup, I pressed the vertical knob to toggle into “vernier” control. Then I set my volts per division to 750 mV.  From there, I changed the time per division to about 500 nS, allowing the scope to capture 5 µS. Add a horizontal delay of about 2.3 µS. Or move the trigger point to the left about 2.3 µS. In other words, we want to capture about 5 µS AFTER the trigger event. (You’ll see why.) Set up the trigger for a rising edge on channel 1. Just like the first measurement in this tutorial, change the sweep or trigger mode to “Normal.”
Don’t be alarmed if the oscilloscope screen stops updating. The trigger condition must be met for the screen to update.
Lastly, turn on a “delay” measurement. (Most scopes have one, it might be hidden in an “advanced” horizontal menu.) This measurement measures the time between two “signals.” I put signals in quotes because it is not always channels.

digitalWrite Example

First, upload this code using digitalWrite() to turn on the two pins.

void setup() {
  pinMode(1, OUTPUT);
  digitalWrite(1, LOW);
  pinMode(3, OUTPUT);
  digitalWrite(3, LOW);

  delay(1000); //clear delay for auto-restart

  // turn on pin 1
  digitalWrite(1, HIGH);
  // turn on pin 3
  digitalWrite(3, HIGH);
}

void loop() {}
You might notice the code is all in setup(). For the scope to update, you must hit the Arduino’s reset button. Each time I hit the Arduino’s reset, I see a waveform like below. 10b digitalWrite The yellow trace (left) is D1 and the orange trace (right) is D3. The scope triggers on the rising edge of D1 and later captures D3. This oscilloscope measurement shows it takes about 4.3 µs for the Arduino to turn on two pins with the digitalWrite() function.

Direct port manipulation Example

Now change the Arduino code to the following:

void setup() {
  pinMode(1, OUTPUT);
  digitalWrite(1, LOW);
  pinMode(3, OUTPUT);
  digitalWrite(3, LOW);
  delay(1000); //clear delay for auto-restart

  // turn on pin 1
  PORTD = PORTD | B00000010;
  // turn on pin 3
  PORTD = PORTD | B00001000;
}

void loop() {}
Just like before, each time you reset, the scope screen updates. But notice the time delay difference. Now it is on the order of 185 ns! That is 20X faster!
Oscilloscope Measurements: Comparing digitalWrite() to Port Access
Oscilloscope Measurements: Comparing digitalWrite() to Port Access
What difference did you see with your Arduino? Let me know in the comments.

Reader Exercise: Try replicating my screenshot above.

I used the Reference channel on the RTM3004 to store the first C3 result. Then I set up two delay measurements. One measurement is between C1 and C3, while the other is being C1 and R1. R1 is the “reference” waveform. Scopes treat reference waveforms like physical channels. So you can make measurements on them.

Conclusion

Can you believe all of these oscilloscope measurements are possible using ONLY an Arduino Uno board? I find that amazing. How about you? I encourage to understand how to make these measurements with your scope.
That said, can you suggest to others simple measurements like these to learn how to use a scope?
Author

Fan of making things beep, blink and fly. Created AddOhms. Stream on Twitch. Video Host on element14 Presents and writing for Hackster.IO. Call sign KN6FGY.

11 Comments

  1. Nicholas Dimitriou Reply

    Fantastic article, thanks!

    I am just curious why you chose 4.5v and not 5v or the RMS value at the auto-reset measuring?

    • For the 328p’s RESET signal, a HIGH level is anything over 4.5 volts and a LOW signal is anything below 0.5 volts.

  2. Stefan Bambach Reply

    Great article!

    But there’s little bug… For PIN3 on PORTD you should toggle corresponding bit with
    PORTD = PORTD | B00001000;

    Now its indeed 130ns instead of 4.41us.

    • Good catch. Thanks. I updated the code. (Originally I used pin 2, but when writing and taking pictures, decided to use pin 3 so that it would match the channels on the scope. I forgot about the code!)

  3. Rafael Larios Reply

    Great article!

    Measuring the time between two signals reminded me of a time when I had to measure how long it took a set of relay’s contacts to close from the time its coill got first energized. I only had an analog scope and I had to use a PC’s parallel port and write an assembly language program to record this”closing time.”

    Also, you can find out how coil’s voltage affects closing and opening times. This should be easier with a DSO.

  4. Maybe change the title to specify digital oscilloscope. Very few of the lessons are reproducible on a good old analog.

  5. Ooooh fantastic article. I would love to see you do something similar exploring other devices using a oscilloscope. This really is a one of a kind piece and invaluable if your trying to learn ‘scope usage at home.

    • What about something like the popular pinout diagrams for a microcontroller board, but with scope traces surrounding the board instead of pin numbers?

  6. A little more analysis of the serial waveform would be beneficial so that one can send out a letter “A” for example ($41 if I remember correctly), see the start and stop bits, calculate true through-put. I had this as a lab exercise for my students so they could better understand how serial communications really works.

    Also, include some I2C waveforms and analysis. Where is the acknowledge signal? (I had to dig for answers…)

    • I like the calculating bit rate tip. That would be a fun exercise in itself.

      Regarding I2C analysis, that is actually the genesis of this post. A couple of years ago, I created a Mixed-Signal demo board. It displays a binary counting pattern on 16 LEDs. There is a button to toggle a fault condition. My next step would be to include some I2C stuff and maybe a RC filter on PWM for analog. I don’t remember now, but I think I broke out I2C and SPI, with the idea of ganging up the boards. I never moved forward on that project.

      The other day, I came across the board. I2C has been a big one for me. In the past, I had to learn to read I2C waveforms without any decode. No fun. Then I got to thinking, what could you demo and learn without any additional hardware. What if you only had an Arduino board. Could that be enough to get familiar with a scope? Then I came up with these.

Write A Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.