Ich hab ein Problem mit dem Hardware-TWI bei einem Mega32.
ich will von einem I2C Slave Daten empfangen, das versuche ich wie
folgt:
- START senden //TWCR: (1<<TWINT) | (1<<TWSTA) | (1<<TWEN)
- warten bis START gesendet wurde (warten bis TWINT gesetzt ist)
- überprüfen ob erfolgreich (TWSR auslesen)
- Slave-Adresse mit Read Bit senden: 0b00111011 (Die Slave Adresse ist
0011101) //TWCR: (1<<TWINT) | (1<<TWEA) | (1<<TWEN)
- warten bis die Slave-Adresse gesendet wurde (warten bis TWINT gesetzt
ist)
- überprüfen ob erfolgreich (TWSR auslesen)
aber wie gehts hier nun weiter?
am Ende kommt natürlich noch das STOP-Signal, aber wo ist das Datenbyte
das ich empfangen will?
In TWDR ist immernoch die gesendete Slave-Adresse.
Muss ich noch irgendwas senden um letzendlich das Datenbyte zu bekommen?
Immer brav weiter takten, dann findet sich das datenbayte im twdr ein.
Am einfachsten ein FF schicken und nachschauen was hernach in TWDR steht
wenn es kein WW ist ist's ne Antwort vom Slave
Weis genau du mit weiter takten meinst weis ich nicht.
Aber ich hab versucht einfach danach nochmal ein Byte zu schicken, wenn
ich das mach setzt der controller aber hinterher TWINT nicht mehr.
Das Datenblatt verwirrt mich auch an der Stelle:
"When SLA+R have been transmitted and an acknowledgement bit has been
received, TWINT is set again and a number of status codes in TWSR are
possible. Possible status codes in master mode are $38, $40, or $48. The
appropriate action to be taken for each of these status codes is
detailed in Table 75. Received data can be read from the TWDR Register
when the TWINT Flag is set high by hardware. This scheme is repeated
until the last byte has been received."
Da steht wenn ich die Slave-Adresse übertragen hab soll ich warten bis
TWINT gesetzt wird, dann ist die Slave-Adresse übertragen.
Und dann soll ich direkt nochmal warten bis TWINT gesetzt wird, ohne was
dazwischen zu machen, dann ist das Byte da.
Das macht doch keinen Sinn, das TWINT ist ja eh schon von der
Slave-Adressen-Übertragung gesetzt.
Weitertakten brauchst du nicht (ist beim SPI so), das sollte der
'Gesprächspartner' übernehmen .
Im TWDR steht immer das zuletzt gesendete/Empfangene Byte. Also wenn was
empfangen wurde (TWINT ausgelöst), dann sollte auch das Datenbyte vom
Empfänger drinstehen.
dass das Datenbyte am Ende in TWDR ist ist klar, aber ich denk eben,
dass man nachdem man die Slave-Adresse gesendet hat und TWINT wieder
gesetzt ist noch irgendwas machen muss, damit das Datenbyte in TWDR
landet.
Zumindest müssste einem ja irgendein Mechanismus Bescheid sagen sobald
es da gelandet ist.
Schau mal in den Anhang, ich hatte mir damals die Mühe gemacht das zu
übersetzen, wenn ich's wiederfinde stelle ich Dir auch noch meine
12C-Versuche rein war genau dein thema aber schon 3 Jahre her.
Hi,
nachdem die Slaveadresse gesendet ist, und der neue Status abgefragt
wurde, muss irgendwas geschehen, damits bei TWI weitergeht, also mit
TWINT setzen, damit das Byte vom Slave empfangen werden kann.
Erst danach ist das Byte da.
Mit den Grafiken im DB sollte es doch recht gut hinzubekommen sein, auch
was man alles machen kann je nach Status, ist in schönen Tabellen
aufgeführt, welche Bits man setzen kann/soll damit die nächste
TWI-Aktion gemacht wird.
Ein wenig mit Programmtext ist hier zu finden:
http://www.roboternetz.de/wissen/index.php/TWI_Praxis
Ist zwar in Basic, aber nix spezielles von Bascom verwendet, damit man
das Prinzip erkennen können sollte.
den Thread kenn ich, ich mach das im Prinzip wie in dem Code da, aber es
tut trotzdem nicht.
Im Anhang ist ein Diagramm aus dem Datenblatt des Slave-Bausteins
(LIS3LV02DQ) den ich ansprechen will, wie die Übertragung aussehen soll.
das hier sollen die einzelnen Abkürzungen bedeuten:
ST - Start
SR - Repeated Start
SAK - Slave Acknowledge
NMAK - Not Master Acknowledge
SAD+W - Slave-Adresse mit Write-Bit
SAD+R - Slave-Adresse mit Write-Bit
SUB - Die Adresse des Registers dass man von dem Baustein auslesen
möchte
bis zu der mit dem roten Pfeil markierten Stelle komme ich ohne
Probleme, ich bekom auch immer ein NACK vom Slave zurück.
Ich hab dann also die Slave Adresse mit Read-Bit gesendet und hab ein
NACK darauf zurückbekommen, an dem Punkt ist der rote Pfeil.
Anschließen versteh ich aber nicht was genau ich machen muss um die
Daten zu lesen, die ja noch kommen sollen.
Ich hab versucht einfach 0x00 o.ä. auf den Bus zu schreiben und dann zu
warten bis TWINT gesetzt ist, aber das passiert nie.
wenn du ein NACK zurück bekommst ist schon etwas schief gelaufen. Du
mußt ein ACK zurück bekommen, erst dann wird dir auch das gewünschte
Datum ausgegeben werden!
achso, aber was sind mögliche Ursachen dafür, dass man ein NACK bekommt?
Der SCL Takt müsste eigentlich stimmen, ich benutz einen 16Mhz Quarz und
hab in TWBR 72 stehen, sollten also 100Khz rauskommen.
Leider sind meine Erstversuche mit I2C in Assembler auf tiny12 verloren
gegangen (hd chrash).
aber ich schau noch mal nach meinen CVAVR Anfängen eventuell hab ich
dort noch was dazu.
Stell doch mal deine Quellcodeschnipsel ein. Dann weiß man woran man
doktorn muss. So ist alles ziemlich abgehoben von der Realität. Ebenso
ein Plan vom betreffenden HW Ausschnitt ich denke da sind noch keine
Geheimnisse drin ;-) oder?
Zu deiner Frage ein NACK bekommst du immer, wenn sich niemand findet der
ein ACK generiert. Das erzeugt der Sender selbst. Nur wenn sich ein
Busteilnehmer angesprochen fühlt macht der durch zupfen an SDA aus dem
NACK ein ACK.
so habe da noch 2 Dateien gefunden,
direkt zu verwenden unter CVAVR
zuerst eine twi.h
und im nächsten Beitrag eine twi.lib
welche ich auf einen Atmega128 verwende
In der twi.lib sind die zeitlichen Abläufe innerhalb der Funktionen
erkennbar.
für die Nutzung der Routinen suche ich auch noch was raus.
Danke für die Mühe mit der Library, aber ich bräuchte ja wenn dann den
Quellcode.
Ich will das TWI selber zusammengebastelt bekommen und nicht den Code
von jemand anders benutzen.
Aber langsam glaub ich auch mein Code ist richtig, ich hab mir ein
Assembler-, ein Basic- und ein C-Beispiel angeguckt und ich machs
eigentlich genau so.
In den Anhang hab ich mal meinen Schaltplan getan, vielleicht ist da was
verkehrt.
(An den beiden ICs ist natürlich noch mehr dran, VCC hab ich nur mit
eingezeichnet, damit man erkennt, dass das eine ein 5V und das andere
ein 3,3V Gerät ist.)
Wenn sich da kein Fehler finden lässt, post ich mal meinen Code (den
muss ich erst so umschreiben, dass man den einigermaßen lesen kann :) )
Das sieht ja alles extrem Hochohmig aus.
Bei zwei 5V-Teilnehmern nehme ich normalerweise 4k7 als Pullup, den
Spannungsteiler 100k und 200k würde ich drastisch verkleinern und direkt
vor den 3V3-Teilnehmer setzen. Die Pullups vor die AVR-Leitungen.
Hi
Das kann nicht gehen. I2C-Ausgänge sind faktisch Open-Kollektor-Stufen.
D.h. der H-Pegel wird durch die Pull-Up-Widerstände bestimmt. An deiner
Stelle würde ich die Widerstände bis auf die Pull-Ups entfernen. Der
Pegel auf den Leitungen ist dann maximal 3,3V. Der AVR sollte das noch
als H-Pegel erkennen. Ist allerdings nicht ganz sauber.
MfG Spess
Aber wenn an den AVR-Ausgängen High-Pegel anliegt und ich den
Spannungsteiler komplett wegmache, dann liegen doch auch an dem
LIS3LV02DQ 5V an.
Der Reset Zustand des AVRs ist ja das überall High anliegt, d.h. bei
jedem Start und bei jedem Programmiervorgang würden an dem LIS3LV02DQ 5V
anliegen.
Ich glaub nicht dass der das lange ausshält.
@ Thilo M.:
das Problem ist das in dem Datenblatt von dem LIS3LV02DQ nicht steht
wieviel A ich aus den SCL und SDA ziehen darf, wenn ich jetzt einen zu
kleinen Spannungsteiler nehm geht der ja überlastet.
Je größer die Pullups desto kleiner die maximale Datenrate.
Du kannst auch mal probieren, die Datenrate extrem klein zu machen.
Aber ich denke, 1..5mA sollten die Ausgänge treiben können.
Hi
Der AVR muss SDA/SCL auf Masse ziehen können. Und das kann deine
Schaltung nicht. Im Reset-Zustand sind die AVR-Ports als Eingang
geschaltet. Liefern also auch keine Spannung.
MfG Spess