Changing I2C clock speed

I am looking to increase the I2C clock speed for better I2C throughput.

I see lots of posts about how to do this for the various arduino variants. It appears that some Wire libraries have a Wire.setClock() function that works, while others suggest changing twi.h file in the library to increase the speed.

None of these seem to apply to the 101 though.

I looked in C:\Users\xxxxx\AppData\Local\Arduino15\packages\Intel\hardware\arc32\1.0.4\libraries\Wire

and found Wire.h file.

There does not seem to be any reference to a clock speed in the file.

Any ideas on how to accomplish this?

Hi,
the Wire library ported to 101 doesn't contain a setClock() function; you can change the interface speed by navigating to Intel\hardware\arc32\1.0.4\cores\arduino\i2c.c -> function i2c_openadapter() and change

i2c_cfg.speed = I2C_SLOW;

into
i2c_cfg.speed = I2C_FAST; (400khz)

I'll open an issue on github to add that function and it will probably be included in next core update. Thanks for the report!

OK thanks, I think that worked.

You can see a scope trace here, with the clock in red. It is now around 317 kHz, and appears to have some capacitance as it isn't very square wavey, and doesn't make it all the way to 3.3V.

I hooked the same slave up to a raspberry pi, and used its I2C decoding. It must have different pullup resistors, as the clock trace looked much better.

Any reason why I'm not quite getting 400kHz?

I performed the initial test without any load and the signals looked good.
Adding a peripheral shows the issue you are experiencing; by adding an external 4K7 pullup resistor to both SDA and SCL lines I was able to get a nicer (and faster) signal.
Hope it helps!

Hi facchinm

Did they ever add a setClock function to the new corelib?

Mike

Hi facchinm

Came up with an easy way, I think, to make the chose between fast or slow clock speed an option. Here are the changes:

In Wire.h
Add the following line to public:

void begin(bool i2c_clock);

In Wire.cpp
Add the following function call:

void TwoWire::begin(bool i2c_speed)
{
 init_status = i2c_openadapter(i2c_speed);
}

edit the existing TwoWire::begin() to

init_status = i2c_openadapter(false);

In i2c.h
change the i2c_openadapter line to read:

int i2c_openadapter(bool i2c_speed);

In i2c.c
delete line i2c_cfg.speed and insert:

if(i2c_speed == true) {
 i2c_cfg.speed = I2C_FAST;
 } else {
 i2c_cfg.speed = I2C_SLOW;
 }

Simple usage:

For slow i2c clock just use wire.begin() or wire.begin(false).

For fast i2c_clock just use wire.begin(fast)

It compiles with no problem but not 100% sure its taking. I don't have a scope so I can not test. Hope someone can verify and maybe we can get them to incorporate it.

Thanks
Mike

Mike,
I've tried implementing your Wire.cpp, Wire.h, i2c.h and i2c.c changes in .....1.0.5\Libraries\ and ......1.0.5\cores\ on two Win7 PCs. In both cases, the IDE sketches (including the blank sketch) will not compile. Error message: "exit status 1 Error compiling for board Arduino/Genuino 101".

Hoping to figure this out and see if my DMM's frequency counter will confirm a speed change at SDA and SCL pins with 4k7 pull-up resistors per facchinm's Jan 19 post. Please check your instructions.

Bill

Hi Bill

Just checked and the changes look correct. If you scroll up in the compile window there should be a more detailed message on where the error is, I hope.

Mike

PS Just to recap the changes::

In wire.h you should have the following two lines for wire.begin():

void begin();
 void begin(bool i2c_speed);

In wire.cpp it should read for the TwoWire.wire.begin functions:

void TwoWire::begin()
{
	init_status = i2c_openadapter(false);
}

void TwoWire::begin(bool i2c_speed)
{
	init_status = i2c_openadapter(i2c_speed);
}

In i2c.h the openadapter line should be:

int i2c_openadapter(bool i2c_speed);

In i2c.c the openadapter function should read:

int i2c_openadapter(bool i2c_speed)
{
	int ret;

	SET_PIN_MODE(24, I2C_MUX_MODE); // Rdx SOC PIN (Arduino header pin 18)
	SET_PIN_MODE(25, I2C_MUX_MODE); // Txd SOC PIN (Arduino header pin 19)

	SET_PIN_PULLUP(24, 1);
	SET_PIN_PULLUP(25, 1);

	i2c_cfg_data_t i2c_cfg;
	memset(&i2c_cfg, 0, sizeof(i2c_cfg_data_t));

	if(i2c_speed == true) {
		i2c_cfg.speed = I2C_FAST;
	} else {
		i2c_cfg.speed = I2C_SLOW;
	}
	i2c_cfg.addressing_mode = I2C_7_Bit;
	i2c_cfg.mode_type = I2C_MASTER;
	i2c_cfg.cb_tx = ss_i2c_tx;
	i2c_cfg.cb_rx = ss_i2c_rx;
	i2c_cfg.cb_err = ss_i2c_err;

	i2c_tx_complete = 0;
	i2c_rx_complete = 0;
	i2c_err_detect = 0;

	ss_i2c_set_config(I2C_SENSING_0, &i2c_cfg);
	ss_i2c_clock_enable(I2C_SENSING_0);
	ret = wait_dev_ready(I2C_SENSING_0, false);

	return ret;
}

Thank you again, Mike.

First, I hadn't noticed IDE's compile window scroll-up feature. It's very useful to know.

Second, with your help, I located the library recoding problem: i2c.c line 102 needed to change from i2c_openadapter(void) to int i2c_openadapter(bool i2c_speed).

Once the modified i2c and wire libs were compiling, I tried replacing TWBR references with wire.begin() and wire.begin(fast) in Adafruit's library for the MCP4725 DAC breakout. This produced two error messages:
'wire' was not declared in this scope, and
'fast' was not declared in this scope

These errors went away when I changed to twowire.begin, which I noticed was more obviously defined in the library code. I don't know enough C and C++ to know why. In any case, fast and slow doesn't change performance of Adafruit's MCP4725 sketches, not a bit.

Unfortunately, I was unable to find a signal to measure frequency at the SDA and SCL pins with my DMM. Need to get a scope someday soon (I hope).

After reviewing Adafruit's MCP4725 sketches further, I realized today that communications with and output from the DAC are much faster than previously thought. The speed of voltage changes in DAC output is dependent on code complexity, I'm seeing DAC output speeds high as 27,414/sec using the Uno, and 4,023/sec using the Arduino 101 with a test code that simply flips between high and low with no delays.

I can't seem to get the 101 anywhere close to the Uno's performance with this i2c DAC. Coding to change i2c frequency makes no difference, but it might when Intel core libraries get fixed. Since the observed difference between Uno and 101 with this DAC are much greater than a multiple of 4, though, it may be that differences in processor, I/O speeds speeds in the two Ardino variants are at play. Is it possible that the 101 isn't as fast as the Uno overall for certain tasks?

Bill

Hi Bill

Glad you got it somewhat working. I finally broke down and bought a cheap USB scope and just finished running some tests with it. SDA you can see a difference and the trace makes sense even though not great - probably need to reduce the pullups to 2k2 from 4k7.

SCL at either speed just doesn't look right to me. It just looks like the clock is messed up. The scope can't even get a good frequency reading. But then again I am not sure how to use a scope

Here is a link to all the screen shots.

Think I am done with this board for a while until someone from Intel lets us know whats going on with I2C, not sure anymore if the internal SPI from the IMU is interfering with the I2C timing.

As for the uno being faster for some tasks, don't know. Think it may be more of a maturity of the board.

UPDATE: After I posted this thought I would just test the 5883L by itself without the BMI160. Guess what - now the 101 does not even find the magnetometer.

Mike

Is the wire library updated now ? - is there a per-project way of setting the I2C clock ?

I believe it has. Just use wire.setClock(400000L) for fast or wire.setClock(100000L). You could also use wire.setClock(I2C_SPEED_FAST).

Have fun.

Yes, I thought so too after looking at the wire library in Arduino 1.6.12
but Wire.setclock(400000L) gives me:

'class TwoWire' has no member named 'setclock'
Wire.setclock(400000L)
^
exit status 1
'class TwoWire' has no member named 'setclock'

Try using capital C in clock so it reads Wire.setClock(400000L) instead of Wire.setclock(400000L).

Mike

ok, that's embarrassing !

  • Thank you. :slight_smile:

Not to worry. Done that about a million times myself and drove me nuts. :slight_smile: