This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

FDC2212: Trouble reading and writing to the sensor using I2C protocol in Arduino Environment

Part Number: FDC2212

Hi TI team,

I am trying to program the FDC2212 sensor registers using the Teensy board and I am having difficulty with using I2C protocol to read/write from registers. I believe that the register address is 8bits and each register contains 16bits. In my debugging, when I attempt to read from registers after writing, I keep getting 1111111111111111 as the output. I have tried exploring various solutions (including the code Josue kindly provided in FDC2214 in the Arduino environment - Sensors forum - Sensors - TI E2E support forums) but I am still having this issue. Any advice or feedback is appreciated. My code is below:

#define CDC_I2C_ADDR 0x2B
#define SDA1 17
#define SCL1 16
uint16_t I2CReadRegister(uint8_t registerAddr){
  Wire.beginTransmission(CDC_I2C_ADDR);
  Wire.write(registerAddr);
  Wire.endTransmission();

  Wire.requestFrom(CDC_I2C_ADDR, 2); // This register is 16 bits = 2 bytes long

  // Read into a 2-byte buffer
  byte buf[2];
  uint8_t b1 = Wire.read();
  uint8_t b2 = Wire.read();

  uint16_t val = (b1 << 8) | b2;

  return val;
}

void I2CwriteRegister(uint8_t registerAddr, uint8_t val, uint8_t val2) {
  byte writeArray[2];

  writeArray[0] = val;
  writeArray[1] = val2;

  Wire.beginTransmission(CDC_I2C_ADDR);
  Wire.write(registerAddr);
  Wire.write(writeArray, 2);
  Wire.endTransmission();
}

void setup() {
  Wire.setSDA(SDA1);
  Wire.setSCL(SCL1);
 
  Wire.begin();
  Wire.setClock(100000); // speed of I2C interface, max value 400kbits
  Serial.begin(9600); // Default to 9600 baud rate for COM port
  initCDC();
  
}
void initCDC() {
  // Setting clock dividers for Ch0 and Ch1
  // Affected fields: CHx_FIN_SEL, CHx_FREF_DIVIDER
  // CHx_FIN_SEL: b01 divide by 1. Choose for sensor frequencies between 0.01MHz and 8.75MHz (expected ~5-6 MHz)
  // CHx_FREF_DIVIDER: Sets the divider for channel x reference. Use this to scale the maximum conversion frequency.
  I2CwriteRegister(CLOCK_DIVIDERS_CH0, 0b00010000, 0b00000001); // finalized b0001_00_0000000001
  //I2CwriteRegister(CLOCK_DIVIDERS_CH1, 0b00010000, 0b00000001); // finalized b0001_00_0000000001

  Serial.println(I2CReadRegister(CLOCK_DIVIDERS_CH0), BIN);
  //I2CReadRegister(CLOCK_DIVIDERS_CH1);

  // Sensor drive current: ensure oscillation amplitude is between 1.2V and 1.8V
  // Affected fields: CHx_IDRIVE
  // CHx_IDRIVE: defines the Drive Current used during the settling + conversion time of the channel x sensor clock. Set such that 1.2V <= sensor oscillation amplitude (pk) <= 1.8V
  // Notes: Measure Vpk with an oscilloscope and adjust the IDRIVE value manually
  //I2CwriteRegister(DRIVE_CURRENT_CH0, 0b00000000, 0b00000000); // not finalized: start with 0.108mA and measure the voltage then retry. b11000_00000000000
  //I2CwriteRegister(DRIVE_CURRENT_CH1, 0b00000000, 0b00000000); // not finalized b00111_00000000000 set to 0.044mA, can take it down as long as sensor activates

  //I2CReadRegister(DRIVE_CURRENT_CH0);
  //I2CReadRegister(DRIVE_CURRENT_CH1);

  // Sensor activation time: The amount of settling time required for the sensor oscillation to stablize
  // Set to a value that is long enough to allow stable oscillation.
  // The FDC will use this settling time to allow the LC sensor to stabilize before initiation of a conversion on Channel 0.
  // If the amplitude has not settled prior to the conversion start, an Amplitude warning will be generated if reporting of this type of warning is enabled.
  // Affected fields: CHx_SETTLECOUNT
  //I2CwriteRegister(SETTLECOUNT_CH0, 0b00000000, 0b11111111); // not finalized: set to 100 clk cycles b0000000001100100
  //I2CwriteRegister(SETTLECOUNT_CH1, 0b00000000, 0b00000111); // finalized to minimum allowed value (dummy channel) b0000000000000100

  //I2CReadRegister(SETTLECOUNT_CH0);
  //I2CReadRegister(SETTLECOUNT_CH1);

  // The number of reference clock cycles used to measure the sensor frequency. Higher the number, the longer the conversion time.
  // Affected fields: CHx_RCOUNT
  //I2CwriteRegister(RCOUNT_CH0, 0b00100000, 0b00000000); // not finalized: start with ENOB = 13bits and then readjust as needed b0010000000000000
  //I2CwriteRegister(RCOUNT_CH1, 0b00000000, 0b00001001); // finalized to minimum allowed value (dummy channel) b0000000000001001

  //I2CReadRegister(RCOUNT_CH0);
  //I2CReadRegister(RCOUNT_CH1);

  // Enable interrupts to report status and error conditions (also referred to as ERROR_CONFIG in datasheet)
  // Affected fields: ERROR_CONFIG
  // WD_ERR2OUT: b1 Report Watchdog Timeout errors in DATA_CHx.CHx_ERR_WD register field
  // AH_WARN2OUT: b1 Report Amplitude High warnings in the DATA_CHx.CHx_ERR_AW register field
  // WD_ERR2INT, DRDY_2INT: General Watchdog Timeout error and Data Ready Flag set to off since we want specific flags for CH0 only.
  // Only care about CH0 and ignore the flags in CH1 (dummy channel)
  //I2CwriteRegister(STATUS_CONFIG, 0b00110000, 0b00000000); // not finalized: should toggle between AH_WARN2OUT and AL_WARN2OUT for amplitude errors. b00_1_1_0_00000_0_0000_0
  //I2CReadRegister(STATUS_CONFIG);

  // Channel Multiplexing Configuration
  // Affected Fields: AUTOSCAN_EN, RR_SEQUENCE, DEGLITCH
  // AUTOSCAN_EN, RR_SEQUENCE: b00 Enable multi-channel operation, scanning on Ch0, Ch1
  // DEGLITCH: b101 set input deglitch filter bandwidth to 10MHz, the lowest setting that exceeds the oscillation tank oscillation frequency (~5-6 MHz). b1_00_0001000001_101
  //I2CwriteRegister(MUX_CONFIG, 0b10000010, 0b00001101);
  //I2CReadRegister(MUX_CONFIG);

  // Device Configuration (this register write must occur last because device configuration is not permitted while the FDC is in active mode).
  // Affected Fields: ACTIVE_CHAN, SLEEP_MODE_EN, SENSOR_ACTIVATE_SEL, REF_CLK_SRC, INTB_DIS, HIGH_CURRENT_DRV
  // ACTIVE_CHAN: inconsequential since we are running in multichannel operation
  // SLEEP_MODE_EN: b0 exit Sleep mode to begin conversion process
  // SENSOR_ACTIVATE_SEL: b0 set to Full Current Activation Mode - the FDC will drive maximum sensor current for a shorter sensor activation time.
  // REF_CLK_SRC: b1 use the external clock frequency 40MHz
  // INTB_DIS: the INTB pin will be asserted when status register updates.
  // HIGH_CURRENT_DRV: b0 The FDC will drive all channels with normal sensor current (1.5mA max).
  //I2CwriteRegister(CONFIG, 0b00010110, 0b00000001); // not finalized: toggle SENSOR_ACTIVATE_SEL if Vpk is too high >1.8V b00_0_1_0_1_1_0_0_0_000001
  //I2CReadRegister(CONFIG);

  Serial.println("Done.");
}

Many thanks,

Shane

  • Hi Shane,

    TI does not have Arduino code available for the FDC2212, but I was able to find the code below, which could be useful.  Be sure that you have pull up resistors on the I2C lines also since I2C is open drain.  Typically, a value of 4.7k ohms is good.

    https://github.com/zharijs/FDC2214 

  • Hi Eddie,


    Thank you for the suggestion. I have 4.7k ohms for my pull resistors already. Unfortunately the code did not resolve the issue. I will continue to work on it and see if I can get it to work.

  • No problem.  If you have a logic analyzer available, a good next step would be to check what the Arduino is actually putting out on the bus.

  • Thank you Eddie,

    I was debugging with the logic analyzer earlier to scan for the I2C messages on the data and clk lines. I have managed to resolve the issue by using the correct wire ports for the wire library on the microcontroller and in the code. It appears that I was using Wire which default I2C ports are SDA = 18, SCL = 19, but instead I was using a different pair of I2C ports on the microcontroller that should've been referenced using Wire1.

    Wire Arduino Library, connecting I2C (TWI) devices to Teensy (pjrc.com)

    I note that the addresses for the registers in the FDC sensor are 1 byte long whereas the data contained within each register are 2 bytes long. I modified the read and write functions as such and they work for me. I debugged based off the Example Program from the above link with some modifications to the read/write calls. Below is my debugging code which I got to successfully work. Thank you kindly for your help and I will post on the forum again if I encounter any new problems I'm struggling with.

    // Include I2C libraries
    #include <Wire.h>

    // Register definitions for FDC2212

    #define DATA_CH0 0x00 // Channel 0 MSB Conversion Result and status
    #define DATA_LSB_CH0 0x01 // Channel 0 LSB Conversion Result and status
    #define DATA_CH1 0x02 // Channel 1 MSB Conversion Result and status
    #define DATA_LSB_CH1 0x03 // Channel 1 LSB Conversion Result and status

    #define RCOUNT_CH0 0x08 // Reference Count setting for Channel 0
    #define RCOUNT_CH1 0x09 // Reference Count setting for Channel 1

    #define SETTLECOUNT_CH0 0x10 // Channel 0 Settling Reference Count
    #define SETTLECOUNT_CH1 0x11 // Channel 1 Settling Reference Count

    #define CLOCK_DIVIDERS_CH0 0x14 // Reference divider settings for Channel 0
    #define CLOCK_DIVIDERS_CH1 0x15 // Reference divider settings for Channel 1

    // status registers are for debugging purposes only
    #define STATUS 0x18 // Device Status Reporting
    #define STATUS_CONFIG 0x19 // Device Status Reporting Configuration

    #define CONFIG 0x1A // Conversion Configuration
    #define MUX_CONFIG 0x1B // Channel Multiplexing Configuration
    #define RESET_DEV 0x1C // Reset Device

    #define DRIVE_CURRENT_CH0 0x1E // Channel 0 sensor current drive configuration
    #define DRIVE_CURRENT_CH1 0x1F // Channel 1 sensor current drive configuration

    #define MANUFACTURER_ID 0x7E // Manufacturer ID
    #define DEVICE_ID 0x7F // Device ID

    /* I2C Interface Specifications: This sequence follows the standard I2C 7-bit slave address followed by an 8-bit pointer
    register byte to set the register address. When the ADDR pin is set low, the FDC I2C address is 0x2A; when the
    ADDR pin is set high, the FDC I2C address is 0x2B. The ADDR pin must not change state after the FDC exits
    Shutdown Mode. */
    #define CDC_I2C_ADDR 0x2B
    #define SDA1 17
    #define SCL1 16
    #define SD 14

    int cycle=0;
    byte num=10;

    void setup() {
      Wire.begin();
      Serial.begin(9600);
      // pull shutdown pin low to disable shutdown mode
      pinMode(SD, OUTPUT);
      digitalWrite(SD, LOW);

      delay(1000);
    }

    void loop()  {
      byte a = 0;

      delay(2000);
     
      // I2C Write //
      Serial.println("before read " + String(cycle));
      Serial.print("num = ");
      Serial.println(num, DEC);  

      Wire.beginTransmission(CDC_I2C_ADDR);
      Wire.write(SETTLECOUNT_CH0);    // address
      Wire.write(0);    // send high byte
      Wire.write(num);  // send low byte
      Wire.endTransmission();
     
      // next time loop runs, it should retrieve the
      // same number it wrote last time... even if you
      // shut off the power
      delay(2000);

      // I2C Read //
      Wire.beginTransmission(CDC_I2C_ADDR);
      Wire.write(SETTLECOUNT_CH0);  // address
      Wire.endTransmission();
     
      // read 2 byte, from address 0x2B
      Wire.requestFrom(CDC_I2C_ADDR, 2);
      while(Wire.available()) {
        a = Wire.read();
        num = Wire.read();
      }
      Serial.println("after read " + String(cycle));
      Serial.print("num = ");
      Serial.println(num, DEC);  
     
      // increment num
      num = num + 1;
      ////////

      cycle++;

    }