ich habe eine Frage zur Verwendung des I2C-Bus mit einem ATMEGA328p als Master und einem AD-Wandler PCF8591 als Slave.
Beim Master werden der SDA-Pin als auch der SCL-Pin jeweils als Ausgang und als Eingang verwendet. Kann ich dazu z.B. die Port-Pins PD.2 und PD.3 verwenden?
Wenn diese als Ausgänge konfiguriert werden, sollte dann trotzdem das Einlesen der Eingangspegel an den Pins mit den folgenden Makros funktionieren?
if(SDA_READ())// SDA auf Low: ACK vom Empfaenger, ok
16
error=ERROR_ACK;// SDA auf High: NACK, Fehler
Bei meinen Tests funktioniert es leider nicht wie gewünscht:
offensichtlich liefern SDA_READ() und SCL_READ() nicht den Zustand des jeweiligen Pins zurück, sondern den Wert, der zuletzt am Port ausgegeben wurde.
Falls das so ist, wie funktioniert es dann richtig?
Oder geht das so grundsätzlich nicht und man muss beim ATMEGA 328p die im Datenblatt beschriebene TWI-Schnittstelle für den I2C-Bus verwenden?
Hallo,
zu einem anderen I2C-Sensor, den ich ebenfalls verwenden möchte, hat der Hersteller eine Beispiel-Applikation zur Verfügung gestellt, die die oben beschriebene Lösung verwendet. Allerdings mit einem anderen MC, bei dem das vermutlich so funktioniert. Die Anpassung der Beispiel-Applikation an den ATMEGA328p erschien mir deshalb als der geringere Aufwand.
Die Anpassung der
Beispiel-Applikation an den ATMEGA328p erschien mir deshalb als der
geringere Aufwand.
:Ironie:
Natürlich ist es "viel" einfacher ein Beispiel für einen Fremdprozessor auf einen Avr zu portieren, der das gar nicht braucht.
Zumindest ist es einfacher, als die Vorschläge zu befolgen und den Beispielcode zu verwenden, der vom Hersteller des verwendeten µC herausgegeben wurde.
:/Ironie:
Selbst wenn dir die TWI Hardwarelösung nicht gefällt, gibt es Dutzende Software Lösungen für AVRs in den Weiten des Internet.
Hallo,
der Sensorhersteller hat eine Portierung in seiner Beispielapplikation für den Anwender quasi schon vorbereitet:
// Porting to a different microcontroller (uC):
// - change the port functions / definitions for your uC
// - adapt the timing of the delay function for your uC
// - adapt the SystemInit()
// - change the uC register definition file <stm32f10x.h>
Leider hat das nun doch nicht so einfach geklappt.
Ihr habt mich überzeugt, doch besser die TWI-Schnittstelle zu verwenden.
Vielen Dank!
Indem der Master den SCL-Zustand einliest, kann/muss er sich versichern, dass der Bus freigegeben ist. Wenn der Slave die SCL-Leitung auf Low hält, muss der Master warten und kann nicht senden.
und der muss Ausgang sein um den SCL auf low zu ziehen damit ist er
Ausgang!
Naja, beide haben irgendwie Recht. Es gibt halt verschiedene
Ausgänge, hauptsächlich Open-Drain und Push-Pull. Open-Drain
ist so quasi nur ein halber Ausgang.
Übrigens:
Der TO strauchelt bei der SoftI2C Implementierung.
Da muss man ihn nicht mit falschen Informationen füttern.
Und "immer" ist schlicht falsch.
Und mit "beide haben irgendwie recht" kann man soziale Probleme angehen/lösen. Aber technische eher nicht.
Oder sollte man die Sache vielleicht demokratisch angehen, und so entscheiden, ob SCL immer ein Ausgang sein muss?
Nachtrag:
Ich bin übrigens schon lange sicher, dass Crazy H. (crazy_h) ganz genau weiß, dass er mit seinem "immer" über das Ziel hinausgeschossen ist.
Ich glaube nicht, dass man ihm das jetzt noch schön reden muss.
In der High-Phase des Clock ist SCL kein Ausgang, sondern High-Z.
Sonst gäbe es einen Kurzschluss, wenn der Slave SCL auf Low zieht.
Nun, Slaves mit Hardware-I2C ziehen aber SCL nie auf low, wie z.B. im PCF8574/A Datenblatt zu sehen ist. Da ist SCL ausschließlich ein Eingang.
Und auch beim oben genannten PCF8591 steht eindeutig im Datenblatt:
SCL: I2C-bus serial clock input
Wird also kein Slave mit MC verwendet, der SCL anhalten muß, weil er z.B. gerade eine andere Task behandelt, darf der Master SCL natürlich als push/pull betreiben und den Pullup sparen.
Ehe man sich künstlich aufregt, einfach erstmal ins Datenblatt schauen.
Nun, Slaves mit Hardware-I2C ziehen aber SCL nie auf low, (...)
Bist Du sicher, dass es keine HW-Slaves mit clock stretching gibt? Das Busy kann man auch völlig ohne µC realisieren, ein Monoflop oder Zähler reicht völlig aus. Um da für alle verfügbaren Bausteine zu sprechen, muss man eine recht umfangreiche Marktrecherche durchführen.
Daher, eine SCL-Phase ist erst dann zuende, wenn der Master SCL high gesetzt hat und durch Gegenlesen bestätigt hat, dass dort high anliegt.
Das
Busy kann man auch völlig ohne µC realisieren, ein Monoflop oder Zähler
reicht völlig aus.
Wozu sollte man sowas tun, Hardware arbeitet parallel.
Und die Schreibzeit beim EEPROM wird über das NACK auf die I2C-Adresse realisiert. Dann kann der Master nen anderen Slave bedienen und muß nicht 10ms lang hängen bleiben.
OK, das ist jetzt die die dritte Strophe in dem Lied:
"Wir scheißen auf die I2C Spezifikation"
Die I2C Pullup werden sowieso überbewertet.
Ich kann mir vorstellen, dass es Leute gibt, die zu blöd oder zu faul sind, sich an den Standard zu halten, sogar, dass es ein Einzelfällen funktioniert.
Aber Peda, dass du dazu gehörst und das auch noch öffentlich hier rausposaunst, das hätte ich nicht erwartet.
Auf der Respektskala bist du damit, zumindest bei mir, um mindestens 3 Stufen gesunken.
Aber das wird dir dann auch wohl scheißegal sein.....
Ich kann mir vorstellen, dass es Leute gibt, die zu blöd oder zu faul
sind, sich an den Standard zu halten, sogar, dass es ein Einzelfällen
funktioniert.
Es funktioniert garantiert. Ein Eingang kann nunmal nicht auf low ziehen, das widerspricht logischem Denken.
Daß ein Standard alle möglichen Betriebsarten abdeckt, heißt noch lange nicht, daß man sklavisch auch die Zustände implementieren muß, die in der konkreten Anwendung gar nicht auftreten können. Man darf auch mitdenken.
Die Multimasterzustände werden ja in der Regel auch nicht beachtet. Es wird vorausgesetzt, daß man die Arbitration nicht verlieren kann.
Ach herrje. jetzt verzichtet DIESE Impentierung nun ausgerechnet auf das Ack vom Slave.
Nundenn: trotzdem sieht man schön, wie die Ausgänge von "aktiv-Low" als Ausgang auf "passiv"-Input umgeschaltet werden.
Sorry - war ich wieder zu voreilig.
Das aber ist völlig irrelevant; wenn /ein/ I2C-Baustein nicht die SCL-Leitung ansteuert, bedeutet das nicht, daß alle anderen sich derartig verhalten.
Auch wenn noch zwei oder drei weitere Datenblätter zitiert werden, ändert das nichts daran, daß der Standard "clock-stretching" als elementaren Bestandteil enthält; welchen persönlichen Vorteil hat man davon, eine I2C-Master-Implementierung zu wählen, die sich nicht um den Standard kümmert und nur mit ausgesuchten I2C-Bausteinen funktioniert? Lohnen die paar Bytes eingespartes Flash-ROM?
darf der Master SCL natürlich als push/pull betreiben und den Pullup
sparen.
So ein Schwachsinn! Da bleibt mir nur noch ein Kopfschütteln übrig...
Unter Zuhilfenahme natürlicher Intelligenz kann man das in bestimmten Fällen durchaus machen. Beispielsweise um höhere Datenraten zu erhalten, wenn µC interne Pullup-Widerstände zu schlapp und die kapazitive Belastung hoch ist. Es reicht ja, den '1'-Zustand nur für < 1 µs zu aktivieren, um schnelle Anstiegszeiten zu bekommen. Beim 8051 war das schon per Hardware eingebaut.
Aus Platznot hatte ich auch schon IIC-Bus und Schieberegisteransteuerung auf die selben Pins gelegt.
Auch wenn noch zwei oder drei weitere Datenblätter zitiert werden,
ändert das nichts daran, daß der Standard "clock-stretching" als
elementaren Bestandteil enthält; welchen persönlichen Vorteil hat man
davon, eine I2C-Master-Implementierung zu wählen, die sich nicht um den
Standard kümmert und nur mit ausgesuchten I2C-Bausteinen funktioniert?
Lohnen die paar Bytes eingespartes Flash-ROM?
Bei entsprechenden Stückzahlen kann sich ein eingesparter Widerstand sehr wohl lohnen, da können Material- und Bestückungskosten schon einen merklichen Anteil erhalten. Es kommt halt immer auf das konkrete Produkt an. ;)
Es funktioniert garantiert. Ein Eingang kann nunmal nicht auf low
ziehen, das widerspricht logischem Denken.
Mag ja alles sein, nur wo ist der Vorteil? Ob ich nun einen IO-Pin auf einem Mega328p als Ausgang zwischen high und low umschalte, oder zwischen High-Z-Eingang und Low-Ausgang, macht doch keinen Unterschied. Da kann man es auch gleich richtig machen.
Ob ich nun einen IO-Pin als
Ausgang zwischen high und low umschalte, oder den Pin zwischen
High-Z-Eingang und Low-Ausgang, macht doch keinen Unterschied.
Es ging mir auch nur um die Behauptung, daß es verboten sei:
Benutze mal den eigenen Kopf,
als nur das zu machen, was andere Dir sagen.
Wenn ich einmal eine Funktionssammlung schreibe, welche sich am Standard hält, brauche ich sie nie mehr anzufassen, kann sie quasi blind immer und überall nutzen.
Das sagt mir mein eingeschalteter Kopf!
Offensichtlich funktioniert dein und Pedas Kopf anders.
Vermutlich habt ihr zu wenig Probleme.
Offensichtlich funktioniert dein und Pedas Kopf anders.
Sicherlich.
In der Praxis gibt es keinen "Standard" und richtige Probleme werden nicht durch Zusammenklicken von LIBs gelöst.
Aber mach ruhig, wie Du meinst.
Ich sehe dich gerade vorm Richter, weil du mit 180 Stuckis durch eine Fußgängerzone geballert bist. Wie du dem Richter erklärst, dass man auf Regeln/Spezifikationen scheißen kann. Verbunden mit deinem Aufruf, an alle Jünglinge, es dir gleich zu tun.
Laß Deine Schwurbelei mal stecken.
Sie zeigt nur, daß Du keine praktische Erfahrung in der
Geräteentwicklung hast.
Aha.
Wissentlich Standards zu ignorieren ist also deiner Meinung nach das, was man tun sollte, um Geräte zu entwickeln?
Oder das, was man tun sollte, um selber die Erfahrung zu machen, dass dieser Ansatz Schwachsinn ist (weil man es den wirklich Erfahrenen nicht glauben mag)?
inzwischen habe ich die TWI-Schnittstelle aus dem Datenblatt des ATMEGA328p anhand der detaillierten Beschreibung implementiert. Leider hat es nicht auf Anhieb funktioniert, da der I2C-Stopp nicht ausgeführt wurde.
Mit dem dort vogeschlagenen delay funktioniert es nun:
TWCR = ((1 << TWINT) | (1 << TWEN) | (1 << TWSTO));
delay_micro(20);
Die von Axel R. oben gezeigte Implementierung finde ich übrigens sehr interessant. Ist zwar eine Sonderlösung, die nicht für jeden Anwendungsfall bestimmt und geeignet ist, aber zumindest für mich recht lehrreich:
„Nundenn: trotzdem sieht man schön, wie die Ausgänge von "aktiv-Low" als
Ausgang auf "passiv"-Input umgeschaltet werden.“
Vielen Dank für Eure hilfreichen Beiträge!
Gruß Rainer
Mit dem dort vogeschlagenen delay funktioniert es nun:
TWCR = ((1 << TWINT) | (1 << TWEN) | (1 << TWSTO));
delay_micro(20);
Die saubere Lösung wäre aber, das TWSTO-Bit zu pollen, bis es von der Hardware rückgesetzt wurde.
"When the STOP condition is executed on the bus, the TWSTO bit is cleared automatically."
Wenn nur die 'Bauer'-Funktion gebraucht wird, bietet es sich an, die Routinen per Software mit frei wählbaren Pins umzusetzen. Das läuft bei mir ab 8051 über den 68K mit GAL, den AT90S2313 bis zum RP2040. Eine Hardware IIC-Schnittstelle ist nicht erforderlich und man implementiert den Umfang, den man benötigt.
Hardware IIC ist dann sinnvoll bzw. notwendig, wenn ein µC als 'Knecht' angesprochen werden muß. Das kann im Hintergrund per Polling ablaufen. Die Anfrage wird bedient, wenn der µC frei ist und die Unterbrechung durch eine ISR das Timing stören würde. Hier ist auch der Vorteil gegenüber einer UART-Verbindung, die man immer zügig bedienen muß.
Oje, der arme PCF8591 kann doch nur max 100kHz. Ohne Delays wird das
nichts bei nem 16MHz AVR.
Hab egerade einen ATtiny2313MU mit 8Mhz und en 64x32 OLED am laufen. Das geht komplett problemlos, obwohl ja eigentlich "ein wenig zu schnell", Stimmt schon.
Ging ja auch eher um die Makros von AusgangLOW auf Input ...
Hab egerade einen ATtiny2313MU mit 8Mhz und en 64x32 OLED am laufen.
Das OLED ist ja auch kein PCFxxx. Die alten PCFxxx kann man vielleicht bis 200kHz triezen, aber das wird schon instabil.
Neuere ICs können dagegen oft über 1MHz I2C Takt.
Die I2C Spezifikation lässt kein aktives High zu.
(wurde eben schon zitiert)
Und zwar aus gutem Grund. Es geht nicht nur darum, Kurzschlüsse zu vermeiden. Es ist auch wichtig, dass die steigenden Flanken beim aktiven Treiben zu steil wären und schlimmstenfalls unerwünschte Reflexionen im Kabel auslösen würden.
Es ist auch wichtig, dass die steigenden Flanken beim aktiven
Treiben zu steil wären und schlimmstenfalls unerwünschte Reflexionen im
Kabel auslösen würden.
Interessant. Bei fallenden Flanken passiert das nicht?
Es ist auch wichtig, dass die steigenden Flanken beim aktiven
Treiben zu steil wären und schlimmstenfalls unerwünschte Reflexionen im
Kabel auslösen würden.
Interessant. Bei fallenden Flanken passiert das nicht?
Wenn man sich an die I²C-Spezifikation hält.
t_of und t_f haben Minimum 20 ns × (V_DD / 5.5 V).
Wenn aktive steigende Flanken erlaubt wären, hätten sie natürlich das gleiche Limit.
Daß ein Standard alle möglichen Betriebsarten abdeckt, heißt noch lange
nicht, daß man sklavisch auch die Zustände implementieren muß, die in
der konkreten Anwendung gar nicht auftreten können. Man darf auch
mitdenken.
Die Multimasterzustände werden ja in der Regel auch nicht beachtet. Es
wird vorausgesetzt, daß man die Arbitration nicht verlieren kann.
Es gibt I²C-Isolatoren mit zwei bidirektionalen Kanälen (z.B. ISO1640, ADuM1250). Und für Systeme mit einem Master und ohne Clock Stretching gibt es Varianten mit unidirektionalem SCL-Kanal (ISO1641, ADuM1251). Aber selbst die haben Open-Drain-Ausgänge.
Man benutzt die I/O Pins im Open-Drain Modus, indem man die Bits im PORT
Register unangetastet (auf 0) belässt und nur das DDR Register
beschreibt.
So macht es die I²C Library von Peter Fleury auch, und die erlaubt auch Clockstretching. Generell funktioniert diese Lib so gut, das ich es mir spare, immer wieder neue I²C Routinen zu implementieren.