Go Down

Topic: Wire.requestFrom() hangs when there is an analogRead() after it (Read 2598 times) previous topic - next topic

steeljack

I'm trying to use the BQ76925 to monitor a battery bank. One of the pins on the chip is an analog output that give the voltage of the currently selected cell selected by writing to a register using the I2C protocol. However, when I try to read the value of that output after doing some I2C commands to confirm communications have been established, I never get a response from the chip (as far as my Uno is concerned). The problem goes away as soon as I remove the analogRead(), but I need that to monitor my batteries. Is this a known issue with the Wire library, or am I doing something screwy?

Code: [Select]
#include <Wire.h>

#define PWR_I2C_ADDRESS 1

#define ALERT_PIN 2
#define VCOUT_PIN A1
#define VIOUT_PIN A2

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

void loop()

  Wire.beginTransmission(accessAddress(0x07));
  Wire.endTransmission();
 
  Wire.requestFrom(accessAddress(0x07),1);
  while(Wire.available() < 1)
    Serial.print("Wating... \n");
  Serial.println(Wire.read());
 
  Wire.beginTransmission(accessAddress(0x01));
  Wire.write(B00010000);
  Wire.endTransmission();
  Serial.println(analogRead(VCOUT_PIN));
//  Wire.beginTransmission(accessAddress(0x01));
//  Wire.write(B00010001);
//  Wire.endTransmission();
//  Serial.println(analogRead(VCOUT_PIN));
//  Wire.beginTransmission(accessAddress(0x01));
//  Wire.write(B00010010);
//  Wire.endTransmission();
//  Serial.println(analogRead(VCOUT_PIN));
//  Wire.beginTransmission(accessAddress(0x01));
//  Wire.write(B00010011);
//  Wire.endTransmission();
//  Serial.println(analogRead(VCOUT_PIN));
//  Wire.beginTransmission(accessAddress(0x01));
//  Wire.write(B00010100);
//  Wire.endTransmission();
//  Serial.println(analogRead(VCOUT_PIN));
//  Wire.beginTransmission(accessAddress(0x01));
//  Wire.write(B00010101);
//  Wire.endTransmission();
//  Serial.println(analogRead(VCOUT_PIN));
}

int accessAddress(int regAddress)
{
  return (PWR_I2C_ADDRESS<<5)+regAddress;
}

Krodal

Is the chip voltage supply 3.3V ?  Are there pull-up resistors for the i2c-bus ?

When reading the chip, you write the address, and request the data.
The function Wire.available() ( http://arduino.cc/en/Reference/WireAvailable ) actually checks a buffer for data.
So you don't have to wait, just read the data.

old:
Code: [Select]

while(Wire.available() < 1)
    Serial.print("Wating... \n");
  Serial.println(Wire.read());


new:
Code: [Select]

while(Wire.available())
{
  Serial.println(Wire.read());
}


You also do an analogRead immediate after changing a register. Perhaps you should wait 10ms to 500ms until the voltage has settled.

You could make a function to read from the BQ76925, and a function to write data to the BQ76925. That way your code is easier to read and it prevents mistakes.

You could also run the i2c_scanner, to see if the i2c bus is still okay. http://playground.arduino.cc/Main/I2cScanner
http://playground.arduino.cc/Main/I2cScanner

pylon

The call of analogRead() does not directly influence the reading of the I2C bus. Can you post the serial output you get in both cases (with and without the analogRead() call)? Because you call analogRead() after you read from the I2C bus this cannot be the reason for the failure.

steeljack

Chip supply voltage is 3.3V. I am not currently using external resistors on the I2C bus, just letting the internal Arduino ones handle it.



old:
Code: [Select]

while(Wire.available() < 1)
    Serial.print("Wating... \n");
  Serial.println(Wire.read());


new:
Code: [Select]

while(Wire.available())
{
  Serial.println(Wire.read());
}




Only problem with that is I'm trying to confirm communications with that code (0x07 is the CHIP_ID register), so I'm waiting for the chip to communicate. Your code would be wonderful if I was getting a variable amount of data back, but I'm not.


Because you call analogRead() after you read from the I2C bus this cannot be the reason for the failure.


That would be why I'm posting here asking about it: it doesn't make any sense. I can remove everything before and after the analogRead() call and get "Waiting..." forever, but the second I remove it, data starts printing.

Here's the output with:
Code: [Select]
Wating...
Wating...
Wating...
Wating...
Wating...
Wating...
Wating...
Wating...
Wating...
Wating...
Wating...
Wating...
Wating...
Wating...
Wating...
Wating...
Wating...
Wating...
Wating...
Wating...
Wating...
Wating...
Wating...
Wating...


without:
Code: [Select]
16
16
16
16
16
16
16
16
16
16
16
16
16
16
16
16
16
16
16
16
16
16
16
16
16
16
16

Krodal

#4
Dec 11, 2012, 07:26 pm Last Edit: Dec 11, 2012, 07:38 pm by Krodal Reason: 1
Just follow the rules, and it should work.

First of all, use 4k7 resistors to the 3.3V for the SCL and SDA line of the I2C-bus.
You may have to read this: http://playground.arduino.cc/Main/I2CBi-directionalLevelShifter

Next, you don't have to wait for data. You are not reading from the chip, you are reading from the stream. Retrieving bytes from the chip has already been done by "requestFrom".
It doesn't matter how much data is read (1 byte, or many bytes), the Wire.requestFrom() function did tell the software already how many bytes should be read.
So, just use my code example.
See also the example here: http://arduino.cc/en/Reference/WireRead
Read also the section about "available" here : http://playground.arduino.cc/Main/WireLibraryDetailedReference

For  a good analog value, you should wait sometime. Add some delay before reading the analog value, like I wrote before.

steeljack

Okay, I now have 4k7 pullups on the I2C bus, I'm using your recommended code, and I've added a delay before analogRead(). Now I get
Code: [Select]
1023
1022
1022
1023
1022
1023
1023
1022
1023
1023
1021
1023
1023
1023
1023
1023
1023
1023
1023
1023

as my output, indicating that I am reading the analog port, but never getting a reply from the chip, meaning I have no idea if it's actually listening to me, and therefore whether the data is valid.

Krodal

Can you make a function of the i2c_scanner : http://playground.arduino.cc/Main/I2cScanner
You could rename the 'loop' function and remove the delay at the end.
What happens if you run the i2c_scanner before everything else, and after your code ?

steeljack

The BQ76925 uses a condensed version of the I2C protocol where the device address and register address are combined into one address (to reduce overhead or something like that), but for what it's worth, here's what I get when I run the scanner
Code: [Select]
I2C Scanner
Scanning...
I2C device found at address 0x20 !
I2C device found at address 0x21 !
I2C device found at address 0x22 !
I2C device found at address 0x23 !
I2C device found at address 0x24 !
I2C device found at address 0x25 !
I2C device found at address 0x26 !
I2C device found at address 0x27 !
I2C device found at address 0x28 !
I2C device found at address 0x29 !
I2C device found at address 0x2A !
I2C device found at address 0x2B !
I2C device found at address 0x2C !
I2C device found at address 0x2D !
I2C device found at address 0x2E !
I2C device found at address 0x2F !
I2C device found at address 0x30 !
I2C device found at address 0x31 !
I2C device found at address 0x32 !
I2C device found at address 0x33 !
I2C device found at address 0x34 !
I2C device found at address 0x35 !
I2C device found at address 0x36 !
I2C device found at address 0x37 !
I2C device found at address 0x38 !
I2C device found at address 0x39 !
I2C device found at address 0x3A !
I2C device found at address 0x3B !
I2C device found at address 0x3C !
I2C device found at address 0x3D !
I2C device found at address 0x3E !
I2C device found at address 0x3F !
done


The address format is 01(5-bit reg address)

steeljack

I missed the bit about running it before and after my code. Here is what I get then

Code: [Select]
Scanning...
I2C device found at address 0x20 !
I2C device found at address 0x21 !
I2C device found at address 0x22 !
I2C device found at address 0x23 !
I2C device found at address 0x24 !
I2C device found at address 0x25 !
I2C device found at address 0x26 !
I2C device found at address 0x27 !
I2C device found at address 0x28 !
I2C device found at address 0x29 !
I2C device found at address 0x2A !
I2C device found at address 0x2B !
I2C device found at address 0x2C !
I2C device found at address 0x2D !
I2C device found at address 0x2E !
I2C device found at address 0x2F !
I2C device found at address 0x30 !
I2C device found at address 0x31 !
I2C device found at address 0x32 !
I2C device found at address 0x33 !
I2C device found at address 0x34 !
I2C device found at address 0x35 !
I2C device found at address 0x36 !
I2C device found at address 0x37 !
I2C device found at address 0x38 !
I2C device found at address 0x39 !
I2C device found at address 0x3A !
I2C device found at address 0x3B !
I2C device found at address 0x3C !
I2C device found at address 0x3D !
I2C device found at address 0x3E !
I2C device found at address 0x3F !
done

16
1023
Scanning...
No I2C devices found

Scanning...
No I2C devices found

1023
Scanning...
No I2C devices found

Krodal

I'm not sure, but does that mean that your code make the i2c-bus or the i2c device get stuck ?
This can happen, if there is a aknowlegde mismatch on the i2c-bus.

You could do more tests. A test with only reading from the device and another test with only writing to the device.

Can you perhaps make routines for reading and writing and make them from scratch ?

dc42

Can you confirm that the Arduino Aref pin is not connected to anything, and not accidentally shorting to anything either?
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

steeljack

Here's what I've written:
Code: [Select]
#include <Wire.h>

#define PWR_I2C_ADDRESS 1

int accessAddress(int regAddress)
{
  return (PWR_I2C_ADDRESS<<5)+regAddress;
}

void writeTo(int regAddress, byte data)
{
  Wire.beginTransmission(accessAddress(regAddress));
  Wire.write(data);
  Wire.endTransmission();
}

byte readFrom(int regAddress)
{
  Wire.beginTransmission(accessAddress(regAddress));
  Wire.endTransmission();
  Wire.requestFrom(accessAddress(regAddress),1);
return Wire.read();
}

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

void loop()
{
  writeTo(0x01,B00010010);
  Serial.println(readFrom(0x01));
  Serial.println(analogRead(A1));
}


Reading from the registers works fine right up until I add the analogRead(), at which point I start getting 255 back from readFrom(), which is, apparently, the default value, as it is what I get back when I try reading from a non-existent register.

Krodal

Your code looks okay.
But you have to make small steps to get to the problem.
The Arduino Wire library might not be able to handle that kind of communication.
But there are still some things you could try.

(1) Do you have the latest version:  Arduino 1.0.2 ?

(2) Are you sure you have a Arduino Uno, and you have selected the Arduino Uno from the Extra/Board menu ?

(3) Code 'A1' is value '15' or so, It must be okay but you could try just number '1', like so: "analogRead(1);"

(4) The Wire library could be confused, it might not expect such behaviour with the registers of the device. The Wire.endTransmission was updated. It has now a boolean parameter to hold or release the i2c-bus. You could try to use "Wire.endTransmission(true);" ( http://arduino.cc/en/Reference/WireEndTransmission ). Perhaps that will avoid that the device is expecting the checksum.

(5) You could send the error code from the Wire functions to the serial monitor.

(6) Instead of writing to the device. You could just read the CHIP_ID again and again. That makes it easier to check when the values turns to 255.

steeljack

Ah, excellent. Adding the "true" parameter seems to have fixed the issue. Many thanks for your help.

Krodal

Good to know. So the (updated) Wire library can also handle this chip with a not-so-standard communication.

Go Up