how to read from certain register address of i2c slave with wire.h library?

hi, everyone! I am learning "wire.h", I come across a problem, really confuse me.

the method Wire.requestFrom(address,numberofdata), the address is the slave's address, it is not the slave's register's address. for example, the i2c slave's address is 0x5A, the code Wire.requestFrom(0x5A,2) can read two 8-bits data from slave 0x5A, from the register address ox01 and 0x02.

but i want to read data from register address ,such as ox04, directly? how should i do?

my English is poor, wish i have made my question clear.

thanks very much!

Hi wounique

You need to look at the datasheet for the device you are using. Typically, you need to write a command to the device first using I2C, to specify which register to start reading from.

Regards

Ray

wounique:
the method Wire.requestFrom(address,numberofdata), the address is the slave's address, it is not the slave's register's address. for example, the i2c slave's address is 0x5A, the code Wire.requestFrom(0x5A,2) can read two 8-bits data from slave 0x5A, from the register address ox01 and 0x02.

but i want to read data from register address ,such as ox04, directly? how should i do?

You will have to select the register by using a write command.

Typical I2C read from a selected start register goes like that for reading two bytes from register 0x04 and 0x05:

  #define DEVICE_I2C_ADDRESS 0x5A  // this must be the I2C bus address of your device
  byte register4;
  byte register5;

  Wire.beginTransmission(DEVICE_I2C_ADDRESS); // select device with "beginTransmission()"
  Wire.write(0x04); // select starting register with "write()"
  Wire.endTransmission(); // end write operation, as we just wanted to select the starting register
  Wire.requestFrom(DEVICE_I2C_ADDRESS, 2); // select number of bytes to get from the device (2 bytes in this case)
  register4= Wire.read(); // read from the starting register
  register5= Wire.read(); // read next byte from the following register

OK?

Hackscribble:
Hi wounique

You need to look at the datasheet for the device you are using. Typically, you need to write a command to the device first using I2C, to specify which register to start reading from.

Regards

Ray

the datasheet says, i should write the slave address ,then write the register's address, but i don't know how to realize this action with wire.h library.

jurs:
You will have to select the register by using a write command.

Typical I2C read from a selected start register goes like that for reading two bytes from register 0x04 and 0x05:

  #define DEVICE_I2C_ADDRESS 0x5A  // this must be the I2C bus address of your device

byte register4;
  byte register5;

Wire.beginTransmission(DEVICE_I2C_ADDRESS); // select device with "beginTransmission()"
  Wire.write(0x04); // select starting register with "write()"
  Wire.endTransmission(); // end write operation, as we just wanted to select the starting register
  Wire.requestFrom(DEVICE_I2C_ADDRESS, 2); // select number of bytes to get from the device (2 bytes in this case)
  register4= Wire.read(); // read from the starting register
  register5= Wire.read(); // read next byte from the following register




OK?

i have a try with your code, and i think your code seems right, but the output data still begins from the first register:0x00.
this is the whole code:
#include "mpr121rdctrg.h"
#include <Wire.h>

int irqpin = 2; // Digital 2

void setup(){
pinMode(irqpin, INPUT);
digitalWrite(irqpin, HIGH); //enable pullup resistor

Serial.begin(9600);
Wire.begin();

mpr121_setup();
Serial.println("start");
}

void loop(){
readTouchInputs();
}

void readTouchInputs(){
if(!checkInterrupt()){

//read the touch state from the MPR121

Wire.beginTransmission(0x5A); // select device with "beginTransmission()"
Wire.write(0x04); // select starting register with "write()"
Wire.endTransmission(); // end write operation, as we just wanted to select the starting register

Wire.requestFrom(0x5A,2);

byte LSB = Wire.read();
byte MSB = Wire.read();

uint16_t touched = ((MSB << 8) | LSB); //16bits that make up the touch states
byte bit0=bitRead(touched,0);
Serial.print(bit0);
byte bit1=bitRead(touched,1);
Serial.print(bit1);
byte bit2=bitRead(touched,2);
Serial.print(bit2);
byte bit3=bitRead(touched,3);
Serial.print(bit3);
byte bit4=bitRead(touched,4);
Serial.print(bit4);
byte bit5=bitRead(touched,5);
Serial.print(bit5);
byte bit6=bitRead(touched,6);
Serial.print(bit6);
byte bit7=bitRead(touched,7);
Serial.print(bit7);
byte bit8=bitRead(touched,8);
Serial.print(bit8);
byte bit9=bitRead(touched,9);
Serial.print(bit9);
byte bit10=bitRead(touched,10);
Serial.print(bit10);
byte bit11=bitRead(touched,11);
Serial.print(bit11);
Serial.println();

}
}

void mpr121_setup(void){

set_register(0X5A, ELE_CFG, 0x00);

// Section A - Controls filtering when data is > baseline.
set_register(0X5A, MHD_R, 0x01);
set_register(0X5A, NHD_R, 0x01);
set_register(0X5A, NCL_R, 0x00);
set_register(0X5A, FDL_R, 0x00);

// Section B - Controls filtering when data is < baseline.
set_register(0X5A, MHD_F, 0x01);
set_register(0X5A, NHD_F, 0x01);
set_register(0X5A, NCL_F, 0xFF);
set_register(0X5A, FDL_F, 0x02);

// Section C - Sets touch and release thresholds for each electrode
set_register(0X5A, ELE0_T, TOU_THRESH);
set_register(0X5A, ELE0_R, REL_THRESH);

set_register(0X5A, ELE1_T, TOU_THRESH);
set_register(0X5A, ELE1_R, REL_THRESH);

set_register(0X5A, ELE2_T, TOU_THRESH);
set_register(0X5A, ELE2_R, REL_THRESH);

set_register(0X5A, ELE3_T, TOU_THRESH);
set_register(0X5A, ELE3_R, REL_THRESH);

set_register(0X5A, ELE4_T, TOU_THRESH);
set_register(0X5A, ELE4_R, REL_THRESH);

set_register(0X5A, ELE5_T, TOU_THRESH);
set_register(0X5A, ELE5_R, REL_THRESH);

set_register(0X5A, ELE6_T, TOU_THRESH);
set_register(0X5A, ELE6_R, REL_THRESH);

set_register(0X5A, ELE7_T, TOU_THRESH);
set_register(0X5A, ELE7_R, REL_THRESH);

set_register(0X5A, ELE8_T, TOU_THRESH);
set_register(0X5A, ELE8_R, REL_THRESH);

set_register(0X5A, ELE9_T, TOU_THRESH);
set_register(0X5A, ELE9_R, REL_THRESH);

set_register(0X5A, ELE10_T, TOU_THRESH);
set_register(0X5A, ELE10_R, REL_THRESH);

set_register(0X5A, ELE11_T, TOU_THRESH);
set_register(0X5A, ELE11_R, REL_THRESH);

// Section D
// Set the Filter Configuration
// Set ESI2
set_register(0X5A, FIL_CFG, 0x04);

// Section E
// Electrode Configuration
// Set ELE_CFG to 0x00 to return to standby mode
set_register(0X5A, ELE_CFG, 0x0C); // Enables all 12 Electrodes

// Section F
// Enable Auto Config and auto Reconfig
/set_register(0X5A, ATO_CFG0, 0x0B);
set_register(0X5A, ATO_CFGU, 0xC9); // USL = (Vdd-0.7)/vdd
256 = 0xC9 @3.3V set_register(0X5A, ATO_CFGL, 0x82); // LSL = 0.65USL = 0x82 @3.3V
set_register(0X5A, ATO_CFGT, 0xB5);
/ // Target = 0.9*USL = 0xB5 @3.3V

set_register(0X5A, ELE_CFG, 0x01);

}

boolean checkInterrupt(void){
return digitalRead(irqpin);
}

void set_register(int address, unsigned char r, unsigned char v){
Wire.beginTransmission(address);
Wire.write(r);
Wire.write(v);
Wire.endTransmission();
}

wounique:
i have a try with your code, and i think your code seems right, but the output data still begins from the first register:0x00.

I think you have basic programming problems with "bitshifting" and "bitwise or" operations, dealing with 8-bit "byte" and 16-bit "int" data types.

If you have a "byte" which is an 8-bit value and you shift the value 8 bits to the left, you always get 0 as the result.

Perhaps you better read the values into "unsigned int" before, if you want to shift 8 bits to the left afterwards:

  unsigned int LSB = Wire.read();
  unsigned int MSB = Wire.read();

Or do it more elegantly and read both bytes into your final variable "touched" directly, without helping variables LSB and MSB, which are not really needed.

jurs:
I think you have basic programming problems with "bitshifting" and "bitwise or" operations, dealing with 8-bit "byte" and 16-bit "int" data types.

If you have a "byte" which is an 8-bit value and you shift the value 8 bits to the left, you always get 0 as the result.

Perhaps you better read the values into "unsigned int" before, if you want to shift 8 bits to the left afterwards:

  unsigned int LSB = Wire.read();

unsigned int MSB = Wire.read();




Or do it more elegantly and read both bytes into your final variable "touched" directly, without helping variables LSB and MSB, which are not really needed.

the shifting works ok! this is the output read from register 0x00 and 0x01:

000000000011
000000000111
000000111110
000001111000
000111100000
001110000000
011100000000
111100000000
011110000000
000001111000
000000011111
000000000111
000000000011
000000000111
000000111100
001111100000
111100000000
111000000000
111100000000
000111110000
000000011111

maybe we didn't do reading as the chip's datasheet show, the datasheet is list below, if you are convenient, please have look at it, thanks.

wounique:
maybe we didn't do reading as the chip's datasheet show

Maybe. I don't know what you have read and what not.

Did you read this:

Features
• 1.71 V to 3.6 V supply operation

Most Arduino boards operate on 5 Volts.

So what about your circuit schematics?

  • which Arduino board?
  • which Arduino board voltage?
  • pull-up resistors on I2C bus and how connected?

jurs:
Maybe. I don't know what you have read and what not.

Did you read this:

Features
• 1.71 V to 3.6 V supply operation

Most Arduino boards operate on 5 Volts.

So what about your circuit schematics?

  • which Arduino board?
  • which Arduino board voltage?
  • pull-up resistors on I2C bus and how connected?

I have read the datasheet from first page to the last, the output data(12 bits) of the first two registers are the touch state(1 means touched and 0 means untouched),the output data is coincidence with the pin I touched, so the I2C circuit is ok, the pull-up resistors mentioned reminds me that this board certainly has no pull-up resistors, but why it works? I have also bought another PCB board for mpr121, this board has pull-up resistors, I will have a try. Regarding to supply voltage, my Arduino is UNO, it has 3.3v and 5v pin, the supply is ok.

I have a try with the board which has pull-up resistors, it works the same, read data from 0x00 and 0x01.

jurs:
Maybe. I don't know what you have read and what not.

Did you read this:

Features
• 1.71 V to 3.6 V supply operation

Most Arduino boards operate on 5 Volts.

So what about your circuit schematics?

  • which Arduino board?
  • which Arduino board voltage?
  • pull-up resistors on I2C bus and how connected?

maybe I find the reasons: please have a look at this website:

it says wire.h doesn't support re-start action, the mpr121 actually need re-start to read data. i don't know if Arduino UNO supports i2c.h library, i will have a try.

http://playground.arduino.cc/Main/SoftwareI2CLibrary