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:
- 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).
- 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).
- 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.
- 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.
- 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.
- 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()