Some more info, I chopped up the example sketch of the CMPS03 lib to make the
following sketch which runs without need for the lib.
#include "Wire.h"
byte deviceId = 0x60;
void setup()
{
Serial.begin(9600);
Wire.begin();
}
void loop()
{
Serial.println("About to begin transmission");
Wire.beginTransmission(deviceId);
Serial.println("About to send a 2");
Wire.send(2);
Serial.println("About to end transmission");
Wire.endTransmission();
Serial.println("Transmission ended");
delay(1);
Serial.println("About to request data");
Wire.requestFrom(deviceId,
(uint8_t) 2);
unsigned int value =
((unsigned int)
Wire.receive()) << 8;
value = value + ((unsigned int)
Wire.receive());
Serial.print("Data received, value is: ");
Serial.println(value);
delay(1000);
}
If you have an I2C device you want to test it with, put the relevant deviceId.
Now, the code hangs if I cut power to the compass after having printed:
"About to end transmission"
so we know that something naughty is happening at:
Wire.endTransmission();
Looking inside the Wire.cpp we find:
uint8_t
TwoWire::endTransmission(void)
{
// transmit buffer (blocking)
int8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, 1);
// reset tx buffer iterator vars
txBufferIndex = 0;
txBufferLength = 0;
// indicate that we are done transmitting
transmitting = 0;
return ret;
}
Now, it seems that twi_writeTo() is the guilty party so if I go to "twi.c"
("utility" folder of "Wire" library) and stick a "return 0" at the very start of
the function, my original code gets past the previous snag, only to get stuck
at:
"About to request data"
Same detective work uncovers that "Wire.requestFrom()" in "Wire.cpp" goes and
calls "twi_readFrom()" in "twi.c". Again going and sticking a "return 0" at the
start of "twi_readFrom()" unsnags my code and everything flows perfectly. Of
course all results are zeros but hey, the code does not hang.
The really weird bit is the placing of the "return" statements. When looking
at, say, "twi_readFrom()" I saw two while loops (line 129 and 153) where things
could be getting stuck and thought it would be easy to modify them to exit
after a timeout had elapsed. No such luck. The first while loop and following
code is as follows:
// wait until twi is ready, become master receiver
while(TWI_READY != twi_state){
continue;
}
twi_state = TWI_MRX;
// reset error state (0xFF.. no error occured)
twi_error = 0xFF;
sticking the return immediately after the loop closing bracket still makes the
code flow without hanging so there is nothing bad happening in there.
However, placing the "return 0" after the "twi_state = TWI_MRX;"
breaks the code completely, so completely that it hangs after "About to request
data" irrespective of whether the compass is on or off.
So, any ideas what could be happening here? BTW, a couple more clues. BenF
pointed out something about the lines being pulled low and adding a
"Wire.available()" before trying to read. Now, the (first) hanging occurs after
"Wire.endTransmission()" so that is not really an option. However, notice that
I 'm using an Arduino Mega and not a Duemilanove. Now, from what I remember in
the Duemilanove you have to use a couple of pull up resistors to pull the SDA
and SCL lines to +5V. In the Mega pulling the lines up results in nothing being
read so I plug
the lines directly to the relevant pins (20 and 21). Could that be significant
i.e., the internal wiring of the Mega not be the same as that of the Duemilanove
where the pulling up was done externally? After all, if the lines were pulled up
internally, nothing would change if I also pulled them up externally, right?
One more clue, when I cut power to the compass (without having altered the libs)
and it hangs after printing:
"About to end transmission"
when I restore power, the value read is zero, as opposed to the expected value.
This leads me to believe that something somewhere really does time out but then
the result does not trickle up to my sketch.