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.