Hallo zusammen,
ich versuche gerade eine I2C Verbindung zwischen 2 atmega328p (arduino
unos) aufzubauen. Es soll zunächst nur vom Master die Übertragung
initiiert und ein paar bytes übertragen werden, beim Slave soll nach
Erkennen der eigenen Adresse die entsprechende Interrupt Routine
ausgeführt werden. Fehlercodes werden noch nicht wirklich
berücksichtigt, es geht erstmal nur um die Grundfunktion. Der Slave
springt tatsächlich auch in die IR, meldet aber für das Statusregister
TWSR 0x00, also "Bus error due to an illegal
START or STOP condition". Der Master kommt bis zum Aussenden der
Adresse, aber nicht weiter. Auch der Logic Analyzer zeigt seltsames.
Hier die Funktionen zur Initialisierung, Senden und Interrupt Routine:
Wie im Datenblatt vorgegeben sind SDA und SCL über Pull-up Widerstände
mit Vcc verbunden (4k7). Die SCL Frequenz wird mit 50k initialisiert.
Ist da ein dummer Fehler im Code oder könnte es eher an der Hardware
liegen?
Philipp H. schrieb:> Auch der Logic Analyzer zeigt seltsames
Welche Abtastrate verwendest du?
> Logic_2.png
Aus deinem Bild kann man nichts erkennen, weil die Auflösung für 50kHz
Clock absolut unzureichend ist. Hänge die logicdata-Datei mit an.
Philipp H. schrieb:> while(!(TWCR & (1<<TWINT)));> while ((TWSR & 0xF8) != 0xA0)>...
Das ist in der TWI ISR allerdings völliger Murks.
Da fehlt es doch noch etwas am grundsätzlichen Verständnis, was
Interrupt ist, und was er macht.
Die grundlegende Ablauf bei TWI Master mit Interrupt ist:
Start senden
ISR: Adresse Write senden, reti
ISR: wenn ACK, Datenbyte senden, wenn Nack, Stop senden, reti
...
ISR: Stop senden, reti
Oliver
Oliver S. schrieb:> Die grundlegende Ablauf bei TWI Master mit Interrupt ist:>> Start senden>> ISR: Adresse Write senden, reti> ISR: wenn ACK, Datenbyte senden, wenn Nack, Stop senden, reti> ...> ISR: Stop senden, reti>> Oliver
Die ISR ist nur für den Slave aktiviert, der Master soll nur mit der
entsprechenden Funktion senden. Aber klar, ich sehe was du meinst, in
der ISR sollte nur der Status Code bei einem Interrupt ausgelesen und
entsprechend ein Schritt ausgeführt werden, das ändere ich. Aber dann
leuchten mir immer noch nicht die wiederholten STARTs ein. Der Master
sendet zuletzt Adress write und wartet dann auf TWINT, der Slave gibt
den Status Code für fehlerhaftes START/STOP aus und springt aus der ISR,
danach passiert bei beiden nichts mehr.
Oliver S. schrieb:> Philipp H. schrieb:>> Die ISR ist nur für den Slave aktiviert,>> Dann zeig halt mal deinen ganzen Code.>> Oliver
Das wäre die while Schleife der main zum testen der Verbindung. Das
obere für den Master, unten für den Slave. Der Rest des gesamten Codes
hat noch nichts mit dem I2C Bus zu tun, aber ich hänge mal die
Projektdatei an.
Philipp, du musst schon aussagekräftige Bilder vom Signal zeigen und den
ganzen Quelltext, sonst kann dir nach wie vor niemand helfen.
Am besten reduzierst du den Code auf eine minimale Menge von Zeilen, die
das Problem noch haben, so dass derirrelevante Teil möglichst entfällt.
Aber es muss compilier- und ausführbar sein, damit wir es nachvollziehen
können.
Ein kleiner Tipp: "&test[0]" kannst du durch "test" ersetzen. Das ist
das Selbe und besser lesbar.
Stefan ⛄ F. schrieb:> Philipp, du musst schon aussagekräftige Bilder vom Signal zeigen und den> ganzen Quelltext, sonst kann dir nach wie vor niemand helfen.
Bei der .logicdata kann man doch beliebig ranzoomen? Das ist das was ich
bekomme. Und mehr Quelltext als das komplette Projekt habe ich nicht.
Stefan ⛄ F. schrieb:> Am besten reduzierst du den Code auf eine minimale Menge von Zeilen, die> das Problem noch haben, so dass derirrelevante Teil möglichst entfällt.
Da ich die Ursache des Problems nicht kenne wüsste ich nicht wie, ich
habe ja schon die Funktionen die für das Problem relevant sind gepostet.
Stefan ⛄ F. schrieb:> Ein kleiner Tipp: "&test[0]" kannst du durch "test" ersetzen. Das ist> das Selbe und besser lesbar.
Sicher? Die Funktion erwartet einen Pointer.
Tut mir leid wenn ich mich etwas doof anstelle, bin ja dankbar dass ihr
euch die Zeit nehmt mir zu helfen. Aber hier verstehe ich nicht ganz was
ich noch zusätzlich an Infos liefern kann.
Philipp H. schrieb:> Sicher? Die Funktion erwartet einen Pointer.
Sicher!
Der Name eines Arrays zerfällt zu einem Pointer.
Tipp:
Ein Fachbuch erwerben.
Philipp H. schrieb:> Bei der .logicdata kann man doch beliebig ranzoomen? Das ist das was ich> bekomme.
Das hat halt mit I2C nix zu tun, was man da sieht.
Ich habe den Sourcecode jetzt mal kurz überflogen.
Mit welcher Frequnez läuft dein Arduino Uno?
Oliver
Oliver S. schrieb:> Das hat halt mit I2C nix zu tun, was man da sieht.
Genau deshalb werde ich ja auch nicht schlau daraus.
Oliver S. schrieb:> Mit welcher Frequnez läuft dein Arduino Uno?
16MHz, die Fuse bits stehen auf external clock und es sollte kein
prescaler aktiv sein.
Igendwie fehlt mir da ein define für F_CPU, aber egal. Die
Initialisierung der USART solltest du dir dazu nochmal anschauen, und
alle Warnungen einschalten schadet auch nicht.
Das bzw. ein Hauptproblem am TWI ist dein rumgefummel an den TWCR-Bits.
Schief geht das schonmal in i2cTxMaster in der Zeile hier:
1
TWCR&=!(1<<TWIE);
Die macht nicht das, was du wolltest, sondern disabled dir den TWI, die
Leitungen gehen high, und danach macht der nicht mehr das, was du dir
vorstellst.
Anstelle von
1
TWCR|=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
schreib einfach:
1
TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
Da ist alles gesetzt, was soll, und alles andere nicht. Das gilt für
alle Zugriffe auf TWCR.
Weiter hab ich mir das nicht angeschaut, den Rest kriegst du auch selber
hin.
Oliver
Habe die Anmerkungen umgesetzt und jetzt sieht das ganze schon etwas
anders aus. Aber dennoch sendet der Master jetzt ununterbrochen STARTS,
TWINT wird nicht gesetzt, der Slave gibt nach interrupt noch immer 0x00
als status code.
Sagt dein TWI-Master-Code gegen einen dummy-Slave. Der Master-Code
funktioniert also soweit.
Da wirst du wohl entweder in den nicht-TWI-relevanten Codestellen (die
ich für den test auskommentiert habe) oder im Slave oder in der
Hardware ein Problem haben.
Oliver
Vielen Dank, es funktioniert jetzt! GND war nicht richtig verbunden und
beim Slave musste man zusätzlich noch TWEA TWIE auf 1 halten, das hatte
ich durch den wechsel von |= zu = zwischendurch nicht mehr drin.
Eine Sache ist allerdings noch seltsam. Nach erfolgreicher Übertragung
steht payloadPendingUp auf true, in der while(1) schleife der main
sollte also "I2C receive: ... " ausgegeben und payloadPendingUp wieder
auf false gesetzt werden, die if(payloadPendingUp) schleife wird aber
nicht ausgeführt. Wenn ich aber z.b UartPrintLine("Main Loop",0,0) vor
die if schreibe geht es dann. Eine Idee warum das so ist?
Auf jeden Fall danke für eure Zeit und Hilfe!