There are several ways to hang the bus, one is to hang a slave device, another is to get the hardware to think it has sent an I2C STOP when in fact it did not (this case would not be something that is your fault, it would be the ISR code).
I have personally seen the I2C interface mangle the STOP when doing a receive using max baud rates (2400 setting), in fact I had to insert a delay in the latest rev (v6) to help with this. It is possible your problems are related to the STOP that occurs at the end of a Tx or Rx, although I have never seen this occur on a Tx, and your begin() function is only Tx. There have been other people complaining about sporadic hangs, so if this could be identified as the cause I would be interested to know.
For Rx problem I have seen, what is happening is that it is trying to change from a Rx mode back to Tx (as happens at the end of a receive) too quickly, which confuses the I2C hardware. I had a test case at the 2400 rate that would cause this fairly reliably which is what I used to figure out my delay patch. However if this is happening at lower rates also then it will have to be fixed.
Some questions:
- What baud rate are you using?
- Can you be more specific about the hang conditions:
- When it hangs, is it exiting your begin() with a false, or it is hanging inside the begin() function? If it is STOP related it will hang inside the begin(), specifically on an endTransmmission() call, because it will think the bus is busy and will be waiting inside that call.
- If it does exit begin() with a false, which Tx command does it hang on (first, second, third, fourth?) and what is the I2C error return value?
- Do you have any kind of a logic analyzer or scope dump of the I2C traffic? Your commands are short, so if you trigger on the START (SDA falling-edge while SCL high) then you should be able to capture the entire command.
One thing I notice right off:
static const uint16_t timeout = 100000; // this was 100, but I wanted 100 ms (!)
You have over-ranged this. The largest delay you can get with a uint16 will be 65535us. If you really want a timeout that long I can try to rework the routines to maybe support milliseconds. I did not expect people would use timeouts that long.
I'm having serious problems with an LSM303D. In the first version of my code I didn't have error checking, and the bus seemed to hang from time to time. So I added error checking. This is what I'm doing now:
...
I also have code for reading values from the chip, but begin() already fails with a timeout error. The wiring is correct, the pullups are correct as well - otherwise the previous code without error checking wouldn't have worked. My first question is: am I using the i2c_t3 methods correctly in the first place?
The code looks ok at first glance. If you can provide more information I'll think about it some more. I am not familiar with a LSM303D, I'll need to pull a datasheet on it. If we can't identify a solution then I can probably acquire one and experiment on it. What specifically are you using?
Has anyone used the LSM303D? What might cause it to hang?
Slaves can hang if the clocking gets somehow confused between Master and Slave. For instance on a bit-banged Master (not what we are using here, just an example), if the Master drives the SCL line as a CMOS line, not a open-drain, then it will not recognize Slave clock-stretching. So on a Rx command (Slave sending data to Master) the Slave thinks it is stretching the clock and the Master keeps banging away, they become completely out-of-sync and eventually the Slave ends up getting a partial clock and hangs in the middle of transmitting a byte. At that point you are done, the bus is hung. There are other similar ways, basically anything that ends up holding SCL or SDA low indefinitely will hang the bus.
The problem I described at the top is an internal problem due to the I2C hardware. Basically the ISR tells it to send a STOP, it doesn't do it (but it thinks it did), and on the next command it hangs because SCL/SDA is low, it thinks its no longer the Master, and it hangs waiting for the "other" (non-existant) Master to release the bus.
What can I do to "unhang" the bus again? I know that is a complex issue (it already was on AVRs), but there might be readily available code that attempts to it on a Teensy 3.0
Well the real solution is to not hang the bus in the first place. The less correct (but probably equally workable) solution is for single-Master setups. In the i2c_t3.cpp file look for lines like this (I think there are two spots):
Code:
// we are not currently the bus master, so wait for bus ready
while(*(i2c->S) & I2C_S_BUSY);
Comment it out, it will no longer hang waiting for the bus to release. I would be interested to know if that works, I haven't tried it. If it does, it implies there is some condition where the STOP isn't properly being sent.