# Two-Wire Interface (TWI) Frequency and SMBus Compatibility

Have I understood the ATmega328P datasheet correctly regarding the TWI clock frequency?

From §21.5.2 Bit Rate Generator Unit, the TWI clock frequency is calculated as follows: Then solving for TWBR: However, §8.12.2 CLKPR – Clock Prescale Register mentions that the CPU frequency is prescaled by CLKPR. So should the equation be: And solving for TWBR: Is the following code a correct implementation of the equations?

void SetFrequency(uint32_t twi_freq)
{
if (smbus)
{
// SMBus clock frequency is 10 kHz to 100 kHz.
if (twi_freq > 100000u)
{
twi_freq = 100000u;
}
else if twi_freq < 10000u)
{
twi_freq = 10000u;
}
}
else if (twi_freq > 400000u)
{
// Up to 400 kHz data transfer speed.
// §21.1 Features
twi_freq = 400000u;
}

// TWI prescaler of 1.
// Table 21-8. TWI Bit Rate Prescaler
// TWPS1 = 0, TWPS0 = 0
TWSR &= B11111100;

// Achievable maximum TWI frequency with current CPU frequency, CLK prescaler and minimum TWBR with TWI prescaler of 1.
// Rounded down to nearest integer.
const uint32_t TWI_FREQ_MAX = F_CPU / ( ( 1 << CLKPR ) * ( 16 + 2 * 0x00 * 1 ) );

// Achievable minimum TWI frequency with current CPU frequency, CLK prescaler and maximum TWBR with TWI prescaler of 1.
// Rounded up to nearest integer.
const uint32_t DIVISOR = ( ( 1 << CLKPR  ) * ( 16 + 2 * 0xFF * 1 ) );
const uint32_t TWI_FREQ_MIN = (F_CPU + (DIVISOR - 1)) / DIVISOR;

if (twi_freq > TWI_FREQ_MAX)
{
twi_freq = TWI_FREQ_MAX;
}
else if (twi_freq < TWI_FREQ_MIN)
{
twi_freq = TWI_FREQ_MIN;
}

// TWI bit rate.
// §21.5.2 Bit Rate Generator Unit
// §8.12.2 CLKPR – Clock Prescale Register
byte bit_rate = (F_CPU / (1 << CLKPR) / twi_freq - 16) / 2

TWBR = bit_rate;

// Check.
const uint32_t twi_freq = F_CPU / ( ( 1 << CLKPR ) * ( 16 + 2 * TWBR * 1 ) );
}


Note that smbus is a flag set elsewhere (global or class member) to indicate SMBus mode.

Just to confirm, in case anyone else is wondering, the second pair of equations in my question are the correct ones which take the CPU clock prescaler (CLKPR) into account. And solving for TWBR: 