I2C read problems

Hi folks
A strange problem perhaps - I am having trouble reading registers of a SigmaDSP from Analog Devices using an Arduino using the Wire library. I can easily write to these registers and then verify them with the AD software/hardware.

So the write operation looks as follows:
Wire.beginTransmission(0x38);
Wire.send((int)0xE2);
Wire.send((int)0x80);
Wire.send((int)0x01);
Wire.send((int)0x01);
Wire.endTransmission();
Again, I verify this on the hardware as having changed

However, the read operation
int addr=0x38;
int leng = 2;

Wire.beginTransmission(addr);
Wire.send((int)0xE2);
Wire.send((int)0x80);
Wire.endTransmission();
delayMicroseconds(200);
Wire.requestFrom(addr,leng);
for(int i=0;i<leng;i++){
delayMicroseconds(50);
if(Wire.available()) {
Serial.println((int)Wire.receive());
} else {Serial.println("nada");}
}

Gives me a whole bunch of nada. The delays are to replicate what I see the AD hardware doing using a 'scope. Just to fully document that, the AD hardware produces an I2C sequence of:
Start Bit, Chip Address, Read bit, ACK bit (0), Register Address (4 bytes), 00, 200 microsecond delay, start bit, chip address, ACK bit (0) then Data

Looking at what the above code produces I get the same, but no final ACK bit from my hardware. Also, I don't know if this has any bearing, however, the SCL is held low by the AD hardware and the Arduino hardware holds the SCL line high during the 200 microsecond delay. I've tried forcing this using a pinMode(A5, OUTPUT); digitalWrite(A5, LOW); but that functionality seems to have been taken away in the Wire library?

Anyhow, any clues, hints or suggestions would be greatly appreciated. I've spent many hours on this and am completely stumped. Obviously the AD hardware can read this, so I must be able to as well, just missing something!
Can provide screen shots of the scope if those would be useful at all.

Can you post a link to the datasheet?

i am also having a trouble with wire library

void setup()
{
Serial.begin(UartBaudRate);
Wire.begin(I2C_Address); // 2
Wire.onRequest(requestEvent);
Wire.onReceive(ReceiveCommand);
}

void requestEvent()
{

if ( command == 'H' ) // Heading
{
Wire.send(HeadingMSB);
Wire.send(HeadingLSB);
}
else if ( command == 'P' ) // Pitch
{
Wire.send(PitchMSB);
Wire.send(PitchLSB);
}


and on receiver

void loop(){
Wire.beginTransmission(2);
Wire.send('H');
Wire.endTransmission();
Wire.requestFrom(2,2);

while(Wire.available()<2):
headingMSB = Wire.receive();
headingLSB = Wire.receive();

Serial.print(headingMSB,BIN);
Serial.print(" ");
Serial.println(headingLSB,BIN);

delay(250);
}

but i am getting

11000100 11111111
10101000 11111111
1110100 11111111
10011110 11111111
1010110 11111111
11001 11111111
10000 11111111
101111 11111111

i am sure that the HeadingMSB and HeadingLSB on the slave device have values from the compass
i am not sure if the first byte that apears on screen is the MSB or the LSB
also

when i am trying that

if ( command == 'H' ) // Heading
{
Wire.send("AB");
}

i am getting

1000001 1000010

but when i am trying

if ( command == 'H' ) // Heading
{
Wire.send("A");
Wire.send("B");
}

i am getting

1000010 11111111

*headingMSB and headingLSB on both codes are byte type
why???

Ciao,

using Wire library You have the I2C activity only on this commands

Wire.endTransmission(); and Wire.requestFrom(addr,leng);

The others commands work on buffers and status variables.

Probably You have SCL high during the 200 microseconds delay because You freeze the stop condition sent by Arduino
"... the stop bit is indicated by a low-to-high transition of SDA with SCL high ...".

Internally library waits for data, so delays are not useful.

You can check the returned errors codes on twi.c file.

Ciao,
Marco.

so how can i make it work?

You have the code going through for loop iterations even when data is not available from the bus. You need to hold in the for loop until data is available.

drzerog:

      Wire.beginTransmission(addr);

Wire.send((int)0xE2);
      Wire.send((int)0x80);
      Wire.endTransmission();




... the AD hardware produces an I2C sequence of: Start Bit, Chip Address, Read bit, ACK bit (0), Register Address (4 bytes), ...

Wire.send sends a byte. Casting a byte to an int doesn't change that. Look:

void TwoWire::send(int data)
{
  send((uint8_t)data);
}

It just casts it back!

herctrap:
i am also having a trouble with wire library

and on receiver

void loop(){

Wire.beginTransmission(2);
  Wire.send('H');
  Wire.endTransmission();
  Wire.requestFrom(2,2);
 
  while(Wire.available()<2):
  headingMSB = Wire.receive();
  headingLSB = Wire.receive();

Serial.print(headingMSB,BIN);
  Serial.print(" ");
  Serial.println(headingLSB,BIN);

delay(250);
}

That doesn't even compile. (The colon).

Anyway, you don't need to do:

 while(Wire.available()<2) {}

After the requestFrom either the data is available or it isn't. Looping doesn't make more become available. In other words, requestFrom is blocking. It returns when stuff is available.

void requestEvent()
{

  if ( command == 'H' ) // Heading
  {
    Wire.send(HeadingMSB);
    Wire.send(HeadingLSB);
  }
  else if ( command == 'P' ) // Pitch
  {
    Wire.send(PitchMSB);
    Wire.send(PitchLSB);
  }

You can only successfully do one Wire.send in an requestEvent function, because each one resets the buffer to the start. You need to assemble your response into a buffer (eg. a 2-byte array) and do a single Wire.send of that.

ok if i send the int heading

wire.send(heading);

that contains the headingMSB and headingLSB

i am also getting the 11111111

Don't just summarize. It's Wire.send not wire.send. Post the code. Show what heading is. Show what you are doing. It's the detail that makes the difference.

#include <Wire.h>

#define I2C_Address 2
#define UartBaudRate 19200

int Position;
int NextData;

boolean SentenceState = false;
char OS4000Data[128];

char command;

int Heading;
int Heading100;
int Heading10;
int Heading1;
int Heading01;
byte HeadingMSB;
byte HeadingLSB;

int Pitch;
int Pitch100;
int Pitch10;
int Pitch1;
int Pitch01;
byte PitchMSB;
byte PitchLSB;

int Roll;
int Roll100;
int Roll10;
int Roll1;
int Roll01;
byte RollMSB;
byte RollLSB;

int Temp;
byte TempMSB;
byte TempLSB;
int Depth;
byte DepthMSB;
byte DepthLSB;
int MagneticVector;
byte MagneticVectorMSB;
byte MagneticVectorLSB;
int MagneticX;
byte MagneticXMSB;
byte MagneticXLSB;
int MagneticY;
byte MagneticYMSB;
byte MagneticYLSB;
int MagneticZ;
byte MagneticZMSB;
byte MagneticZLSB;
int AccelarationVector;
byte AccelarationVectorMSB;
byte AccelarationVectorLSB;
int AccelarationX;
byte AccelarationXMSB;
byte AccelarationXLSB;
int AccelarationY;
byte AccelarationYMSB;
byte AccelarationYLSB;
int AccelarationZ;
byte AccelarationZMSB;
byte AccelarationZLSB;
int GyroX;
byte GyroXMSB;
byte GyroXLSB;
int GyroY;
byte GyroYMSB;
byte GyroYLSB;

void setup()
{
Serial.begin(UartBaudRate);
Wire.begin(I2C_Address);
Wire.onRequest(requestEvent);
Wire.onReceive(ReceiveCommand);
}

void loop()
{
Capture_OS4000();
Check_Sentence();
if ( SentenceState == true ) Extract_Info();
}

void ReceiveCommand(int howMany)
{
while(!Wire.available());
command = Wire.receive();
}

void requestEvent()
{
if ( command == 'A' ) // Send All
{
Wire.send(HeadingMSB);
Wire.send(HeadingLSB);
Wire.send(PitchMSB);
Wire.send(PitchLSB);
Wire.send(RollMSB);
Wire.send(RollLSB);
Wire.send(TempMSB);
Wire.send(TempLSB);
Wire.send(DepthMSB);
Wire.send(DepthLSB);
Wire.send(MagneticVectorMSB);
Wire.send(MagneticVectorLSB);
Wire.send(MagneticXMSB);
Wire.send(MagneticXLSB);
Wire.send(MagneticYMSB);
Wire.send(MagneticYLSB);
Wire.send(MagneticZMSB);
Wire.send(MagneticZLSB);
Wire.send(AccelarationVectorMSB);
Wire.send(AccelarationVectorLSB);
Wire.send(AccelarationXMSB);
Wire.send(AccelarationXLSB);
Wire.send(AccelarationYMSB);
Wire.send(AccelarationYLSB);
Wire.send(AccelarationZMSB);
Wire.send(AccelarationZLSB);
Wire.send(GyroXMSB);
Wire.send(GyroXLSB);
Wire.send(GyroYMSB);
Wire.send(GyroYLSB);
}
else if ( command == 'H' ) // Heading
{
Wire.send(Heading);
}
else if ( command == 'P' ) // Pitch
{
Wire.send(PitchMSB);
Wire.send(PitchLSB);
}
else if ( command == 'R' ) // Roll
{
Wire.send(RollMSB);
Wire.send(RollLSB);
}
else if ( command == 'T' ) // Temp
{
Wire.send(TempMSB);
Wire.send(TempLSB);
}
else if ( command == 'D' ) // Depth
{
Wire.send(DepthMSB);
Wire.send(DepthLSB);
}
else if ( command == 'M' ) // Magnetic Vector
{
Wire.send(MagneticVectorMSB);
Wire.send(MagneticVectorLSB);
}
else if ( command == 'X' ) // Magnetic X
{
Wire.send(MagneticXMSB);
Wire.send(MagneticXLSB);
}
else if ( command == 'Y' ) // Magnetic Y
{
Wire.send(MagneticYMSB);
Wire.send(MagneticYLSB);
}
else if ( command == 'Z' ) // Magnetic Z
{
Wire.send(MagneticZMSB);
Wire.send(MagneticZLSB);
}
else if ( command == 'a' ) // Accelaration Vector
{
Wire.send(AccelarationVectorMSB);
Wire.send(AccelarationVectorLSB);
}
else if ( command == 'x' ) // Accelaration X
{
Wire.send(AccelarationXMSB);
Wire.send(AccelarationXLSB);
}
else if ( command == 'y' ) // Accelaration Y
{
Wire.send(AccelarationYMSB);
Wire.send(AccelarationYLSB);
}
else if ( command == 'z' ) // Accelaration Z
{
Wire.send(AccelarationZMSB);
Wire.send(AccelarationZLSB);
}
else if ( command == 'G' ) // Gyro X
{
Wire.send(GyroXMSB);
Wire.send(GyroXLSB);
}
else if ( command == 'g' ) // Gyro Y
{
Wire.send(GyroYMSB);
Wire.send(GyroYLSB);
}
else
{
//Error
}
command = 'N';
}

void Capture_OS4000()
{
Serial.flush();
while ( Serial.read () != '$' );
Serial.flush();
while( Serial.available() < 127 );
for ( Position = 0; Position < 126; Position++ ){
OS4000Data[Position] = char( Serial.read());
}
}

void Check_Sentence()
{
if ( ( OS4000Data[0] == 'O' ) && ( OS4000Data[1] == 'H' ) && ( OS4000Data[2] == 'P' ) && ( OS4000Data[3] == 'R' ) && ( OS4000Data[4] == ',' ) )SentenceState = true;
else SentenceState = false;
}

void Extract_Info()
{
Heading100 = 0;
Heading10 = 0;
Heading1 = 0;
Heading01 = 0;
if ( OS4000Data[8] == '.' ){
Heading100 = OS4000Data[5] - '0';
Heading10 = OS4000Data[6] - '0';
Heading1 = OS4000Data[7] - '0';
Heading01 = OS4000Data[9] - '0';
NextData = 10;
}
else if ( OS4000Data[7] == '.' ){
Heading10 = OS4000Data[5] - '0';
Heading1 = OS4000Data[6] - '0';
Heading01 = OS4000Data[8] - '0';
NextData = 9;
}
else if ( OS4000Data[6] == '.' ){
Heading1 = OS4000Data[5] - '0';
Heading01 = OS4000Data[7] - '0';
NextData = 8;
}
Heading = 1000Heading100 + 100Heading10 + 10*Heading1 + Heading01;

Pitch100 = 0;
Pitch10 = 0;
Pitch1 = 0;
Pitch01 = 0;
if ( OS4000Data[NextData+1] == '-' ){
if ( OS4000Data[NextData+5] == '.' ){
Pitch100 = OS4000Data[NextData+2] - '0';
Pitch10 = OS4000Data[NextData+3] - '0';
Pitch1 = OS4000Data[NextData+4] - '0';
Pitch01 = OS4000Data[NextData+6] - '0';
NextData += 7;
}
else if ( OS4000Data[NextData+4] == '.' ){
Pitch10 = OS4000Data[NextData+2] - '0';
Pitch1 = OS4000Data[NextData+3] - '0';
Pitch01 = OS4000Data[NextData+5] - '0';
NextData += 6;
}
else if ( OS4000Data[NextData+3] == '.' ){
Pitch1 = OS4000Data[NextData+2] - '0';
Pitch01 = OS4000Data[NextData+4] - '0';
NextData += 5;
}
Pitch = - ( 1000Pitch100 + 100Pitch10 + 10Pitch1 + Pitch01 );
}
else
{
if ( OS4000Data[NextData+4] == '.' ){
Pitch100 = OS4000Data[NextData+1] - '0';
Pitch10 = OS4000Data[NextData+2] - '0';
Pitch1 = OS4000Data[NextData+3] - '0';
Pitch01 = OS4000Data[NextData+5] - '0';
NextData += 6;
}
else if ( OS4000Data[NextData+3] == '.' ){
Pitch10 = OS4000Data[NextData+1] - '0';
Pitch1 = OS4000Data[NextData+2] - '0';
Pitch01 = OS4000Data[NextData+4] - '0';
NextData += 5;
}
else if ( OS4000Data[NextData+2] == '.' ){
Pitch1 = OS4000Data[NextData+1] - '0';
Pitch01 = OS4000Data[NextData+3] - '0';
NextData += 4;
}
Pitch = ( 1000
Pitch100 + 100Pitch10 + 10Pitch1 + Pitch01 );
}

Roll100 = 0;
Roll10 = 0;
Roll1 = 0;
Roll01 = 0;
if ( OS4000Data[NextData+1] == '-' ){
if ( OS4000Data[NextData+5] == '.' ){
Roll100 = OS4000Data[NextData+2] - '0';
Roll10 = OS4000Data[NextData+3] - '0';
Roll1 = OS4000Data[NextData+4] - '0';
Roll01 = OS4000Data[NextData+6] - '0';
NextData += 7;
}
else if ( OS4000Data[NextData+4] == '.' ){
Roll10 = OS4000Data[NextData+2] - '0';
Roll1 = OS4000Data[NextData+3] - '0';
Roll01 = OS4000Data[NextData+5] - '0';
NextData += 6;
}
else if ( OS4000Data[NextData+3] == '.' ){
Roll1 = OS4000Data[NextData+2] - '0';
Roll01 = OS4000Data[NextData+4] - '0';
NextData += 5;
}
Roll = - ( 1000Roll100 + 100Roll10 + 10Roll1 + Roll01 );
}
else
{
if ( OS4000Data[NextData+4] == '.' ){
Roll100 = OS4000Data[NextData+1] - '0';
Roll10 = OS4000Data[NextData+2] - '0';
Roll1 = OS4000Data[NextData+3] - '0';
Roll01 = OS4000Data[NextData+5] - '0';
NextData += 6;
}
else if ( OS4000Data[NextData+3] == '.' ){
Roll10 = OS4000Data[NextData+1] - '0';
Roll1 = OS4000Data[NextData+2] - '0';
Roll01 = OS4000Data[NextData+4] - '0';
NextData += 5;
}
else if ( OS4000Data[NextData+2] == '.' ){
Roll1 = OS4000Data[NextData+1] - '0';
Roll01 = OS4000Data[NextData+3] - '0';
NextData += 4;
}
Roll = ( 1000
Roll100 + 100Roll10 + 10Roll1 + Roll01 );
}
}

You have:

void requestEvent()
{
  if ( command == 'A' ) // Send All
  {
    Wire.send(HeadingMSB);
    Wire.send(HeadingLSB);
    Wire.send(PitchMSB);
    Wire.send(PitchLSB);
    Wire.send(RollMSB);
    Wire.send(RollLSB);
    Wire.send(TempMSB);
    Wire.send(TempLSB);
    Wire.send(DepthMSB);
    Wire.send(DepthLSB);
    Wire.send(MagneticVectorMSB);
    Wire.send(MagneticVectorLSB);
    Wire.send(MagneticXMSB);
    Wire.send(MagneticXLSB);
    Wire.send(MagneticYMSB);
    Wire.send(MagneticYLSB);
    Wire.send(MagneticZMSB);
    Wire.send(MagneticZLSB);
    Wire.send(AccelarationVectorMSB);
    Wire.send(AccelarationVectorLSB);
    Wire.send(AccelarationXMSB);
    Wire.send(AccelarationXLSB);
    Wire.send(AccelarationYMSB);
    Wire.send(AccelarationYLSB);
    Wire.send(AccelarationZMSB);
    Wire.send(AccelarationZLSB);
    Wire.send(GyroXMSB);
    Wire.send(GyroXLSB);
    Wire.send(GyroYMSB);
    Wire.send(GyroYLSB);
  }

Do you seriously think that is one Wire.send?

#include <Wire.h>
int heading;

byte headingMSB;
byte headingLSB;

void setup(){
Wire.begin();
Serial.begin(9600);
}

void loop(){
Wire.beginTransmission(2);
Wire.send('H');
Wire.endTransmission();
Wire.requestFrom(2,2);

while(Wire.available()<2){}
headingMSB = Wire.receive();
headingLSB = Wire.receive();

Serial.print(headingMSB,BIN);
Serial.print(" ");
Serial.println(headingLSB,BIN);

delay(250);
}

the first is connected to the OS4000

the Heading contains a number from 0 to 3600
i have checked that

On the serial monitor i get

10101011 11111111
10110010 11111111
10101110 11111111
10110011 11111111
10110000 11111111
10101110 11111111
10101110 11111111
10101110 11111111
10101100 11111111

and its frozen after a while

this is never executed because i never send an A

i want to send 2 bytes on each request

the master send an H //heading

and requests two bytes

Wire.send("AB"); sends two bytes
Wire.send("ABCD"); sends four bytes

but how i will send an int16_t?

herctrap:
this is never executed because i never send an A

... must not comment ... :open_mouth:

herctrap:
but how i will send an int16_t?

Like this:

int val = 1234;
byte buf [2];

  buf [0] = val >> 8;
  buf [1] = val & 0xFF;
  Wire.send (buf, 2);

You could make a generic function to do that, to save doing it in many places:

void sendInt (int val)
  {
  byte buf [2];

  buf [0] = val >> 8;
  buf [1] = val & 0xFF;
  Wire.send (buf, 2);
  } // end of sendInt

thank you
its working

but this is freezing after some time

#include <Wire.h>
int heading;
byte headingMSB;
byte headingLSB;

void setup(){
Wire.begin();
Serial.begin(9600);
}

void loop(){
Wire.beginTransmission(2);
Wire.send('H');
Wire.endTransmission();
Wire.requestFrom(2,2);

while(Wire.available()<2){
}
headingMSB = Wire.receive();
headingLSB = Wire.receive();
Serial.print(headingMSB,BIN);
Serial.print(" ");
Serial.print(headingLSB,BIN);
Serial.print(" ");
heading = ( ( headingMSB<<8 ) | ( headingLSB ) );
Serial.println(heading);
delay(500);
}

Did you decide to ignore that?

Let me amplify ... the loop doesn't help. And if the other end doesn't respond, it will cause your program to freeze - the exact symptoms you got.

@Nick
If as you say:-

You can only successfully do one Wire.send ........, because each one resets the buffer to the start.

Why does this work?

void setLED(byte address, int ledNumber, int onValue, int offValue) {  // this function assumes the auto incerment is on
  byte reg = (ledNumber * 4) + 6;
  if(reg > 69) reg = 0xfa;  // if the led number is greater than 15 assume it is a command for all LEDs
  Wire.beginTransmission(address);
  Wire.send(reg);    //  set control register to point at start of LED control block
  Wire.send(onValue & 0xff);
  Wire.send(onValue >> 8);
  Wire.send(offValue & 0xff);
  Wire.send(offValue >> 8);
  Wire.endTransmission();  
}

This is a bit of code I have been using to test the NXP PCA9685 16 LED 12 PWM driver chip.

also this working too

for ( Eeprom_Address = 0; Eeprom_Address < 16; Eeprom_Address++ )
{
Wire.beginTransmission(HMC6343_ID);
Wire.send(0xE1);
Wire.send(Eeprom_Address);
Wire.endTransmission();
delay(10);
Wire.requestFrom(HMC6343_ID, 1);
while ( Wire.available() == 0 );
ReceivedBytes[Eeprom_Address] = ( Wire.receive() );
HardwareFile.print(Eeprom_Address);
HardwareFile.print(" - ");
HardwareFile.println( ReceivedBytes[Eeprom_Address],HEX );
}

with the HMC6343 compass from honeywell

Grumpy_Mike:
@Nick
If as you say:-

You can only successfully do one Wire.send ........, because each one resets the buffer to the start.

Why does this work?

Because you omitted four important words from the quote:

If you look at the code, inside the interrupt service routine you can only do one (successful) Wire.send because Wire.send puts stuff in a buffer for the ISR to promptly return to the caller, and every call to Wire.send resets the buffer back to the start.

Both of your examples are not inside an interrupt service routine.