Table of Contents
KEY TAKEAWAYS
- An oscilloscope shows analog voltage over time — essential for power supply quality, signal integrity, and analog debugging.
- For embedded work, a 50-100MHz bandwidth, 2-channel digital scope ($300-$500) handles most debugging tasks.
- Use AC coupling to see noise and ripple on power rails; DC coupling for absolute voltage measurements.
- Proper grounding (spring clip, not the long wire) is critical for accurate measurements above a few MHz.
- Math functions (FFT, measurement cursors) help identify noise sources and quantify signal quality automatically.
Why Embedded Engineers Need an Oscilloscope
A logic analyzer tells you if a bit is HIGH or LOW. An oscilloscope tells you how HIGH, how fast it transitioned, whether there’s ringing on the edges, and whether your power supply has noise that’s corrupting everything. The oscilloscope sees the analog reality that digital tools hide.
Many embedded bugs — random crashes, intermittent communication failures, incorrect ADC readings — are caused by analog issues that are invisible to digital debugging tools. A noisy 3.3V rail, a slow I2C rise time, or a brownout during motor startup can only be diagnosed with an oscilloscope.
Oscilloscope Basics for Embedded
Before diving into specific measurements, you need to understand what an oscilloscope actually shows you and how its controls map to embedded debugging tasks. Unlike a logic analyzer that shows clean digital 1s and 0s, an oscilloscope shows the actual analog voltage waveform — including noise, ringing, overshoot, and all the imperfections that cause real-world bugs. Here are the fundamental concepts every embedded engineer should know.
/* Oscilloscope Key Concepts
*
* ─── Bandwidth ───
* The highest frequency the scope can accurately measure.
* Rule of thumb: scope bandwidth ≥ 5× the signal frequency.
* - 50MHz scope: good for signals up to 10MHz
* - 100MHz scope: good for signals up to 20MHz
* - For 72MHz ARM clock edges: need ≥200MHz (but you rarely
* measure the CPU clock directly)
*
* For most embedded work (I2C, SPI, UART, power rails):
* 50-100MHz bandwidth is MORE than enough.
*
* ─── Sample Rate ───
* How many samples per second the ADC takes.
* Nyquist theorem: sample rate ≥ 2× bandwidth.
* In practice: ≥ 5× the highest frequency component.
*
* A 100MHz scope typically has 1GSa/s sample rate = fine.
*
* ─── Voltage Division (V/div) ───
* Each grid square on the screen = one division.
* 1V/div with 8 divisions = 8V total range.
* For 3.3V signals: use 1V/div (signal fills ~3.3 divisions)
* For millivolt noise: use 20mV/div or less
*
* ─── Time Division (s/div) ───
* Each horizontal grid square = one time division.
* 1ms/div with 10 divisions = 10ms visible.
* For 100kHz I2C: use 5-10µs/div
* For 115200 UART: use 50-100µs/div
*
* ─── Trigger ───
* Tells the scope WHEN to capture.
* Edge trigger: capture when signal crosses a threshold.
* Rising edge trigger at 1.6V on CH1 = capture when CH1 goes
* from below 1.6V to above 1.6V.
*/Essential Measurements for Embedded Systems
1. Power Supply Quality
Power supply problems are the most common cause of mysterious embedded bugs — random crashes, corrupted communication, sensors returning garbage data. A multimeter shows you the average voltage, but an oscilloscope reveals the transient noise, ripple, and voltage droops that occur when the microcontroller switches GPIO pins or draws burst current from peripherals. Here is how to measure your power rail quality.
/* Checking your 3.3V power rail
*
* Setup:
* CH1 probe → 3.3V rail (near MCU VDD pin, not at regulator!)
* GND clip → MCU GND (closest GND pin)
* Coupling: AC (removes the 3.3V DC offset, shows only noise/ripple)
* V/div: 20mV/div or 50mV/div
* Time/div: 1ms/div for low-frequency ripple
* 1µs/div for high-frequency switching noise
*
* What good looks like:
* - Ripple < 50mV peak-to-peak (for most MCUs)
* - No sharp spikes during GPIO transitions
* - Clean during ADC conversions
*
* What bad looks like:
* - 200mV+ ripple → voltage regulator undersized or bad capacitors
* - Sharp spikes when motors/relays activate → need decoupling caps
* - Dips below 3.0V under load → brownout risk
*
* Critical measurement: Power during Wi-Fi/BLE transmission
* ESP32 TX burst can draw 300mA+ for ~1ms
* If your supply can't handle it, you'll see VCC dip
* Solution: add 100µF bulk capacitor near module
*/
/* Firmware test: toggle a GPIO rapidly to stress power supply */
void power_supply_stress_test(void) {
/* Toggle all port B pins at maximum speed */
/* Watch the 3.3V rail on the scope during this */
for (volatile int i = 0; i ODR = 0xFFFF;
GPIOB->ODR = 0x0000;
}
}
/* ADC noise test: read ADC while monitoring power supply */
void adc_noise_test(void) {
/* Connect ADC input to a stable reference (voltage divider) */
/* Read 1000 samples and check for outliers */
uint16_t min_val = 4095, max_val = 0;
uint32_t sum = 0;
for (int i = 0; i < 1000; i++) {
uint16_t val = read_adc(0);
if (val max_val) max_val = val;
sum += val;
}
/* If (max_val - min_val) > 20 counts on a 12-bit ADC,
* you likely have power supply noise.
* Check with scope in AC coupling mode. */
uint16_t noise_pp = max_val - min_val;
uint16_t average = sum / 1000;
/* Print via UART or semihosting */
}2. I2C Signal Quality
I2C relies on open-drain signals with pull-up resistors, which means the signal edges are not sharp like push-pull GPIO outputs. If the pull-up resistors are too large, the rising edges will be slow and may not reach the logic-high threshold in time. If they are too small, the open-drain drivers may not be able to pull the line low enough. An oscilloscope lets you see these analog characteristics that a logic analyzer hides from you. For I2C protocol details, see I2C Protocol Deep Dive.
/* Measuring I2C signal quality with an oscilloscope
*
* Setup:
* CH1 → SDA
* CH2 → SCL
* Coupling: DC
* V/div: 1V/div (for 3.3V logic)
* Time/div: 5µs/div (for 100kHz I2C)
* Trigger: Falling edge on SDA (captures START condition)
*
* ─── What to check ───
*
* 1. Rise time (tr):
* Measure from 30% to 70% of VCC on the rising edge.
* I2C Standard mode: tr ≤ 1000ns
* I2C Fast mode: tr ≤ 300ns
* If too slow → pull-up resistance too high or too much capacitance
* If too fast → pull-up resistance too low (wastes power)
*
* 2. Voltage levels:
* VIL (input low): < 0.3 × VCC = 0.7 × VCC = > 2.31V for 3.3V
* If HIGH doesn't reach 2.31V → pull-up too weak or bus overloaded
*
* 3. Ringing/overshoot:
* Sharp transitions should not overshoot above VCC or below GND
* by more than 0.5V. Excessive ringing = signal integrity issue.
*
* 4. Clock stretching:
* SCL should show clean square waves.
* If SCL stays LOW for unusually long → slave is clock stretching.
* Measure the stretch duration to verify it's within your timeout.
*
* Practical example:
* You see SDA rise time = 2µs on 400kHz I2C (max allowed: 300ns)
* Solution: Reduce pull-up from 10kΩ to 2.2kΩ
* After fix: rise time = 250ns ✓
*/3. PWM Output Verification
PWM (Pulse Width Modulation) is used everywhere in embedded systems — motor control, LED dimming, audio generation, and power regulation. The oscilloscope is the definitive tool for verifying that your PWM output matches your intended frequency and duty cycle. It also reveals problems like jitter (variation in timing between cycles) and glitches (momentary spikes or dips) that software alone cannot detect.
/* Verifying PWM output with an oscilloscope
*
* Use the scope's built-in measurement functions:
* - Frequency: Should match your PWM timer configuration
* - Duty cycle: Should match your compare register setting
* - Rise/fall time: Important for motor drivers (switching losses)
*/
/* Example: Generate 1kHz PWM with variable duty cycle */
void pwm_init(uint16_t duty_percent) {
/* Timer setup for 1kHz PWM on PA0 (TIM2 CH1)
* 72MHz / 72 prescaler = 1MHz timer clock
* 1MHz / 1000 period = 1kHz PWM frequency
*/
#define TIM2_BASE_ADDR 0x40000000
volatile uint32_t *TIM2_PSC = (volatile uint32_t *)(TIM2_BASE_ADDR + 0x28);
volatile uint32_t *TIM2_ARR = (volatile uint32_t *)(TIM2_BASE_ADDR + 0x2C);
volatile uint32_t *TIM2_CCR1 = (volatile uint32_t *)(TIM2_BASE_ADDR + 0x34);
volatile uint32_t *TIM2_CCMR1 = (volatile uint32_t *)(TIM2_BASE_ADDR + 0x18);
volatile uint32_t *TIM2_CCER = (volatile uint32_t *)(TIM2_BASE_ADDR + 0x20);
volatile uint32_t *TIM2_CR1 = (volatile uint32_t *)(TIM2_BASE_ADDR + 0x00);
*TIM2_PSC = 72 - 1; /* Prescaler: 72MHz / 72 = 1MHz */
*TIM2_ARR = 1000 - 1; /* Period: 1MHz / 1000 = 1kHz */
*TIM2_CCR1 = (1000 * duty_percent) / 100; /* Duty cycle */
*TIM2_CCMR1 = (6 << 4); /* PWM mode 1 */
*TIM2_CCER = 1; /* Enable CH1 output */
*TIM2_CR1 = 1; /* Enable timer */
/* Oscilloscope verification:
* 1. Probe PA0 with CH1
* 2. Set trigger: Rising edge, 1.6V threshold
* 3. Time/div: 200µs/div (shows ~2 full cycles of 1kHz)
* 4. Use scope's "Frequency" measurement: should read 1.000kHz
* 5. Use scope's "Duty" measurement: should match duty_percent
* 6. If frequency is off: check your system clock configuration
* 7. If duty is off: recalculate CCR1 value
*/
}
/* Scope measurements for motor control:
* - Measure PWM at driver input AND motor terminal
* - Check for voltage spikes at motor terminal (back-EMF)
* - Verify dead-time between high/low side drives (H-bridge)
* - Check gate driver rise/fall times
*/4. Debugging Reset and Brownout Issues
Unexpected resets are among the hardest embedded bugs to diagnose because, by definition, your firmware stops running when they happen. The oscilloscope lets you monitor the power supply and reset pin simultaneously, correlating voltage droops with reset events. You can also use GPIO toggle pins as timing markers to understand exactly when in your code the reset occurs. See Brownout Detection and Reset Systems for related firmware topics.
/* Catching power-related resets with an oscilloscope
*
* Problem: MCU randomly resets during motor startup.
*
* Setup:
* CH1 → VCC (3.3V rail), AC coupling, 100mV/div
* CH2 → NRST pin (reset), DC coupling, 1V/div
* Trigger: Falling edge on CH2 (captures the reset event)
* Time/div: 1ms/div
* Trigger mode: SINGLE (capture one event and stop)
*
* What you might see:
* CH1 (VCC): Sharp dip to 2.8V lasting ~500µs during motor start
* CH2 (NRST): Goes LOW 200µs after VCC dips below 2.9V
* → BOR (Brown-Out Reset) triggered!
*
* Fix:
* 1. Add 100µF bulk capacitor near VCC
* 2. Use separate power supply for motor
* 3. Ramp motor speed gradually (soft start)
* 4. Adjust BOR threshold in firmware if possible
*
* See our articles on brownout detection and reset systems
* for firmware-level solutions.
*/Oscilloscope Probing Best Practices
How you connect the oscilloscope probe to your circuit matters more than most engineers realize. A long ground lead acts as an antenna, picking up noise and distorting high-frequency measurements. Proper probing technique is the difference between seeing real signal issues and chasing measurement artifacts.
- Use the spring ground clip (not the alligator clip with long wire) for anything above 1MHz. The long ground wire acts as an antenna and picks up noise.
- Probe near the MCU pin, not at the connector or cable end. Signal quality degrades along PCB traces and wires.
- 1X vs 10X probe setting: 10X divides the signal by 10 (reduces loading on the circuit). Use 10X for most measurements. Use 1X only for very small signals (< 100mV).
- Compensate your probes: Connect to the scope’s calibration output (square wave) and adjust the probe trimmer until the square wave has sharp corners with no overshoot or rounding.
Related Articles
- Using a Logic Analyzer for Embedded Debugging
- Debugging Communication Protocols
- Brownout Detection in Microcontrollers
- Reset Systems in Microcontrollers
- GDB for Embedded Debugging
- Logging and Trace in Embedded C
- Debugging Embedded Systems: Tools and Techniques
- Power Supply and Voltage Regulators
- PWM in Embedded Systems
- ADC and DAC in Microcontrollers
📖 Related: Voltage Divider Network

Vivek Bhageria — Lead Firmware R&D Engineer, 12+ years. Ex-Bosch (automotive powertrain), MusicTribe (real-time audio), medical devices. M.Tech BITS Pilani. I write at NerdyElectronics — practical, register-level embedded systems for engineers who want to understand what’s actually happening under the hood.




