I2C, understanindg SAK, MAK, ST and SR with Arduino "wire" library

Greetings everybody. I’ve been searching on the web how to implement an I2C communication. But, I think that I have a lot of things to learn first. I’ve been reading about it, but I haven’t been able to really understand it.

To make an example, let me show the next protocol of the sensor that I’m using.

147724030987743.png

By showing the commands, here are a couple of questions that I have.

  • Which is the command that I should send to “ST” and “HwADDR”? According to the datasheet I should send 0x18.
  • After sending this command, the “SAK (Slave Acknowledgement)” is going to send a command. How do I read it or interpret it with the Arduino?.
  • The master will send “0x31”, ad the Slave will answer back again with a “SAK”. The master will send a “SR (Start repeat)”. Will I have to repeat all the previous commands so far? Which would be the start repeat in the wire library?

My question can be reduced to the following. How do I read or interprete the “ST”, “SR”, “SAK” and “MAK”, using the Arduino wire library. Is it a pulse? How can I read it?

Last but not least, I wish to thanks all of your answers.

How do I read or interprete the "ST", "SR", "SAK" and "MAK", using the Arduino wire library. Is it a pulse? How can I read it?

Those are taken care of by the I2C library. You should read the return values for each of the wire calls to determine the result.

SurferTim. Thanks a lot for your answer. Could you give me an small example?

Let's say for example that I send the valule 0x31 using Wire.write(0x31) to the slave, I should wait for an "AK" from the slave (SAK), how do I read this value, or which is the function that tells me that I got the "AK" right?

Thanks again for your time.

anfedres:
SurferTim. Thanks a lot for your answer. Could you give me an small example?

Let’s say for example that I send the valule 0x31 using Wire.write(0x31) to the slave, I should wait for an “AK” from the slave (SAK), how do I read this value, or which is the function that tells me that I got the “AK” right?

Thanks again for your time.

I2C operations using the Wire.H library are composed of transactions, either to transmit data or receive data.

To transmit data you need to know two things:

  • The I2C address of the slave you wish to communicate with.
    A byte value from 1 to 127. Usually express in hexidecimal (i.e. 0x51).
  • And the data you want to send. This data is limited to 32 bytes max.

If you want to send 0x31 to I2C slave 0x50, the following is example Arduino code:

#include <Wire.h>
void setup(){
Wire.begin(); // initialize I2C hardware

Wire.beginTransmission(0x50); // 
Wire.write(0x31); // add 0x31 to the Wire.h output buffer
uint8_t err = Wire.endTransmission(true); // Actually preform I2C write Transaction, Terminate with STOP

// err will return:
// 0 = success
// 1 = data to big for buffer
// 2 = NAK on transmit of Address
// 3 = NAK on transmit of DATA
// 4 = other Error, possibly lost bus arbitration
}

To request a block of data from a slave I2C device you also need to know two things:

  • The slave that has the data.
  • And how many bytes you wish to receive.
#include <Wire.h>

void setup(){
Wire.begin();

uint8_t err=Wire.requestFrom(0x50,3,true); // request three bytes of data from I2C slave 0x50, and send
// a STOP condition

// err will either return the number of requested bytes, or Zero (0) to indicate an error.

// To actually inspect the returned bytes of data use

while(Wire.available()){
  uint8_t a aByte = Wire.read();
  }
}

Chuck.

To transmit data you need to know two things:
The I2C address of the slave you wish to communicate with.
1.A byte value from 1 to 127. Usually express in hexidecimal (i.e. 0x51).
2. And the data you want to send. This data is limited to 32 bytes max.

  1. In my case HwADDR=0x18.
  2. I want to send 0x31. Acording to the datasheet it should be ST>HwADDR>0X31>SAK>0X31.

To request a block of data from a slave I2C device you also need to know two things:
1.The slave that has the data.
2.And how many bytes you wish to receive.

  1. Sensor in Slave mode,HwADDR=0x18.
  2. I want to receive 8 bytes, Each of the 4 quaternions have MSB and LMB.

I have implemented the following code, based in a similar code here .

#include<Wire.h>
int SPC=0x18;  // I2C address of the MPU-6050
int16_t QX,QY,QZ,QW;
void setup(){
  Serial.begin(9600);
  Wire.begin();                                                      //ST 
  Wire.beginTransmission(SPC);                                      //HwADDR
  uint8_t succs=Wire.endTransmission(false);                        //Falase end transmission 
  Wire.write(0x31);                                               //0x31 According to the Datasheet    
  Serial.print("succesful? = "); Serial.println(succs);             //Print if it was a succesfull 
}
void loop()
{
  Wire.beginTransmission(SPC);
  Wire.requestFrom(SPC,8,false);  
  
  unsigned int data_av=Wire.available();
  Serial.print("Data_av = "); Serial.println(data_av);
  
    QX=Wire.read()<<8|Wire.read();       
    QY=Wire.read()<<8|Wire.read();  
    QZ=Wire.read()<<8|Wire.read();  
    QW=Wire.read()<<8|Wire.read();  
    
    
    Serial.print("QX = "); 
    Serial.println(QX);
    Serial.print("QY = "); 
    Serial.println(QY);
    Serial.print("QZ = "); 
    Serial.println(QZ);
    Serial.print("QW = "); 
    Serial.println(QW);
    
  delay(500);
}

Wire.endTransmission(false) and Wire.requestFrom(SPC,8,false) are set to false since I don’t want to send a “Stop” command (I have read that setting these function with “True” will release the slave and send a “STOP” command.

The previous code has giving the following output.

succesful? = 2
Data_av = 0
QX = -1
QY = -1
QZ = -1
QW = -1
Data_av = 0
QX = -1
QY = -1
QZ = -1
QW = -1
Data_av = 0
QX = -1
QY = -1
QZ = -1
QW = -1
.
.
.

Meaning that there was not acknowledgment (NACK=2) from the slave to transmit the address.

I hope that someone can guide into the right direction. If someone wants more information about the sensor I’m using, the reference is SpacePoint Scout motion-tracking module, pn 13317, From PNI Sensor’s Corporation.

anfedres:

  1. In my case HwADDR=0x18.

  2. I want to send 0x31. Acording to the datasheet it should be ST>HwADDR>0X31>SAK>0X31.

  3. Sensor in Slave mode,HwADDR=0x18.

  4. I want to receive 8 bytes, Each of the 4 quaternions have MSB and LMB.

I have implemented the following code, based in a similar code here .

#include<Wire.h>

int SPC=0x18;  // I2C address of the MPU-6050
int16_t QX,QY,QZ,QW;
void setup(){
 Serial.begin(9600);
 Wire.begin();                                                      //ST
 Wire.beginTransmission(SPC);                                      //HwADDR
 uint8_t succs=Wire.endTransmission(false);                        //Falase end transmission
 Wire.write(0x31);                                               //0x31 According to the Datasheet    
 Serial.print("succesful? = "); Serial.println(succs);             //Print if it was a succesfull
}
void loop()
{
 Wire.beginTransmission(SPC);
 Wire.requestFrom(SPC,8,false);  
 
 unsigned int data_av=Wire.available();
 Serial.print("Data_av = "); Serial.println(data_av);
 
   QX=Wire.read()<<8|Wire.read();      
   QY=Wire.read()<<8|Wire.read();  
   QZ=Wire.read()<<8|Wire.read();  
   QW=Wire.read()<<8|Wire.read();  
   
   
   Serial.print("QX = ");
   Serial.println(QX);
   Serial.print("QY = ");
   Serial.println(QY);
   Serial.print("QZ = ");
   Serial.println(QZ);
   Serial.print("QW = ");
   Serial.println(QW);
   
 delay(500);
}




Wire.endTransmission(false) and Wire.requestFrom(SPC,8,false) are set to false since I don't want to send a "Stop" command (I have read that setting these function with "True" will release the slave and send a "STOP" command.

The previous code has giving the following output. 

succesful? = 2
Data_av = 0
QX = -1
QY = -1
QZ = -1
QW = -1
Data_av = 0
QX = -1
QY = -1
QZ = -1
QW = -1
Data_av = 0
QX = -1
QY = -1
QZ = -1
QW = -1
.
.
.

Meaning that there was not acknowledgment (NACK=2) from the slave to transmit the address. 

I hope that someone can guide into the right direction. If someone wants more information about the sensor I'm using, the reference is __*[SpacePoint Scout motion-tracking module, pn 13317, From PNI Sensor's Corporation.](http://www.manualshelf.com/manual/pni/spacepoint-scout/user-manual-english.html)*__

Not quite,

If I am understanding what you want, you want to set the address pointer(register) of your device to 0x31, then read the next eight bytes?

#include<Wire.h>
int SPC=0x18;  // I2C address of the MPU-6050
int16_t QX,QY,QZ,QW;
void setup(){
  Serial.begin(9600);
  Wire.begin();                                                      //ST 
}
void loop()
{
// set I2C device's internal address register to 0x31 
 Wire.beginTransmission(SPC);                                      //HwADDR
  Wire.write(0x31);                                               //0x31 According to the Datasheet    
  uint8_t succs=Wire.endTransmission(false);                        //False (restart Condition) 
  Serial.print("succesful? = "); Serial.println(succs);             //Print if it was a succesfull 
  if(succs==0){ // sucessfully set the IMU's address pointer to 0x31
    Wire.requestFrom(SPC,8,true);                           // look at your Spec Sheet, 
// normally a reStart is not used between reads, only between an Address Set, data Read sequence.
  
    unsigned int data_av=Wire.available();
    Serial.print("Data_av = "); Serial.println(data_av);
  
    QX=(((int)Wire.read())<<8)|Wire.read();

// I feel more comfortable when I explicitly promote integer types,
// I have been bitten when the compiler chooses not to promote a Byte to an int 
// if the compiler does not do the promotion, byte <<8 will always equal zero!       

    QY=(((int)Wire.read())<<8)|Wire.read();  
    QZ=(((int)Wire.read())<<8)|Wire.read();  
    QW=(((int)Wire.read())<<8)|Wire.read();  
    
    
    Serial.print("QX = "); 
    Serial.println(QX);
    Serial.print("QY = "); 
    Serial.println(QY);
    Serial.print("QZ = "); 
    Serial.println(QZ);
    Serial.print("QW = "); 
    Serial.println(QW);
    }    
  delay(500);
}

Chuck.