I2C CLK frequency not what requested

Go To Last Post
6 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi.  I get OK operation on an I2C bus, but I am concerned the CLK frequecies differ from what they should be.

The set up is;

  Adruino UNO 328p CPU

  with I2C connected to an EEPROM

  AS 7

  using library

    /*************************************************************************
     * Title:    I2C master library using hardware TWI interface
     * Author:   Peter Fleury <pfleury@gmx.chhttp://jump.to/fleury
     * File:     $Id: twimaster.c,v 1.4 2015/01/17 12:16:05 peter Exp $
     * Software: AVR-GCC 3.4.3 / avr-libc 1.2.3
     * Target:   any AVR device with hardware TWI
     * Usage:    API compatible with I2C Software Library i2cmaster.h
     **************************************************************************/

 

F_CPU=16,0000,00UL

With SCL_CLOCK=33000 the clock period is about 33 uSec (Oscilloscope measurement).  This is OK.

With SCL_CLOCK=10000 the clock period is about  4 usec while the expectation is about 100 uSec.

 

With other values less than 10000 Hz the period were much shorter than expected.

Is the library not meant to be used in this range ?

 

Regards JC.....

 

 

Last Edited: Wed. Sep 15, 2021 - 11:24 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The result indicates that the prescaler is not being manipulated.

If the prescaler is set up correctly, you can achieve your purpose.

That is, the library does not consider being set below about 30000Hz at 16MHz.
The choice is to either throw away the library or give up 10000Hz.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


 

This is all speculation, as I haven't looked at the contents of that library.

 

Perhaps the library calculates the value to be set in the TWBR (TWI Bit Rate Register) in this way.

TWBR = (Fcpu / Fscl -16) / 2 / (Prescaler Value)

 

case 1:

Fcpu = 16,000,000Hz

Fscl = 33,000Hz

Prescaler Value = 1

Under this condition, TWBR = 234 (0xEA) and it works properly.

 

Case 2:

Fcpu = 16,000,000Hz

Fscl = 10,000Hz

Prescaler Value = 1

Under this condition, TWBR = 792 (0x318), which is a problem.

 

Since TWBR is an 8-bit register, trying to store this value only stores the lower 8-bit value 24 (0x18).

As a result, Fscl will be 250,000Hz.

 

Prescaler Value can be selected from 1,4,16,32.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jmclifford@aanet.com.au wrote:

  Adruino UNO 328p CPU

  with I2C connected to an EEPROM

  AS 7

  using library

    /*************************************************************************
     * Title:    I2C master library using hardware TWI interface
     * Author:   Peter Fleury <pfleury@gmx.chhttp://jump.to/fleury
     * File:     $Id: twimaster.c,v 1.4 2015/01/17 12:16:05 peter Exp $
     * Software: AVR-GCC 3.4.3 / avr-libc 1.2.3
     * Target:   any AVR device with hardware TWI
     * Usage:    API compatible with I2C Software Library i2cmaster.h
     **************************************************************************/

 

F_CPU=16,0000,00UL

If you make the calculations with F_CPU = 1.6MHz and run it on a 16MHz Uno things go wrong.

 

Normally you calculate for prescaler = 1:

TWBR = 0.5 * (F_CPU / I2C_CLK - 16);

TWBR = 0.5 * (1.6MHz / 100kHz - 16) = 0.5 * (16 - 16) = 0;   //ALL WRONG

TWBR = 0.5 * (16MHz / 100kHz - 16) = 0.5 * (160 - 16) = 72;  //normal

TWBR = 0.5 * (16MHz / 400kHz - 16) = 0.5 * (40 - 16) = 12;  //normal

TWBR = 0.5 * (16MHz / 10kHz - 16) = 0.5 * (1600 - 16) = 792; // EXCEEDS 8-bit

TWBR = 0.5 * (16MHz / 33kHz - 16) = 0.5 * (484 - 16) = 234;  //just fits in 8-bit

If you want to calculate values you should always use accurate F_CPU value.

 

If you really want unusual bus speeds like 10kHz you need to use a prescaler.

But you have probably noticed that F_CPU = 1MHz or 1.6MHz will go WRONG for 100kHz.

And it is a struggle to achieve 400kHz with F_CPU = 8MHz

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you.

You both are correct with my initial request.  My Peter Fleury  library initialisation now looks like;

 

/*************************************************************************
 Initialization of the I2C bus interface. Need to be called only once
*************************************************************************/
void i2c_init(void)
{
  /* initialize TWI clock: to SCL_CLOCK, with TWSR = 0  =>  TWPS = 00B  =>  prescaler = 1
   * or
   * initialize TWI clock: to SCL_CLOCK, with TWSR = 2  =>  TWPS = 10B  =>  prescaler = 16
   *
   * Going down the SCL_CLOCK scale the next boundary condition is 1949 Hz where the
   * prescaler of 16 becomes inadequate.
   */
  #if SCL_CLOCK > 30303L
   
    TWSR =        0;                  /* prescaler of 1 */
    TWBR = ((F_CPU/SCL_CLOCK)-16)/2;  /* must be > 10 for stable operation */
 
  #else  
 
    TWSR =        2;                       /* prescaler of 16 */
    TWBR = ((F_CPU/SCL_CLOCK)-16)/(2*16);   /* must be > 10 for stable operation */
 
  #endif

}/* i2c_init */

 

So I should be able to investigate 2K Hz upwards without any such scaling issues.

 

Regards JC.....

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No,  your conditionals are not foolproof.

 

You can see where the TWBR result > 255.  i.e. when (F_CPU / SCL_CLOCK - 16 > 511)

The Preprocessor can do these calculations.

 

It can also tell you if (F_CPU / SCL_CLOCK <= 16)

 

But seriously.   Your Uno is 16MHz.   You will use the standard 100kHz bus unless you know your Slaves work with 400kHz.

 

In practice,  most AVRs will work at 8MHz, 12MHz, 16MHz, 20MHz.    Or perhaps baud-friendly XTALs in a similar range.

No one will ever want to use 10kHz unless they know F_CPU is very SLOW.    Fine for a low-traffic Slave but criminal for say an OLED display.

 

David.