change I2C speed WITHOUT modifying library?

Is there any way to change I2C speed from 100K to 400K in one's own code, i.e. without modifying libraries/Wire/utility/twi.h?

I would like to ensure that if someone else later builds my code having re-downloaded the libraries, they don't unknowingly revert to 100K speed.

Alternatively, is there any way to detect in my code what speed I2C is running at - either at runtime, or, ideally, during the build process (I build from edam's Arduino makefile).

This code sequence should give you the current frequency.

uint32_t prescaler = 4 ^ (TWSR & 0x03);
uint32_t freq = 16000000L / (16 + 2 * TWBR * prescaler);

I don't see a possibility to get that frequency at compile time.

To set a frequency of 400k use:

TWSR &= 0xFC;
TWBR = 12;

Thank you!

I finally got a chance to actually try this.

If I say:

Wire.begin();                                // set up I2C comms
TWSR &= 0xFC;                                // set I2C frequency of 400K
TWBR = 12;
uint32_t i2c_prescaler = 4 ^ (TWSR & 0x03);
uint32_t i2c_freq = 16000000L / (16 + 2 * TWBR * i2c_prescaler);

and then later on

serial_printf("i2c=%d\n", (int) (i2c_freq / 1000))

It prints [b]142[/b] instead of the expected [b]400[/b].

If I put the [b]Wire.begin()[/b] after the two register setting lines instead of before them, I get [b]27[/b] instead of the expected [b]400[/b].

What am I doing wrong?

There is a limit of values TWBR can take as IIRC it is only 8 bit.

Check this code - MultiSpeed I2C Scanner - 50,100,200,400 KHz. - Libraries - Arduino Forum - of the multispeed i2c scanner

I am setting TWBR correctly according to the link you just posted.

F_CPU = 16000000
speed = 400
TWBR = (F_CPU/(speed*1000) - 16)/2;

So TWBR = 12 which is what I have up above.

So I guess my question is about the prescaler.

The first answerer above said:

uint32_t prescaler = 4 ^ (TWSR & 0x03);
uint32_t freq = 16000000L / (16 + 2 * TWBR * prescaler);

But freq would be 400 only if prescaler = 1.

TWSR &= 0xFC;

that code clears the lowest two bits in the register, so TWSR & 0x03 is always 0 and 4 ^ 0 is 1 as you would expect. If you get the result 142, TWSR must have bit 0 set but I see absolutely no reason for that. To test, don't divide by 1000 in the print. What do you get then?

and 4 ^ 0 is 1 as you would expect

Wait, what? 4 ^ 0 is 4, not 1.

As expected, I get 142857, which means the prescaler is coming out as 4, which is what 4 ^ 0 is.

(You do know that ^ means XOR, not exponent, right?)

(You do know that ^ means XOR, not exponent, right?)

Although I actually do know I didn't realize, I definitely switch between languages too often. That's my error, please excuse. The good news is that just the calculation of the set speed is wrong, the speed itself is correct.

The correct calculation would be:

#include <math.h>
uint32_t i2c_prescaler = pow(4, TWSR & 0x03);
uint32_t i2c_freq = 16000000L / (16 + 2 * TWBR * i2c_prescaler);