I2c wire emulation-changing the I2C bus speed

Status
Not open for further replies.

vsurducan

Member
Hi all,

I have a complex split I2C bus with 20 devices on it.
The communication with all devices works ok with with Teensy 3.1 at 100KHz, emulating the wire library.
I wasn't able to make it run with newest i2c_t3 library because the leak of examples I found, perhaps I didn't set everything right.

I want to increase the I2C bus speed to 400KHz or 1MHz, using the wire library.
Since I do not understand the emulation concept even I've looked to the twi and wire files, do I have to modify the twi.h file (arduino1.6.5r2/hardware/tensy/avr/libraries/wire/utility/twi.h) ?

#ifndef TWI_FREQ
#define TWI_FREQ 100000L // 400000L for 400KHz, 1000000L for 1MHz?
#endif

However, the TWBR emulation code from wire.h looks like 400KHz is maximum accepted while the "TwoWire::setClock(uint32_t frequency)" routine from wire.ccp shows that 1MHz I2C is possible.

How do I set the I2C wire for 400KHz or 1MHz speed in a proper way, without altering the library ?

thx,
Vasile
 
The likely problem is bus capacitance and the length of the wires involved. Longer wires either require additional circuitry or lower clock speeds. How long are the connections?
 
The likely problem is bus capacitance and the length of the wires involved. Longer wires either require additional circuitry or lower clock speeds. How long are the connections?

"The communication with all devices works ok with with Teensy 3.1 at 100KHz, emulating the wire library"

I do not have any hardware problem, I don't know to setup the wire library for 400KHz or 1MHz I2C bus frequency.

thx,
 
Please post schematics and links to device specifications. As constantin has already explained the ( electrical) limitation to bus speed is the overall bus capacitance that cannot exceed 400pF.

The i2c_t3 library is really a drop in replacement for the Wire library. You just need to change the includes from wire.h to i2c_t3.h

The thread for the library explains how to change the bus frequency and many other things:
https://forum.pjrc.com/threads/21680-New-I2C-library-for-Teensy3?highlight=i2c_t3

Without additional hardware you'll not get to raise the bus frequency above 400MHz. Devices for over 400MHz are FM+ devices (Fast Mode +) and you'll need a bus buffer at least for the Teensy. The FM+ specification deals with the negative effects of the bus capacitance by raising the max current that can be sunk by I2C pins from 3mA to 30MA and allows a max bus capacitance of 4000pF.
I use the PCA9600 from NXP in my LED lighting systems ( trippylighting.com) with 11 I2C devices on the bus over 14ft of CAT5 Ethernet cable at 1MHz. Works like a charm.

Please also explain how you've split the bus as that also usually requires additional devices such as as said bus buffers.
 
The i2c_t3 library is really a drop in replacement for the Wire library. You just need to change the includes from wire.h to i2c_t3.h


The thread for the library explains how to change the bus frequency and many other things:
https://forum.pjrc.com/threads/21680-New-I2C-library-for-Teensy3?highlight=i2c_t3

I read this post. Simple replacement of the includes does not work for me.

Without additional hardware you'll not get to raise the bus frequency above 400MHz. Devices for over 400MHz are FM+ devices (Fast Mode +) and you'll need a bus buffer at least for the Teensy. The FM+ specification deals with the negative effects of the bus capacitance by raising the max current that can be sunk by I2C pins from 3mA to 30MA and allows a max bus capacitance of 4000pF.
I use the PCA9600 from NXP in my LED lighting systems ( trippylighting.com) with 11 I2C devices on the bus over 14ft of CAT5 Ethernet cable at 1MHz. Works like a charm.

Please also explain how you've split the bus as that also usually requires additional devices such as as said bus buffers.

I don't understand which is the 400MHz bus you are talking about, this is impossible on any I2C bus or perhaps you are talking about something else. I do not have any hardware problems on the I2c bus as I already said.

In this moment I want to use the wire library and not the i2c_t3. Can anyone tell me how to set the wire lib for 1MHz I2C?

Assuming the datasheet of MK20DX256, Teensy does not need any I2C buffer for 400KHz or 1MHz I2C bus as long the bus met the specification. I have a short one, timings looks quite ok on my Tek MSO4000.
 
Last edited:
Sorry, I meant 400KHz of course :p

Of course you don't have any problems as you still running at 100KHz.
Maybe you won't have any at 400KHz either or even at 1MHz

I can't help with the wire library as I use the i2c_t3 library where setting the bus frequency is easy.
If you don't get responses that help you with this, perhaps post your code so we can figure out why the i2c_t3 library is not working for you.
 
Found it in Wire.cpp

In order to use 400KHz or 1MHz you need to edit Wire.cpp. With Arduino 1.6.x the Teensyduino libraries are not in .../Java/Libraries/Wire/ but in .../Java/hardware/teensy/avr/libraries/Wire

Then in Wire.cpp comment/un-comment the obvious lines

Code:
void TwoWire::setClock(uint32_t frequency)
{
#if F_BUS == 60000000
	if (frequency < 400000) {
		I2C0_F = 0x2C;	// 104 kHz
	} else if (frequency < 1000000) {
		I2C0_F = 0x1C; // 416 kHz
	} else {
		I2C0_F = 0x12; // 938 kHz
	}
	I2C0_FLT = 4;
#elif F_BUS == 56000000
	if (frequency < 400000) {
		I2C0_F = 0x2B;	// 109 kHz
	} else if (frequency < 1000000) {
		I2C0_F = 0x1C; // 389 kHz
	} else {
		I2C0_F = 0x0E; // 1 MHz
	}
	I2C0_FLT = 4;
#elif F_BUS == 48000000
	if (frequency < 400000) {
		I2C0_F = 0x27;	// 100 kHz
	} else if (frequency < 1000000) {
		I2C0_F = 0x1A; // 400 kHz
	} else {
		I2C0_F = 0x0D; // 1 MHz
	}
	I2C0_FLT = 4;
#elif F_BUS == 40000000
	if (frequency < 400000) {
		I2C0_F = 0x29;	// 104 kHz
	} else if (frequency < 1000000) {
		I2C0_F = 0x19; // 416 kHz
	} else {
		I2C0_F = 0x0B; // 1 MHz
	}
	I2C0_FLT = 3;
#elif F_BUS == 36000000
	if (frequency < 400000) {
		I2C0_F = 0x28;	// 113 kHz
	} else if (frequency < 1000000) {
		I2C0_F = 0x19; // 375 kHz
	} else {
		I2C0_F = 0x0A; // 1 MHz
	}
	I2C0_FLT = 3;
#elif F_BUS == 24000000
	if (frequency < 400000) {
		I2C0_F = 0x1F; // 100 kHz
	} else if (frequency < 1000000) {
		I2C0_F = 0x12; // 375 kHz
	} else {
		I2C0_F = 0x02; // 1 MHz
	}
	I2C0_FLT = 2;
#elif F_BUS == 16000000
	if (frequency < 400000) {
		I2C0_F = 0x20; // 100 kHz
	} else if (frequency < 1000000) {
		I2C0_F = 0x07; // 400 kHz
	} else {
		I2C0_F = 0x00; // 800 MHz
	}
	I2C0_FLT = 1;
#elif F_BUS == 8000000
	if (frequency < 400000) {
		I2C0_F = 0x14; // 100 kHz
	} else {
		I2C0_F = 0x00; // 400 kHz
	}
	I2C0_FLT = 1;
#elif F_BUS == 4000000
	if (frequency < 400000) {
		I2C0_F = 0x07; // 100 kHz
	} else {
		I2C0_F = 0x00; // 200 kHz
	}
	I2C0_FLT = 1;
#elif F_BUS == 2000000
	I2C0_F = 0x00; // 100 kHz
	I2C0_FLT = 1;
#else
#error "F_BUS must be 60, 56, 48, 40, 36, 24, 16, 8, 4 or 2 MHz"
#endif
}

Let us know how that works.

Edit: no commenting / un-commenting needed.

in Wire.cpp change

Code:
setClock(100000);
to your preferred I2C bus speed.
 
Last edited:
Headroom (maybe you'll tell me your real name)
this is the answer I wanted.

setClock (400000); Teensy3.1 at 48MHz gives a real I2C clock of about 280KHz
setClock (1000000); Teensy3.1 at 48MHz gives a real I2C clock of about 540KHz


The F_BUS probably is computed when you set the board, however there is a difference when change directly
the I2C0_F = 0x0D; // 1 MHz and I2C0_FLT = 4; for a 48MHz bus compared when you let the library to set it in the if-then else part.

Sometimes, quite randomly, the I2C pins are not intialized. Please do not ask me if I have pull-ups on the I2C clk and sda. :)
 
Do you have external pullup resistors for the I2C and if so, of what value?

Yes I have, everything seems almost ok now, both with wire and with i2c_t3 library.
The i2c_t3 does work for me only with internal pullups. The external pull-up is 1k5, the real I2C clock around 700KHz.
I also have a 5KV I2C isolator (which I've designed) on the bus between the MK20 and the slaves....

Not the pull-up was the problem for me, thanks for asking... :)
 
setClock (400000); Teensy3.1 at 48MHz gives a real I2C clock of about 280KHz
setClock (1000000); Teensy3.1 at 48MHz gives a real I2C clock of about 540KHz

Those speeds might be bugs. The Wire.setClock() function is relatively new, so maybe some if it needs tuning?

As a general rule, I only investigate bugs when a complete test program is posted. In this case, it ought to be fairly trivial. Still, a complete test program is essential, so I know I'm testing the exact same program you used. Sometime small, seemingly insignificant details turn out to matter.

Any chance you could post the (hopefully small) program you used for testing these speeds?
 
Those speeds might be bugs. The Wire.setClock() function is relatively new, so maybe some if it needs tuning?

As a general rule, I only investigate bugs when a complete test program is posted. In this case, it ought to be fairly trivial. Still, a complete test program is essential, so I know I'm testing the exact same program you used. Sometime small, seemingly insignificant details turn out to matter.

Any chance you could post the (hopefully small) program you used for testing these speeds?

Hi Paul,
I don't think are bugs, almost the same bus speed I see with i2c_t3 too, perhaps a little bit more accurate.
I'll try to do a simple i2C clk speed measurement with a single i2c device, to be easier for testing, but I can't right now, I'm a little bit busy.

However, the i2c_t3 library to be fully compatible with arduino wire, it seems the I2C mode should be set to I2C_OP_MODE_IMM and not I2C_OP_MODE_ISR as written in the github documentation:

"Wire.setOpMode(opMode); - this configures operating mode of the I2C as either Immediate, ISR, or DMA. By default Arduino-style begin() calls will initialize to ISR mode. "


thank you all for your support!
 
Status
Not open for further replies.
Back
Top