When makers search for 'inductor code', they are usually looking for one of two things: the cryptic three-digit SMD value codes printed on tiny surface-mount components, or the microcontroller firmware required to measure an unknown inductor's value. Because inductors are passive components, they don't have a digital communication protocol you can just query. Instead, we measure them by building an LC resonant tank circuit, reading the oscillation frequency, and using math in our firmware to back-calculate the inductance.
This guide provides the exact ESP32 inductor code and hardware setup to build a highly accurate benchtop LC resonance meter. We will cover the circuit theory, the precise pin mapping, the compilable C++ firmware with built-in error handling, and the exact debugging steps when your serial monitor throws a timeout error.
The LC Resonance Principle
To measure an inductor with a microcontroller, we rely on the natural resonant frequency of an LC (inductor-capacitor) tank circuit. When you charge the capacitor and let it discharge through the inductor, the energy sloshes back and forth, creating a decaying sine wave. The frequency of this oscillation is dictated by the formula:
f = 1 / (2 * π * √(L * C))
By rearranging this formula to solve for inductance (L), we get the math our ESP32 inductor code will execute:
L = 1 / (4 * π² * f² * C)
Let's look at a concrete numeric example. If we use a known 100nF (0.1µF) C0G capacitor and an unknown 10µH inductor, the theoretical resonant frequency is approximately 159.15 kHz. Our ESP32 will measure this frequency via a comparator and calculate the inductance in Henrys.
Hardware Spec Sheet and Pin Mapping
The ESP32 cannot read analog sine waves directly at 150kHz+ with enough precision using its internal ADC. We need to square off the decaying sine wave into a clean digital pulse using a high-speed comparator. The LM393 is a classic, cheap dual comparator that works perfectly here, provided you respect its open-collector output architecture.
Parts List
- Microcontroller: ESP32-WROOM-32 DevKit V1 (Target board for this firmware)
- Comparator: LM393 Dual Comparator Module (or bare IC)
- Known Capacitor: 100nF (0.1µF) C0G/NP0 Ceramic Capacitor (5% tolerance or better)
- Resistors: 1x 10kΩ (pull-up), 1x 100Ω (current limiting kick resistor)
- Test Inductor: Unknown DUT (Device Under Test)
Pin Mapping Table
| ESP32 Pin | Direction | Connects To | Purpose |
|---|---|---|---|
| GPIO 12 | Output | LC Node (via 100Ω resistor) | 'Kick' pulse to start oscillation |
| GPIO 14 | Input (Interrupt) | LM393 Output (OUT1) | Reads squared-off frequency pulses |
| 3.3V | Power | LM393 VCC & 10kΩ Pull-up | Powers comparator and logic high |
| GND | Ground | LM393 GND & LC Node | Common ground reference |
For a deeper understanding of the comparator's internal architecture and why the pull-up resistor is non-negotiable, refer to the Texas Instruments LM393 datasheet, specifically the section on open-collector outputs.
The ESP32 Inductor Code
The following C++ code is written for the Arduino IDE using the ESP32 Arduino Core (v2.0.14 or newer). It uses an interrupt service routine (ISR) marked with IRAM_ATTR to ensure the timing logic resides in RAM, preventing crashes if the ESP32 is simultaneously accessing the SPI flash.
The code initiates oscillation by pulsing GPIO 12 high for a few microseconds (the 'kick'), then sets it to high-impedance (INPUT mode) so it doesn't dampen the LC tank. It then measures the time between rising edges on GPIO 14 to determine the period, averages it, and calculates the inductance.
#include <Arduino.h>
// --- PIN DEFINITIONS ---
#define KICK_PIN 12 // Sends the initial pulse to start resonance
#define INTERRUPT_PIN 14 // Reads the comparator output
// --- CONSTANTS ---
const float KNOWN_CAPACITANCE = 100e-9; // 100nF in Farads
const int SAMPLE_PULSES = 50; // Number of periods to average
const unsigned long TIMEOUT_MS = 2000; // Timeout for oscillation detection
// --- VOLATILE VARIABLES FOR ISR ---
volatile unsigned long lastMicros = 0;
volatile unsigned long periodSum = 0;
volatile int pulseCounter = 0;
// --- INTERRUPT SERVICE ROUTINE ---
void IRAM_ATTR isr() {
unsigned long now = micros();
if (lastMicros != 0) {
periodSum += (now - lastMicros);
pulseCounter++;
}
lastMicros = now;
}
void setup() {
Serial.begin(115200);
delay(1000); // Allow serial monitor to connect
Serial.println("ESP32 LC Resonance Meter Initialized.");
Serial.println("Connect unknown inductor between LC Node and GND.");
pinMode(KICK_PIN, OUTPUT);
digitalWrite(KICK_PIN, LOW);
pinMode(INTERRUPT_PIN, INPUT); // External pull-up on LM393 handles high state
}
void loop() {
// 1. Reset measurement variables
lastMicros = 0;
periodSum = 0;
pulseCounter = 0;
// 2. Attach interrupt BEFORE the kick
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), isr, RISING);
// 3. 'Kick' the LC tank to start oscillation
pinMode(KICK_PIN, OUTPUT);
digitalWrite(KICK_PIN, HIGH);
delayMicroseconds(10); // Charge the capacitor
digitalWrite(KICK_PIN, LOW);
// 4. Set kick pin to High-Z (Input) so it doesn't dampen the circuit
pinMode(KICK_PIN, INPUT);
// 5. Wait for samples or timeout
unsigned long startTime = millis();
while (pulseCounter < SAMPLE_PULSES) {
if (millis() - startTime > TIMEOUT_MS) {
detachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN));
Serial.println("ERROR: Timeout - No oscillation detected on GPIO 14. Check LM393 pull-up.");
delay(2000);
return; // Exit loop and try again
}
}
// 6. Detach interrupt and calculate
detachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN));
float avgPeriod_us = (float)periodSum / (float)(pulseCounter - 1);
float frequency_Hz = 1000000.0 / avgPeriod_us;
// Calculate Inductance: L = 1 / (4 * pi^2 * f^2 * C)
float inductance_H = 1.0 / (4.0 * pow(PI, 2) * pow(frequency_Hz, 2) * KNOWN_CAPACITANCE);
float inductance_uH = inductance_H * 1e6;
Serial.printf("Freq: %.2f Hz | Inductance: %.2f uH\n", frequency_Hz, inductance_uH);
delay(1000); // Pause before next reading
}
Debugging: First Checks and Exact Error Strings
When building hardware that relies on analog resonance, things will go wrong on the first power-up. If your serial monitor outputs the exact error string: ERROR: Timeout - No oscillation detected on GPIO 14. Check LM393 pull-up., do not immediately rewrite the code. The firmware is correctly identifying a hardware failure.
Here are the first three things to check when the meter fails to oscillate:
- Missing Open-Collector Pull-Up: The LM393 can only pull its output LOW; it cannot drive it HIGH. If you forgot the 10kΩ resistor connecting the LM393 OUT1 pin to the 3.3V rail, the ESP32 GPIO 14 will float, and the interrupt will never trigger. Verify the pull-up with your multimeter.
- Shorted Inductor (DCR near 0Ω): If your test inductor has a dead short internally, or if you accidentally shorted the LC node to ground on your breadboard, the tank circuit will have a Q-factor of nearly zero. It will dissipate the energy instantly without ringing. Measure the DC resistance of your inductor; it should be between 0.1Ω and 5Ω, not 0.0Ω.
- Kick Pulse Not Reaching the Tank: Verify that GPIO 12 is actually outputting 3.3V during the 10-microsecond kick phase. Use an oscilloscope or a logic analyzer to confirm the pulse is reaching the LC node through the 100Ω current-limiting resistor.
Extending and Simplifying the Build
The beauty of this baseline ESP32 inductor code is that it is modular. Depending on your bench needs, you can easily scale the project up or down.
How to Extend the Build
- Add an I2C OLED Display: Wire an SSD1306 128x64 OLED to GPIO 21 (SDA) and GPIO 22 (SCL). Use the
Adafruit_SSD1306library to print the µH value directly to the screen, turning this into a standalone handheld tool. - Auto-Ranging Capacitors: A 100nF capacitor is great for 10µH to 1mH inductors. For smaller RF inductors (10nH to 1µH), the frequency exceeds the ESP32's reliable
micros()interrupt latency limits. Add a relay module to switch in a 1nF capacitor for high-frequency ranges, and use the ESP32's hardware PCNT (Pulse Counter) peripheral instead of software interrupts.
How to Simplify the Build
If you don't have an LM393 comparator and need a quick-and-dirty measurement, you can replace the comparator with a NE555 timer wired in astable mode. The 555 will generate a continuous square wave based on the RC/LC network. However, be aware that the 555 introduces significant timing jitter and internal propagation delays (typically 100ns), which will reduce your measurement accuracy from ~1% to roughly 10%. For precise bench work, stick to the LM393.
FAQ: Inductor Codes and Measurement Edge Cases
How do I read SMD inductor code markings manually?
If you are trying to decode the physical 'inductor code' printed on a surface-mount component before testing it, the system mirrors resistor codes but uses microhenrys (µH) as the base unit. A 3-digit code like 101 means 10 × 10¹ = 100µH. A code like 4R7 uses 'R' as a decimal point, meaning 4.7µH. Always verify these printed codes with your ESP32 LC meter, as cheap unshielded SMD inductors often have actual values that drift 20% or more from their printed code due to core saturation.
Why does my inductor code output fluctuate at high frequencies?
If your serial monitor shows the inductance value jumping around by 5-10% on small inductors (under 1µH), you are hitting the limits of parasitic capacitance. A standard solderless breadboard introduces 2pF to 5pF of stray capacitance between rows, and the ESP32 GPIO pin itself adds roughly 5pF. When your known capacitor is 100nF, 5pF is negligible. But if you swap to a 100pF known capacitor to measure high frequencies, that 5pF parasitic capacitance becomes a 5% error source. For high-frequency stability, move the LC tank and LM393 to a soldered perfboard or custom PCB, keeping leads as short as possible.
Can I use this inductor code to measure ferrite bead impedance?
No. Ferrite beads are not designed to store energy and resonate like standard inductors; they are designed to dissipate high-frequency noise as heat. They are highly lossy components with a very low Q-factor. If you place a ferrite bead in this LC tank circuit, the oscillation will dampen and die within one or two cycles, triggering the timeout error in the ESP32 inductor code. To measure a ferrite bead, you need an impedance analyzer or a network analyzer that sweeps AC frequencies and measures voltage drop, not a resonance timer.






