What to expect when reading from a register using I2C

Hi,
I'm trying to check the value of a bit in a byte register.
To start, this is the readRegister function for the i2c
ignore the SPI_MODE part

//  ReadRegister
//
//  Parameters:
//    *outputPointer -- Pass &variable (address of) to save read data to
//    offset -- register to read
//
//****************************************************************************//
status_t LSM6DS3Core::readRegister(uint8_t* outputPointer, uint8_t offset) {
	//Return value
	uint8_t result = 0;
	uint8_t numBytes = 1;
	status_t returnError = IMU_SUCCESS;

	switch (commInterface) {

	case I2C_MODE:
		Wire.beginTransmission(I2CAddress);
		Wire.write(offset);
		if( Wire.endTransmission() != 0 )
		{
			returnError = IMU_HW_ERROR;
		}
		Wire.requestFrom(I2CAddress, numBytes);
		while ( Wire.available() ) // slave may send less than requested
		{
			result = Wire.read(); // receive a byte as a proper uint8_t
		}
		break;

	case SPI_MODE:
		// take the chip select low to select the device:
		digitalWrite(chipSelectPin, LOW);
		// send the device the register you want to read:
		SPI.transfer(offset | 0x80);  //Ored with "read request" bit
		// send a value of 0 to read the first byte returned:
		result = SPI.transfer(0x00);
		// take the chip select high to de-select:
		digitalWrite(chipSelectPin, HIGH);
		
		if( result == 0xFF )
		{
			//we've received all ones, report
			returnError = IMU_ALL_ONES_WARNING;
		}
		break;

	default:
		break;
	}

	*outputPointer = result;
	return returnError;
}

Here is my register, the FUNC_SRC in highlighted in yellow

This is what i do to read from it.

// Tilt detection check
//
//***************************************************************************//
uint8_t LSM6DS3::readTilt( void )
{
  uint8_t output;
  readRegister(&output, LSM6DS3_ACC_GYRO_FUNC_SRC);
  return output;
}

readRegister reads a byte and the FUNC_SRC is a byte, unless i'm wrong ?? am i ??
Does readRegister reads the whole byte and packs them up into the output variable ?
How do i get the value of the 5'th bit of FUNC_SRC, from the output variable ??
the 5'th bit is TILT_IA.

It would really help a lot.
kind regards,
gitduino

Using bitRead() would be a convenient way to get the value
https://www.arduino.cc/reference/en/language/functions/bits-and-bytes/bitread/

If you are going to read just one byte, then why use a while-loop ?
I know you took it from the Sparkfun source code, but that does not mean that you have to write the same cheesy code.
I think that this makes more sense:

    Wire.requestFrom(I2CAddress, 1);
    if (Wire.available() == 1)
    {
      result = Wire.read();
    }

This command is wrong and can be removed: "// slave may send less than requested".

You can turn a parameter that is a pointer into "by reference". Then the source code is easier to read.

Hello

The most common way to get the value of a bit N is to shift N bits to the right, and mask the result with 1 so to keep only the right-most bit.

Example to get the value of bit 5

0b10010111
>> 5
= 0b00000100
& 0b00000001
= 0b00000000

Code : uint8_t bit5 = (value >> 5) & 1;

As said you can use the bitRead macro (it will do exactly the same thing), but now you know how it works :slight_smile:

Hi guys,
thanks for the reply.
alright so this is how i get the byte from the register.

uint8_t LSM6DS3::sensor( void )
{
  uint8_t output;
  readRegister(&output, LSM6DS3_ACC_GYRO_FUNC_SRC);
  return output;
}

So if i'm supposed to use bitRead(x, n);
then i replace the x with output then the n is 5 right ?
example:

int something = 0;
something = bitRead(output, 5);

the return output definitely does contain some values
but when i print output
say,

Serial.print(output);

I get 0 as a result
I know uint8_t returns a byte
after return output, should i convert the content of output into another type
before bitRead(x, n); ??
or perhaps using uint8_t isn't the right approach to extract byte from the register

The bitRead() accepts all variables. It is not even a function but a macro.
It is located in Arduino.h: https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/Arduino.h#L111

#define bitRead(value, bit) (((value) >> (bit)) & 0x01)

The return value is 0 or 1.

The bit number starts counting from 0.
Bit 0 is always shown on the right.

You don't need to test this with I2C. You can make a small sketch with a value and print that value hexadecimal, binary and with bitRead().

If your variable 'something' is zero, then that bit was really zero.
Please show a full sketch. There is a website for that: https://snippets-r-us.com/

Hi Keopel,
Here is the full main sketch

#include "SparkFunLSM6DS3.h"
#include <Wire.h>
LSM6DS3 xMEMS; // addr 0x6B i2c
bool start_up = false;

int something; // check tilt

void setup()
{

  Serial.begin(9600);
  Wire.begin();
  delay(10);
  if(xMEMS.beginCore() != 0){
    Serial.println("lsm6ds3 sensor is invalid!");
    start_up = false;
    
  }
  else{
    Serial.println("passed!");
    start_up = true;
    xMEMS.begin();
    xMEMS.tiltDetect();
  }

}

void loop()
{
  something = xMEMS.sensor();
  Serial.println(bitRead(something, 5));// bitRead(x, n)
  delay(1000);
    
}

What do you see when you print the something variable in binary ?

Hi UKHeliBob,
this is what i get as a result of printing something variable in binary

#include "SparkFunLSM6DS3.h"
#include <Wire.h>
LSM6DS3 xMEMS; // addr 0x6B i2c
bool start_up = false;

int something; // check tilt

void setup()
{

  Serial.begin(9600);
  Wire.begin();
  delay(10);
  if(xMEMS.beginCore() != 0){
    Serial.println("lsm6ds3 sensor is invalid!");
    start_up = false;
    
  }
  else{
    Serial.println("passed!");
    start_up = true;
    xMEMS.begin();
    xMEMS.tiltDetect();
  }

}

void loop()
{
  something = xMEMS.sensor();
  Serial.println(something, BIN);
  delay(1000);
    
}

result is

Processor came out of reset.


passed!
0
0
0
0
0
0
0

  Serial.println(something, BIN);

did not produce this output

Processor came out of reset.


passed!
0
0
0
0
0
0
0

but as you have found the value of the variable was zero so bitRead() was returning the correct value