Project Overview & Parts List

An Inductance-to-Digital Converter (LDC) measures changes in the inductance of a coil when a conductive target (like aluminum or copper) enters its magnetic field. Unlike capacitive sensors, an LDC ignores non-conductive materials like plastic, glass, or water, making it ideal for precision metal proximity sensing, dial encoders, and fluid level detection through sealed containers.

For this build, we are targeting the Texas Instruments LDC1612, a 28-bit, 2-channel I2C sensor. We will interface it with an Arduino Uno R3. Because the LDC1612 is strictly a 3.3V device and the Uno operates at 5V, this guide includes the mandatory logic level shifting required to prevent bricking the sensor.

Difficulty Rating: Intermediate (Requires I2C debugging, custom LC tank component selection, and 5V-to-3.3V logic shifting).

Required Parts & Exact Variants

  • Microcontroller: Arduino Uno R3 (or Nano v3 ATmega328P variant).
  • Sensor Module: LDC1612 Breakout Board (e.g., Adafruit 4469 or generic I2C LDC1612 module with exposed ADDR pin).
  • Level Shifter: BSS138 Bidirectional Logic Level Converter (4-channel). Do not skip this; the LDC1612 absolute max VCC is 3.6V.
  • Resonant Capacitor: 100pF to 330pF NP0/C0G ceramic capacitor (50V). X7R or Y5V dielectrics will cause severe temperature drift.
  • Sensor Coil: Custom PCB coil or hand-wound AWG 28 enameled copper wire (approx. 30 turns, 15mm outer diameter).
  • Wiring: 22 AWG solid-core hook-up wire for breadboard prototyping.

Wiring the LDC1612 to Arduino (Pin Mapping)

The LDC1612 communicates via I2C. The default address is 0x2A when the ADDR pin is tied to GND, and 0x2B when tied to VCC. Below is the exact pin mapping utilizing the BSS138 level shifter to protect the 3.3V sensor from the Uno's 5V I2C pull-ups.

Arduino Uno R3 (5V) BSS138 Level Shifter LDC1612 Breakout (3.3V) Notes
5V Pin HV (High Voltage) - Powers the high-side pull-ups
3.3V Pin LV (Low Voltage) VCC Powers the low-side pull-ups and LDC
GND GND (Both sides) GND Common ground reference
A4 (SDA) HV1 - 5V I2C Data input to shifter
- LV1 SDA 3.3V I2C Data output to LDC
A5 (SCL) HV2 - 5V I2C Clock input to shifter
- LV2 SCL 3.3V I2C Clock output to LDC
- - ADDR Tie to GND for I2C address 0x2A
Bench Tip: Keep the I2C wires between the level shifter and the LDC1612 under 10cm (4 inches). High-speed I2C transitions on long, unshielded 3.3V lines can cause signal ringing that the LDC misinterprets as data bits.

Complete Arduino Code for LDC1612

Rather than relying on third-party libraries that frequently break with IDE updates, the code below uses the native Arduino Wire library to read the 28-bit conversion data directly from the LDC1612 registers. This targets the Arduino Uno R3 and includes robust I2C error handling.

#include <Wire.h>

// --- Pin & Address Definitions ---
const int STATUS_LED_PIN = 13;
const uint8_t LDC_ADDR = 0x2A; // ADDR pin tied to GND

// --- LDC1612 Register Map ---
const uint8_t REG_DATA_CH0_MSB = 0x00;
const uint8_t REG_DATA_CH0_LSB = 0x01;
const uint8_t REG_CONFIG       = 0x14;
const uint8_t REG_DRIVE_CH0    = 0x1E;
const uint8_t REG_CH0_RCOUNT   = 0x08;

void writeRegister16(uint8_t reg, uint16_t value) {
  Wire.beginTransmission(LDC_ADDR);
  Wire.write(reg);
  Wire.write((value >> 8) & 0xFF); // MSB
  Wire.write(value & 0xFF);        // LSB
  Wire.endTransmission();
}

uint32_t readChannelData(uint8_t msb_reg) {
  Wire.beginTransmission(LDC_ADDR);
  Wire.write(msb_reg);
  Wire.endTransmission(false); // Repeated start
  
  Wire.requestFrom(LDC_ADDR, (uint8_t)4);
  uint32_t msb = Wire.read();
  uint32_t lsb_mid = Wire.read();
  uint32_t lsb_low = Wire.read();
  uint32_t lsb_lowest = Wire.read(); // 28-bit data spans across registers
  
  // Note: LDC1612 28-bit data format requires specific bit shifting
  // For simplicity in standard 16-bit reads, we combine MSB and LSB registers
  // Here we read the 28-bit value properly
  uint32_t raw_data = ((msb & 0x0F) << 24) | (lsb_mid << 16) | (lsb_low << 8) | lsb_lowest;
  return raw_data;
}

void setup() {
  Serial.begin(115200);
  pinMode(STATUS_LED_PIN, OUTPUT);
  Wire.begin();
  Wire.setClock(400000); // Set I2C to 400kHz Fast Mode

  // 1. Verify I2C Presence
  Wire.beginTransmission(LDC_ADDR);
  byte error = Wire.endTransmission();
  if (error != 0) {
    Serial.print("Error: LDC1612 init failed! Wire.endTransmission() returned error code ");
    Serial.println(error);
    // Blink LED rapidly to indicate hardware fault
    while(1) { 
      digitalWrite(STATUS_LED_PIN, HIGH); delay(100); 
      digitalWrite(STATUS_LED_PIN, LOW); delay(100); 
    }
  }

  // 2. Configure Sensor
  // CONFIG Register (0x14): 0x1E01 sets 16-bit mode, 1 channel active, auto amplitude
  writeRegister16(REG_CONFIG, 0x1E01);
  
  // DRIVE_CH0 (0x1E): 0x8000 enables auto-drive amplitude
  writeRegister16(REG_DRIVE_CH0, 0x8000);
  
  // CH0_RCOUNT (0x08): Set conversion time / resolution (higher = slower but more stable)
  writeRegister16(REG_CH0_RCOUNT, 0xFFFF);

  Serial.println("LDC1612 initialized successfully.");
}

void loop() {
  // Read 28-bit data from Channel 0
  uint32_t ch0_data = readChannelData(REG_DATA_CH0_MSB);
  
  // Check for error flags in the upper bits (Bit 28-31)
  if (ch0_data & 0x80000000) {
    Serial.println("Warning: Amplitude too low. Check coil connections.");
  } else {
    // Mask out the 28-bit actual data
    uint32_t clean_data = ch0_data & 0x0FFFFFFF;
    Serial.print("CH0 Raw Inductance Value: ");
    Serial.println(clean_data);
  }
  
  delay(100); // 10 Hz read rate
}

Debugging: "LDC Init Failed" and Common I2C Errors

When working with raw I2C on the workbench, hardware faults are inevitable. If your serial monitor outputs the exact string Error: LDC1612 init failed! Wire.endTransmission() returned error code 2, it means the Arduino received a NACK (Not Acknowledged) on the address byte. If it returns code 1, the data was too long for the transmit buffer. If it returns code 3, you received a NACK on a data byte.

The First Three Things to Check When It Fails

  1. Verify the I2C Address Jumper: Use your multimeter in continuity mode. Ensure the ADDR pin on the breakout is physically soldered or jumpered to GND. If it is floating, the LDC1612 will not respond to 0x2A or 0x2B.
  2. Check Level Shifter Orientation: The BSS138 board has a "HV" and "LV" side. If you accidentally feed 5V into the LV side, you may have already destroyed the LDC's internal ESD protection diodes. Measure the voltage at the LDC's VCC pin; it must read exactly 3.3V (±0.1V).
  3. Validate Pull-Up Resistors: The TI LDC1612 Datasheet specifies I2C bus capacitance limits. If your wires are long, the internal pull-ups on the Arduino and breakout might be too weak. Add external 4.7kΩ pull-up resistors to the 3.3V line on the SDA and SCL pins.

Ranked Causes for Wildly Fluctuating Readings

If the code compiles but the serial output jumps erratically (e.g., from 4,000,000 to 12,000,000 without moving the target):

  • Cause 1 (Most Likely): Wrong Capacitor Dielectric. You used an X7R or Y5V capacitor for the LC tank. These are piezoelectric and highly temperature-dependent. Replace it with a C0G/NP0 ceramic capacitor immediately.
  • Cause 2: Microphonic Coil. Your hand-wound coil is loose. The vibration from the desk or even acoustic noise changes the coil geometry. Secure the coil with a dab of non-conductive epoxy or hot glue.
  • Cause 3: Ground Loop Noise. You are powering the Arduino from a noisy switching laptop charger. Power the Uno via a linear USB hub or a battery bank to isolate the ground plane.

Extending and Simplifying the Build

Once you have a stable baseline reading, you can adapt this LDC Arduino setup for specific production or hobby needs.

How to Extend the Build

  • Add a Second Channel: The LDC1612 is a dual-channel device. Wire a second LC tank to the IN1 and COM1 pins, and read register 0x02 (DATA_CH1_MSB) to create a differential metal thickness sensor.
  • Add an OLED Display: Integrate an SSD1306 128x64 I2C OLED. Because the LDC and OLED share the I2C bus, ensure the OLED has 3.3V logic or use the other channels on your BSS138 level shifter.

How to Simplify the Build

  • Drop to the LDC1312: If 28-bit resolution is overkill for your dial encoder or proximity switch, switch to the LDC1312. It offers 12-bit resolution, uses the exact same I2C register map structure, but costs roughly 40% less and is more forgiving of parasitic capacitance.
  • Use SMD Coils: Instead of winding your own wire, purchase fixed-value SMD inductors (e.g., 10µH to 47µH shielded power inductors) and place them flat against the target. While less sensitive than a custom PCB spiral coil, it eliminates the physical winding variable entirely.

LDC Arduino FAQ

Can I use an LDC sensor to measure the thickness of non-metallic materials?

No. Inductance-to-Digital Converters rely on Eddy currents induced in conductive materials. Non-metallic materials like plastic, wood, glass, or water do not support Eddy currents and will be completely invisible to the sensor. If you need to measure non-metallic thickness, you must use a capacitive sensor (like the FDC2214) or an ultrasonic transducer.

Why is my LDC1612 Arduino reading fluctuating wildly?

Wild fluctuations are almost always caused by the resonant capacitor in your LC tank. Standard ceramic capacitors (X7R, Z5U) exhibit severe capacitance drift with temperature and applied voltage (DC bias). For an LC oscillator circuit, you must exclusively use C0G (also known as NP0) dielectric capacitors, which have a near-zero temperature coefficient.

What is the difference between the LDC1000 and LDC1612 for Arduino projects?

The older LDC1000 uses SPI and outputs a 24-bit value, but it is largely obsolete and difficult to source. The LDC1612 uses I2C, offers higher 28-bit resolution, supports multiple channels natively, and has vastly superior auto-amplitude control. For any new Arduino project, the LDC1612 (or its 12-bit sibling, the LDC1312) is the definitive choice.

How do I calculate the resonant frequency of my LC tank for the LDC?

The LDC1612 drives the LC tank at its natural resonant frequency. You can calculate this using the standard formula: f = 1 / (2 * π * √(L * C)). For example, a 10µH coil paired with a 100pF (0.0000000001 F) capacitor will resonate at approximately 5.03 MHz. The LDC1612 can measure sensor frequencies up to 10 MHz, so ensure your L and C values keep the resonance under this limit.