I am testing TWI module in AVR (Atmega328P). I have pulled up SCL and SDA lines. Why TWI interrupt service routine can not fire even once after switch (PB5) clicked?
Please notice that I have this interrupt enabled, I have also TWI module enabled and I have also start transmission after switch clicked.
Please help.
My code is:
#include <avr/io.h>
#include <avr/interrupt.h>
/* define slave (MPU6050) address as 0x68 because AD0 is low */
#define SLAVE_ADDRESS (0x68)
#define WHO_AM_I (0x75)
volatile enum state
{
IDLE,
START_BIT_TRANSMIT,
SLAVE_ADDRESS_TRANSMIT,
DATA_TRANSMIT
} sm;
void TimerInit()
{
/* overflow interrupt enable and start timer on frequency 8MHz / 1024 */
TIMSK0 |= (1 << TOIE0);
TCCR0B |= (1 << CS00) | (1 << CS02);
}
void TwiInit()
{
/* 100 kHz frequency of TWI and enable TWI module and interrupt from them */
TWBR = 8;
TWCR = (1 << TWEN) | (1 << TWIE);
}
/* TWI interrupt service routine */
ISR(TWI_vect)
{
PORTB &= ~(1 << PB0);
switch (sm)
{
case IDLE:
{
break;
}
case START_BIT_TRANSMIT:
{
/* clear start bit manually and prepare slave address SLA+W */
TWCR &= ~(1 << TWSTA);
TWDR = (SLAVE_ADDRESS << 1);
TWCR |= (1 << TWINT);
if ((TWSR == 0x08) || (TWSR == 0x10))
{
sm = SLAVE_ADDRESS_TRANSMIT;
}
break;
}
case SLAVE_ADDRESS_TRANSMIT:
{
/* prepare data */
TWDR = WHO_AM_I;
TWCR |= (1 << TWINT);
if ((TWSR == 0x18) || (TWSR == 0x20))
{
sm = DATA_TRANSMIT;
}
break;
}
case DATA_TRANSMIT:
{
/* prepare stop bit */
TWCR |= (1 << TWINT) | (1 << TWSTO);
if ((TWSR == 0x28) || (TWSR == 0x30))
{
sm = IDLE;
}
break;
}
default:
{
break;
}
}
}
/* timer overflow interrupt service routine */
ISR(TIMER0_OVF_vect)
{
PORTD &= ~(1 << PD7);
}
int main(void)
{
/* diodes output */
DDRB |= (1 << PB0);
DDRD |= (1 << PD7);
/* diodes turn off */
PORTB |= (1 << PB0);
PORTD |= (1 << PD7);
/* pull up resistor on PD5 input switch */
PORTD |= (1 << PD5);
TimerInit();
TwiInit();
sei();
while (1)
{
if (!((PIND >> PD5) & 1))
{
if (sm == IDLE)
{
sm = START_BIT_TRANSMIT;
TWCR |= (1 << TWSTA) | (1 << TWINT);
}
}
}
}