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 ...
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?
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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.