I2C read - is there anything wrong with this code?

Because I am getting back nothing but 255 (0b11111111) from the device and I don't understand why.

m_nDevAddrRead == 3Dh as per the data sheet.

What AM I doing wrong?

uint8_t Adafruit_Sensor::readReg8(uint8_t nRegAddr)
{
	uint8_t nValue;

	Wire.beginTransmission(m_nDevAddrRead);
	#if ARDUINO >= 100
		Wire.write(nRegAddr);
	#else
		Wire.send(nRegAddr);
	#endif
	Wire.requestFrom(nRegAddr, (uint8_t)1);
	#if ARDUINO >= 100
		nValue = Wire.read();
	#else
		nValue = Wire.receive();
	#endif  
	Wire.endTransmission();

	Serial.print("nValue = ");
	Serial.print(nValue, BIN);
	Serial.println("");
	Serial.print("nRegAddr = ");
	Serial.print(nRegAddr, HEX);
	Serial.println("");
	Serial.print("m_nDevAddrRead = ");
	Serial.print(m_nDevAddrRead, HEX);
	Serial.println("");

	return nValue;
}

First thing that I always do is run the I2C scanner to confirm the address and communication.
Are you including Wire.h in your .ino file? Do you have Wire.begin() in setup?

// I2C scanner by Nick Gammon.  Thanks Nick.

#include <Wire.h>

void setup() {
  Serial.begin (115200);

  // Leonardo: wait for serial port to connect
  while (!Serial) 
    {
    }

  Serial.println ();
  Serial.println ("I2C scanner. Scanning ...");
  byte count = 0;
  
  Wire.begin();
  for (byte i = 1; i < 120; i++)
  {
    Wire.beginTransmission (i);
    if (Wire.endTransmission () == 0)
      {
      Serial.print ("Found address: ");
      Serial.print (i, DEC);
      Serial.print (" (0x");
      Serial.print (i, HEX);
      Serial.println (")");
      count++;
      delay (1);  // maybe unneeded?
      } // end of good response
  } // end of for loop
  Serial.println ("Done.");
  Serial.print ("Found ");
  Serial.print (count, DEC);
  Serial.println (" device(s).");
}  // end of setup

void loop() {}

I ran the device scanner sketch and get 1E depending with the SDO pin low.

I have checked the return value from Wire.endTransmission() on my regRead(...) and regWrite(...)
functions and I get 0 / successful.

But no matter what damn register I read I get a return value of FF / 255., including the WHO_AM_I register / 0Fh.

So what could I possibly be doing wrong?

If I download the adafruit LSM303D library I can get some sensible output out of it although it seemed a bit 'jumpy'.

But as soon as I use my own library I get nothing.

Here is my readReg(...)

uint8_t CSensor::readReg8(uint8_t nRegAddr)
{
	uint8_t nValue;

	Wire.beginTransmission(m_nDevAddrRead);
	#if ARDUINO >= 100
		Wire.write(nRegAddr);
	#else
		Wire.send(nRegAddr);
	#endif
	Wire.requestFrom(nRegAddr, (uint8_t)1);
	#if ARDUINO >= 100
		nValue = Wire.read();
	#else
		nValue = Wire.receive();
	#endif  
	m_nWireError = Wire.endTransmission();

	Serial.println("@@@@@@@@@@@@@@@@@@@@@");
	Serial.println(nRegAddr, HEX);
	Serial.println(m_nDevAddrRead, HEX);
	Serial.println("");
	Serial.println(m_nWireError);
	Serial.println("");
	Serial.println(nValue, HEX);
	Serial.println("@@@@@@@@@@@@@@@@@@@@@");

	return nValue;
}
The out out of those println(...) calls is as follows.
Correct register address.
Correct device address.
No error condition.
But total garbage as the contents of the register.

@@@@@@@@@@@@@@@@@@@@@
F
1E

0

FF
@@@@@@@@@@@@@@@@@@@@@

I changed my I2C readReg(...) to the following to try and get more info.

bool CSensor::dataReady(uint8_t nNumBytes)
{
	uint32_t nMillisStart = millis(), nDeltaMillis = 0;
	
	m_nWireError = 0;
	
	while ((Wire.available() < nNumBytes) && (m_nWireError == 0))
	{
Serial.println(nDeltaMillis);
Serial.println(Wire.available());
Serial.println(m_nI2CTimeOut);
Serial.println("");
		nDeltaMillis = millis() - nMillisStart;
		if (nDeltaMillis > m_nI2CTimeOut)
			m_nWireError = 5;
    }
	return m_nWireError == 0;
}

uint8_t CSensor::readReg8(uint8_t nRegAddr)
{
	uint8_t nValue = 0;

	Wire.beginTransmission(m_nDevAddrRead);
	#if ARDUINO >= 100
		Wire.write(nRegAddr);
	#else
		Wire.send(nRegAddr);
	#endif
	m_nWireError = Wire.endTransmission();
	
	if (m_nWireError == 0)
	{
		Wire.requestFrom(nRegAddr, (uint8_t)1);
		if (dataReady(1))
		{
			#if ARDUINO >= 100
				nValue = Wire.read();
			#else
				nValue = Wire.receive();
			#endif  
			m_nWireError = Wire.endTransmission();

			Serial.println("@@@@@@@@@@@@@@@@@@@@@");
			Serial.println(nRegAddr, HEX);
			Serial.println(m_nDevAddrRead, HEX);
			Serial.println("");
			Serial.println(m_nWireError);
			Serial.println("");
			Serial.println(nValue, HEX);
			Serial.println("@@@@@@@@@@@@@@@@@@@@@");
		}
		else
			m_nWireError = 5;
	}
	return nValue;
}

In the serial monitor that dataReady(...) function counts all the way up to 2000 ms with wire.available() always returning 0.

So I just don't get it.

What is the fundamental difference between my code and the code above from the similar code in the LSM303 library that does work with my device????? I just can't see it!

// Reads the 3 accelerometer channels and stores them in vector a
void LSM303::readAcc(void)
{
  Wire.beginTransmission(acc_address);
  // assert the MSB of the address to get the accelerometer
  // to do slave-transmit subaddress updating.
  Wire.write(OUT_X_L_A | (1 << 7));
  last_status = Wire.endTransmission();
  Wire.requestFrom(acc_address, (byte)6);

  unsigned int millis_start = millis();
  while (Wire.available() < 6) {
    if (io_timeout > 0 && ((unsigned int)millis() - millis_start) > io_timeout)
    {
      did_timeout = true;
      return;
    }
  }

  byte xla = Wire.read();
  byte xha = Wire.read();
  byte yla = Wire.read();
  byte yha = Wire.read();
  byte zla = Wire.read();
  byte zha = Wire.read();

  // combine high and low bytes
  // This no longer drops the lowest 4 bits of the readings from the DLH/DLM/DLHC, which are always 0
  // (12-bit resolution, left-aligned). The D has 16-bit resolution
  a.x = (int16_t)(xha << 8 | xla);
  a.y = (int16_t)(yha << 8 | yla);
  a.z = (int16_t)(zha << 8 | zla);
}

boylesg:
I changed my I2C readReg(...) to the following to try and get more info.

bool CSensor::dataReady(uint8_t nNumBytes)

{
uint32_t nMillisStart = millis(), nDeltaMillis = 0;

m_nWireError = 0;

while ((Wire.available() < nNumBytes) && (m_nWireError == 0))
{
Serial.println(nDeltaMillis);
Serial.println(Wire.available());
Serial.println(m_nI2CTimeOut);
Serial.println("");
nDeltaMillis = millis() - nMillisStart;
if (nDeltaMillis > m_nI2CTimeOut)
m_nWireError = 5;
   }
return m_nWireError == 0;
}

uint8_t CSensor::readReg8(uint8_t nRegAddr)
{
uint8_t nValue = 0;

Wire.beginTransmission(m_nDevAddrRead);
#if ARDUINO >= 100
Wire.write(nRegAddr);
#else
Wire.send(nRegAddr);
#endif
m_nWireError = Wire.endTransmission();

if (m_nWireError == 0)
{
Wire.requestFrom(nRegAddr, (uint8_t)1);
if (dataReady(1))
{
#if ARDUINO >= 100
nValue = Wire.read();
#else
nValue = Wire.receive();
#endif  
m_nWireError = Wire.endTransmission();

Serial.println("@@@@@@@@@@@@@@@@@@@@@");
Serial.println(nRegAddr, HEX);
Serial.println(m_nDevAddrRead, HEX);
Serial.println("");
Serial.println(m_nWireError);
Serial.println("");
Serial.println(nValue, HEX);
Serial.println("@@@@@@@@@@@@@@@@@@@@@");
}
else
m_nWireError = 5;
}
return nValue;
}




In the serial monitor that dataReady(...) function counts all the way up to 2000 ms with wire.available() always returning 0.

So I just don't get it.

What is the fundamental difference between my code and the code above from the similar code in the LSM303 library that does work with my device????? I just can't see it!



// Reads the 3 accelerometer channels and stores them in vector a
void LSM303::readAcc(void)
{
 Wire.beginTransmission(acc_address);
 // assert the MSB of the address to get the accelerometer
 // to do slave-transmit subaddress updating.
 Wire.write(OUT_X_L_A | (1 << 7));
 last_status = Wire.endTransmission();
 Wire.requestFrom(acc_address, (byte)6);

unsigned int millis_start = millis();
 while (Wire.available() < 6) {
   if (io_timeout > 0 && ((unsigned int)millis() - millis_start) > io_timeout)
   {
     did_timeout = true;
     return;
   }
 }

byte xla = Wire.read();
 byte xha = Wire.read();
 byte yla = Wire.read();
 byte yha = Wire.read();
 byte zla = Wire.read();
 byte zha = Wire.read();

// combine high and low bytes
 // This no longer drops the lowest 4 bits of the readings from the DLH/DLM/DLHC, which are always 0
 // (12-bit resolution, left-aligned). The D has 16-bit resolution
 a.x = (int16_t)(xha << 8 | xla);
 a.y = (int16_t)(yha << 8 | yla);
 a.z = (int16_t)(zha << 8 | zla);
}

Your are not using the Arduino's I2C Wire.h library correctly.

// to send data to a device.
Wire.beginTransmission(byte); // address of I2C (7bit value 0x08 .. 0x78) 0x00..0x07 and 0x79..0x7F are reserved for special function,  You can uses them at your parel.
 
Wire.write(byte);  // the byte to send, limited to 31 bytes at a time.
Wire.endTransmission();  // actually do the I2C transaction.

//to Receive data from a device

Wire.requestFrom(byte,byte); // the first byte is the 7bit I2C address, the Second is howmany byte to request.
  // a maximum to 31 is possible at one time.
while(Wire.available()){ // available returns a count of bytes in input buffer
  char ch = Wire.read();
  }

Don't put Wire.endTransmission() after Wire.requestFrom().
Chuck.

I figured it out - I used the register address in Serial.requestFrom(...) rather than the device address.