I2C "Arbitration lost" im master-slave modus

Gast #2019501
Lesenswert?

Hallo alle miteinander

Ich habe ein komisches problem mit einer I2C verbindung. Ein Master 
(Arduino) sendet jeweils 4 bytes über den I2C bus, 3 datenbytes und eine 
checksum. Am bus hängen momentan 2 slaves (2x attiny24 mit dem USI code 
von Don Blake). Der Master am einen Ende der Leitung hat einen Pullup 
von 2k, der Slave am Ende der Leitung einen von 5k. Die Leitung ist 
5-Adrig, 2m lang und nebst GND, SCL und SDA noch zwei adern mit 230VAC. 
I2C clock ist bei 10kHz.
Problem: nach einigen hundert bis tausend commands kommt  es immer 
wieder vor, dass der master sich mit dem TWI-errorcode "0x38 = 
Arbitration lost in SLA+W or data bytes" meldet. Bei einem erneuten 
senden der bytes reagiert der Slave nicht und der master bleibt deshalb 
hängen.
Ich denke die Ursache liegt im Rauschen der Leitung, sodass der Master 
eine kollision detektiert oder der slave einen falschen Befehl empfängt 
und anfängt dem Master reinzufunken.
Kennt jemand dieses Problem und weiss die genaue Ursache oder noch 
besser: eine Lösung?
Gast #2019917
Lesenswert?

Jens Martin schrieb:
> Geht es denn mit einem kurzen Kabel ohne 230~ ?

Ja, bei einem Test mit kurzem Kabel (ca. 30cm) ohne 230V hats problemlos 
funktioniert.

Das mit den pullups hatte ich anfangs anders, die pullups am ender der 
Leitung haben die kommunikation eher verbessert, der Fehler trat danach 
weniger schnell auf, viel geholfen hats aber nicht.
Gast #2019943
Lesenswert?

I²C ist eigentlich zur Kommunikation auf verschiedenen Komponenten AUF 
einer Platine gedacht. Für größere Strecken ist I²C schlichtweg nicht 
vorgesehen. Versuchs mal probeweise mit I²C-Bus-Extendern. Gibts von 
verschiedenen Firmen, unter anderem glaube ich auch von Texas 
Instruments. Also einfach mal samples ordern und versuchen. Die 230V 
begünstigen natürlich auch nicht unbedingt. Wenn du ein Oszi hast schau 
dir mal den Signalverlauf an. Und zwar bei 2m + 230V und bei den 30cm. 
Da wirste schöne Unterschiede feststellen.
#2020106
Lesenswert?

nicht Gast schrieb:
> dede schrieb:
>> Die Leitung ist
>> 5-Adrig, 2m lang und nebst GND, SCL und SDA noch zwei adern mit 230VAC.
> Grusel... Was ist das für eine Leitung, Isolierung zwischen den Adern
> ausreichend?

Doppel-Grusel.
Warscheinlich ist dann die GND-Leitung gleich auch noch der 
Schutzleiter.

Daß es nicht funktioniert, ist kein Wunder.
Daß es funktioniert, wäre aber ein Wunder.


Peter
Gast #2020880
Lesenswert?

Danke für die vielen Antworten.
Also dass I2C nur für kurze Leitungen gemacht wurde ist wohl richtig, 
anscheinend wird aber auch z.b. bei HDMI Kabeln eine TWI Verbindung 
zwischen den Geräten geführt, was ja auch problemlos zu funktionieren 
scheint. Gelesen hab ich schon, dass man anscheinend Leitungen bis 10m 
problemlos betreiben kann, wenn man die taktrate runter nimmt und 
kleinere pullups verwendet.
Dass ein pullup auf beiden Seiten der Leitung stören soll versteh ich 
nicht. Vcc wird ja nicht über die Leitung übertragen. Jeder Slave wird 
über 230V gespiesen und hat seinen eigenen 5V-regler. Nur die GND 
leitung, SCL, SDA sowie 230VAC sind auf der leitung. Schutzerdung brauch 
ich nicht, die Gehäuse sind aus Holz (hmm, nicht wirklich Feuersicher 
merk ich grad...).
Die kommunikation funktioniert eigentlich ziemlich gut, es tritt nur 
alle paar hundert bytes ein NACK auf, womit ich problemlos leben kann. 
Das eigentliche Problem besteht darin, dass der Slave ein "Arbitration 
lost" im master verursacht (vermutlich ist läuft der timer durch ein 
rauschen im clock zu früh ab und er zieht den SDA runter) und danach 
nicht mehr reagiert.
Wenn ich jetzt einfach eine STOP condition erzeuge falls der Fehler 
detektiert wird und dann wieder sende, wartet der Master vergeblich auf 
ein ACK nach dem START.
So wie ich die Programmierung von Don Blake verstehe, müsste der Slave 
bei detektiertem STOP wieder auf ein START reagieren, tut er aber nicht. 
Der bleibt irgendwo hängen und ich finde nicht raus wo, da es ja keine 
unendlichen while-loops in der programmierung gibt, die nicht auf ein 
STOP reagieren.

Ich werde mir die Signale mal auf dem Oszi anschauen, habe das zwas 
schon gemacht, jedoch auf Master seite, die können ja beim Slave ganz 
anders ankommen...
#2021020
Lesenswert?

Irgendeine Schaltstörung auf den 230V koppelt kapazitiv ein und erzeugt 
für den Slave einen zusätzlichen SCL-Impuls. Der Slave legt nun sein ACK 
zu früh an und der Master erkennt die Kollision.
Der Master kann aber kein Stop senden, da der Slave ja SDA auf low 
zieht.
Du mußt also das HW-TWI abschalten und per SW-I2C einen SCL-Puls 
generieren und dann versuchen, Stop zu senden. Erst dann ist der Slave 
wieder adressierbar.

Trotzdem ist 230V und Niederspannung auf dem selben Kabel verboten.


Peter
#2023851
Lesenswert?

Ein einfacher Workaround wäre:


1. TWI Modul am Master abschalten.
2. Am Master SDA als Input und SCL als Output konfigurieren.
3. SCL im TWI Takt so lange toggeln bis SDA wieder high ist
4. TWI wieder initialisieren und weiter machen ...

Ist zwar nicht schön, aber sehr effektiv um den Bus respektive den Slave 
wieder in Gang zu kriegen ...

Grüße,
Michael
Gast #2025849
Lesenswert?

Michael L. schrieb:
> Peter Dannegger schrieb:
>> Trotzdem ist 230V und Niederspannung auf dem selben Kabel verboten.
>
> Genau so ist es. - K.A. warum der Frager so einen groben Unfug treibt.

Den unfug treib ich, weil ich nicht zwei leitungen ziehen will, sieht 
unschön aus im Wohnzimmer.
Wenn alles fehlschlägt werd ich wohl oder übel ein kabel mit 
paarverseilten und isolierten leitern suchen müssen... was ich da bis 
jetzt gefunden habe ist entweder nicht bis 400V betreibbar oder nur in 
grau erhältlich, ich will aber ein schwarzes kabel.

Hab mittlerweilen einiges versucht. Der Slave stürzt nun nicht mehr ab, 
da ich dort den TWI bei ausbleiben von daten auf "RECEIVE START" mode 
setze.
Wenn ich die Arduino TWI library (interruptbasiert) verwende, läuft die 
kommunikation einige sekunden, auch bei Taktraten von über 100kHz. Dann 
ist aber fertig.
Bei der Sendemethode aus dem Atmega datenblatt (ohne TWI interrupt) 
funktionierts eher weniger. Meistens kommt der Fehler 0x20 = kein ACK 
bei der adresse, sonst kommt 0x30 =kein ACK bei den Daten (adresse aber 
erfolgreich übertragen). So alle paar hundert versuche kommt mal ein 
Befehl komplett durch, dann gibts aber datenübertragungsfehler, die 
checksum stimmt nicht.

Irgendwo muss da zuviel noise sein, obwohl die Signale am Oszi sauber 
aussehen.
Gibt es eine Möglichkeit die HIGH und LOW pegel von atmelchips 
einzustellen? Dann könnte ich den Slave auf noise weniger empfindlich 
machen.
Alternative werde ich versuchen einen hardware filter einzubauen. Ich 
bin mir ziemlich sicher, dass die probleme von noise kommen, denn bei 
höheren clockrates funktioniert die kommunikation besser als bei tiefen 
(da geht gar nix) was heisst, dass der Slave vermutlich mehr clocks 
sieht als der Master sendet und darum keine Daten bestätigt.
Gast #2026017
Lesenswert?

update:

habe mit Filterung experimentiert, ein RC Filter am SDA pin macht das 
Ganze schon viel stabiler (einige Minuten fehlerfrei). Es scheint 
wirklich zu viel noise auf dem Bus zu haben, eingefangen über die AC 
leitung. Wenn ich z.B. die Lampe an der selben Steckdose ausschalte, 
bleibt die Kommunikation hängen. Da muss wohl auch noch eine Drossel an 
den AC Eingang.

Aber etwas ist noch ganz komisch: in meiner Softwareroutine wird der Bus 
nach einer Übertragung nicht freigegeben, sondern beide Leitungen sind 
Low (im gegensatz zur standard Arduino TWI library). Ich habe den code 
mit diesem abgeglichen:

http://www.nongnu.org/avr-libc/user-manual/group__twi__demo.html

nach einem STOP bleiben aber beide Leitungen low...
Gast #2027987
Lesenswert?

Ok, problem gelöst:
1. der clock darf nicht zu tief sein da sonst das signalrauschen stärker 
reinspielt
2. Eine drossel auf der AC linie dämpft das Rauschen ein bisschen
3. Die Arduino TWI library stürzt öfters mal ab wenn noise auf dem Bus 
vorhanden ist. Diese reset funktion schafft abhilfe:

void resetTWI(void) //resets TWI pins and registers
{
   TWCR &= ~(1<<TWEN); //disable TWI
 //release TWI lines:
   pinMode(18, INPUT);
   pinMode(19, INPUT);
   digitalWrite(18, HIGH); //activat internal pullups
   digitalWrite(19, HIGH);
   delay(1); //wait for the lines to be released
   Wire.begin(); //TWI reinitialize
    TWBR = ((CPU_FREQ / TWI_FREQ) - 16) / 2; //set TWI frequency (if 
necessary)
  // Serial.println("TWI reset");
}

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