ATTINY402 I2C slave max. speed vs. Fclk Periph

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

Hello,

I use ATTINY 402 as I2C Slave. SCL have 100kHz. Invalid Data are readed with default clock (=20/6 MHz). With 20MHz Clock the Data are readed correctly. What is the relationship between Fclk Periph and I2C data speed?

 

This topic has a solution.
Last Edited: Fri. Jan 14, 2022 - 02:29 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please link to the example code you are using or post your custom code.

 

From memory,  you can achieve 400kHz Slave with 8MHz tiny2313 with USI.  So I would expect you can get 1MHz Slave @ 20MHz on a modern tiny402.

You should get 100kHz fine with F_CPU @ 3.33MHz

 

Untested.  I will dig out old project when I see what library code you are using.

 

David.

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

Welcome to AVR Freaks

dania wrote:
I use ATTINY 402 as I2C Slave. SCL have 100kHz

What are you using as the Master? Are you sure it is really doing 100kHz?

 

Invalid Data are read with default clock 

In what way(s), exactly, is the data "invalid"? How are you observing this?

 

Do you have an oscilloscope or analyser to see what's actually happening on the wires?

 

Please see Tip #1 in my signature, below, for how to post source code:

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#include <avr/io.h>
#include <avr/interrupt.h>

#define I2C_ADDRESS		0x80
#define SDATA_LENGHT	4

volatile uint8_t sended;
volatile unsigned char sdata[2] [SDATA_LENGHT];
volatile uint8_t valid = 0;					//first sdata index to valid data
volatile bool sync_lock = false;

int main(void)
{
    //enable pullups
    PORTA.PIN0CTRL = 0x08;
    PORTA.PIN1CTRL = 0x08;
    PORTA.PIN2CTRL = 0x08;
    PORTA.PIN3CTRL = 0x08;
    //PORTA.PIN4CTRL = 0x08;
    //PORTA.PIN5CTRL = 0x08;
    PORTA.PIN6CTRL = 0x08;
    PORTA.PIN7CTRL = 0x08;

	//IIC output buffer init
	for(int i = 0; i < SDATA_LENGHT; i++)
	{
		sdata[0] [i] = 0x30 + i;
		sdata[1] [i] = 0x30 + i;
	}

	//IIC init
	TWI0.SADDR = I2C_ADDRESS;
	TWI0.SCTRLA = 0xE2;			//all IIC interrupts enabled, smart mode
	TWI0.SCTRLA |= 0x01;		//IIC enable

	sei();

    while (1)
    {
    }
}

//***************************************************************************************
//IIC
void SendByte()
{
	TWI0.SDATA = sdata[valid] [sended];
	if (++sended >= SDATA_LENGHT)
	{
		sended = SDATA_LENGHT;
	}
}

ISR(TWI0_TWIS_vect)
{
	if (TWI0.SSTATUS & 0x40)			//APIF interrupt
	{
		if (TWI0.SSTATUS & 0x01)
		{								//address detection
			if (TWI0.SSTATUS & 0x02)	//direction
			{							//read
				sync_lock = true;
				sended = 0;
				TWI0.SCTRLB = 0x03;		//ACK
			}
			else
			{							//write not supported
				TWI0.SCTRLB = 0x07;		//NACK
			}
		}
		else
		{								//STOP condition
			TWI0.SCTRLB = 0x02;
			sync_lock = false;
		}
	}

	if (TWI0.SSTATUS & 0x80)			//DIF interrupt
	{
		if (TWI0.SSTATUS & 0x02)		//direction
		{								//read
			if (sended)
			{
				if (TWI0.SSTATUS & 0x10)
				{						//NACK received
					TWI0.SCTRLB = 0x07;
				}
				else
				{						//ACK received
					SendByte();			//send next byte
				}
			}
			else
			{
				SendByte();				//send first byte
			}
		}
		else
		{								//write not supported
			TWI0.SCTRLB = 0x07;			//NACK
		}
	}
}

Master: FT4232H, MPSSE used

I2C monitored by logic analyzer. SCL have period = 10 020 ns. Master and analyzer reads the same result 0x06, 0x3F, 0xFF, 0xFF. All bytes are confirmed by ACK.

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

dania wrote:
Master and analyzer reads the same result 0x06, 0x3F, 0xFF, 0xFF.

So what does the Slave see, and how are you observing that?

 

EDIT

 

Sorry, which direction are you calling "read" here?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Thu. Jan 13, 2022 - 12:25 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Master (FT4232H) read from Slave (ATTINY402).

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

Have you used the debugger to see what's happening inside the Tiny ?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please post your Master test code.   I normally just put it in an Arduino sketch.

 

i.e send some known command / data.

Receive data.

Compare what I received with what I expected.

 

Write the whole "test suite" like above.   Stop when the comparison fails.

 

When all the tests pass.   Print "done"

 

I will run your code on a Tiny817 later this afternoon.

 

David.

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

JTAG ICE 3 connected to UPDI.

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

and what have you learned from using that?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I went through it several times and I don't see a mistake. Write step by step what you would do.

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

I tried a 100kHz Master from a Uno with a Slave running on a Tiny817.

 

I altered the ISR() to support SLAVE_W.   e.g. to control the valid variable.   (and initialised sdata[1] = "5678" )

 

It ran fine at 20MHz div6 i.e. 3.33MHz

It ran ok at 20MHz div32 i.e. 625kHz  but the Slave was very visibly stretching SCL.

It failed at 20MHz div48 i.e. 417kHz

It seems a fairly pointless Slave functionality.   What do you really want to do ?

Do you have an official test suite ?

 

David.

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

Post your code, please.

 

I tested following combinations:

1. 20MHz with div2 and SCL 100kHz - OK

2. 20MHz with div4 and SCL 100kHz - Fail

3. 20MHz with div6 and SCL 25kHz - OK

 

When communication fails, Address Packet is accepted, ACK is sent from my slave. After this is first Data Packet send - at BUS is invalid. After first Data Packet is RXACK flag in SSTATUS set even though the master has sent an ACK.

 

I still tried to edit my Slave for writing. With 20MHz (no divided clock) and SCL 100kHz work fine. With default clock SDA line is corrupted. Slave Write NACK.

 

There are two ADCs on the same bus that communicate without problems.

Need measuring two signals frequency (<110Hz).

I don't have an official test suite.

 

I still wondered if there was a conflict with the galvanic separation ADUM1251.

 

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

Here is my Slave

/*
* i2c_slave_t402.c
*
* Created: 13-Jan-22 14:19:56
* Author : David Prentice
*/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdbool.h>

#define I2C_ADDRESS		0x80  // 7-bit address 0x40
#define SDATA_LENGHT	4

volatile uint8_t sended;
volatile unsigned char sdata[2] [SDATA_LENGHT];
volatile uint8_t valid = 0;					//first sdata index to valid data
volatile bool sync_lock = false;

int8_t CLKCTRL_init()
{
    uint8_t n;
#if defined(__AVR_ATtiny817__)
    n = CLKCTRL_CLKSEL_OSC20M_gc | 1 << CLKCTRL_CLKOUT_bp; //PB5
#else
    n = CLKCTRL_CLKSEL_OSC20M_gc; //t402 has no CLKOUT pin
#endif
    CCP = CCP_IOREG_gc;
    CLKCTRL.MCLKCTRLA = n;
    while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm) ;
    //n = 0 << CLKCTRL_PEN_bp;    //div1 i.e. no prescale 20MHz
    //n = CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm;    //div2 i.e. 10MHz
    n = CLKCTRL_PDIV_4X_gc | CLKCTRL_PEN_bm;    //div4 i.e. 5MHz
    //n = CLKCTRL_PDIV_6X_gc | CLKCTRL_PEN_bm;    //div4 i.e. 3.33MHz
    //n = CLKCTRL_PDIV_32X_gc | CLKCTRL_PEN_bm;    //div16 i.e. 1.25MHz
    CCP = CCP_IOREG_gc;
    CLKCTRL.MCLKCTRLB = n;
    n = 0 << CLKCTRL_LOCKEN_bp;
    CCP = CCP_IOREG_gc;
    CLKCTRL.MCLKLOCK = n;
    CLKCTRL.OSC20MCTRLA = 0 << CLKCTRL_RUNSTDBY_bp;
    CLKCTRL.OSC32KCTRLA = 0 << CLKCTRL_RUNSTDBY_bp;
#if defined(__AVR_ATtiny817__)   //t402 has no XOSC32K
    CLKCTRL.XOSC32KCTRLA = CLKCTRL_CSUT_1K_gc;
#endif
    return 1;
}

int main(void)
{
    CLKCTRL_init();  //prescale 20MHz RC. CLKOUT on PB5
#if defined(__AVR_ATtiny817__)
    PORTMUX.CTRLB |= PORTMUX_TWI0_ALTERNATE_gc;  //use PA1,PA2 [SDA, SCL] on t817
#endif

    //enable pullups  .kbv I don't know why
    PORTA.PIN0CTRL = 0x08;
    PORTA.PIN1CTRL = 0x08;
    PORTA.PIN2CTRL = 0x08;
    PORTA.PIN3CTRL = 0x08;
    //PORTA.PIN4CTRL = 0x08;
    //PORTA.PIN5CTRL = 0x08;
    PORTA.PIN6CTRL = 0x08;
    PORTA.PIN7CTRL = 0x08;

    //IIC output buffer init
    for(int i = 0; i < SDATA_LENGHT; i++)
    {
        sdata[0] [i] = 0x30 + i; //"0123"
        sdata[1] [i] = 0x35 + i; //"5678"
    }

    //IIC init
    TWI0.SADDR = I2C_ADDRESS;
    TWI0.SCTRLA = 0xE2;			//all IIC interrupts enabled, smart mode. DIEN APIEN PIEN SMEN
    TWI0.SCTRLA |= TWI_ENABLE_bm;		//IIC enable

    sei();

    while (1)
    {
        asm("nop");             // somewhere to break
    }
}

//***************************************************************************************
//IIC
void SendByte()
{
    TWI0.SDATA = sdata[valid] [sended];
    if (++sended >= SDATA_LENGHT)
    {
        sended = SDATA_LENGHT;
    }
}

ISR(TWI0_TWIS_vect)
{
    if (TWI0.SSTATUS & 0x40)			//APIF interrupt
    {
        if (TWI0.SSTATUS & TWI_AP_bm)
        {								//address detection
            if (TWI0.SSTATUS & TWI_DIR_bm)	//direction
            {							//read
                sync_lock = true;
                sended = 0;
                TWI0.SCTRLB = TWI_SCMD_gm | (0 << TWI_ACKACT_bp);		//ACK
            }
            else
            {
                //write not supported
                //TWI0.SCTRLB = TWI_SCMD_gm | (1 << TWI_ACKACT_bp); //NACK

                //.kbv enable ADDR_W
                TWI0.SCTRLB = TWI_SCMD_gm | (0 << TWI_ACKACT_bp);		//ACK
            }
        }
        else
        {								//STOP condition
            TWI0.SCTRLB = (2 << TWI_SCMD_gp); //COMPTRANS
            sync_lock = false;
        }
    }

    if (TWI0.SSTATUS & TWI_DIF_bm)  	//DIF interrupt
    {
        if (TWI0.SSTATUS & TWI_DIR_bm)  //direction
        {								//read
#if 0
            uint8_t c = 'X';            //return X for overruns
            if (sended < SDATA_LENGHT) c = sdata[valid][sended++];
            TWI0.SDATA = c;
            // I don't see why a Slave sets TWI_ACKACT
            if ((TWI0.SSTATUS & TWI_RXACK_bm))
            {						//NACK received
                TWI0.SCTRLB = TWI_SCMD_gm | (1 << TWI_ACKACT_bp);
            }
#else
            if (sended)
            {
                if (TWI0.SSTATUS & TWI_RXACK_bm)
                {						//NACK received
                    TWI0.SCTRLB = TWI_SCMD_gm | (1 << TWI_ACKACT_bp);
                }
                else
                {						//ACK received
                    SendByte();			//send next byte
                }
            }
            else
            {
                SendByte();				//send first byte
            }
#endif
        }
        else
        {
            //write not supported
            //TWI0.SCTRLB = TWI_SCMD_gm | (1 << TWI_ACKACT_bp);			//NACK

            //.kbv enable DATA_W
            TWI0.SCTRLB = TWI_SCMD_gm | (0 << TWI_ACKACT_bp);			//ACK
            valid = TWI0.SDATA & 0x01;
        }
    }
}

And this is an Arduino sketch to test it.

#include <Wire.h>

const int SLAVE = 0x80 >> 1;   //Wire uses 7-bit addressing

void setup() {
    Serial.begin(9600);
    Wire.begin();
}

void loop() {

    static uint8_t cnt;
    Wire.beginTransmission(SLAVE);
    Wire.write(cnt++);  //toggles 'valid' on odd values
    Wire.endTransmission();

    int n = Wire.requestFrom(SLAVE, 4); //ask for more to view overruns
    Serial.print(n);
    Serial.println(" bytes");
    while (Wire.available())   // slave may send less than requested
    {
        char c = Wire.read();    // receive a byte as character
        Serial.print(c);         // print the character
    }
    Serial.println();
    delay(5000);
}

Note that your Tiny402 does not need Alternate SDA, SCL.   And you don't have a CLKOUT pin.

My DATA_R logic looks simpler than yours.   Edit the #if 0

Obviously I have external pullup resistors as  Nature intended.   (4k7)

And I was running at a civilised 3.3V.   I can change Tiny817 and "Uno clone" to 5V if you want.

 

David.

 

Edit.  Edited the Slave code conditionals to compile with Tiny402 out of the box.

Last Edited: Fri. Jan 14, 2022 - 02:00 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I connected ATTINY404 directly to I2C from FT4232H. The problem persists, but I was able to measure what was happening. ATTINY keeps the SCL on Low for the duration of the interrupt servicing. The FT4232H cannot work with this. If Fclk Per is small, this condition lasts a long time and several SCL pulses are lost.

 

The search for the cause has been complicated by the use of the ADUM1251 galvanic isolation, where the SCL is unidirectional. The logic analyzer was connected only on the Master side where everything seemed fine.

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

The ATtiny402 is an 8-pin device with SDA , SCL on PA1, PA2

The ATtiny404 is a 14-pin device with SDA , SCL on PB1, PB0.

Neither have CLKOUT.

 

FT4232H seems to be a multi-role USB chip.

ADUM1251 seems to be an I2C isolator with only SDA bidirectional.

 

I suggest that you always start tests with regular I2C bus.

 

When regular is shown to be ok:

I would hope that you can bench test with common GND.

And the Logic Analyser can show both sides of the ADUM1251.

 

It seems very odd that SCL is unidirectional.   After all,  I2C requires SCL clock stretching, ...

 

Yes,  any MCU-style Slave will hold SCL through the ISR().   All Masters should cope with this.

 

I could post Saleae traces for the F_CPU=1.25MHz.   The ACK response is noticeably delayed.   After all,  the ISR() takes a few cycles.  

Since you have a Logic Analyser you have probably seen this for yourself.

 

It is very easy to implement your "Master tests" with an Arduino.   And it means that anyone in the world can replicate (if they have a tiny402, 404, 406, 414, 417, ... or even any of the mega4809, avr128xxx chips 

 

David.

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

Looking at the ADUM1250 / ADUM1251 datasheet,   the ADUM1250 has bidirectional SCL and has the same package and pinout.

 

I suggest that you use the ADUM1250.

 

But you can test the FT4232 chip without the isolator.   I bet that it understands clock stretching.

 

David.

 

 

Last Edited: Fri. Jan 14, 2022 - 05:27 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dania wrote:
The search for the cause has been complicated by ... 

As David says, that's the reason why it's always best to start simple.

 

Get the basics working first, then - and only then - move on to adding complications.

 

Also note that you had never previously mentioned anything about using an  ADUM1251  - so there's no way we could have foreseen that as a potential problem.

 

This is why posting a full schematic is always helpful.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...