ATTiny441 TWI/I2C clamping bus, interrupt issue.

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

I want to use the ATTiny441's hardware I2C Bus.  It was very easy to set up based on the datasheet, and get it to only trigger on an address match, however, as soon as I try enabling interrupts, everything falls apart and it clamps the bus hard.

 

If  I put the code in my main and keep interrupts disabled, everything works flawlessly.

 

What is going on here?

 

If I #define USE_INTERRUPTS, it locks the bus up on address matches.  If I don't, it works flawlessly.  I want to use interrupts, though!

 

P.S. Why has it been years since the 441's been released and support for it is still not there?

 

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>

uint8_t operation = 0;

#ifdef USE_INTERRUPTS
ISR( _VECTOR( 29 ) )
{
		if( TWSSRA & _BV(TWDIF) )
		{
			if( TWSSRA & _BV(TWDIR) )
			{
				TWSD = 0xAA;  //Master reading data.
			}
			else
			{
				operation = TWSD; //Master sending data.
			}
			TWSCRB = _BV(TWCMD1) | _BV(TWCMD0); //Send ACK
		}
		else if( TWSSRA & _BV( TWASIF ) )
		{
			if( TWSSRA & _BV(TWAS) )
			{
				//We were addressed...
				TWSCRB = _BV(TWCMD1) | _BV(TWCMD0); //Send ACK
			}
			else
			{
				//We got a stop or other operation.
			   	TWSCRB = _BV(TWAA) | _BV(TWCMD1) | _BV(TWCMD0); //Send NAK
			}
		}
}
#endif

int main( )
{
	CCP = 0xD8;
	CLKPR = 0x00;  //Disable scaling.
	OSCCAL0 = 0xFF;

	//We don't use interrupts in this program.
	cli();
	TWSCRA = _BV(TWDIE) | //Data Interrupt Flag
//		_BV( TWSHE ) | //TWI SDA Hold Time Enable
		_BV( TWASIE ) | //Stop+Address Flag
		_BV( TWEN ) | //Enable TWI.
		_BV( TWSIE ) | //Stop flag
		_BV( TWSME ) | //Smart mode.
		0;
	TWSCRB = _BV(TWHNM) | //High noise mode.
		0;

	TWSA = 0x30; //Slave address.
	TWSAM = 0; //Don't mask.

#ifdef USE_INTERRUPTS
	sei();
#endif

	while(1)
	{

#ifndef USE_INTERRUPTS
		//TWSSRA |= _BV(TWC) | _BV(TWBE);
		if( TWSSRA & _BV(TWDIF) )
		{
			if( TWSSRA & _BV(TWDIR) )
			{
				TWSD = 0xAA;  //Master reading data.
			}
			else
			{
				operation = TWSD; //Master sending data.
			}
			TWSCRB = _BV(TWCMD1) | _BV(TWCMD0); //Send ACK
		}
		else if( TWSSRA & _BV( TWASIF ) )
		{
			if( TWSSRA & _BV(TWAS) )
			{
				//We were addressed...
				TWSCRB = _BV(TWCMD1) | _BV(TWCMD0); //Send ACK
			}
			else
			{
				//We got a stop or other operation.
			   	TWSCRB = _BV(TWAA) | _BV(TWCMD1) | _BV(TWCMD0); //Send NAK
			}
		}
#endif
	}

	return 0;
} 

 

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

1)  I'm not a user of this AVR family.

2)  The chip-include file says

/* Two-wire Serial Interface */
#define TWI_SLAVE_vect            _VECTOR(29)
#define TWI_SLAVE_vect_num        29

 

3)  That appears to be right, but it is curious that you didn't use the name?

 

 

OH, WAIT, I THINK I SEE IT!

ISR( _VECTOR( 29 ) )
{
		if( TWSSRA & _BV(TWDIF) )
		{

By the time you get to this point, TWDIF flag has been cleared.

 

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

2: Because TWI_vect didn't exist, I didn't realize that was the name, and chalked it up to incomplete headers.

3: False (or so I hope) the datasheet says that it doesn't clear unless specific other operations happen.

 

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

3: False (or so I hope) the datasheet says that it doesn't clear unless specific other operations happen.

 

You may well be correct.  Different than [all?] other AVR8  "one shot" interrupts?  I suppose it is because there are multiple IE bits that are handled by the same interrupt vector, so there needs to be a mechanism to sort them out?

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

From the datasheet:

Bit 7 – TWDIF: TWI Data Interrupt Flag
This flag is set when a data byte has been successfully received, i.e. no bus errors or collisions have occurred during the
operation. When this flag is set the slave forces the SCL line low, stretching the TWI clock period. The SCL line is
released by clearing the interrupt flags.

Writing a one to this bit will clear the flag. This flag is also automatically cleared when writing a valid command to the
TWCMDn bits in TWSCRB.

Bit 6 – TWASIF: TWI Address/Stop Interrupt Flag
This flag is set when the slave detects that a valid address has been received, or when a transmit collision has been
detected. When this flag is set the slave forces the SCL line low, stretching the TWI clock period. The SCL line is
released by clearing the interrupt flags.

If TWASIE in TWSCRA is set, a STOP condition on the bus will also set TWASIF. STOP condition will set the flag only if
system clock is faster than the minimum bus free time between STOP and START.
Writing a one to this bit will clear the flag. This flag is also automatically cleared when writing a valid command to the
TWCMDn bits in TWSCRB.