Estoy enviando un byte a través de I2C desde un esclavo ATtiny85. Lo estoy probando con un maestro ATmega328.
La secuencia debe ser START, SLA + R, ACK, datos, NACK , STOP. El código funciona solo cuando la secuencia es START, SLA + R, ACK, datos, ACK , STOP. Específicamente, en el código maestro a continuación, debe ser receive_i2c_data (val, false) y no receive_i2c_data (val, true). Las últimas obras, las primeras no. ¿Por qué es eso.
Además, a veces el código no funciona en la primera descarga. Necesito descargarlo de nuevo.
Código ATtiny85 de esclavo
#include <stdint.h>
#include <avr/interrupt.h>
#define SLAVE_ADDRESS 0x40
#define TIMER_OVERFLOW_COUNT 279
volatile uint8_t i2cstage = 0;
void reset_i2c()
{
USISR = 0xF0;
USICR = (1 << USISIE | 1 << USIWM1) | 1 << USICS1;
PORTB |= 1 << PORTB0;
PORTB |= 1 << PORTB2;
DDRB |= 1 << DDB2;
DDRB &= ~(1 << DDB0);
i2cstage = 0;
}
#define transmit_i2c_data() {DDRB |= 1 << DDB0;USISR = 0xF0;}
#define transmit_i2c_ACK() {DDRB |= 1 << DDB0;USIDR = 0x00;USISR = 0xFE;}
#define receive_i2c_ACKNACK() {DDRB &= ~(1 << DDB0);USISR = 0xFE;}
ISR(USI_START_vect)
{
USISR |= 1 << USISIF;
USICR |= 1 << USIOIE;
i2cstage = 1;
}
volatile uint8_t i2c_0 = 0;
ISR(USI_OVF_vect)
{
uint8_t data = USIDR;
switch ( i2cstage)
{
case 1:
if( data == (SLAVE_ADDRESS << 1) + 1)
{
i2cstage = 2;
transmit_i2c_ACK();
}
else
{
reset_i2c();
}
break;
case 2:
i2cstage = 3;
USIDR = i2c_0;
transmit_i2c_data();
break;
/*case 3:
i2cstage = 4;
receive_i2c_ACKNACK();
break;*/
default:
reset_i2c();
break;
}
}
volatile uint16_t timerCount = TIMER_OVERFLOW_COUNT;
ISR(TIMER1_OVF_vect)
{
timerCount++;
}
int main(void)
{
reset_i2c();
TIMSK |= 1 << TOIE1;
TCCR1 |= 1 << PWM1A;
OCR1C = 27;
sei();
TCCR1 |= (1 << CS13) | (1 << CS11) | (1 << CS10);
while( 1)
{
if( timerCount >= TIMER_OVERFLOW_COUNT)
{
timerCount = 0;
if(++i2c_0 > 5)
i2c_0 = 0;
}
if( (USISR & (1 << USIPF)) == (1 << USIPF))
{
USISR = 1 << USIPF;
reset_i2c();
}
}
return 0;
}
Código Master ATmega328
#include <stdint.h>
#include <avr/interrupt.h>
#include <stdbool.h>
#include <util/delay.h>
#define SLAVE_ADDRESS 0x40
volatile bool i2cCompletedQ = true;
void wait_for_i2c()
{
while( !(TWCR & 1 << TWINT))
{
}
if( TWCR & 1 << TWINT)
{
i2cCompletedQ = true;
}
else
{
i2cCompletedQ = false;
}
}
void transmit_i2c_start()
{
if( !i2cCompletedQ)
{
return;
}
TWCR = 1 << TWINT | 1 << TWEN | 1 << TWSTA;
wait_for_i2c();
}
void transmit_i2c_stop()
{
if( !i2cCompletedQ)
{
return;
}
TWCR = 1 << TWINT | 1 << TWEN | 1 << TWSTO;
}
void transmit_i2c_data(uint8_t data)
{
if( !i2cCompletedQ)
{
return;
}
TWDR = data;
TWCR = 1 << TWINT | 1 << TWEN;
wait_for_i2c();
}
void receive_i2c_data(uint8_t *odata, bool ack)
{
if( !i2cCompletedQ)
{
return ;
}
if( ack)
{
TWCR = (1 << TWINT | 1 << TWEN) | 1 << TWEA;
}
else
{
TWCR = 1 << TWINT | 1 << TWEN;
}
wait_for_i2c();
*odata = TWDR;
}
void update_i2c_Input(uint8_t *val)
{
transmit_i2c_start();
transmit_i2c_data((SLAVE_ADDRESS << 1) + 1);
receive_i2c_data(val, true);//should be false?
transmit_i2c_stop();
}
int main(void)
{
TWBR = 100;
TWSR &= ~(1 << TWPS1 | 1 << TWPS0);
DDRD |= 1 << DDD6;
TCCR0A |= 1 << COM0A1;
TCCR0A |= 1 << WGM00;
sei();
TCCR0B |= (1 << CS02) | (1 << CS00);
uint8_t val = 0;
while( 1)
{
i2cCompletedQ = true;
update_i2c_Input(&val);
OCR0A = (val * 255) / 5;
_delay_ms(1000);
}
return 0;
}