Forum: Compiler & IDEs grundlegende I2C-Probleme


von Alf Jäger (Gast)


Lesenswert?

Hi,
ich zimmere mir gerade eine I²C-Schnittstelle zusammen und habe etwas 
den Überblick verloren - war hier wohl etwas zu heiß [1].

Problem eins:
mit den folgende Befehlen kann ich einzelne Ports schalten:
#define setbit(x,y) ((x) |= (y))      // setbit(P2DIR,BIT0) schaltet auf 
Ausg
                                      // setbit(P2OUT,BIT0) setzt Pin 
auf Hi
#define clrbit(x,y) ((x) &= ~(y))     // clrbit(P2OUT,BIT0) setzt Pin 
auf LOW
#define invbit(x,y) ((x) = ((x)^(y))) // invbit(P2OUT,BIT0) invertiert 
Pin.
Mein Problem: wenn ich so schalte bekomme ich spätestens beim ACK-Signal 
des EEPROMs einen Kurzschluß auf der SDA-Leitung. Wie kann ich einen 
Port so definieren, daß er für Wired-OR tauglich ist?

Problem zwei: wie kann ich abfragen, welches Signal an SDA als Eingang 
anliegt?

Gruß, ALF


[1] Diesen Juni: 19 Tage über 30 Grad, der "Rest" über 25 ...

von Bernward Mock (Gast)


Lesenswert?

Hallo Alf,

das grunsätzliche Problem bei I2C ist, daß die SDA-Leitung bidirektional 
arbeitet, im Gegensatz zur SCL-Leitung, wo immer der Master (Controller) 
die Leitung treibt und die Clock-Impulse ausgibt.

Damit auf der SDA-Leitung Daten bidirektional gesendet werden können, 
wurde sie als WIRED OR definiert, d.h. ein 10k Widerstand hält die 
Leitung immer High; die einzelnen Busteilnehmer dürfen sie zu bestimmten 
Zeitpunkten gegen Masse ziehen (=Low). Tun das mehrere zur gleichen 
Zeit, entsteht zumindest kein Schaden.

Dazu ist ein Open-Collector- oder Open-Drain-Transistor erforderlich. 
Wird ein Prozessorport als Ausgang konfiguriert, bekommst Du nicht nur 
beim Acknowledge Probleme, sondern auch wenn der Slave (EEPROM) seine 
Daten sendet.

Hier gibt es jetzt zwei Möglichkeiten:

1. Beim PIC gibt es je nach Modell meistens am Port A einen Pin, der nur 
als Open-Drain arbeitet, d.h. der Transistor, der die Leitung auf High 
zieht, fehlt. Zu den Zeiten, wo Du Daten vom Slave erwartest, mußt Du 
den Pin High schalten, dann ist er vom Prozessor her passiv, und das 
EEPROM kann die SDA-Leitung auf Masse legen.

2. Beim Atmel und den meisten anderen Controllern gibt es so einen Pin 
nicht. Hier muß man einen normalen Port benutzen. Das funktioniert aber 
auch: Solange der Master Daten sendet, gibst Du über SDA entweder High 
oder Low aus. Der externe 10k Widerstand ist in diesem Fall 
bedeutungslos, und dem EEPROM ist es egal.

Sobald aber Daten vom EEPROM erwartet werden, also z.B. beim neunten 
Clock oder beim Einlesen der Daten, schaltest du bereits vorher den 
SDA-Pin als Eingang! Dann wird der Pegel auf der SDA-Leitung nur vom 
EEPROM bestimmt. Jetzt brauchst Du nur noch den Zustand des Pins 
einzulesen (Achtung: beim Atmel geht das über die PINx-Register, die 
PORTx-Register sind nur für den Ausgang) Achte auch darauf, die internen 
Pull-Up-Widerstände des Atmels zu deaktivieren, diese sind so 
niederohmig, daß es manchmal Probleme mit externen Pull-Ups gibt.

Anschließend schaltest Du den SDA-Pin wieder als Ausgang (mit dem 
richtigen Pegel).

Noch ein Tip: die meisten EEPROMS sind für 100 kHz oder 400 kHz Bustakt 
gedacht. Achte darauf, die notwendige Anzahl Mikrosekunden zu warten, 
nachdem eine Leitung ihren Zustand gewechselt hat. Auch beim Einlesen 
von SDA empfehlen sich einige NOPs, da das Aufladen der 
Leitungskapazität durch den 10k Widerstand in Controller-Dimensionen 
recht lange dauert.

Welchen Prozessor benutzt Du eigentlich?

von Peter D. (peda)


Lesenswert?

Laut I2C Spezifikation sind beide, also SDA und SCL open drain !

Dadurch kann ein Slave auch den Takt auf Low ziehen, wenn es ihm zu 
schnell geht. Der Master muß dann solange warten, bis der Slave auf SCL 
wieder High anlegt.
Das ist z.B. wichtig, wenn ein anderer MC als Slave verwendet wird.

Einen open-drain Ausgang realisiert man so, daß man das Ausgangsbit 
ständig auf Low läßt. Muß man dann ein Low-Bit senden, stellt man das 
Richtungsbit auf Ausgang und bei einem High-Bit auf Eingang.


Bei ganz kurzen Leitungen reichen die internen Pull-Ups aus. Ansonsten 
sind 10k ... 1,8k eine gute Wahl. Die meisten I2C-IC sind nur für 3mA 
spezifiziert, deshalb die Pull-Ups nicht unter 1,8k wählen.


Peter

von Alf Jäger (Gast)


Lesenswert?

Hi,

ich benutze den MSP430. Wenn ich den Application Report richtig in 
Erinnerung habe, kann er Ausgänge als Open Drain schalten.
Warteschleifchen sind im Programm schon vorgesehen.
Der Trick von Peter mit der Umschaltung Ein/Ausgang ist nicht schlecht 
...

Gruß, ALF

von Bernward Mock (Gast)


Lesenswert?

Danke für den Tip, die Daten über das Richtungsbit auszugeben. Bin ich 
von selbst noch gar nicht drauf gekommen. Könnte noch einige Bytes im 
Programmcode sparen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.