On the Arduino development platform, the high-level TwoWire interface is provided by the Wire library, which itself depends on the underlying code utility/twi.c to manipulate the microcontroller hardware. During initialization, TWI frequency prescaler (TWBR) is calculated and programmed to set SCL clock run at 100 KHz in twi_init() and twi_setFrequency() according to this formula:
TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;
Where F_CPU is CPU frequency and TWI_FREQ is the target SCL frequency, default to 100 kHz under all circumstances.
However, it is flawed. If F_CPU is at 1 MHz, a negative value, -3 will be calculated and set as the frequency prescaler. All frequencies that are slower than 1.8 MHz results an integer underflow, and program TWBR to a large value, causing extremely slow SCL frequency which affects usability of the bus.
The recommanded solution is to lower TWI_FREQ to the largest possible value under a low CPU frequency instead of trying 100 kHz, and provide a fallback if the formula gives unreasonable value, such as TWBR = 2.
We also need to ensure TWBR is not to low at other frequencies to stay within the spec, the comments stated "TWBR should be 10 or higher for master mode", but I haven't checked the datasheet for more information.
This is because datasheet states that "CPU clock
frequency in the Slave must be at least 16 times higher than the SCL frequency" that is we need F_CPU 16 times greater than SCL frequency.
On the Arduino development platform, the high-level TwoWire interface is provided by the Wire library, which itself depends on the underlying code
utility/twi.c
to manipulate the microcontroller hardware. During initialization, TWI frequency prescaler (TWBR
) is calculated and programmed to set SCL clock run at 100 KHz intwi_init()
andtwi_setFrequency()
according to this formula:Where
F_CPU
is CPU frequency andTWI_FREQ
is the target SCL frequency, default to 100 kHz under all circumstances.However, it is flawed. If
F_CPU
is at 1 MHz, a negative value,-3
will be calculated and set as the frequency prescaler. All frequencies that are slower than 1.8 MHz results an integer underflow, and programTWBR
to a large value, causing extremely slow SCL frequency which affects usability of the bus.The recommanded solution is to lower
TWI_FREQ
to the largest possible value under a low CPU frequency instead of trying 100 kHz, and provide a fallback if the formula gives unreasonable value, such asTWBR = 2
.We also need to ensure
TWBR
is not to low at other frequencies to stay within the spec, the comments stated "TWBR should be 10 or higher for master mode", but I haven't checked the datasheet for more information.