Hallo allerseits,
ich habe hier einen ATmega 644P welcher Daten per TWI an einen ATtiny2313 schicken soll, welcher diese dann auf einem LCD-Display ausgibt.
Nun kann der ATtiny2313 ja kein echtes TWI, stattdessen läuft das Ganze über USI ab. Daher würde ich gerne zunächst wissen, ob man Hardware-TWI des 644P überhaupt mit dem USI-TWI des 2313 zum Laufen kriegen kann.
Mein Problem ist nämlich, dass ich nun schon das Ganze Wochenende dran gesessen habe, die Kommunikation zum Laufen zu kriegen, das Ganze jedoch vollkommen erfolglos. Ich habe bereits fertig implementierte I2C-Slaves für den 2313 ausprobiert, aber auch hier kriege ich keine Daten übertragen.
Master-seitig sieht der Code wie folgt aus:
Code:
#ifndef F_CPU
#define F_CPU 8000000
#endif
#include <avr/io.h>
#include <util/delay.h>
uint8_t twiControl;
void send_i2c() {
// signalisiere START
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
// warte auf Bus
waitForTWI();
// falls Bus nicht frei
if((TWSR & 0xF8) != 0x08 && (TWSR & 0xF8) != 0x10) {
// TODO
} else {
// grüne LED an
PORTA &= ~(1<<PB2);
// Slave-Adresse und WRITE senden
TWDR = 0x40<<1;
TWCR = (1<<TWINT)|(1<<TWEN);
// warte auf Bus
waitForTWI();
// falls kein ACK oder NACK empfangen
if((TWSR & 0xF8) != 0x18 && (TWSR & 0xF8) != 0x20) {
// rote LED an
PORTA &= ~(1<<PB4);
} else {
// gelbe LED an
PORTA &= ~(1<<PB3);
}
}
_delay_ms(20);
// LEDs aus
PORTA = 0b11111111;
_delay_ms(20);
}
void waitForTWI() {
do {
twiControl = TWCR & 0x80;
} while(twiControl != 0x80);
}
int main() {
// setze TWI auf 100 kHz
TWBR = (F_CPU/200000)-18;
// aktiviere TWI
TWCR = 0b00000100;
// aktiviere PORT A
DDRA = 0b11111111;
PORTA = 0b11111111;
while(1) {
send_i2c();
}
}
Auf dem Slave habe ich bis jetzt das hier:
Code:
uint8_t state = 0x00;
int main() {
// initialisiere PWM für Ladungspumpe
initPWM();
// initialisiere Display
initLCD();
// aktiviere Interrupts
USICR = 0b11111000;
// aktiviere SCL-Pin
PORTB |= (1<<PORTB7);
// aktiviere SDA-Pin
PORTB |= (1<<PORTB5);
// SCL auf Eingang
DDRB |= (1<<PORTB7);
// SDA auf Ausgang
DDRB &= ~(1<<PORTB5);
// Interrupts aktivieren
sei();
while(1) {
// fortlaufend Inhalt von USICR, USISR und USIDR ausgeben
lcd_home();
hexout(USICR);
lcd_data(' ');
hexout(USISR);
lcd_data(' ');
hexout(USIDR);
}
}
// START-Bedingung per USI erhalten
ISR(SIG_USI_START) {
// schreibe "START" auf LCD
lcd_setcursor(0,2);
lcd_string("START");
uint8_t tmpUSISR;
tmpUSISR = USISR;
// setze Start-State
state = 0x00;
// SDA auf Eingang
DDRB &= ~(1<<PORTB5);
while ((PINB & (1<<PORTB7)) & !(tmpUSISR & (1<<USIPF)) );
// aktiviere Interrupts
USICR = 0b11111000;
USISR = (1<<USI_START_COND_INT)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|(0x0<<USICNT0);
lcd_clear();
}
// USI-Overflow-Interrupt
ISR(SIG_USI_OVERFLOW) {
switch(state) {
// Start-State
case 0x00:
// General oder eigene Adresse erhalten
if ((USIDR == 0) || (( USIDR>>1 ) == 0x40)) {
// akzeptiere nur Write-Requests
if (!(USIDR & 0x01)) {
state = 0x01;
}
// schreibe "CHECK" auf LCD
lcd_setcursor(6,2);
lcd_string("CHECK");
// leere USIDR
USIDR = 0;
// SDA auf Ausgang
DDRB |= (1<<PORTB5);
USISR = (0<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|(0x0E<<USICNT0);
}
else {
USICR = 0b101010000;
USISR = (0<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|(0x00<<USICNT0); \
}
break;
}
_delay_ms(20);
lcd_clear();
}
Allerdings erscheint mir der Slave-Code auch irgendwie spanisch, ich habe den aus den Appnotes AVR312 für einen USI-TWI-Slave entnommen. Doch scheint sich z.B. der Inhalt von USISR bei den entsprechenden Zuweisungen gar nicht zu ändern. Am schlimmsten ist aber, dass sich in USIDR keine Daten finden d.h. die Adresse, die ich im Master sende scheint gar nicht am Ziel anzukommen. Zudem bin ich auch skeptisch, was die Funktion des Masters angeht, da die LEDs auch fröhlich flackern, wenn der Tiny gar nicht angeschlossen ist.
Ich bin da leider wirklich mit meinem Latein am Ende und auch etwas entnervt, dass so ein Krampf als "TWI-fähig" verkauft wird.
Vielleicht kann mir ja hier jemand helfen oder mich auf die richtige Bahn lenken. Ich bin ja schon froh, dass ich am Master und Slave überhaupt ein wenig sehen kann, was passiert, aber selbst das ist doch eher dürftig
Achja, SCL und SDA sind auf dem Master mit 10k Ohm gegen VCC geschaltet, beide µC werden mit 3.3V versorgt.
Lesezeichen