Совместимость с частотой двухпроводного интерфейса (TWI) и SMBus

Правильно ли я понял спецификацию ATmega328P относительно тактовой частоты TWI?

Из §21.5.2 Блока генератора скорости передачи битов тактовая частота TWI рассчитывается следующим образом:

f_{scl}=\frac{f_{cpu}}{16+2\timesTWBR\timesPrescaler}

Затем решаем для TWBR:

TWBR=\frac{\frac{f_{cpu}}{f_{scl}}-16}{2\timesPrescaler}

Однако в §8.12.2 CLKPR – Регистр предварительной настройки тактовой частоты упоминает, что частота процессора задается CLKPR. Таким образом, уравнение должно быть:

f_{scl}=\frac{f_{cpu}}{2^{CLKPR}\times(16+2\timesTWBR\timesPrescaler)}

И решение для TWBR:

TWBR=\frac{\frac{f_{cpu}}{2^{CLKPR}\times f_{scl}}-16}{2\timesPrescaler}

Является ли следующий код правильной реализацией уравнений?

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 ) );
}

Обратите внимание, что smbus-это флаг, установленный в другом месте (глобальный или член класса) для указания режима SMBus.

, 👍0


1 ответ


Лучший ответ:

0

Просто для подтверждения, на случай, если кому-то еще интересно, вторая пара уравнений в моем вопросе является правильной, которая учитывает прескалер тактовой частоты процессора (CLKPR).

Тактовая частота TWI:

f_{scl}=\frac{f_{cpu}}{2^{CLKPR}\times(16+2\timesTWBR\timesPrescaler)}

И решение для TWBR:

TWBR=\frac{\frac{f_{cpu}}{2^{CLKPR}\times f_{scl}}-16}{2\timesPrescaler}

,