Forum: Mikrocontroller und Digitale Elektronik I2C-Bus: SDA und SCL an ATMEGA328p


von Rainer G. (rainerg)


Lesenswert?

Hallo zusammen,

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?
1
#define I2C_SDA_PIN  2   // PD.2 
2
#define I2C_SCL_PIN  3   // PD.3 
3
#define tst_bit(port, bit) (((port)&(1 << (bit))) >> (bit))
4
#define SDA_READ() (tst_bit (PIND,I2C_SDA_PIN))   // read SDA
5
#define SCL_READ() (tst_bit (PIND,I2C_SCL_PIN))     // read SCL
6
7
void Port_Init (void)
8
     {
9
     set_bit(DDRD, I2C_SDA_PIN);   // PD.2  Port-Direction Output 
10
     clr_bit(PORTD,I2C_SDA_PIN);   // PD.2  auf 0V setzen
11
     set_bit(DDRD, I2C_SCL_PIN);   // PD.3  Port-Direction Output 
12
     clr_bit(PORTD,I2C_SCL_PIN);   // PD.3  auf 0V setzen
13
     }
14
Müsste dann der folgende Aufruf das ACK vom Slave korrekt einlesen?
15
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?

Vielen Dank für Eure Antworten im Voraus!

Gruß Rainer

: Bearbeitet durch Moderator
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Rainer G. schrieb:
> ich habe eine Frage zur Verwendung des I2C-Bus mit einem ATMEGA328p

Der konkrete AVR hat eine TWI Einheit in Hardware.
Wieso willst du das in Software erledigen?

Wo ist deine Notlage, die dich dazu zwingt?


Zudem:
Rainer G. schrieb:
> void Port_Init (void)
I2C Pins sind open collector, bzw. open drain.
Der Ruhezustand ist also Input und High.
Und nicht Output Low

: Bearbeitet durch User
von Rainer G. (rainerg)


Lesenswert?

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.

Gruß Rainer

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Rainer G. schrieb:
> 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.

von Sebastian R. (sebastian_r569)


Lesenswert?

Rainer G. schrieb:
> Wenn diese als Ausgänge konfiguriert werden,  sollte dann trotzdem das
> Einlesen der Eingangspegel an den Pins mit den folgenden Makros
> funktionieren?

Nein.

Weil:

Rainer G. schrieb:
> sondern den Wert, der zuletzt am Port ausgegeben wurde.

Eingangs- und Ausgangsregister sind unterschiedliche Register, zwischen 
denen mit dem DDR "hin und her" geschaltet wird.

Rainer G. schrieb:
> Falls das so ist, wie funktioniert es dann richtig?

Es gibt noch einen dritten Zustand: Tri-State oder HiZ.

Schreiben:
Daten-Pin als Ausgang und Low (GND) für eine 0, Pin als Eingang als High 
(VCC)
Einlesen dann dauerhaft als Eingang.


Aber ganz ehrlich: Nutze das HardwareI2C, das der Controller hat.
Beliebt dazu ist die I2C Master Lib von Peter Fleury.

von Peter D. (peda)


Lesenswert?

Rainer G. schrieb:
> offensichtlich liefern SDA_READ() und SCL_READ()  nicht den Zustand des
> jeweiligen Pins zurück, sondern den Wert, der zuletzt am Port ausgegeben
> wurde.

Vermutlich doch. Nur ist entweder kein Slave angeschlossen oder nicht 
adressiert worden.
Offensichtlich ist daher noch nichts.

von Rainer G. (rainerg)


Lesenswert?

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!

Gruß Rainer

von Crazy Harry (crazy_h)


Lesenswert?

Rainer G. schrieb:
> Beim Master werden der SDA-Pin als auch der SCL-Pin jeweils als Ausgang
> und als Eingang verwendet.

Der SCL ist immer Ausgang. Der Master gibt den Takt vor.

von Rainer G. (rainerg)


Lesenswert?

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.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Crazy H. schrieb:
> Der SCL ist immer Ausgang. Der Master gibt den Takt vor.

Ganz großer Blödsinn!
High wird durch einen Pullup gezogen.
dann kann der Pin kein Ausgang sein!
Unmöglich.

Suchtipp (am Rande): clock stretching

von Crazy Harry (crazy_h)


Lesenswert?

Auch wenn er den Pegel auf GND zieht ist er ein Ausgang.

Da gefällt mir die Erklärung von Rainer besser.

von Joachim B. (jar)


Lesenswert?

Arduino F. schrieb:
> Crazy H. schrieb:
>> Der SCL ist immer Ausgang. Der Master gibt den Takt vor.
>
> Ganz großer Blödsinn!
> High wird durch einen Pullup gezogen.
> dann kann der Pin kein Ausgang sein!
> Unmöglich.

OK streiche das IMMER aber trotzdem gilt:
https://www.ipd.kit.edu/~buchmann/microcontroller/i2c.htm

Da der Busmaster, also der Initiator einer I2C-Übertragung, den Takt mit 
übermittelt

und der muss Ausgang sein um den SCL auf low zu ziehen damit ist er 
Ausgang!

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Crazy H. schrieb:
> Auch wenn er den Pegel auf GND zieht ist er ein Ausgang.

Nicht "Auch", sondern "Nur"!

Joachim B. schrieb:
> ....
Sprichst du mit mir?

von Wastl (hartundweichware)


Lesenswert?

Joachim B. schrieb:
> 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.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Wastl schrieb:
> Naja, beide haben irgendwie Recht.
Nein!
Auch der Master muss SCL beobachten!
Sonst wäre kein Clockstretching möglich.
Darum darf SCL keinesfalls IMMER ein Ausgang sein.

Wastl schrieb:
> Push-Pull
Gibts in I2C nicht.
Ist also eine Nebelkerze.


Ü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.

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

Arduino F. schrieb:
> 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.

mag sein

Arduino F. schrieb:
> Ganz großer Blödsinn!
> High wird durch einen Pullup gezogen.
> dann kann der Pin kein Ausgang sein!
> Unmöglich.

und du bist nicht über das Ziel hinausgeschossen?
Ich bin sicher das du genau weißt das SCL nur als Ausgang den Clock 
vorgeben kann vom Master.

von Rainer W. (rawi)


Lesenswert?

Joachim B. schrieb:
> und der muss Ausgang sein um den SCL auf low zu ziehen damit ist er
> Ausgang!

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.

von Joachim B. (jar)


Lesenswert?

Rainer W. schrieb:
> In der High-Phase des Clock ist SCL kein Ausgang

hab ich auch nicht geschrieben, keine Nebelkerzen werfen.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Joachim B. schrieb:
> ...

I2C ist kein WünschDirWas, wo man mit Realitätsverfälschungen sonderlich 
weit kommt.

von Joachim B. (jar)


Lesenswert?

Arduino F. schrieb:
> I2C ist kein WünschDirWas, wo man mit Realitätsverfälschungen sonderlich
> weit kommt.

warum tust du es dann?

Joachim B. schrieb:
> Arduino F. schrieb:
>> Ganz großer Blödsinn!
>> High wird durch einen Pullup gezogen.
>> dann kann der Pin kein Ausgang sein!
>> Unmöglich.
>
> und du bist nicht über das Ziel hinausgeschossen?
> Ich bin sicher das du genau weißt das SCL nur als Ausgang den Clock
> vorgeben kann vom Master.

von Rainer W. (rawi)


Lesenswert?

Joachim B. schrieb:
> und der muss Ausgang sein um den SCL auf low zu ziehen damit ist er
> Ausgang!

Er ist genau dann und nur dann Ausgang, wenn er SCL auf low zieht, sonst 
nicht.
Deine Formulierung ist ausgesprochen uneindeutig, sorry.

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Rainer W. schrieb:
> 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.

von Ge L. (Gast)


Lesenswert?

Peter D. schrieb:

> 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.

von Peter D. (peda)


Lesenswert?

Soul E. schrieb:
> Bist Du sicher, dass es keine HW-Slaves mit clock stretching gibt?

Ich hab ja deshalb gesagt, ins Datenblatt schauen.
Z.B. die PCFxxx und 24Cxxx/FM24Cxxx kenne ich mit SCL = nur Eingang.

von Peter D. (peda)


Lesenswert?

Soul E. schrieb:
> 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.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

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.....

: Bearbeitet durch User
von Christian M. (christian_m280)


Lesenswert?

Peter D. schrieb:
> 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...

Gruss Chregu

von Peter D. (peda)


Lesenswert?

Arduino F. schrieb:
> 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.

: Bearbeitet durch User
von Axel R. (axlr)


Lesenswert?

Ich hab das schnell für diech gegoogelt

https://github.com/wagiminator

daraus:
1
// ===================================================================================
2
// I2C Master Implementation (Write only)
3
// ===================================================================================
4
5
// I2C macros
6
#define I2C_SDA_HIGH()  DDRA &= ~(1<<I2C_SDA) // release SDA   -> pulled HIGH by resistor
7
#define I2C_SDA_LOW()   DDRA |=  (1<<I2C_SDA) // SDA as output -> pulled LOW  by MCU
8
#define I2C_SCL_HIGH()  DDRA &= ~(1<<I2C_SCL) // release SCL   -> pulled HIGH by resistor
9
#define I2C_SCL_LOW()   DDRA |=  (1<<I2C_SCL) // SCL as output -> pulled LOW  by MCU
10
11
// I2C transmit one data byte to the slave, ignore ACK bit, no clock stretching allowed
12
static void I2C_write(uint8_t data) {
13
  for(uint8_t i = 8; i; i--) {                // transmit 8 bits, MSB first
14
    I2C_SDA_LOW();                            // SDA LOW for now (saves some flash this way)
15
    if (data & 0x80) I2C_SDA_HIGH();          // SDA HIGH if bit is 1
16
    I2C_SCL_HIGH();                           // clock HIGH -> slave reads the bit
17
    data<<=1;                                 // shift left data byte, acts also as a delay
18
    I2C_SCL_LOW();                            // clock LOW again
19
  }
20
  I2C_SDA_HIGH();                             // release SDA for ACK bit of slave
21
  I2C_SCL_HIGH();                             // 9th clock pulse is for the ACK bit
22
  asm("nop");                                 // ACK bit is ignored, just a delay
23
  I2C_SCL_LOW();                              // clock LOW again
24
}
25
26
// I2C start transmission
27
static void I2C_start(uint8_t addr) {
28
  I2C_SDA_LOW();                              // start condition: SDA goes LOW first
29
  I2C_SCL_LOW();                              // start condition: SCL goes LOW second
30
  I2C_write(addr);                            // send slave address
31
}
32
33
// I2C stop transmission
34
static void I2C_stop(void) {
35
  I2C_SDA_LOW();                              // prepare SDA for LOW to HIGH transition
36
  I2C_SCL_HIGH();                             // stop condition: SCL goes HIGH first
37
  I2C_SDA_HIGH();                             // stop condition: SDA goes HIGH second
38
}

von Axel R. (axlr)


Lesenswert?

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.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Peter D. schrieb:
> Es funktioniert garantiert.

Du beziehst dich auf einen PCF8574 !
Verwendet der TO einen solchen?
Nein!

Bitte zeige mir im Datenblatt des  PCF8591 die Stelle, welche das 
erlauben könnte.
Ich sehe sie nicht.

Du beziehst dich auf irgendwelche 24Cxxx!
Verwendet der TO einen solchen?
Nein!

Rainer G. schrieb:
> zu einem anderen I2C-Sensor, den ich ebenfalls verwenden möchte,
Wie kannst du garantieren, dass sich der "andere Sensor" auch so 
verhält?
Kannst du nicht!

Was du tust, ist Fallen stellen.
Einen Unwissenden in die Irre schicken
Und das bewusst!
Wider besseren Wissens.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Peter D. schrieb:
> Ehe man sich künstlich aufregt, einfach erstmal ins Datenblatt schauen.

Wie absurd ist das denn? Am Ende schlägst du noch vor mal solle erstmal 
drüber nachdenken, was man tut, bevor man es tut... :D

von Michael F. (Firma: IAR Systems) (michael_iar)


Lesenswert?

Moin
1
Both, SDA and SCL, must be open drain and must not be driven high by any device attached to the I2C bus.

https://www.i2c-bus.org/i2c-primer/requirements/

Gruß,
Michael

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Arduino F. schrieb:
> Bitte zeige mir im Datenblatt des  PCF8591 die Stelle, welche das
> erlauben könnte.
> Ich sehe sie nicht.

Siehe Bild.

von Peter D. (peda)


Lesenswert?

Axel R. schrieb:
> Ich hab das schnell für diech gegoogelt

Oje, der arme PCF8591 kann doch nur max 100kHz. Ohne Delays wird das 
nichts bei nem 16MHz AVR.

von Harald K. (kirnbichler)


Lesenswert?

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?

von Mi N. (msx)


Lesenswert?

Christian M. schrieb:
> Peter D. schrieb:
>> 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.

Michael F. schrieb:
> Both, SDA and SCL, must be open drain and must not be driven high by any
> device attached to the I2C bus.

Das sagt die Bibel, aber die 'Sünden' sind schon immer reizvoller ;-)

von M. K. (sylaina)


Lesenswert?

Harald K. schrieb:
> 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. ;)

von Oliver S. (oliverso)


Lesenswert?

Peter D. schrieb:
> 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.

Oliver

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Oliver S. schrieb:
> 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:

Arduino F. schrieb:
> Darum darf SCL keinesfalls IMMER ein Ausgang sein.

Und das trifft eben nicht zu, wenn kein Slave am Bus Clock Stretching 
kann.

: Bearbeitet durch User
von Harald K. (kirnbichler)


Lesenswert?

Peter D. schrieb:
> Und das trifft eben nicht zu, wenn kein Slave am Bus Clock Stretching
> kann.

Doch, es trifft auch dann zu, nur stört es nicht, wenn man es falsch 
macht.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Peter D. schrieb:
> Es ging mir auch nur um die Behauptung, daß es verboten sei:
>
> Arduino F. schrieb:
>> Darum darf SCL keinesfalls IMMER ein Ausgang sein.

Die I2C Spezifikation lässt kein aktives High zu.
(wurde eben schon zitiert)

Und das kommt einem Verbot gleich.

von Mi N. (msx)


Lesenswert?

Arduino F. schrieb:
> Der konkrete AVR hat eine TWI Einheit in Hardware.
> Wieso willst du das in Software erledigen?

Arduino F. schrieb:
> Die I2C Spezifikation lässt kein aktives High zu.
> (wurde eben schon zitiert)
>
> Und das kommt einem Verbot gleich.

Das ist doch alles kleinkariertes Zeug. Benutze mal den eigenen Kopf, 
als nur das zu machen, was andere Dir sagen.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Mi N. schrieb:
> 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.

von Mi N. (msx)


Lesenswert?

Arduino F. schrieb:
> 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.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Mi N. schrieb:
> In der Praxis gibt es keinen "Standard"

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.

von Mi N. (msx)


Lesenswert?

Laß Deine Schwurbelei mal stecken.
Sie zeigt nur, daß Du keine praktische Erfahrung in der 
Geräteentwicklung hast.

von C-hater (c-hater)


Lesenswert?

Mi N. schrieb:

> 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)?

von Mi N. (msx)


Lesenswert?

C-hater schrieb:
> Wissentlich Standards zu ignorieren ist also deiner Meinung nach das,
> was man tun sollte, um Geräte zu entwickeln?

Hast mal wieder nichts gelesen und begriffen. Aber schön von Dir zu 
hören ;-)

von Rainer G. (rainerg)


Lesenswert?

Hallo zusammen,

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.

Die Lösung dafür habe ich hier gefunden:
Beitrag ""I2C-Stopp" wird nicht ausgeführt (HW-TWI, AVR)"

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

von Peter D. (peda)


Lesenswert?

Rainer G. schrieb:
> 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."

von Rainer G. (rainerg)


Lesenswert?

Das werde ich auch ausprobieren.

von Mi N. (msx)


Lesenswert?

Peter D. schrieb:
> Die saubere Lösung wäre aber

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ß.

: Bearbeitet durch User
von Axel R. (axlr)


Lesenswert?

Peter D. schrieb:
> Axel R. schrieb:
>> Ich hab das schnell für diech gegoogelt
>
> 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 ...

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Axel R. schrieb:
> 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.

von Mi N. (msx)


Lesenswert?

Axel R. schrieb:
> obwohl ja eigentlich "ein wenig zu schnell",

Du böser Mensch, machst einfach, was Du willst :-(
Siehe hier:

Michael F. schrieb:
> https://www.i2c-bus.org/i2c-primer/requirements/

Aber eigentlich sehr gut, um keine Zeit zu vertüddeln ;-)

von Steve van de Grens (roehrmond)


Lesenswert?

Axel hat das richtig gezeigt:

Axel R. schrieb:
> #define I2C_SDA_HIGH()  DDRA &= ~(1<<I2C_SDA)
> #define I2C_SDA_LOW()   DDRA |=  (1<<I2C_SDA)

> #define I2C_SCL_HIGH()  DDRA &= ~(1<<I2C_SCL)
> #define I2C_SCL_LOW()   DDRA |=  (1<<I2C_SCL)

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.

Arduino F. schrieb:
> 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.

Rainer, vielleicht gefällt dieser Code: 
http://stefanfrings.de/avr_i2c/index.html

: Bearbeitet durch User
von Mi N. (msx)


Lesenswert?

Steve van de Grens schrieb:
> 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?

von Rainer G. (rainerg)


Lesenswert?

Steve van de Grens schrieb:
> Rainer, vielleicht gefällt dieser Code:
> http://stefanfrings.de/avr_i2c/index.html

Danke für den interessanten Link, das schaue ich mir genauer an.
Gruß Rainer

von Clemens L. (c_l)


Lesenswert?

Mi N. schrieb:
> Steve van de Grens schrieb:
>> 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.

von Clemens L. (c_l)


Lesenswert?

Peter D. schrieb:
> 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.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Steve van de Grens schrieb:
> 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.

http://www.peterfleury.epizü.com/avr-software.html?i=1 (1)

Unterstützt Hard- oder Software Interface.

(1) Leider muss man das ü im Link durch ein y ersetzen, das Forum 
behauptet 'Spamverdacht'.

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.