Ich hab mir scheinbar doch was am SDA Pin der CPU zerstört.
Hier eine kurze Diganoseanleitung, alles natürlich OHNE angebaute Teile am I2C Bus mit dem Oszi und einem Multimeter geprüft!
SDA verhält sich so als wenn kein Pullup (R32) da wäre, der ist aber gewechselt und mehrfach getetet. Darauf hin habe ich die Ports SCL und SDA als Ausgang geschaltet und volle Rechteckflanken gemessen, schaute also gut aus. Als Ausgang ist das ok. Hier der Code dazu.
Code:
while (true) {
DDRC |= (SCL | SDA);
PORTC |= SCL;
PORTC |= SDA;
mSleep(100);
PORTC &= ~SCL;
PORTC &= ~SDA;
mSleep(100);
}
Dann SDA und SCL als Eingang geschaltet und den Prozessor die Werte ansagen lassen.
Code:
PORTC &= ~SCL;
PORTC &= ~SDA;
DDRC &= ~SDA;
DDRC &= ~SCL;
while (true) {
writeString_P("SCL / SDA -> ");
writeInteger(PINC & SCL , BIN);writeString_P(" / ");
writeInteger(PINC & SDA , BIN);writeChar('\n');
mSleep(500);
}
Ergebnis war, das beide Pins zunächst logisch 1 hatten, der SDA aber manchmal auf 0 kippte. Mit einer Brücke konnte ich beide Pins gegen GND auf 0 ziehen, was ok ist, SCL sprang danach sofort auf 1. SDA kippelte zwischen 0 und 1. Gemessen habe ich am SDA dabei 1,4v statt der erwarteten 4v wie am SCL. Das erklärt das kippeln, ein Verhalten wie bei fehlendem R32 nur das dann 0,7 statt 1,4v zu messen sind.
Also noch mal R32 ausgebaut, gemessen, anderen besorgt, eingebaut... immer das gleiche. SlyD gab mir dann den Tip, mal einen Diodentest zu machen.
Was misst Du mit dem Multimeter im Diodentest (gegen GND und VDD bei beiden
I2C Pins in allen Kombinationen also Rot/Schwarzes Kabel auch tauschen)? Das sollte bei beiden Pins identisch sein. (0,7V 0,6V 1,6V 1,7V sowas in der Richtung je nachdem wie mans polt)
Der Diodentest zeigt eine Auffälligkeit.
Mit - am SDA/SCL gegen gnd gemessen 0,5v, gegen vdd 1,5v
Mit + am SCL gegen gnd gemessen 1,7v, gegen vdd 0,6v
Mit + am SDA gegen gnd gemessen 1,2-1,0v, gegen vdd 0,4-0,3v und schwankt ein wenig
Meine Folgerung daraus ist, das der Port SDA als Eingang in der CPU einen Schaden hat. Ich glaube nicht an einen Fehler durch den Dauertest oder beschädigung durch Software, vermutlich eher statische Entladung oder der defekten Slave. Es wäre aber auch denkbar das der Slave dabei mit zu Bruch ging (was bedeuten kann, das die M32 auch im Eimer ist). Werde ich gleich noch per Diodentest durchmessen.
Da ich mir nicht zutraue, die CPU selbst zu wechseln, werde ich den RP6 wohl zur reparatur einschicken müssen und mit dem TWI Treiber länger pausieren.
Ich hänge meine letzte aktuelle TWI-Version noch an, sie müsste so ziemlich laufen, testen kann ich sie leider nicht mehr. Wichtigste Änderung ist die Umstellung aller Masterfunktionen auf asyncronen Betrieb da es immer wieder zu Problemen kam, wenn man syncrone und asyncrone Funktionen mischte. Man kann die Befehle aber quasi syncronisieren wenn man nach dem TWI-Befehl sofort task_I2CTWI aufruft, ein folgender TWI-Befehl würde das auch tuen. Es ist also nur für den ersten/letzten in einer Kette von Befehlen sowie bei I2CTWI_requestRegisterFromDevice und I2CTWI_readRegisters relevant, welche aus Mehrfachinstruktionen für die TWI bestehen - sowie für die Fehlerprüfung die auch dort abgewickelt wird. Anders ausgedrückt, es wird immer erst ein Befehl ausgeführt wenn ein weiterer abgeschickt wird oder mit task_I2CTWI nachgeholfen wird. Das ist in zeitkritischen Situationen wie Abfragen eiens SRF zu bedenken. Es erlaubt aber die einstufige Entkoppelung einer TWI Aktion wenn man selbst zeitkritische Dinge zu erledigen hat, die nichts mit dem TWI zu tun haben. Jede Medaille hat eben 2 Seiten. Die Idee dafür stammt übrigends aus SlyDs TWI Version wo es dann manchmal (für den User zuweilen schlecht nachvollziehbar) zu verzögerten TWI-Reaktionen kam, ich habe das nun auf alle Funktionen umgesetzt, damit das Verhalten eindeutig ist.
Wer oft syncrone Funktionen braucht, kann sich mit einem Macro Set ala #define SyncTWIBEFEHL TWIBEFEHL;task_I2CTWI(); für jeden Befehl ähnlich der LCD-Macros in twi_target.h oder einige Macros in RP6I2CTWI.h das Ausführen direkt hinten dran klatschen. Allerdings spart das (noch) nicht den Aufruf von task_I2CTWI(); in der Idle-Loop ein. Ich hatte vor, das später per twi_target.h einstellbar zu machen ob generell sync oder async gearbeitet werden soll.
LG Rolf
Lesezeichen