PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : TWI will nicht so wie ich wohl will



Ceos
24.04.2008, 21:48
situation: 2 mega8
10k pullup
100kHz sollten eingestellt sein

start condition klappt, address klappt ... nur das databyte haut einfach net hin, da bleiben se hängen, bitte um hilfe

master

void TWI_Init_Master(void)
{
cli();
TWI_RCount = 0;
TWI_WCount = 0;
TWBR = 32;
TWSR &= ~(BV(TWPS0)|BV(TWPS1));
TWSR |= BV(TWPS0);
TWCR = BV(TWEN);
sei();
}

bool TWI_SendByte(unsigned char target, unsigned char data )
{
char b[3];
PORTB = BV(PB1);
TWCR |= BV(TWINT)|BV(TWSTA);
while(!(TWCR & BV(TWINT)));
if (TW_STATUS != TW_START) {
PORTB |= BV(PB2);
itoa(TW_STATUS, b, 16);
USART_Transmit(b[0]);
USART_Transmit(b[1]);
TWI_ERROR;
return false;
}
TWDR = (target | TW_WRITE);
TWCR |= BV(TWINT);
while (!(TWCR & BV(TWINT)));
if (TW_STATUS != TW_MT_SLA_ACK) {
PORTB |= BV(PB3);
itoa(TW_STATUS, b, 16);
USART_Transmit(b[0]);
USART_Transmit(b[1]);
TWI_ERROR;
return false;
}
TWDR = data;
TWCR |= BV(TWINT);
while (!(TWCR & BV(TWINT)));
if (TW_STATUS != TW_MT_DATA_ACK) {
PORTB |= BV(PB4);
itoa(TW_STATUS, b, 16);
USART_Transmit(b[0]);
USART_Transmit(b[1]);
TWI_ERROR; // <------ steigt aus mit TW_STATUS 0x10
return false;
}
TWCR |= BV(TWINT)|BV(TWSTO);
PORTB = 0;
return true;
}

slave

void TWI_Init_Slave(unsigned char addr) //Even Addr. does not respond to general call
{
cli();
TWAR = addr;
TWI_RCount = 0;
TWI_WCount = 0;
TWBR = 32;
TWSR &= ~(BV(TWPS0)|BV(TWPS1));
TWSR |= BV(TWPS0);
TWCR = BV(TWEN)|BV(TWIE)|BV(TWEA);
sei();
}

SIGNAL(SIG_2WIRE_SERIAL)
{
char b[3];
PORTB = BV(PB0);
if (TW_STATUS != TW_SR_SLA_ACK) {
PORTB |= BV(PB1);
itoa(TW_STATUS, b, 16);
USART_Transmit(b[0]);
USART_Transmit(b[1]);
TWCR |= BV(TWEA)|BV(TWINT);
while(1);
return;
}
TWCR |= BV(TWEA)|BV(TWINT);
while(!(TWCR & BV(TWINT)));
if (TW_STATUS != TW_SR_DATA_ACK) {
PORTB |= BV(PB2);
itoa(TW_STATUS, b, 16);
USART_Transmit(b[0]);
USART_Transmit(b[1]); <---- steigt aus mit 0xA0
while(1);
return;
}
TWI_ringbuff[TWI_WCount] = TWDR;
TWI_WCount++;
TWCR |= BV(TWEA)|BV(TWINT);
while(!(TWCR & BV(TWINT)));
if (TW_STATUS != TW_SR_STOP) {
PORTB |= BV(PB3);
itoa(TW_STATUS, b, 16);
USART_Transmit(b[0]);
USART_Transmit(b[1]);
TWCR |= BV(TWEA)|BV(TWINT);
while(1);
return;
}
PORTB = 0;
TWCR |= BV(TWEA)|BV(TWINT);
}

linux_80
24.04.2008, 23:53
Hallo,

was Probleme machen könnte, wäre, wie Du das TWCR setzt, ich würde das nach Möglichkeit immer komplett neu beschreiben, also mit allen Bits die man braucht, nicht mit |= ändern.
Genauso TWSR, da spart man sich nix, eher das Gegenteil.

Und den TWI immer in einem definierten Zustand hinterlassen, bei einem Fehler spingst Du einfach mit return aus der function raus.

Ed:
Und ganz übersehen, das mit der ISR für den Slave klappt so nicht, denn nach jedem löschen von TWINT muss die ISR beendet werden, damit die beim nächsten auftreten wieder aufgerufen wird. Also das was beim Master mit der while-Schleife gemacht wird, die wartet bis das TWINT gesetzt ist !
Deswegen sollte man sich einen Status von ISR-Aufruf zu ISR-Aufruf mitgeben, um damit zu checken ob der Richtige Status zum richtigen Zeitpunkt auftritt. Deswegen hängt er sich jetzt auch. Das Beispiel im Wiki schaut ja soweit ganz gut aus, bis auf das mit TWCR ;-)

Was macht TW_STATUS, bzw wie ist das definiert ?

Ceos
26.04.2008, 07:42
twi.h das ist das statusregistr mit ausmaskierten prescale bits ... warum kann ich in der isr nicht mit while auf twint warten? ich werds mal umbauen .. btw. ich habe den fehlerfall nicht abgefagen sondern blockiere danach um die diioden un fehler auslesen zu können ... quasi zu verstehen wie und wo erhängt .... ausserdem bekomm ichnur für das databate kein ack sonder ein repeat start seltsamerweise...