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.
Guck' dir mal das Datenblatt Seite 185 'Data Transfer in Master Receiver Mode' an, da ist es recht gut beschrieben.
grade das hab ich mir doch angeguckt, von da hab ich doch oben zitiert und gesagt welcher teil mir daran unklar 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.
hier noch ein paar Codeschnipsel welche meine Funktionen verwenden viel Spaßß beim verstehen ;-)
1 | void rexeeprom(unsigned char bhigh, unsigned char blow, unsigned char bufferlen) |
2 | {
|
3 | delay_ms(10); |
4 | TWI_STARTCONDITION(); |
5 | TWI_SLA_W (exteeprom_SLA_W); |
6 | TWI_SENDDATA (bhigh); |
7 | TWI_SENDDATA (blow); |
8 | TWI_RSTARTCONDITION(); |
9 | TWI_SLA_R (exteeprom_SLA_R); |
10 | for (n=0;n<bufferlen-1;n++) |
11 | putchar1(TWI_RECIVEDATA_ACK ()); |
12 | putchar1(TWI_RECIVEDATA_NACK ()); |
13 | TWI_STOPCONDITION(); |
14 | }
|
1 | void timeread() // DS3231 |
2 | TWI_STARTCONDITION(); |
3 | TWI_SLA_W (clock_SLA_W); |
4 | TWI_SENDDATA (0x00); |
5 | TWI_RSTARTCONDITION(); |
6 | TWI_SLA_R (clock_SLA_R); |
7 | s0=TWI_RECIVEDATA_ACK (); |
8 | m0=TWI_RECIVEDATA_ACK (); |
9 | h0=TWI_RECIVEDATA_NACK (); |
10 | TWI_STOPCONDITION(); |
1 | void timeset() // DS3231 |
2 | {
|
3 | s0=0x0; |
4 | h0=(settime[0]&0x03)*0x10+(settime[1]&0x0f); |
5 | m0=(settime[3]&0x07)*0x10+(settime[4]&0x0f); |
6 | TWI_STARTCONDITION(); |
7 | TWI_SLA_W (clock_SLA_W); |
8 | TWI_SENDDATA (0x00); |
9 | TWI_SENDDATA (s0); |
10 | TWI_SENDDATA (m0); |
11 | TWI_SENDDATA (h0); |
12 | TWI_STOPCONDITION(); |
13 | UART1_Write_Strf("\n\r"); |
14 | UART1_Write_Str (settime); |
15 | UART1_Write_Strf("\n\r"); |
16 | UART1_Write_Strf("time will be set.\n\r"); |
17 | delay_ms(15); |
18 | }
|
1 | void dateset()//DS3231 |
2 | {
|
3 | wd0=1; |
4 | if (setdate[0]=='M' | setdate[0] =='m') if (setdate[1]=='o') wd0=1; |
5 | if (setdate[0]=='D' | setdate[0] =='d') if (setdate[1]=='i') wd0=2; |
6 | if (setdate[0]=='M' | setdate[0] =='m') if (setdate[1]=='i') wd0=3; |
7 | if (setdate[0]=='D' | setdate[0] =='d') if (setdate[1]=='o') wd0=4; |
8 | if (setdate[0]=='F' | setdate[0] =='f') if (setdate[1]=='r') wd0=5; |
9 | if (setdate[0]=='S' | setdate[0] =='s') if (setdate[1]=='a') wd0=6; |
10 | if (setdate[0]=='S' | setdate[0] =='s') if (setdate[1]=='o') wd0=7; |
11 | |
12 | |
13 | |
14 | d0=(setdate[3]&0x03)*0x10+(setdate[4]&0x0f); |
15 | mo0=(setdate[6]&0x07)*0x10+(setdate[7]&0x0f); |
16 | y0=(setdate[11]&0x0f)*0x10+(setdate[12]&0x0f); |
17 | |
18 | TWI_STARTCONDITION(); |
19 | TWI_SLA_W (clock_SLA_W); |
20 | TWI_SENDDATA (0x03); |
21 | TWI_SENDDATA (wd0); |
22 | TWI_SENDDATA (d0); |
23 | TWI_SENDDATA (mo0); |
24 | TWI_SENDDATA (y0); |
25 | |
26 | TWI_STOPCONDITION(); |
27 | UART1_Write_Str (setdate); |
28 | UART1_Write_Strf("\n\r"); |
29 | UART1_Write_Strf("date will be set.\n\r"); |
30 | delay_ms(15); |
31 | }
|
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
alles klar jetzt tuts, hab den spannungsteiler komplett weggemacht und die Ports im Programm auf Eingang gelassen. Vielen Dank für die Hilfe!
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.