Electronic – How is the clock frequency established between master and slave in I2C protocol

i2c

This is a follow-up question to What happens if I omit the pullup resistors on I2C lines?

In a digital wall clock I designed (using the DS1307 RTC and the ATmega328 MCU), I accidentally omitted the pull-up resistors that must be wired to both I2C lines. In the end I was lucky enough that the internal pull-ups on the ATmega I2C lines were enough to (barely) allow the communication between the devices. The result were long rise times on the I2C lines and speed reduction to 32kHz as seen in the scope shots below.

Edit: Actually, the frequency is exactly 100kHz – there are 2 peaks per 20us on the green trace. I initially thought there was a reduction to 32kHz because my scope calculated the frequency on the yellow trace.

Scope shot 1
Scope shot 2

What's puzzling me now is how the devices decided that 32kHz was enough for the communication to take place. The DS1307 datasheet says that the device supports 100kHz frequency on the I2C bus. How come it ended up using 32kHz instead? Is there some kind of handshake phase where the frequency is stablished?

In the end, my question really is this: How is the clock frequency established between master and slave in I2C protocol?

I couldn't find that information searching the Net.

In case this matters, I'm using Arduino IDE 1.03 and my firmware handles the RTC using the DS1307RTC Arduino lib (through its functions RTC.read() and RTC.write()). That lib in turn uses Wire.h to talk to the RTC.

Best Answer

Following up the comments:

Yes, the frequency is hard-coded into some specific I2C-related registers. At runtime.

That said, your Arduino library might be doing some probing and rise time measurement on the bus for determining a viable clock rate. Let's see.


After doing a bit of source-digging, the answer is in twi.h

#ifndef TWI_FREQ
#define TWI_FREQ 100000L
#endif

Another piece from that very file:

TWBR = ((CPU_FREQ / TWI_FREQ) - 16) / 2;

Where TWBR stands for Two Wire Baudrate Register I suspect.

I'd call that enough evidence and definitely say, yes your I2C frequency is set directly by your library without any negotiations. If you want to change it, I'd suggest you #define TWI_FREQ before you #include twi.h (or indirectly through Wire.h)