1
\$\begingroup\$

I'm trying to get an AD5933 Impedance Converter module (connected via I2C) to work with a Raspberry Pi, but I'm consistently running into an issue where the chip reports an Over-range/Saturation error (0x70 in the status register), leading to a timeout because the measurement never completes.

Here are the details and what I've tried:

  1. Hardware Setup:
    • Module: AD5933 Impedance Converter breakout board.
    • Controller: Raspberry Pi 3.
    • Power Supply: Confirmed stable 5V (measured ~4.93V directly at the AD5933 VCC pin).
    • R_FB Resistor: Identified from board images as 100 kOhms (marked "1003").
    • R_CAL Resistor: Current calibration resistor is 10 kOhms (measured 8-10 kOhms fluctuating, but mostly near 10k).
  2. Software Configuration (Python using smbus2):
    • AD5933 I2C Address: 0x0D.
    • Code correctly writes configuration:
      • R_FB_VALUE = 100000.0
      • KNOWN_RCAL_VALUE = 10000.0
      • AD5933 commanded to lowest possible excitation voltage (200mVp-p) and lowest PGA gain (x1) (using 0xAB for Control Register MSB).
    • Calibration Frequency: 50kHz.
    • I2C communication confirmed working (e.g., i2cdetect sees 0x0D, registers read back correctly after writing, frequency setting is confirmed).
  3. The Problem:
    • After initiating a measurement, the AD5933's Status Register always returns 0x70 (Over-range/Saturation).Because the chip is saturated, the "measurement complete" bit (0x02) is never set.This causes the Python script to timeout while waiting for the measurement to complete.
  4. Detailed Troubleshooting Steps & Results:
    • Initial R_CAL (1 kOhm): Started with a 1 kOhm R_CAL. Calculation showed a massive 20V p-p signal (0.2V / 1kΩ * 100kΩ) into the AD5933, clearly saturating a 5V system. This perfectly explained the 0x70 status.
    • Switched to 10 kOhm R_CAL: Based on the 100k Ohm R_FB on the board, I obtained and connected a 10 kOhm R_CAL.
    • Recalculation with 10k Ohm R_CAL: The expected signal into the AD5933's ADC is now calculated to be ~2V p-p to 2.5V p-p (0.2V / 10kΩ * 100kΩ = 2Vp-p; worst case 0.2V / 8kΩ * 100kΩ = 2.5Vp-p). Still 0x70 Status: Despite the much lower and theoretically acceptable signal, the AD5933 still consistently returns 0x70 in its status register.
  5. Verified Physical Components:
    • 10k Ohm R_CAL: Multimeter reads 8-10 kOhms (fluctuating). While not perfectly stable, even 8k Ohms should not cause full saturation on a 5V supply.
    • 5V Supply: Confirmed stable at ~4.93VDC.
    • I2C Lines: i2cdetect works, and register writes/reads in the script are confirmed to be successful.
  6. Current Hypothesis:
    • Given that the AD5933 is consistently reporting saturation (0x70) even when configured to its lowest gain and receiving a calculated input signal (2-2.5Vp-p) that should be well within its 5V operating limits, it strongly suggests a defective AD5933 chip or module itself. The internal analog front-end (Transimpedance Amplifier or ADC) might be faulty and stuck in an over-range condition.
    • I believe the datasheet says 200kohm resistor I only have a 1M OhM will that work?

Code below.

import smbus2 import time import math AD5933_I2C_ADDRESS = 0x0D I2C_BUS_NUMBER = 1 CALIBRATION_FREQUENCY = 50000 KNOWN_RCAL_VALUE = 330.0 R_FB_VALUE = 2200.0 REG_CONTROL_MSB = 0x80 REG_CONTROL_LSB = 0x81 REG_START_FREQ_23_16 = 0x82 REG_START_FREQ_15_8 = 0x83 REG_START_FREQ_7_0 = 0x84 REG_FREQ_INC_23_16 = 0x85 REG_FREQ_INC_15_8 = 0x86 REG_FREQ_7_0 = 0x87 REG_NUM_INC_15_8 = 0x88 REG_NUM_INC_7_0 = 0x89 REG_SETTLING_TIME_MSB = 0x8A REG_SETTLING_TIME_LSB = 0x8B REG_STATUS = 0x8F REG_REAL_DATA_MSB = 0x94 REG_REAL_DATA_LSB = 0x95 REG_IMAG_DATA_MSB = 0x96 REG_IMAG_DATA_LSB = 0x97 CMD_STANDBY = 0xA2 CMD_INIT_START_FREQ = 0xB1 CMD_START_SWEEP = 0xB2 CMD_INCREMENT_FREQ = 0xB3 CMD_REPEAT_FREQ = 0xB4 CMD_POWER_DOWN = 0xBA CMD_RESET = 0x10 bus = None gain_factor = 0.0 def twos_comp_to_int(val):     if val & 0x8000:         return -(0x10000 - val)     return val def write_register(reg_addr, value):     try:         bus.write_byte_data(AD5933_I2C_ADDRESS, reg_addr, value)     except Exception as e:         print(f"Error writing to register 0x{reg_addr:02X}: {e}") def read_register(reg_addr):     try:         data = bus.read_byte_data(AD5933_I2C_ADDRESS, reg_addr)         return data     except Exception as e:         print(f"Error reading from register 0x{reg_addr:02X}: {e}")         return 0 def read_16bit_signed(reg_msb):     msb = read_register(reg_msb)     lsb = read_register(reg_msb + 1)     raw_val = (msb << 8) | lsb     return twos_comp_to_int(raw_val) def is_measurement_complete():     status = read_register(REG_STATUS)     return (status & 0x02) == 0x02 def calculate_freq_reg_value(frequency_hz):     return int((frequency_hz * (2**29)) / 16000000) def set_frequency(frequency_hz):     freq_val = calculate_freq_reg_value(frequency_hz)     write_register(REG_START_FREQ_23_16, (freq_val >> 16) & 0xFF)     write_register(REG_START_FREQ_15_8, (freq_val >> 8) & 0xFF)     write_register(REG_START_FREQ_7_0, freq_val & 0xFF)     time.sleep(0.01) def setup_ad5933():     print("Initializing AD5933...")     global bus     bus = smbus2.SMBus(I2C_BUS_NUMBER)     initial_status = read_register(REG_STATUS)     print(f"Diagnostic: Initial Status Register: 0x{initial_status:02X}")     if initial_status == 0x00 or initial_status == 0xFF:         print("Diagnostic Warning: AD5933 might not be responding to I2C reads correctly.")     write_register(REG_CONTROL_MSB, CMD_STANDBY | CMD_RESET)     time.sleep(0.1)     control_msb_after_reset = read_register(REG_CONTROL_MSB)     print(f"Diagnostic: Control MSB after Reset/Standby: 0x{control_msb_after_reset:02X}")     write_register(REG_CONTROL_MSB, CMD_STANDBY)     time.sleep(0.05)     control_msb_after_standby = read_register(REG_CONTROL_MSB)     print(f"Diagnostic: Control MSB after Standby command: 0x{control_msb_after_standby:02X}")     set_frequency(CALIBRATION_FREQUENCY)     freq_val_read_back = (read_register(REG_START_FREQ_23_16) << 16) | \                          (read_register(REG_START_FREQ_15_8) << 8) | \                          read_register(REG_START_FREQ_7_0)     print(f"Diagnostic: Start Freq Read Back (raw): 0x{freq_val_read_back:06X} (Expected Freq: {CALIBRATION_FREQUENCY}Hz)")     write_register(REG_NUM_INC_15_8, 0x00)     write_register(REG_NUM_INC_7_0, 0x00)     write_register(REG_SETTLING_TIME_MSB, 0x00)     write_register(REG_SETTLING_TIME_LSB, 0x0A)     print("AD5933 setup complete.") def calibrate_ad5933():     global gain_factor     print(f"\n--- Starting Calibration with R_CAL = {KNOWN_RCAL_VALUE} Ohms ---")     print("Ensure your KNOWN_RCAL_VALUE resistor is connected between the red and black clips.")     write_register(REG_CONTROL_MSB, CMD_INIT_START_FREQ)     time.sleep(0.1)     print("Measuring R_CAL...")     timeout_start = time.time()     while not is_measurement_complete():         time.sleep(0.01)         if (time.time() - timeout_start) > 2.0:             print("Timeout waiting for R_CAL measurement completion.")             return False     real_data_cal = read_16bit_signed(REG_REAL_DATA_MSB)     imag_data_cal = read_16bit_signed(REG_IMAG_DATA_MSB)     magnitude_cal = math.sqrt(float(real_data_cal)**2 + float(imag_data_cal)**2)     if magnitude_cal > 0.0:         gain_factor = 1.0 / (KNOWN_RCAL_VALUE * magnitude_cal)         print(f"Calibration successful!")         print(f"  Real Data: {real_data_cal}")         print(f"  Imag Data: {imag_data_cal}")         print(f"  Magnitude: {magnitude_cal:.2f}")         print(f"  Calculated Gain Factor: {gain_factor:.10e}")         return True     else:         print("Error: Calibration magnitude is zero. This can indicate saturation or no signal.")         gain_factor = 0.0         return False def measure_impedance():     if gain_factor == 0.0:         print("Error: Calibration not performed or failed. Cannot measure impedance.")         return 0.0     print("\n--- Starting Unknown Impedance Measurement ---")     print("!!! NOW, DISCONNECT R_CAL and CONNECT your UNKNOWN RESISTOR (e.g., your 330 Ohm DUT) to the red and black clips !!!")     write_register(REG_CONTROL_MSB, CMD_INIT_START_FREQ)     time.sleep(0.1)     print("Measuring unknown impedance...")     timeout_start = time.time()     while not is_measurement_complete():         time.sleep(0.01)         if (time.time() - timeout_start) > 2.0:             print("Timeout waiting for unknown impedance measurement completion.")             return 0.0     real_data_unknown = read_16bit_signed(REG_REAL_DATA_MSB)     imag_data_unknown = read_16bit_signed(REG_IMAG_DATA_MSB)     magnitude_unknown = math.sqrt(float(real_data_unknown)**2 + float(imag_data_unknown)**2)     Z_unknown = 0.0     if magnitude_unknown > 0.0:         Z_unknown = 1.0 / (gain_factor * magnitude_unknown)         print(f"Measurement successful!")         print(f"  Real Data: {real_data_unknown}")         print(f"  Imag Data: {imag_data_unknown}")         print(f"  Magnitude: {magnitude_unknown:.2f}")         print(f"  Calculated Impedance: {Z_unknown:.2f} Ohms")     else:         print("Error: Unknown impedance magnitude is zero. This can indicate saturation or no signal.")     return Z_unknown if __name__ == "__main__":     try:         setup_ad5933()         if calibrate_ad5933():             input("\n*** IMPORTANT: Now disconnect your R_CAL and connect your UNKNOWN RESISTOR (e.g., your 330 Ohm DUT) to the red and black clips. Press Enter to continue... ***")             measured_z = measure_impedance()             print(f"\nFinal Measured Impedance: {measured_z:.2f} Ohms")         write_register(REG_CONTROL_MSB, CMD_STANDBY)         bus.close()         print("\nAD5933 in Standby mode. I2C bus closed.")     except Exception as e:         print(f"An error occurred: {e}")         if bus:             bus.close() 
\$\endgroup\$
1
  • \$\begingroup\$ Your code works with my AD5933, so I guess this has something to do with your setup. \$\endgroup\$ Commented Nov 11 at 9:03

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.