I2C-Signal SCL & SDA

Gast #3032744
Lesenswert?

Hallo Leute,
ich habe ein Bild im Anhang mit einem aufgenommen I2C-Signal.
Dort wird die Slaveadresse 0x70 übergeben was man auch gut in den
ersten 8 Takten erkennen kann (ich habe Zahlen drüber geschrieben)
nun ist der 9. Takt ja zur Bestätigung zuständig. Der Slave gibt ein
ACK raus in dem er die SDA Leitung auf LOW zieht, passiert ja in diesem
Fall auch, mit der fallenden Taktflanke von dem 9. Takt von SCL wird die
SDA Leitung auf LOW gezogen, doch was soll der Anstieg davor bedeutetn?
Es sollen doch nur NULLEN übertragen werden.
Weiß vielleicht jemand einen Rat?
Vielen Dank schonmal!
Angehängte Dateien:
Gast #3032801
Lesenswert?

Ich glaube, Deine Interpretation des Screenshots ist nicht völlig 
zutreffend:
Der Master läßt nach erfolgter Übertragung des achten Bits - d.h. kurz 
nach der fallenden Flanke des achten Taktimpulses auf SCK - SDA los, 
damit der adressierte Slave sie gegebenenfalls nach Low ziehen kann. Das 
tut er auch, nur zieht er quasi "nicht ganz so kräftig" wie der Master 
(oder der Spannungsabfall der Leitung zwischen beiden ist nicht 
vernächlässigbar und die Messung fand direkt am Master statt), so daß 
der Pegel etwas höher bleibt. Der Slave hält sein Acknowledge so lange, 
bis er die fallende Flanke des neunten Taktimpulses erkennt. Dann läßt 
er SDA los, und der Pegel will gen VCC schnellen (das ist die schmale 
Nadel am Ende des ACK), doch der Master übernimmt SDA sofort wieder für 
die Übertragung des nächsten Bytes.

Im Grunde sieht also alles okay aus.
Gast #3032816
Lesenswert?

der Gast schrieb:
> Der Slave gibt ein
> ACK raus in dem er die SDA Leitung auf LOW zieht, passiert ja in diesem
> Fall auch, mit der fallenden Taktflanke von dem 9. Takt von SCL wird die
> SDA Leitung auf LOW gezogen, doch was soll der Anstieg davor bedeutetn?

Dein Slave schafft es nicht, SDA richtig auf low zu ziehen (obwohl der 
Pegel reichen könnte). Gibt es einen Angst(Längs)widerstand in der SDA 
Leitung?

Tach schrieb:
> Hätte auch gesagt das sieht sehr "Kapazitiv" aus.

Dazu sind fallende und steigende Flanken zu steil, es ist etwas 
"Ohmisches"

MfG Klaus
Gast #3032832
Lesenswert?

Klaus schrieb:
> Tach schrieb:
>> Hätte auch gesagt das sieht sehr "Kapazitiv" aus.
>
> Dazu sind fallende und steigende Flanken zu steil, es ist etwas
> "Ohmisches"

Kann auch der Tastkopf sein.
Aber beim "laden" der Leitung hat es deutlich 1-e Charakter.
Das sieht in meinen Augen halt so aus, als ob die Teilnehmer zwar 
schnell genug entladen, aber die Aufladung durch den Pullup begrenzt 
wird.
Gast #3032856
Lesenswert?

also ich hab 4.7k Widerstände und eine LEitungslänge von unter 30cm.
Ich weiß halt nicht wie der Slave reagiert, da ich ein Display ansteure, 
welches aber nichts ausgibt, doch anhand des ACK erkenn ich doch, dass 
das Display dem Master antwortet?! Seh ich das richtig??
Gast #3033012
Lesenswert?

Patrick C. schrieb:
> Auf welche bus-frequenz arbeitest du ?

Wenn es zu schnell wäre, würde das Signal nicht High werden, hier ist 
das nicht erreichte Low das Problem. Daß der Slave reagiert sieht man, 
sonst würde man das "versuchte" Low, das ACK, nicht sehen (SDA würde 
einfach auf High gehen). Man sieht an der Nadel deutlich, daß der Slave 
den Bus mit der fallenden Flanke von SCL freigibt und dann der Master 
wieder SDA treibt.

Ich wette immer noch auf einen Längswiderstand oder ein Problem in der 
Versorgung des Slaves, so daß der Slave-Treiber die 1mA, die man bei 
4,7kOhm braucht, nicht nach GND ziehen kann.

MfG Klaus
Gast #3033382
Lesenswert?

@Klaus, was genau meinst du mit Längswiderstand? Sowas wie ein 
Leitungswiderstand, also in Reihe mit der Leitung?
Du sagtest es könnte auch an der Versorgung des Slaves liegen,
da liegt auch mein Problem, ich hab zu dem Display kein Datenblatt,
es ist ein Chip on Glass Display und zu dem Chip hab ich aber ein 
Datenblatt,
aus diesem Datenblatt hab ich die Versorgungsspannungen Vcc und Vlcd 
genommen, kann da vielleicht ein Fehler sein?
Gast #3034564
Lesenswert?

Hallo,
bist Du sicher, dass das, was Du für einen "Takt" interpretierst auch 
den definierten Setup- und Hold-Zeiten entspricht?
Diese Taktnadeln generieren aus meiner Sicht "per Zufall" ein 
Datensignal.
Ich würde zuerst einmal versuchen einen sauberen Takt zu generieren. Als 
erstes einmal Anfangen, den Pull-Up zu verkleinern (versuch einen 1k8), 
dann evtl. die Übertragungszeit vergrößern. Und am Besten noch mal ein 
Oszi-Bild mit den passenden Skalen zum Signal (so ist das eher ein 
Schätzdiagramm, aus dem man NICHTS ableiten kann).

Gruß
TK
Gast #3035618
Lesenswert?

In dem Bild kann man schön erkennen dass das erst was übertragen wird 
die Adresse ist 70hex -> 01110000 dies geschieht in den ersten 8 (9) 
Takten,
in den nächsten 8 (9) Takten soll laut Programm 11001000 übertragen 
werden, was man auch wieder im Oszillogram erkennt.
Somit kann wohl ausgeschlossen werden, dass zufällig Daten generiert 
werden!
Gast #3035789
Lesenswert?

Das sieht für mich wie ein Kurzschluß aus:
Der Master treibt ein starkes High (was er nicht darf) und der Slave 
treibt ein starkes Low (was er darf).
Daraus ergibt sich ein Pegel von irgendwo zwischen High und Low, und die 
Bauteile leiden.

Der I2C-Bus arbeitet mit Open-Collector, d.h. ein Teilnehmer darf 
entweder ein starkes Low anlegen oder er muß die Leitung "loslassen".
Der Teilnehmer darf aber nie eine starkes High anlegen.
Check Deine I2C-Implementierung im µC.
High wird erzeugt, indem man den Portpin im DDR auf "Eingang" schaltet. 
Das eigentliche High erzeugt dann der Pullup.
#3035830
Lesenswert?

> Das sieht für mich wie ein Kurzschluß aus

Nö. Er hat halt nur die Pullups auf 1k8 verkleinert, aber der Slave - 
der vorher schon mit 4k7 Probleme hatte mit den Strom fürs Low - kann 
die nicht sauber auf 0 ziehen, weil der SDA Ausgang zu schlapp ist.

Dass der Master nicht auf Push-Pull steht sieht man nur im obersten 
Bild, im unteren kaum noch.

Ich würde eher empfehlen die Pullups auf 10k zu erhöhen und etwas mit 
der Busgeschwindigkeit herunter zu gehen. Aber die Pegel sahen bei 4k7 
soo schlecht eigentlich nicht aus - leider kann man die Spannung  nicht 
wirklich ablesen.

Erhöhter Übergangswiderstand durch schlechten Kontakt hätte übrigens 
dasselbe Fehlerbild.
Gast #3036262
Lesenswert?

Also zuerstmal kann man sehen, dass die Form von SDA und SCL bei 1k8 
Pull-Ups dem entspricht, was ich jetzt auch als "vernünftige" Flanken 
ansehen würde. Je größer die Pull-Ups werden, desto mehr e-Fkt entsteht 
aufgrund von Kapazitäten in den Stichleitungen, in den Verdrahtungen des 
Steckboards, aufgrund von Eingangskapas von Master / Slave - Pins. Daher 
sollten die Pull-Ups NICHT mehr vergrößert werden. Wenn ich mir das 
zweite Bild ansehe, kann man jetzt jedoch erkennen, dass das ACK-Bit vom 
SLAVE "nur" noch auf ca. 2V für einen L-Pegel runtergezogen wird. Im 
ersten Bild lag der L-Pegel noch bei ca. 1V (geschätzt). Dies läßt die 
Vermutung aufkommen, dass in den SDA-Leitungen/Stichleitungen - wie 
einer der Vorredner schon mal anmerkte - irgend eine Art von 
Serienwiderständen existiert (vermutlich Größenordnung von 1k2 - nur 
dann würde der Spannungsteiler 1k8 zu 1k2 mit ca. 3V/2V hinkommen und 
aus dem ersten Bild mit den 4k7 zu 1k2 = 4V/1V!). Da ich jetzt nicht 
davon ausgehe, dass eine Verdrahtungsleitung auf deinem Steckboard mit 
1k2 anzusetzen ist, muss da eben was anderes sein.
Weiterhin solltest Du Dir auch mal die Spec vom IIC ansehen, um zu 
verstehen, wie der angesteuert werden muss - eben nicht mit einem 
AUSGANG H und einem AUSGANG L, sondern mit einem INPUT (=H) und einem 
AUSGANG L.
Und bitte kein Kommentar, dass man EEPROMS doch auch mit AUSGANG H/L 
ansteuern kann - JA das geht aber nur solange, bis ein Device sich an 
die Spec hält - dann geht das eben nicht mehr!

Gruß
TK
Gast #3038020
Lesenswert?

Wenn der Thread-Starter in der Zwischenzeit keine Pinkonfigurationen
verändert hat, kann man in der ersten Aufnahme sehen, dass alle Bus-
teilnehmer in Open-Drain-Konfiguration arbeiten:

Es wird aktiv gegen GND gezogen und nicht mehr gegen die PullUp
-Spannung. Daher kommen die verschliffenen Signale (Ladekurve
der Buskapazität).

In der ersten Aufnahme sieht man, dass das bei jeder Flanke so ist.

Die Signale sind aber mit 4k7 PullUp sehr verschliffen ("Haifisch-
flossen". Es wird ja noch nicht einmal die PullUp-Spannung
beim Clock-Signal erreicht.).
Die I2C-Spezifikation rät hier sowieso zu PullUp
-Widerständen im Bereich unter 2k. Je nach PullUp-Spannung variiert
das noch, damit man einen garantierten Minimalstrom und dadurch
eine gewisse Störunempfindlichkeit hat.

Nachdem der Tread-Starter die beiden PullUp-Widerstände gegen 1k8
getauscht hatte, sehen beide Signale jetzt so aus, wie man sich
das auch vorstellt.

Die "komischen" Pegel und Ausreißer kann man jetzt auch besser erkennen.

Der Pegel, der nicht richtig auf GND liegt, sieht tatsächlich so
aus, als wenn hier die Serienwiderstände (die laut I2C-Spezifikation
standardmäßig bei 100 Ohm liegen sollten) viel zu groß wären.

Der Thread-Starter sollte mal seinen Schaltplan mit allen 
Bus-Teilnehmern
und am besten noch mit den jeweiligen Versorgungsspannungen zeigen.

Die Serienwiderstände würde ich immer vorsehen:

1.: Weil sie die I2C-Spezifikation vorschreibt.
2.: Weil man dadurch wenigstens ein Minimalmaß an Schutz gegenüber
Spannungspeaks auf den Busleitungen erhält (I2C-Spezifikation spricht
hier von "High energy spikes".).
3.: Weil man auch gerade in Debug-Phasen sich den Luxus erlauben
kann, die Serienwiderstände mit unterschiedlichen Werten zu bestücken.
Dann kann man sehr schön sehen, wer gerade am Bus zieht - durch die
unterschiedlichen GND-Shifts.



Ich habe außerdem noch mal die "Haifischflosse" durchgerechnet:

-> f_clk = 100kHz (Pulsbreite daher 5µs)
-> ca. 90% des PullUp-Pegels wird erreicht
-> r_pullup = 4k7

Ich komme da auf ~462pF Buskapazität (zumindest an der Clock-Leitung).

Die I2C-Spezifikation erlaubt maximal 400pF. Und das ist auch nur
schwer zu erreichen. Jeder Busteilnehmer darf maximal 10pF an
seinem Pin erzeugen. Der Rest muss dann der Bus sein:

462pF - 2x 10pF = 442pF ??

Ich habe so eine Konstellation schon einmal gesehen. Da war der Bus
aber 70cm lang und über 5 (!) Platinen verteilt über Flachbandkabel
miteinander verbunden usw. Sowas scheint der Thread-Starter aber
nicht zu haben.

Trotzdem muss aber diese sehr hohe Buskapazität irgendwo her
kommen.
Gast #3038030
Lesenswert?

Na weil ein ACK/NACK-Bit mit L(=2V) definitiv NICHT als L erkannt werden 
darf. "L-Level Input Voltage (Standard Mode) -> 0.3Vdd".
Gut, die 2V auf dem 2. Bild sind von mir geschätzt, aber besser kann man 
das dort nicht ablesen. Und wenn die Spec hier schon nicht eingehalten 
wird, dann gibt es ein Problem in der Ansteuerung/Auswertung.

Da ich die i2cmaster-Library nicht kenne, habe ich mir die jetzt mal 
kurz angesehen. Und OK- ich gebe zu, die Ansteuerung dort ist im Großen 
und Ganzen in ordnung. Aber dann sollte man auch nach jedem i2c_write() 
auch den Returnwert abfragen, denn dort steht das ACK-Bit drin. Und noch 
was als Anmerkung zur Library: Die Abfrage zum Clk-Stretching geht nur 
dann gut, wenn man keinen Watch-Dog aktiviert hat, denn es gibt z.B. 
(Druck-)Sensoren, die benötigen im worst-case bis zu 1s für eine int. 
Wandlung und halten in dieser Zeit den SCL auf L. Das würde mit der 
Library nicht mehr ohne weiteres funktionieren.

Gruß
TK
Gast #3038054
Lesenswert?

Und gavgva43 unterstreicht mit seinem Beitrag auch noch mal das, was ich 
vorher angemerkt habe:
- Lest euch die Spec durch, dann können schon mal Fehlerquellen im 
Vorfeld ausgeschaltet werden. Hier z.B. die Kombi zwischen Pull-Ups (Rp) 
und Serienwiderständen (Rs). Da gibt es mehrere, schöne Diagramme, 
welche die Abhängigkeit aufzeigen und das sogar auch noch in Abh. der 
Versorgungsspannung. Dann ist eine Kombi Rp=4k7 und Rs=1k2 bei Vdd=5V 
eben nicht mehr zulässig! (Ich habe jetzt hier unterstellt, dass es 
einen Rs in dieser Größenordnung gibt.)

Da aber jeder, der mit IIC arbeitet und der dann irgendwelche Probleme 
hat (davon gibt es hier im Forum ja genügend) entweder auf:
1) eine Library zurückgreift, die er nicht selbst programmiert und damit 
verstanden hat (das ist jetzt mal eine Unterstellung!)
2) eine Hardware kreiert, die "andere" auch schon mal benutzt haben und 
die dann in einer speziellen Konstellation nicht mehr funktioniert.

Und um allen Spekulationen ein Ende zu bereiten sollte der TO mal seinen 
Schaltplan anhängen. Weil das Schätzen von Werten anhand von 2 
Oszi-Bildern zwar möglich aber in dem Zusammenhang nicht hilfreich ist.


Gruß
TK
#3038117
Lesenswert?

gavgva43 schrieb:
> Die Serienwiderstände würde ich immer vorsehen:
> 1.: Weil sie die I2C-Spezifikation vorschreibt.

Interessanter Beitrag, und der Trick mit den verschiedenen Werten ist 
echt gut. Allerdings meine ich, das die I2C-Spezifikation die 
Serienwiderstände nur empfiehlt, aber nicht vorschreibt (z.B. 7.2: 
"Series resistors Rs are optional").

LG, Sebastian
Gast #3038137
Lesenswert?

Ja.

Erzähl mal einem Kunden bei einem Fehler später,
dass Du nicht alle Empfehlungen umgesetzt hast.

Ich gebe Dir Recht, dass die Serienwiderstände
"recommended" sind, bin aber auch der Meinung,
dass man hier kein Geld sparen sollte.

Vor allem, weil sie einen tatsächlichen Nutzen
haben.
Gast #3042857
Lesenswert?

Ich schilder ein weiteres Problem,
wie man sieht hat das Display 6 anschlüsse, davon ein NC,
ich weiß dass das Display mit dem Controller PCA85133 arbeitet,
zu dem COntroller hab ich ein Datenblatt, zu dem Display fehlen mir 
sonst
jegliche Informationen. Ich weiß halt auch nicht mit welchen Spannungen 
ich
das Display versorgen muss, ich hab laut DAtenblatt (Anhang S. 30)
Vlcd auf 7V und Vdd auf 5V eingestellt, kann ich so vorgehen?
Vielen Dank für die Hilfe!!
Angehängte Dateien:
Gast #3046090
Lesenswert?

Hallo "der Gast",
das ACK wird in dem Fall vom SLAVE-Device (=LCD) NACH der fallenden 
Flanke des 8.Clk ausgegeben (SDA wird auf L gezogen oder eben nicht). 
Mit dem 9. Clk wird das ACK dann vom MASTER-Device "verarbeitet" (der 
SDA-Pegel wird mit der steigenden SCL-Flanke eingelesen). Sofern die 
Setup- und Hold-Zeiten eingehalten werden (je ca. 5us für H- und L- 
Anteil eines SCL-Impulses) ist die Kommunikation "im grünen Bereich".
SDA-Pegel dürfen sich (außer bei START und STOP) nur bei SCL=L Pegel 
verändern.

Gruß
TK
Gast #3046308
Lesenswert?

Okay, vielen Dank dafür schonmal,
ich habe meine Schaltung gründlichst überprüft nach Längs- bzw. 
Serienwiderständen, alles im grünen Bereich, ich kann mir nicht erklären 
warum der Slave das ACK nicht auf LOW-Pegel gezogen bekommt!
Persönliche Seite #3060880
Lesenswert?

der Gast schrieb:
> Was dort aber nicht wirklich beschrieben ist!!

Doch. Da steht doch eindeutig, daß der Ausgang kein normaler SDA ist. 
Sondern aufgrund der Herstellungstechnologie des Substrates keine großen 
Ströme liefern kann. Daher hat das Teil einen zweiten Ausgang, der einen 
externen Treiber ansteuern könnte.

Naja, so versteh ich das zumindest.
Persönliche Seite #3060932
Lesenswert?

Peter Dannegger schrieb:
> Abdul K. schrieb:
>> Ja und? Pullup am SDA hochohmiger machen
>
> Warum?
>
> Wenn das Datenblatt nicht eingehalten wird, liegt eindeutig ein
> Schaltungsfehler oder ein Defekt vor.
>

Oder ein Verständnisproblem.


> Man bekämpft nicht die Wirkung, sondern man beseitigt den Fehler.
> Wir sind doch schließlich keine Politiker.

;-)

Naja, ich las es so, daß der Chip zwar normal treibt, aber dieses COG 
hochohmige Leitungen bringt. Die haben das vorhergesehen und die Lösung 
mit einem extra SDA-AUSgang gemacht. Habe sowas schonmal irgendwo 
gesehen.
Persönliche Seite #3062193
Lesenswert?

Ich find den Thread langsam langweilig. Vermutlich haben die, die beiden 
SDA-Pins direkt am Chip verbunden und das nun Doppelsignal über die 
hochohmige Bahn des COG nach außen geführt. Gedacht ist es vom 
Chiphersteller aber, daß der nach außen treibende SDA-Pin auf der 
PLATINE einen o.C.-Buffer auf die andere SDA-Leitung bekommt. Dann würde 
es einwandfrei funzen!

Ein Foto würde das klären. Aber wozu, laß die Experten doch kostenfrei 
rätseln.

EOT
Persönliche Seite #3062375
Lesenswert?

Versuche es mit blind Schreiben und dann melde dich wieder. Müßig zu 
erwähnen, daß du dafür eventuell nicht eine fertige i2c-Lib nehmen 
kannst.

Für die blinde Betriebsart spricht auch, daß es offensichtlich kein 
Clock-Stretching gibt, der Chip also auf jeden Fall schnell genug ist, 
daß man von einem impliziten ACK ausgehen kann. Allerdings schaue ich 
deswegen nicht nochmals ins DB.

Viel Spaß!
#3062639
Lesenswert?

Wenn Du HW-I2C nimmst, hast Du keine Chance ohne ACK. Bei NACK geht das 
HW-I2C automatisch in den nichtadressierten Zustand.

Die 1V sollte ein AVR aber noch als Low ansehen, notfalls den Pullup auf 
10k erhöhen und die Baudrate verringern.

Daß die Leiterbahnen 1k hochohmig sind, finde ich sehr erstaunlich. Ist 
das LCD gekauft oder aus der Ausschußkiste?
Gast #3072477
Lesenswert?

eigentlich dachte ich ich hätte einen Plan,
die Pins sind ja eindeutig beschrieben mit

SCL
SDA
Vdd
Vlcd
GND
NC

aber irgendwie wills doch nicht funktionieren, auch wenn nur die 
Spannung anliegt ohne I2C-Signal sollte doch vielleicht schonmal was zu 
sehen sein?!
#3072495
Lesenswert?

der Gast schrieb:
> aber irgendwie wills doch nicht funktionieren, auch wenn nur die
> Spannung anliegt ohne I2C-Signal sollte doch vielleicht schonmal was zu
> sehen sein?!

eigentlich nicht, nein, der RAM des Displays wird sehr wahrscheinlich 
leer sein und Display deaktiviert (siehe 7.12 im Datenblatt)
Und wenn du das Display falsch angeschlossen hast, dann stimmt der 
Kontrast nicht und es zeigt dir auch nichts an.

Hast du mal zwischen VDD und VLCD den Kondensator gesetzt. V0 wirst du 
nicht haben.
Ich selbst habe das EAT123A-I2C in einer +5V Schaltung so betrieben wie 
im Anhang. Frag mich nicht mehr warum ich die Dioden rein gesetzt habe, 
denke aber mich daran zu erinnern, dass dadurch der Kontrast geändert 
wurde.
Vielleicht funktioniert es bei dir so auch, jedoch musst du es natürlich 
davor auch richtig initialisieren und etwas ausgeben bzw. blinken lassen 
(siehe Datenblatt deines ICs für den Befehl)
Angehängte Dateien:
#3072526
Lesenswert?

Ich habe mir mal deinen Code angeschaut, ich verwende zwar keine AVRs, 
aber ich benutze den I2C-Bus anders. Bei mir besteht ein Schreibbefehl 
aus dieser Abfolge:
1
I2C_start();
2
I2C_send_byte(addr);
3
I2C_send_byte(subaddr);
4
I2C_send_byte(value);
5
I2C_stop();

Du sendest die adresse, und danach sofort ein command byte, ohne 
subadresse.
Siehe Fig.17 und 18, dir fehlt das control byte. (bei mir subaddr 
genannt)
Außerdem würde ich für den Anfang nicht alles auf einmal senden, sondern 
in meiner oben geposteten Abfolge. Das ist die Standardabfolge, da 
kannst du nichts mit falsch machen, zudem ist es dadurch einfacher zu 
debuggen.

Diode, eine 08/15 Diode habe ich verwendet, nichts besonderes.
#3073875
Lesenswert?

der Gast schrieb:
> Ich kann doch bei dem Display kein Kontrats einstellen, da ich kein V0
> zur referenz habe, ein Pin ist NC wo normalerweise V0 sein sollte.

Ja, schließ da auch einfach nichts an. Es war ja nur ein Vorschlag bevor 
ich gesehen habe dass dein Code nicht stimmt.

Bisher steuerst du dein Display falsch an, es wird gar nichts machen, da 
du bisher noch gar nicht in den CMD Bereich schreibst. Hast du das 
behoben? Code?
Gast #3073915
Lesenswert?

okay, sorry falsch verstanden, mit dem ControlByte hast du völlig Recht, 
aber ist es wirklich von nöten bei "JEDEM" Schreibbefehl die 
Slaveadresse zu senden und auch den Bus zu starten und zu stoppen?
Persönliche Seite #3073923
Lesenswert?

Nur in diesen Fällen:
1. du willst nun die Schreibadresse ändern, also nicht inkrementiell 
schreiben. So gut wie alle i2c-Devices unterstützen inkrementielles 
Schreiben.
2. du willst nun lesen
3. du adressierst nun ein anderes Device

Eigentlich reicht auch immer ein START senden vorheriges ohne STOP. 
Soweit ich mich erinnere, fand ich aber schonmal die Anmerkung bei einem 
EEPROM, daß dieses nur intern schreibt wenn als Abschluß ein STOP ankam. 
Da muß man dann auch eventuell die Schreibzeit abwarten! Insbesondere 
wenn der Slave-Chip keinen SCL-Treiber hat!!!

Daher schreibe ich das noch:
4. du erkennst einen Busfehler. Dann MUSS ein STOP gesendet werden. Gibt 
da ne spezielle Sequenz mit 9 Bits.


Alles nur für Single-Master-Betrieb. Multi-Master habe ich nie 
durchgespielt.
Gast #3073948
Lesenswert?

Code wie folgt geändert:
1
    i2c_start(Display+I2C_WRITE);
2
    i2c_write(0b10000000);              // ControlByte
3
    i2c_write(0b11001000);              // mode-set
4
    i2c_stop();
5
    
6
    i2c_start(Display+I2C_WRITE);
7
    i2c_write(0b10000000);              // ControlByte
8
    i2c_write(0b01001111);              // load-data-pointer
9
    i2c_stop();
10
    
11
    i2c_start(Display+I2C_WRITE);
12
    i2c_write(0b10000000);              // ControlByte
13
    i2c_write(0b11100111);              // device-select
14
    i2c_stop();
15
    
16
    i2c_start(Display+I2C_WRITE);
17
    i2c_write(0b10000000);              // ControlByte
18
    i2c_write(0b11111011);              // bank-select
19
    i2c_stop();
20
    
21
    i2c_start(Display+I2C_WRITE);
22
    i2c_write(0b00000000);              // ControlByte
23
    i2c_write(0b11110000);              // blink-select
24
    i2c_stop();
#3074043
Lesenswert?

der Gast schrieb:
> okay, sorry falsch verstanden, mit dem ControlByte hast du völlig Recht,
> aber ist es wirklich von nöten bei "JEDEM" Schreibbefehl die
> Slaveadresse zu senden und auch den Bus zu starten und zu stoppen?

Generell ist es immer von nöten diese Abfolge durchzuführen.

Jedoch kann man dem Slave, meist über die Subadresse, auch mitteilen, 
dass man gerne mehr direkt hintereinander senden will, dann reduziert 
sich der overhead, und man sendet Byte an Byte, wobei der Slave die 
Adresse an der er das Byte in seinen RAM speichert dann automatisch 
inkrementiert.
Da dazu aber genau darauf geachtet werden muss was man macht, und du 
noch generell Probleme hast mit dem Display umzugehen, ist es eine 
unnötige Schwierigkeit die du da einbaust.

Die Abfolge aus Start, Adresse, Subadresse, Byte, Stop, ist auch 
leichter zu debuggen.

Nun zu deinem Code, der immer noch nicht stimmt, da du eben das Control 
Byte noch nicht voll verstanden hast.
Figure 17, 18, Table 17 sind die wichtigen.

Figure 17b):
Start - Acknowledge - control byte (CO=1, RS=0) - command byte - control 
byte (CO=0, RS=0) - acknowledge - stop

D.h. RS definiert dir ob das nächste Byte ein command oder ein control 
byte ist.
CO definiert dir ob das darauf folgende Byte ein weiteres Control Byte 
ist.

D.h. du musst vorerst nur 0b00000000 als control byte senden.
Sendest du 0b10000000 wird ein command byte erwartet und darauf hin 
wieder ein control byte. Aber wie gesagt, verknüpfen kannst du später, 
ich würde jetzt alles erst Schritt für Schritt machen.


Dann was du übehaupt sendest:
- Display-Adesse generell: Du weißt nicht ob SA0 = 0 oder 1 sein muss, 
d.h. beides musst du mal seperat durchprobieren

- Mode-Set: Muss gesendet werden, da du jedoch nichts über dein Display 
weißt solltest du hier experimentieren, d.h. B und M seperat 
durchprobieren ob sich dadurch etwas ändert., wobei beim ersten 
Durchgang B=0 und M=01 vllt. sinnvoll sind?
- load-data-pointer: bisher willst du noch nichts in das RAM schreiben, 
also musst du auch den Pointer nicht platzieren, vor allem wohin 
platzierst du ihn denn übehaupt? Weg damit.
- Device Select: Ich bin nicht genau dahinter gestiegen wie es 
funktioniert und wie man diese Funktion nutzt und wann man diese Adresse 
senden muss aber warum sendest du da einfach mal 0b11100111, wenn, dann 
doch eher b11100000, wenn man Fig. 4 anschaut wird A0, A1, A2 auf GND 
gesetzt sein, genauso wie SA0. (also korrigieren und auch mal ohne 
ausprobieren)
- blink-select: das Teil mit dem man vielleicht am einfachsten das 
Display überprüft, nur bisher hast du es deaktiviert. Wie wäre es mit 
0b11110101?


Generell:
Offensichtlich ist das das erste mal dass du den I2C Bus verwendest.
Dann auch noch etwas ansprechen zu wollen, zu dem nur mäßige Doku 
vorhanden ist, ist etwas idiotisch.
Du weißt nicht ob dein I2C Bus überhaupt funktioniert, du weißt nicht ob 
dein Display richtig angeschlossen ist, du weißt nicht wie dein Display 
intern die Adressen verdrahtet hat, du weißt nicht wie man ein 
Datenblatt liest und den I2C Bus benutzt.

Probiere nochmal das aus was ich dir geschrieben habe, d.h. mit den 
anderen Control Bytes und mit den richtigen Command bytes. Gewährleiste 
dass das Program durchläuft. Poste ggf. auch nochmal den Code hier zur 
Überprüfung.

Funktioniert es immer noch nicht, dann besorge dir ein I2C Bauteil zu 
dem du ein Datenblatt bekommst, bspw. MCP9800, und bei dem du testen 
kannst ob das mit deinem I2C Bus überhaupt funktioniert und lernen 
kannst wie der I2C funktioniert. Danach kannst du dich dann nochmal an 
dein Display wagen.
Gast #3074649
Lesenswert?

erstmal vielen Dank für deine Hilfe, trotz der Schmähenden Andeutungen, 
also die Slaveadresse hab ich schon durchgetestet, so schlau war ich 
auch schon und das mein I2C-Bus Daten sendet weiß ich auch, Dank eines 
Oszilloskops. Ich werd deinen Rat befolgen trotzdem gern befolgen denn 
dazu ist man ja auch hier wenn man nicht all zu viel Ahnung hat.
#3074868
Lesenswert?

der Gast schrieb:
> erstmal vielen Dank für deine Hilfe, trotz der Schmähenden Andeutungen,
> also die Slaveadresse hab ich schon durchgetestet, so schlau war ich
> auch schon und das mein I2C-Bus Daten sendet weiß ich auch, Dank eines
> Oszilloskops. Ich werd deinen Rat befolgen trotzdem gern befolgen denn
> dazu ist man ja auch hier wenn man nicht all zu viel Ahnung hat.

Ich hatte, nachdem ich die I2C Routinen neu implementierte auf einer 
neuen Leiterplatte mit einem neuem IC Probleme diesen QFN chip mit dem 
I2C Bus anzusteuern. Ich hatte dort auch zu viel auf einmal geändert. 
Neuer IC, neue Leiterplatte, neue Routine, ...
Um zu sehen ob zumindest der Bus und die Routine funktioniert habe ich 
kurz solch einen Temperatursensor angelötet um damit rum zu testen. Als 
gesichert war, dass der Bus funktioniert und der Ablauf des Lesens und 
Schreibens stimmt, konnte ich eben die möglichen Fehlerquellen 
eingrenzen - ein nicht richtig eingelöteter QFN chip war es am Ende und 
ein falsches Lesen des Datenblatts, nämlich habe ich auch so ein Repeat 
Bit überlesen und mich gewundert warum nur Mist ausgelesen wurde bzw der 
Bus hing und blockierte da ich auch alle Daten auf einmal lesen wollte.

Das Ende meines letzten Posts klingt etwas harsch, aber du hast einfach 
sehr viele Unbekannte und sehr viele mögliche Fehlerquellen und bist 
auch nicht sicher im Umgang mit I2C bzw. der Art wie in Datenblättern so 
ein Protokoll dargelegt wird.
Daher, falls die Tipps nichts brachten, wird es das beste sein, du 
versuchst erst den I2C Bus mit einem einfacheren Bauteil mit 
vollständigem Datenblatt in Betrieb zu nehmen und dessen Eigenheiten 
lernen und dann nochmal das Display.

Ich bin gespannt auf deine Ergebnisse und hoffe das beste.
Gast #3080874
Lesenswert?

@Frank M.

Hab den Code nun geändert, das Display wird angesproche wie vorher auch 
schon, mach sich dadurch bemerkbar dass das Display willkürliche 
Darstellungen aus gibt.
Der Blink-Modus funktioniert auch, bewirkt aber nur, dass in zwei 
verschiedenen Darstellungen hin und her geschaltet wird.
#3080947
Lesenswert?

der Gast schrieb:
> @Frank M.
>
> Hab den Code nun geändert, das Display wird angesproche wie vorher auch
> schon, mach sich dadurch bemerkbar dass das Display willkürliche
> Darstellungen aus gibt.
> Der Blink-Modus funktioniert auch, bewirkt aber nur, dass in zwei
> verschiedenen Darstellungen hin und her geschaltet wird.

Das hast du zum ersten mal erwähnt, dass was angezeigt wird, kannst du 
genau sagen ab welchem Befehl? (nach dem ersten vermutlich?)

Da etwas angezeigt wird, kannst du davon ausgehen dass es richtig 
angeschlossen ist.
Da der Blink Modus funktioniert (alles an/alles aus?) kannst du davon 
ausgehen, dass du es richtig angesprochen hast.

Nun bist du fast am Ziel, sollte nichtmehr viel fehlen.
Dass nur Mist gerade angezeigt liegt nur daran, dass du den Display RAM 
noch nicht geleert hast und mit sinnvollem aufgefüllt.

D.h. du kommentierst den Blink-Modus aus (wollen wir nicht) und 
implementierst nun Fig. 17 c) und verschiebst den RAM Pointer an den 
Anfang und füllst langsam den Display RAM auf (dann erkennst du wie er 
aufgefüllt wird und ggf. musst du bank select und LCD drive mode 
selection anpassen, damit es von links oben nach rechts unten sich 
füllt.
1
Start
2
Adresse
3
Control Byte 10... (in Command register schreiben, nicht wiederholend)
4
Command Byte 0x00 senden (data-pointer auf den Anfang des Display RAMs verschieben, siehe Table 12)
5
Control Byte 01... (in RAM register schreiben, wiederholend)
6
Schleife von 0 bis 1001111 (79) mit jeweils 100ms Pause zwischendrin damit du den Aufbau am Display siehst
7
  RAM Byte 0xFF (alles an, vorerst)
8
Scheifenende
9
Stop

Code posten falls es nicht funktioniert.
Gast #3080989
Lesenswert?

Blink Modus:

ein Wechsel zwischen
willkürliche Zeichen & alles aus

kommt aber drauf an, nach Spannungsabschaltung kann es auch sein
das es zwischen was anderem hin und her schaltet, wie du schon sagtest, 
das was gerade im Ram steht?!
#3081035
Lesenswert?

der Gast schrieb:
> Blink Modus:
>
> ein Wechsel zwischen
> willkürliche Zeichen & alles aus
>
> kommt aber drauf an, nach Spannungsabschaltung kann es auch sein
> das es zwischen was anderem hin und her schaltet, wie du schon sagtest,
> das was gerade im Ram steht?!

du wirst im Bit 'blink mode selection' momentan vermutlich 'blinking by 
alternating display RAM banks' aktiviert haben, was doch mit einer 
Beobachtung übereinstimmen könnte. Du kannst Spaßeshalber ja auch mal 
den anderen modus 'normal blinking' ausprobieren.

Was ist das überhaupt für ein Display? Da auf Seite 5 steht, dass der IC 
sowohl für Dot-Matrix als auch Segment-Displays eingesetzt werden kann?

Aber ersteinmal den Pseudo-Code implementieren und testen.
Gast #3081305
Lesenswert?

@Frank, muss die Schleife nicht so aussehen?
1
for (x=0; x=79; x=x+1)
2
  {   
3
    unsigned char y;
4
    y = x;
5
    i2c_write(0b10000000);  // ControlByte COMMAND
6
    i2c_write(y);
7
    i2c_write(0b01100000);  // ControlByte DATA
8
    i2c_write(0b01111111);        
9
    
10
                  _delay_ms(200);
11
      
12
  }
Gast #3081324
Lesenswert?

1
int main(void)
2
{
3
//   unsigned char ret;
4
  
5
      
6
    i2c_init();                         // Initialisierung des I2C-Bus
7
  
8
    
9
    i2c_start(Display+I2C_WRITE);
10
    i2c_write(0b10000000);              // ControlByte
11
    i2c_write(0b11001101);              // mode-set
12
    
13
    i2c_write(0b10000000);              // ControlByte
14
    i2c_write(0b00000000);              // load-data-pointer
15
    i2c_stop();
16
    
17
  
18
  
19
while(1)
20
  {
21
    _delay_ms(1000);                    // Warten*/
22

23
    i2c_start(Display+I2C_WRITE);
24
    i2c_write(0b10000000);              // ControlByte
25
    
26
    for (x=0; x=79; x=x+1)
27
    {   
28
      unsigned char y;
29
      y = x;
30
      
31
      i2c_write(y);
32
      i2c_write(0b01100000);            // ControlByte
33
      i2c_write(0b11111111);            // Daten
34
      
35
      _delay_ms(100);
36
      
37
    }
38
    i2c_stop();
39
  }  
40
}

erfüllt weitesgehend den erwarteten Zweck, man kann nicht wirklich 
sehen, dass die Symbole (von links oben nach rechts unten) aufgebaut 
werden, es wird zwischen 3 verschiedenen Situationen hin und her 
geschaltet, aber nie alles an oder alles aus.
#3081393
Lesenswert?

Wenn du schon weist, dass es nicht funktioniert, warum machst du dann 
nicht einfach mal das was ich dir gesagt habe, nicht mehr und nicht 
weniger und nicht irgendeinen Mist den du erfunden hast, sinnlos ist und 
absoluter Schwachsinn ist?

Wenn ich deinen Code anschaue, dann sehe ich dass du weder das getan 
hast was ich dir hier:
Beitrag "Re: I2C-Signal SCL & SDA"
geschrieben habe, noch das, was ich dir hier:
Beitrag "Re: I2C-Signal SCL & SDA"
geschrieben habe.
1
    i2c_start(Display+I2C_WRITE);
2
    i2c_write(0b10000000);              // ControlByte
3
    i2c_write(0b11001101);              // mode-set
4
    
5
    i2c_write(0b10000000);              // ControlByte
6
    i2c_write(0b00000000);              // load-data-pointer
7
    i2c_stop();
Die control bytes stimmen nicht.
Warum machst du es nicht nach dem Ablauf, start, adresse, control, data, 
stop wie ich dir empfohlen habe. Was hält dich davon ab???
Warum setzt du hier den data pointer?
Was ist mit der restlichen Initialisierungsroutine passiert die du davor 
noch hattest? Ich sagte du sollst den Blink-Modus raus werfen, nicht 
alles!!
1
    i2c_start(Display+I2C_WRITE);
2
    i2c_write(0b10000000);              // ControlByte
3
    
4
    for (x=0; x=79; x=x+1)
5
    {   
6
      unsigned char y;
7
      y = x;
8
      
9
      i2c_write(y);
10
      i2c_write(0b01100000);            // ControlByte
11
      i2c_write(0b11111111);            // Daten
12
      
13
      _delay_ms(100);
14
      
15
    }
16
    i2c_stop();

Was soll das erste Control Byte machen? Erkläre mir seine Funktion 
bitte.
Was soll diese Schleife, sieht die so aus wie ich es dir gesagt habe? 
NEIN! Warum? Du hast offensichlich keinen Plan wie man den I2C Bus 
benutzt, ich aber schon, dann tu bitte auch das was ich dir sage. Ich 
sage dir wie du ihn benutzen kannst, du ignorierst es, da du es ja 
besser weißt.
Ich weiß nicht wie du drauf kommst eine Variable zu senden, wenn ich 
explizit gesagt habe 0xFF.

Also, lese beide Posts durch die ich dir geschrieben habe, behebe alle 
Probleme und mach es so wie ich dir geschrieben habe, in Kurz 
(ausführlich habe ich es dir oft genug gesagt, also hier fehlt noch 
einiges, es ist wirklich nur Pseudo-Code der total unvollständig ist!!):
1
Initialisieren (dazu gehört mehr als nur das Mode Byte)
2
While Schleife:
3
 Daten pointer setzen
4
 For schleife
5
  Ram füllen
6
 Ende For
7
Ende While

Wenn du weiterhin jeden Rat ignorierst, dann werde ich dir nicht weiter 
helfen. Ich habe dir das Datenblatt vorgekaut und alle Schritte die du 
machen musst genaustens beschrieben.
Bisher bist du absolut Lernresistent und hast so ziemlich alles was ich 
gesagt habe ignoriert.
Bitte Code wieder posten.
Das Display funktioniert schon fast, es ist nicht mehr schwer, aber du 
solltest eben auch zuhören bzw. lesen was der andere dir sagt, dann 
könnte es schon längst problemlos laufen.
#3081415
Lesenswert?

Beim nochmal drüber fliegen habe ich nun den Zweck deiner Schleife 
verstanden. Ist aber falsch implementiert und ein Control Byte auch noch 
um ein Bit versetzt.
Bitte versuche es so zu machen wie ich dir empfholen habe, d.h. (ich 
gebe dir mal den code, da ich sah, dass du doch versucht hattest 
zumindest die for schleife richtig zu implementieren, auch wenn du was 
ganz was anderes gemacht hast als ich eigentlich gesagt habe)
was ich gesagt habe:
1
Start
2
Adresse
3
Control Byte 10... (in Command register schreiben, nicht wiederholend)
4
Command Byte 0x00 senden (data-pointer auf den Anfang des Display RAMs verschieben, siehe Table 12)
5
Control Byte 01... (in RAM register schreiben, wiederholend)
6
Schleife von 0 bis 1001111 (79) mit jeweils 100ms Pause zwischendrin damit du den Aufbau am Display siehst
7
  RAM Byte 0xFF (alles an, vorerst)
8
Scheifenende
9
Stop
wenn man es nun 1:1 umsetzt, was sicherlich kein Hexenwerk sein sollte:
1
    i2c_start(Display+I2C_WRITE); // Start // Adresse
2
    i2c_write(0b10000000);        // ControlByte 10...
3
    i2c_write(0b00000000);        // commandByte 0x00
4
    i2c_write(0b01000000);        // ControlByte 01..
5
    for (x=0; x<=79; x=x+1)
6
    {        
7
      i2c_write(0xFF);            // RAM Byte 0xFF
8
      _delay_ms(100);
9
    }
10
    i2c_stop();

PS: For loops gehen anders, kein Abbruchkriterium! Und Vergleiche in C 
sind ==, nicht =

Es fehlt aber noch die richtige Initialisierung. Poste deinen Code bitte 
immer damit wir dann immer über das selbe reden.
Gast #3081485
Lesenswert?

Doch wie wird der DataPointer um 1 erhöht? Das hab ich halt versucht in 
meiner for-schleife zu verwirklichen, das dieser mit der for- schleife 
auch um eins erhöht wird. Versteh grad nicht wie in deinem Vorschlag der 
DataPointer erhöht wird.
#3081521
Lesenswert?

der Gast schrieb:
> kein bock mehr auf so Kommentare
das hoffe ich doch nicht, sonst habe ich hier nur Zeit verschwendet. 
Zudem habe ich dir die Lösung schon fast gegeben.
Meine letzten zwei Posts waren 'direkter' ;-), aber es nervt einfach zu 
sehen, wenn jemand etwas ganz anderes macht als ihm geraten wird und 
dann sich wundert dass es immer noch nicht funktioniert.

derGast schrieb:
> Doch wie wird der DataPointer um 1 erhöht? Das hab ich halt versucht in
> meiner for-schleife zu verwirklichen, das dieser mit der for- schleife
> auch um eins erhöht wird. Versteh grad nicht wie in deinem Vorschlag der
> DataPointer erhöht wird.
So gefällt es mir schon besser. Anstatt einfach was anderes zu machen 
lieber mal nachfragen.
"Datenblatt:
The display bytes are stored in the display RAM at the address specified 
by the data pointer and the subaddress counter. Both data pointer and 
subaddress counter are automatically updated"
Der Data Pointer wird automatisch um 1 incrementiert. Sonst würde auch 
Fig 17c) keinen Sinn machen.
Wenn du das Ende des RAMs hast wird vermutlich auch der Subaddress 
counter (Nutzen davon steht im Datenblatt) erhöht, den du dann aber 
vermutlich wieder zurücksetzen musst, da du nur ein Display benutzt.

Deine Idee war nicht falsch, nur solltest du nicht mehere Methoden 
miteinander vermixen, willst du den Pointer jedes mal setzen, so ist der 
08/15 Weg (wie ich dir auch schon mehrmals gesagt habe):
1
    for (unsigned char x=0; x<=79; x++)
2
    {        
3
      i2c_start(Display+I2C_WRITE);
4
      i2c_write(0b10000000);            // ControlByte für cmd, es folgt noch ein control
5
      i2c_write(x);                     // Pointer im RAM setzen
6
      i2c_write(0b01000000);            // ControlByte für RAM, es folgt kein weiteres control
7
      i2c_write(0b11111111);            // Daten
8
      i2c_stop();
9

10
      _delay_ms(100);
11
    }

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren