Unexpected extra I2C cycle on Teensy 3.1

danjulio

Member
I am seeing an extra, unexpected, I2C cycle on Teensy 3.1. I expect two cycles:
  1. Write Register Address: 2 bytes [I2C device address + Write] + [device register address]
  2. Read Register Data: 2 bytes [I2C device address + Read] + [data from device]
after the Read Register Data I see another Write Register Address cycle. Why is this occurring? Am I doing something wrong or is there an issue in the Wire Library?

I've included both a test program below and screen shot from my scope. This test is an access to an accelerometer chip where we continue the cycle, however I also see the same behavior when accessing a temperature chip (tmp102) where we do not continue the cycle.

Code:
/*
 * Teensy I2C Wire Library test program
 *
 * Execute a very simple I2C operation for verification using an oscilloscope
 *
 * This test program reads the ID ("Who Am I") register in a MMA8452 accelerometer
 * chip.  The I2C access of this register consists of writing the ID register
 * address to the chip and then performing an I2C read to get the value.
 *
 */
#include <Wire.h>

// I2C address of the accelerometer
#define MMA8452_ADDRESS     0x1D

// Accelerometer ID Register address
#define ID_REG_ADDR         0x0D

// Expected ID Register value
#define ACCEL_ID            0x2A

void setup() {
  uint8_t regVal;
  
  Serial.begin(115200);
  Wire.begin();
  
  delay(5000);  // Allow the user to open the serial monitor & trigger the scope
  
  // Execute one access to the acceleromter to read the ID Register
  if (ReadAccelReg(MMA8452_ADDRESS, ID_REG_ADDR, &regVal)) {
    if (regVal == ACCEL_ID) {
      Serial.println("Successfully read ID Register");
    } else {
      Serial.printf("Got unexpected value from ID register: 0x%x\n", regVal);
    }
  } else {
    Serial.println("Register access failed");
  }
}

void loop() {
}

/* *****************************************************************************
 * ReadAccelReg - Read a register in a MMA8452 accelerometer
 *
 * On entry: a contains the I2C address of the accelerometer
 *           reg contains the address of the register to read
 *           *d contains a pointer to a uint8_t variable to receive the register value
 *
 * On exit: *d may be updated with the register value
 **************************************************************************** */
boolean ReadAccelReg(uint8_t a, uint8_t reg, uint8_t* d) {
  uint8_t n, s;
  
 // Reset the register pointer
  Wire.beginTransmission(a);
  n = Wire.write(reg);
  s = Wire.endTransmission(false);  // Do not release the bus for the subsequent read
  
  if (n != 1) {
    Wire.endTransmission(true); // Force release of the bus
    return false;
  } else if (s != 0) {
    Wire.endTransmission(true);
    return false;
  }
  
  // Read the register value
  n = Wire.requestFrom(a, (uint8_t) 1);
  s = Wire.endTransmission();
  
  if (n != 1) {
    return false;
  } else if (s != 0) {
    return false;
  }
  
  // Success: finally get the data
  *d = Wire.read();
  
  return true;
}

View attachment 1657
 
I don't think you need the Wire.endTransmission() after the wire.requestFrom() lines.

I use something like this:

int readI2C_Register(int Slave_Register) {
Wire.beginTransmission(I2CAddress); // Select address
Wire.write(Slave_Register); // sends one byte
Wire.endTransmission(false); // stop transmitting, with repeated start
Wire.requestFrom(I2CAddress, 1); // request 1 byte
// delayMicroseconds(10);
while(! Wire.available());
return Wire.read();
}
 
Back
Top