PDA

View Full Version : Teensy 3.0 i2c endTransmission() bug



cTn
01-15-2013, 06:01 PM
You might be aware of this, but the endTransmission() returns always 0 (as its hardcoded on line 164), where it should return transmission status (where 0 = success), having 0 hardcoded will make sketches like this completely useless.



#include <Wire.h>

uint8_t address;
int8_t status;

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

void loop() {
Serial.println("Scanning...");

for (address = 0; address <= 127; address++) {
Wire.beginTransmission(address);
status = Wire.endTransmission();

if (status == 0) {
Serial.print("I2C device found at: ");
Serial.println(address, HEX);
}
}

Serial.println("done");

delay(10000);
}

el_supremo
01-15-2013, 08:15 PM
See this thread:
http://forum.pjrc.com/threads/562-TwoWire-endTransmission-always-return-0

Pete

cTn
01-15-2013, 08:31 PM
hmm, thank you (that helped quite a bit) but i am still getting quite "incorrect" reading on the i2c scanner script :/

el_supremo
01-15-2013, 11:53 PM
What does quite "incorrect" mean?
I have four I2C devices on the bus and that one fix to wire.cpp enables an I2C scanner to see them all.
Your code also works although I don't think it should be starting at address zero.

Pete

cTn
01-16-2013, 12:07 AM
i have mpu6050 gyro/accel sensor and ms5611 barometer on the "main" bus, mpu address is 0x68 which is correct on both arduino and teensy, ms5611 address is 0x77 (on arduino) which is correct, but it doesn't show up on teensy, also on teensy the i2c scanner detects "something" on 0x00, but there shouldn't be anyting...

Also, i have HMC5883L magnetometer hooked up to the mpu6050 auxiliary i2c bus, with proper mpu6050 initialization (in i2c bypass mode) i can communicate with the magnetometer without any problems (on arduino), on teensy my scanner also doesn't see it.

I should probably also state that i can communicate with mpu6050 on teensy without any problems, just the second 2 sensors seems completely "non-functional"

el_supremo
01-16-2013, 12:54 AM
Zero isn't a valid I2C device address so your code shouldn't include it in the bus scan.

Pete

PaulStoffregen
01-16-2013, 01:23 AM
I've added the missing return codes:

http://www.pjrc.com/teensy/beta/Wire_slave_mode_15jan13.zip

Please confirm if this solves the problem?

el_supremo
01-16-2013, 02:37 AM
Hi Paul,
That fixes it.

Pete

ploveday
01-16-2013, 02:43 AM
Paul, I notice beta 11 still has the I2C pins (18/19) set up in Wire.cpp as:


CORE_PIN18_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_PE|PORT_PCR_PS;
CORE_PIN19_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_PE|PORT_PCR_PS;

Am I the only one who found it necessary to set these to open drain? Perhaps only relevant for slave operation, though I'd have thought it could cause other issues too?

I have modified my local version to instead do:


CORE_PIN18_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE;
CORE_PIN19_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE;

Which means my two (I2C networked) teensy3s can at least talk to each other, within the previously discussed limitations of STOP detection.

Anyway, perhaps if anyone else is having issues with some I2C devices, the above might be worth a try...

- Peter

PaulStoffregen
01-16-2013, 03:26 AM
Am I the only one who found it necessary to set these to open drain?

Quite possibly yes. I tried numerous combinations. All resulted in open drain output.

I'm going to make another attempt at onReceive() soon... so I'll try this again while I'm at it. I really wanted to find a way to enable the pullups, as is done on AVR, but so far everything I've tried ends up open drain.

ploveday
01-16-2013, 05:09 AM
I thought perhaps I was imagining things, so I just went back and tested again. Using beta 11, with Wire_slave_mode_15jan13.zip, I am still seeing the same thing.

Test setup is pretty simple,
* 2x teensy3s
* GND and Vin connected, powered from USB on either
* SDA and SCL connected, with 1.5k pullups to 3.3V on one of the Teensys.

Master code:

#include <Wire.h>

void setup()
{
pinMode(13, OUTPUT);

Wire.begin();
}

void loop()
{
int num = 0;

Wire.requestFrom(1, 1);

while(Wire.available())
num = Wire.read();

for (int i=0; i < num; i++)
{
digitalWrite(13, 1);
delay(100);
digitalWrite(13, 0);
delay(100);
}

delay(1000);
}


Slave code:

#include <Wire.h>

uint8_t num = 1;

void requestEvent()
{
Wire.write(num++);
}

void setup()
{
Wire.begin(1);
Wire.onRequest(requestEvent);
}

void loop()
{
}


The slave will simply return an incrementing number to the master, which will then flash that many times. Without PORT_PCR_ODE set, nothing happens, with it set, all is fine.

Looking on the scope, it seems the pins are sitting at some inbetween voltage - my assumption was that perhaps both were driving the pin in opposite directions. I'm not sure what sort of output drivers the k20 has? Are they just pullups, or push-pull? If they are push-pull, this could definitely be an issue.

As for the pullups, I can't get much to happen either. The docs explicitly say they should work even if MUXed for I2C, but on the other hand it also says the pullup is only enabled if it's configured as an Input.

Anyway, I'm not sure what's different about my setup, but it seems to behave consistently this way, for me.

- Peter

cTn
01-16-2013, 10:20 AM
Hi Paul, i tried the http://www.pjrc.com/teensy/beta/Wire_slave_mode_15jan13.zip wire version, yes that fixes the "bug" with return codes, however i am still experiencing the same problem (i2c scanner is returning only 1 device, instead of 2)

I also tried the different pin setup from ploveday, that seemed to "open" the main bus properly (i can see both i2c devices on the scanner), i am yet to try getting the auxiliary bus on one of the sensors running, ill get back to you on that.

cTn
01-16-2013, 10:50 AM
Yup, ploveday s different pin 18,19 configuration seems to solve all the device issues that i was having, also accessing 3rd i2c device via auxiliary bus works properly now.

PaulStoffregen
01-16-2013, 02:46 PM
I did some more experimenting. It looks like "PORT_PCR_PE|PORT_PCR_PS" is actually turning on the pullups, but as an output at normal drive strength (not a weak pullup). I put a 100 resistor in series between a Teensy 3.0 and 2.0 (with the pullups disabled on the 2.0), and I measured approx 15 mA current. The AVR is able to pull the line down to about 0.7 volts, but I'm sure many other I2C chips can't. Ouch. I'm pretty sure that's a silicon bug!

I'm going to work on onReceive() today, hopefully with a new version available soon.....

ploveday
01-16-2013, 02:54 PM
Are you sure PORT_PCR_PE|PORT_PCR_PS is doing anything? I'm not seeing much difference with or without those. They seem to be input flags, and the output seems to be either ODE (open drain), or Push-Pull. At least, that's my current guess...

This freescale documentation is abysmal :-/

- Peter

PaulStoffregen
01-16-2013, 03:38 PM
When ODE is set, they seem to do nothing. When it's not set, they enable the pullup, but it's not a weak drive.

Yes, I'm pretty sure. I just spent a few hours experimenting while watching closely on a scope, using external pullups to different voltages, series resistors to try probing the current flow, and lots of other tricks to try observing what the chip is actually doing.

Indeed, Freescale's documentation sucks. It also really looks like there are undocumented silicon bugs with respect to how their I2C peripheral connects to the port mux. I really wanted to find a way to enable the weak pullups and have it be open drain, to give the same experience as Arduino. It looks like ODE without internal pullups is the best option.

PaulStoffregen
01-16-2013, 07:32 PM
I implemented onReceive(). Here's the latest code.

http://www.pjrc.com/teensy/beta/Wire_slave_mode_16jan13.zip

Please give this a try and let me know if it works for you?

cTn
01-16-2013, 07:56 PM
yes Paul, that works properly (at least in my case)

cTn
01-18-2013, 10:15 PM
I implemented onReceive(). Here's the latest code.

http://www.pjrc.com/teensy/beta/Wire_slave_mode_16jan13.zip

Please give this a try and let me know if it works for you?

Paul i think something is not right in that library that you posted, when i have 2+ i2c devices on the bus it works (for me), but if i have just a single i2c sensor connected, it doesn't seem to work at all :/

PaulStoffregen
01-18-2013, 10:39 PM
but if i have just a single i2c sensor connected, it doesn't seem to work at all :/

As always, to investigate I need more information.... detailed enough to reproduce the problem.

ploveday
01-18-2013, 10:45 PM
I'm only testing with a single device (another Teensy3) and it's working fine for me.

What device are you using - and does it matter what single device you try with?

By removing the other devices, you haven't inadvertently removed your pullups have you?

- Peter

cTn
01-18-2013, 10:46 PM
having a single mpu6050 connected (no other i2c devices) on the bus with the last library you posted will make the sensor unresponsive (doesn't even show up on the scanner i posted at the top)

cTn
01-18-2013, 10:50 PM
I'm only testing with a single device (another Teensy3) and it's working fine for me.

What device are you using - and does it matter what single device you try with?

By removing the other devices, you haven't inadvertently removed your pullups have you?

- Peter

I am still using the internal pullups, previously i had mpu6050 and hmc5883l on the main bus (everything was working fine) if i remove the magnetometer i see no devices on the bus :/

ploveday
01-19-2013, 12:30 AM
You can't use the internal pullups. Perhaps the magnetometer has pullups integrated or something. in any case if you don't put pullups on SCL and SDA, it's not going to (reliably) work.

- peter

PaulStoffregen
01-19-2013, 12:58 AM
Pullup resistors on SDA and SCL are required.

Prior versions attempted to activate the on-chip pullups. However, the chip drives basically drives the line high, up to about 15 mA in that mode. Some I2C chips are able to work with such strong pullup, but it's clearly not good. This version disables the on-chip pullup.

You must use 2 resistors.

cTn
01-19-2013, 01:16 AM
ou, so i have to attach some external ones, daaamn :(, well ill do so and get back to you ( i really hoped to avoid external pullups) but when there is no other way .. what you gonna do...

PaulStoffregen
01-19-2013, 02:47 AM
Believe me, I tried to get those internal pullups enabled. It should be possible, according to the chip's documentation, but there seems to be a bug in the chip where enabling the weak pullups while in I2C mode causes an extremely strong pullups (basically driving the line high).

Even if the internal pullups did work, they might not be strong enough. The ones in AVR are just barely able to make I2C work with moderate length wires to 1 chip.

Here's how the signals look using 10K resistors. This is a Teensy 3.0 and a Teensy 2.0 connected together on a breadboard.

162

Changing to 1K resistors dramatically improves the signals:

163

cTn
01-19-2013, 10:52 AM
Thx Paul, i will add 1k external pullups and see how that goes.
Also (just a side note) but i am pretty sure you already tried it, did you try writing the pin configuration "manually" ? a while back when i was working on ppm sampling code, i noticed that PORT_PCR_MUX() wasn't doing what it was supposed to (or it was just some underlying error i made), but i think its worth looking into if you haven't already tried that.