Hi,
da der letzte Thread wohl zu unübersichtlich wurde führe ich erneut in
das Thema ein. Ich betreibe testweise zwei ATmega8 mit dem TWI. Einer
Master, der andere Slave mit der Slaveadresse 127.
Aufbau:
- Master
Ein hardwarenetprellter Taster an PD2 (INT0) gegen Masse um die
Senderoutine auszulösen. Vier Status-LEDs Rot, Grün, Gelb, Blau an PB
0-3 über 1kOhm gegen Masse. Eine dicke Rote Error-LED an PB 4, auch über
1kOhm gegen Masse. An SDA und SCL natürlich die Busleitung, ausserdem
jeweils ein 4,7kOhm Pull-Up gegen Vcc für den Bus.
- Slave
An PD 0-7 jeweils eine gelbe Ausgabe-LED über 1kOhm gegen Masse. An SDA
und SCL die Busleitung.
Das Programm im Master hat den Testwert 100 in R17 gespeichert. Dieser
Wert soll an den Slave gesendet werden. Der Slave soll diesen Wert dann
an PortD ausgeben. Das klappt schon soweit. Der Master inkrementiert
währenddessen diesen Wert wodurch er beim nächstenmal eben die 101
sendet. Leider gibt esnach dem Senden einen Fehler wodurch ich den Bus
kein zweites Mal benutzen kann. Ich habe schon verschiedene Tests
durchgeführt.
Die ISR im Slave führt, abhängig vom TWI Status, eine von drei
verschiedenen Aktionen aus. Entweder für 0x60 (SLA+W wurde empfangen,
ACK wurde gesendet) oder für 0x80 (Daten wurden empfangen, ACK wurde
gesendet) oder für 0xA0 (Stop Condition wurde empfangen). Zum Test habe
ich in jeder Aktion mal eine LED am PortB setzen lassen. Dabei stellte
sich heraus dass er die Stop-Condition irgendwie nicht erkennt. Beim
weiteren Testen hat sich ausserdem noch ein Phänomen rausgestellt. Um zu
prüfen wie viele Interrupts denn im Slave überhaupt ausgeführt werden
habe ich mal einen Zähler in R17 erstellt. Startwert 0. Dann habe ich
ihn am ende jeweils mit inc R17 eins hochzählen lassen und den Wert an
PortD ausgegeben. Sämtliche LEDs leuchteten. Hm, seltsam.. wieso gerade
255 Interrupts? Dann habe ich den inc-befehl mal auskommentiert und in
den Teil für den Status 0x60 gesetzt. Ergebnis: ein Interrupt. OK das
schien zu funktionieren. Dann habe ich ihn in den Teil für 0xA0
eingesetzt. Ergebnis: kein Interrupt. Wie schon erwartet. Dann das
ungewöhnliche: Ich setzte den inc Befehl in den Teil für 0x80 ein. Schon
wieder leuchteten alle LEDs. Aber das geht doch garnicht?! Wenn er hier
schon bis 255 zählt und im Teil für 0x60 dann müsste es doch einen
überlauf geben?!. Dann habe ich den inc Befehl auch in den Teil für 0x60
eingesetzt und immernoch leuchteten alle LEDs, was sehr unlogisch ist,
da ja der 0x60-Teil einmal ausgeführt wird und es somit einen überlauf
geben MÜSSTE. Ich habe auch andere Befehle ausprobiert wie subi R17, -1
oder add R17, R18 über ein Hilfsregister. Überall der gleiche Käse. Hat
jemand eine Idee?
Ich hoffe jemand ist trotz dem Umfang gewillt mir zu helfen, ich sitze
schon seit 3 Tagen da dran und verzweifle langsam!! Habe versucht den
Code für euch so übersichtlich wie möglich zu gestalten. Meine
ICQ-Nummer für direkte Hilfe: 126342470. Danke im Vorraus!!
Master:
Ich habe beide Codes mal mit VMLAB durchsimuliert
Der Mastercode funktioniert.
Der Slavecode bleibt nach der ersten übertragung hängen.
Jörg X. hat recht.
Du vergisst am ende von 0x80 die Flags von TWCR zu setzen.
Mit volgendem Code sollte es funktionieren.
(In VMLAB tut es das zumindest)
Dankeschön für die Antwort! Sry, habe das mit der Taktfrequenz
vergessen. Takt des AVRs ist 1 MHz über den internen Oszi. Der Bustakt
soll 10 kHz betragen. Die formel liefert mir mit prescaler=0 und
bitratefaktor=42 einen glatten wert von 10000 Hz :-) Somit ist der
Systemtakt 100 mal schneller als der Bustakt.
Zum TWINT-Bit. Muss das an dieser Stelle zurückgesetzt werden? Im
Datenblatt in der Tabelle "Status Codes for Slave Receiver Mode" steht
bei 0x80 so ein Read data byte or ... . Daher ging ich davon aus dass
weiteres nicht nötig wäre. Aber nun stehen da zwei optionen:
- Data byte will be received and NOT ACK will be returned
- Data byte will be received and ACK will be returned
Ich erwarte ja an dieser Stelle dass der Master als nächstes das Stop
sendet. Soll ich einfach TWINT und TWEN neu setzen damit ich weiter
machen kann? Ich probier das jetzt mal aus aber wär hilfreich wenn ihr
mir den sinn nochmal erklärt :-)
// Edit: Genial, es geht!! Wirklich ein simpler Fehler aber ich bin echt
nicht weiter gekommen, war schon total verzweifelt. Danke recht
herzlich!
mfg PoWl
Das warum?
Hmmmmmm
Das Rücksetsetzen des TWINT Flags signalisiert der TWI Hardware, das du
das empfangende Byte verarbeitest(ausgelesen) hast, und wieder für
weitere Übertragungen bereitsteht.
Es gibt ja auch die möglichkeit das ein Slave die Clock Leitung solange
herunterzieht bis diese Verarbeitung fertig ist.
Der Master müßte dann solange warten bis der Slave fertig ist.
cu
Hauke
"While the TWINT Flag is set, the SCL low period is stretched.[...]
2
Note that this flag is not automatically cleared by hardware when executing
3
the interrupt routine. Also note that clearing this flag starts the
4
operation of the TWI[...]".
Was bedeutet, dass auf dem I²C-Bus gar nichts passiert, solange bei
irgendeinem beteiligten AVR (mit aktivem TWI-Interfece etc.) das
TWINT-Bit gesetzt ist und dass man das Bit selbst rücksetzen muss.
Falls du das noch nit getan hast, scahu dir mal die App.-Notes AVR311
und AVR315 von Atmel zum TWI-Modul an.
hth. Jörg
Stimmt eigentlich die Formel, ich binn ned so gut in Mathe ;)
.equ TWi = ((F_CPU/8*FSCL)-2)
prescaler lass ich immer auf 0, auch wenn der AVR mit 16mhz rumrotzt.
Ich hab immer gedacht ACK Stop und Start werden immer automatisch
generiert
so geht es doch, wenn der prescaler auf 0 steht, oder?
Und es ist klar, dass da kein sinnvoller Wert rauskommt, wenn F_CPU
kleiner ist als F_SCL * 16.
hth. Jörg
Wenn es ums Clock Stretching geht, wieso führt der Master dann weiterhin
sein Programm aus? Oder ist da so eine art Timeout drin?
By the Way: ist das USI der ATtiny familie schwierig zu verwenden?
mfg PoWl
> wieso führt der Master dann weiterhin sein Programm aus?
Woher weißt du das bzw. Wie kommst du darauf?
Der Master setzt die letzte Status LED, wenn er eine STOP-condition
senden will. Was passiert dann (STO-gesendet löst beim Master keinen
neuen Interrupt aus)?
Es gibt für TWI und USI Appnotes von Atmel, einfach mal reinschauen. Das
USI hat keine eigene Taktquelle, das dürfte das komplizierteste daran
sein.
hth. Jörg