i2c auf Geräten mit unterschiedlicher Logikebene

Ich habe ein Problem damit, dass LPC2148 mit dem SRF10-Sensor funktioniert. LPC ist ein 3,3-V-Gerät mit 5-V-kompatiblem i2c (das behauptet zumindest die Benutzerdokumentation). Auf der anderen Seite befindet sich das SRF10-Gerät mit 5 V. Ich habe es mit beiden Pegeln als Pull-up-Lvl versucht, die mit einem 4,7-k-Widerstand verbunden sind (ich habe 3 Geräte in derselben Leitung, also habe ich einen Widerstand mit höherem Wert verwendet).

Seltsam ist, dass es manchmal den Wert richtig liest, aber keine Werte aus 2 Registern liest ... Grundsätzlich funktioniert es nicht.

I2c schlechte Anzeige

Nun, was an diesem Bild seltsam ist, ist, dass der Logik-Level auf SDA standardmäßig 0 ist und 1 sein sollte. Das bedeutet, dass Pull-up seine Arbeit nicht gut macht? Könnte das mit logischen Lvl-Unterschieden zwischen uc und slave zusammenhängen?

EDIT:01.03

Hier ist meine Implementierung des Zustands 0x50, a_chn ist i2c0 oder i2c1

void slaveDataReceived (uint8_t a_chn)
{
uint8_t k;
volatile unsigned char *i2cConClear;
volatile unsigned char *i2cConSet;
volatile unsigned char *i2cData;

if (a_chn == 1) {
    i2cData = (volatile unsigned char *)(0xE005C008);
    i2cConClear = (volatile unsigned char *)(0xE005C018);
    i2cConSet = (volatile unsigned char *)(0xE005C000);
    }
else {
    i2cData = (volatile unsigned char *)(0xE001C008);
    i2cConClear = (volatile unsigned char *)(0xE001C018);
    i2cConSet = (volatile unsigned char *)(0xE001C000);
    }   

k = *i2cData;
appendToDataBuffer (a_chn, k);
if (i2cDataRcv[a_chn] == i2cDataHead[a_chn]){
    I2CMasterState[a_chn] = I2C_IDLE;
    *i2cConSet = I2CON_SET_STO;
    *i2cConClear = I2CON_CLR_AAC;
    }
else {
    *i2cConSet = I2CON_SET_AA;
    }
*i2cConClear = I2CON_CLR_SIC;   
}
Wenn es von jedem Gerät mit Ausnahme von nur 2 Registern von einem Gerät liest / schreibt, sollte Ihnen das sagen, dass der i2c-Bus ordnungsgemäß funktioniert, und es ist möglicherweise entweder Ihr Code oder der srf10, der fehlerhaft ist. Da der SDA niedrig ist, sollte es keine Rolle spielen, bis eine Startbedingung in Ihrem Single-Master-Setup versucht wird. Ist eines der anderen i2c-Geräte nicht 5V-tolerant? Geht die Leitung hoch, wenn Sie nur den LPC und den SRF10 im Bus platzieren und sonst nichts? Können Sie mit nur LPC und SRF auf dem Bus aus allen Registern lesen?
Alle drei Geräte sind 5 V und nur lpc ist 3,3 V (aber 5 V tolerant). Ich habe versucht, alle Geräte außer einem zu trennen, und ich bekomme das gleiche Verhalten. SRF funktioniert, wie ich es auf AVR (5v) versucht habe. SRF hat 4 Register. Zuerst ist Revision, die ich lesen konnte und 5 als Wert bekam (was ok sein sollte). Second wird nicht verwendet, gibt aber beim Lesen 0x80 zurück. (auch richtig gelesen). Und die Register 3-4 sind 16-Bit-Werte. Das Lesen dieser Register gibt seltsame Werte zurück. (Ich habe eine "Kalibrierungsumgebung", in der ich gelesene Werte getestet und festgestellt habe, dass sie Müll sind.)
Geben Sie Ihrer Oszilloskopausgabe eine ausreichend große Verzögerung? Der Ranger antwortet nicht während des Rangierens. Überprüfen Sie Ihren Code, um festzustellen, warum die SDA-Ausgabe niedrig gehalten wird, bevor die i2c-Übertragung aktiviert wird. Dies könnte die Ursache sein (aber meiner Meinung nach ist dies kein allzu großes Problem). Abgesehen davon könnte sich jemand anderes melden.
Ich weiß, dass zwischen Ranging und Auslesen mindestens 65ms benötigt werden, ich habe 100ms gesetzt. Dieses niedrige Niveau vor und nach dem Lesen ist etwas seltsam. Wenn ich SDA/SCL-Pins als GPIO verwende und ein Rechtecksignal erzeuge, verhält sich alles normal. Unabhängig von Klimmzügen, die mit Leinen verbunden sind. Die Ausgabe erfolgt aus LA, nicht aus dem Geltungsbereich. Ich habe es auch mit Scope überprüft und ich bekomme ein niedriges Level als -0,3 V und ein hohes Level als ~ 3 V.
Diese Probleme liegen wahrscheinlich außerhalb der Fähigkeiten eines Logikanalysators. Ich empfehle Ihnen dringend, ein Oszilloskop zu verwenden, um die Kommunikation zu überprüfen, da es sehr marginale Logikpegel geben kann, die normalerweise funktionieren und dann fehlschlagen.

Antworten (1)

Ich sehe gültige Start- und Neustartbedingungen in Ihrer Wellenform, daher glaube ich nicht, dass SDA die "falsche Polarität" ist. Die gültige Startbedingung liegt vor dem Schreiben von 0xC0 (gekennzeichnet durch den ersten grünen Punkt in der Aufnahme) und der gültige Neustart ist der zweite grüne Punkt (vor 0xC1). Die Tatsache, dass SDA niedrig bleibt, nachdem der Master den Slave bestätigt hat, sollte kein Problem sein, solange der Master es vor der nächsten steigenden Flanke von SCL freigibt.

Ein Problem könnte die Größe der Klimmzüge sein. Wenn Sie versuchen, schneller als 100 kHz zu arbeiten, benötigen Sie möglicherweise steifere Klimmzüge, um sicherzustellen, dass die Kanten scharf sind.

Ein weiteres Problem besteht darin, dass der Master das letzte erwartete gelesene Byte NACKEN sollte, selbst wenn es sich um gültige Daten handelt, da viele Slaves ein NACK erwarten, bevor sie zulassen, dass eine gültige Stoppbedingung durchkommt. Für Ihre Einzelbyte-Lesevorgänge sollte der Master das Datenbyte NACKEN. Für die 16-Bit-Register sollte das erste Byte ACK und das zweite NACK sein. Ich habe einige Slave-Geräte gesehen, die den Bus aufgehängt haben oder eine Fehlfunktion hatten, wenn der letzte Lesevorgang nicht durch ein NACK "beendet" wurde.

Mir ist aufgefallen, dass LPC alles ACK ist. Aber wie im Datenblatt angegeben, ist NACK Standard. Ich habe ACK beim letzten Byte-Empfangsinterrupt explizit gelöscht, aber es wird immer noch ACK gesendet. Ist ACK aus der Logikebene 1 oder 0? Vielleicht, weil mein SDA die ganze Zeit niedrig gezogen wird, ist ACK voreingestellt? In diesem Fall ist der Pull-up-Wert zu groß?
Ich denke, es besteht keine Chance, dass dies mit Klimmzügen zusammenhängt. Wenn Sie den Slave vom Bus trennen, sehen Sie NACKs? (Der Meister kann sein und sich selbst anerkennen)
@Gossamer Acks sind logisch 0 (Leitung wird aktiv auf Low gezogen). Nacks sind logisch 1 (Leitung wird freigegeben, Pull-up wird verwendet). Wenn Ihre Taktrate für den Pull-up zu schnell ist, könnte dies ein Problem sein, aber Sie haben ansonsten eine funktionierende Kommunikation mit diesem Pull-up.
Nun, es scheint, ich hatte zu viele ACKs im Code. Ich wurde von der Dokumentation für LPC21xx geleitet, in der angegeben wurde, dass fast jeder Zustand ein ACK-Bit im Register setzen sollte. Außerdem habe ich den *i2cConSet = I2CON_SET_STO;fraglichen Post aus dem Code entfernt. All diese oder einige dieser kürzlichen Änderungen im Code haben dazu geführt, dass i2c jetzt funktioniert. Jetzt muss ich analysieren, was genau die Probleme verursacht hat, indem ich den alten Code Zeile für Zeile neu aktiviert habe.
Gut gemacht! Ich habe ein bisschen gelitten, meinen eigenen I2C-Mastercode zu schreiben, und verstehe, wie schwierig es sein kann, Dinge zum Laufen zu bringen, insbesondere auf der Protokollseite.