Problem mit TWI / SCL geht nicht

OP #1432219
Lesenswert?

Hey

Ich bin seit einer Woche dran, einen TWI Bus zwischen 2 ATMega8 zu 
programmieren (in C mit Code::Blocks). Und ich verzweifle fast. Das 
Prinzip habe ich verstanden. Aber es geht nicht.

Es kommt nicht mal ein Takt auf dem SCL an. Ich habe externe Pull up 
Widerstände von 2,2 kOhm. An meinem PortB habe ich 8 LEDs angeschlossen 
um den Status des TWI anzuzeigen. Nun sehe ich, dass der Master 0xF8 und 
der Slave 0x00 im TWSR hat. Was hat das zu bedeuten?

Meine Programme habe ich angehängt!

Bitte helft mir! Ich bin verzweifelt!
Angehängte Dateien:
Gast #1432313
Lesenswert?

Die Fehler sind lt. TWI.h:
/* no state information available */
#define TW_NO_INFO    0xF8

/*  illegal start or stop condition */
#define TW_BUS_ERROR    0x00

Ausserdem glaub ich mal, dass  _delay_ms(1000); in der Start-Funktion 
nix zu suchen hat. Der Timeout der TWI-Hardware beisst da zu, noch bevor 
delay überhaupt in den 2-Stelligen ms-Bereich kommt. Raus damit.
Das Senden von Start-Kondition, Slave-ID, Daten, Stop-Kondition sollte 
möglichst in einer Funktion OHNE delays erfolgen.
OP #1432384
Lesenswert?

Ok. Ich hab die delay Funktion rausgeschmissen. Und siehe da, es 
funktioniert! aber leider nur teilweise! Beim Senden das DATA Bytes 
bricht es ab und bekommt als Status die 0x58 . Das bedeutet laut 
datenblatt:Databyte has been received, ACK has been returned
d.h. ich habe den Master nicht im "sende"modus sondern im 
"empfangs"modus!
Muss ich beim Senden der Slaveadresse das R/W Byte 0 oder 1 machen damit 
ich daten schicken kann?
Gast #1432440
Lesenswert?

Dass er abbricht, ist sozusagen normal. 0x58 heisst, dass vom Slave ein 
NACK zurückgekommen ist, d.h. der Slave will keine weiteren Daten mehr.
Wenn er mehr will, muss mit ACK geantwortet werden.

R/W-Byte: Zum Senden Master=>Slave: 0, fürs Auslesen eines Slaves: 1.
OP #1432509
Lesenswert?

ok..also ich habe jetzt mal beim Master das Datenbyte einfach hochzählen 
lassen nach jedem senden und dann beim Slave das Datenbyte auf den PORTB 
gelegt. Es ändert sich nichts. Es wird immer nur der Startwert (0) des 
Datenbytes angezeigt. D.h. der Slave empfängt noch keine Daten. Ich 
verstehen das nicht. Die Adresse wird richtig übermittelt aber er 
erkennt dann nicht das Datenbyte!
So ein S....!!!
Habt ihr vielleicht noch eine Idee für mich!
Ich hänge noch mal den überarbeiteten Quelltext an.
Danke schon mal für eure schnelle Hilfe!
Angehängte Dateien:
Moderator Persönliche Seite #1432532
Lesenswert?

Flo S. schrieb:

> Ich hänge noch mal den überarbeiteten Quelltext an.

Als ich das hier:
1
    if(help==0x60)  TWSI_TW_SR_SLA_ACK();              //x60
2
  if(help==0x68)  TWSI_TW_SR_ARB_LOST_SLA_ACK();     //x68
3
  if(help==0x70)  TWSI_TW_SR_GCALL_ACK()  ;          //x70
4
    if(help==0x78)  TWSI_TW_SR_ARB_LOST_GCALL_ACK();   //x78
5
    if(help==0x80)  Data=TWSI_TW_SR_DATA_ACK();        //x80
6
    if(help==0x88)  Data=TWSI_TW_SR_DATA_NACK ();      //x88
7
    if(help==0x90)  TWSI_TW_SR_GCALL_DATA_ACK();       //x90
8
    if(help==0x98)  TWSI_TW_SR_GCALL_DATA_NACK();      //x98
9
    if(help==0xA0)  TWSI_TW_SR_STOP();                 //xA0
10
    if((help!=0x60)|(help!=0x68)|(help!=0x70)|(help!=0x78)|(help!=0x80)|(help!=0x88)|(help!=0x90)|(help!=0x98)|(help!=0xA0)) error();

in slave.c ziemlich weit oben sah, habe ich aufgehört, weiterzulesen.

Nehmen wir mal an, dass help == 0x60 ist, dann:

1. ... muss der arme µC trotzdem noch weitere 9 if-Statements 
durchchecken, weil Du das "else" vor allen weiteren ifs vergessen hast.
Optimal wäre übrigens ein case-switch.

2. ... dann ist die Bedingung "(help != 0x68)" TRUE und es wird nach 
error() gesprungen. Übrigens wird - egal, welcher Wert help tatsächlich 
hat, immer nach error() gesprungen! Denn mindestens 8 Deiner 9 
Bedingungen, die Du mit dem Operator "|" verknüpfst, sind immer gegeben!

Bedingungen verknüpfen macht man nicht mit "|" oder "&", sondern mit 
"||" bzw. "&&". Lerne bitte die Unterschiede zwischen logischen und 
bitweisen Operatoren. Du hättest hier "&&" statt "|" nehmen müssen. Aber 
das letzte if-Statement ist sowieso für die Tonne, denn bei "else" 
braucht man das nicht:
1
    if(help==0x60)       TWSI_TW_SR_SLA_ACK();              //x60
2
    else if(help==0x68)  TWSI_TW_SR_ARB_LOST_SLA_ACK();     //x68
3
    else if(help==0x70)  TWSI_TW_SR_GCALL_ACK()  ;          //x70
4
    else if(help==0x78)  TWSI_TW_SR_ARB_LOST_GCALL_ACK();   //x78
5
    else if(help==0x80)  Data=TWSI_TW_SR_DATA_ACK();        //x80
6
    else if(help==0x88)  Data=TWSI_TW_SR_DATA_NACK ();      //x88
7
    else if(help==0x90)  TWSI_TW_SR_GCALL_DATA_ACK();       //x90
8
    else if(help==0x98)  TWSI_TW_SR_GCALL_DATA_NACK();      //x98
9
    else if(help==0xA0)  TWSI_TW_SR_STOP();                 //xA0
10
    else error();        // alle anderen erzeugen Fehler!

Deine Hausaufgabe wäre nun, das Ding auf einen case-switch 
umzuschreiben. Ist schneller, kompakter und lesbarer.

Ob noch mehr Köpse in Deinem Source sind, kann ich nicht beurteilen. Wie 
gesagt, ich habe danach aufgehört, weiterzulesen.

Gruß,

Frank
OP #1432569
Lesenswert?

Ich hab es verbessert. Aber leider hat sich rein gar nichts geändert! 
der slave hat zuerst 0x60 im TWSR (bedeutet das er die Adresse empfangen 
hat und ACK zurück geendet hat) und danach gleich 0xA0(bedeutet das Stop 
gesendet wurde). Das heißt es kommen keine Daten an! Aber ich habe beim 
Master doch alles so programmiert, wie es im Datenblatt steht und alle 
anderen es auch machen! :-(
Angehängte Dateien:
Gast #1435744
Lesenswert?

Also nen weiteren Fehler find ich da jetzt nicht.
Nur sind mir einige Dinge aufgefallen, die zwar jetzt nicht falsch sind, 
aber früher oder später für Probleme sorgen könnten.

Die SlaveID wird immer direkt angegeben, idealerweise als Hex-Wert (z.B. 
bei I2C-EEPROMS 0xA0). Nicht als ungerade Zahl und dann verdoppeln durch 
Shift.

Und Punkt 2, in der Init-Funktion:
1
TWCR |= ((1<<TWINT)|(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC)|(1<<TWEN)|(1<<TWIE));

Wie sicher bist du dir bei dieser Zeile, dass z.B. das Bit TWST0 auch 
wirklich 0 ist? (Tip: Was ist, wenn es vor dieser Zeile 1 ist?)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren