Gesundes 2005 euch allen!
Als erstes möchte ich mich entschuldigen, dass ich trotz der
zahlreichen Postings zu diesem Thema hier so blöd fragen muss.
Ich mochte mit einem MEGA32 einen PCF8574 (8-Bit IO-Expander)
ansteuern.
Der Bustakt ist 100kHz. Meine CPU wird mit 16MHz getaktet.
Nach der wundervollen Formel (SCL = CPU/(16+2TWBR*4^TWPS)) sollte mein
TWBR 72 betragen (bei TWPS = 0x00 also Prescaler von 1)
doch das funzt net.
Jetzt das skuriele:
Rechlich Tests haben einen funktionstüchtigen Wert von 0 bis
15 für TWBR ergeben!!!
Häää??? Bustakt von bis zu 1MHz???
Es spielt auch keine Rolle ob ich vom Quarz, vom STK500 oder vom
internen RC Takten lasse. Es funktionieren immer Werte die weit von den
Berechneten abweichen.
Nun bitte ich euch meine Berechnung zu überprüfen.
Danke!
CPU = 16000000
TWPS = 0
SCL = 1000000
ergibt TWBR von 72
Deine Berechnung mit TWPS=1 (also Prescaler 4) kann ich bestätigen. Hab
ich getestet, ohne Erfolg.
(Es funzen aber TWBRs von 0 bis 3 bei TWPS = 1)
Legende der Formel auf Seite 173:
"TWPS = Value of the prescaler !!!BITS!!! in the TWI Status
Register"
also 0 bis 3 (sind ja auch nur 2 Bit)
Kommentat zur Tabelle auf Seite 177:
"The value of TWPS1..0 is used in the equation"
Soll heisen:
Wenn in der Formel ...4^3 steht, ergibt sich ein Prescaler von 64
die Berechnung zu stimmen scheint, hier mal ne kurze Zusammenfassung
meines Progs:
Reset:
interne Pullups an
72 nach TWBR
0 nach TWPS
Main:
Error-Led aus
Adresse setzen
zu sendende Byte setzen
rcall SENDEN
rjmp Main
SENDEN:
siehe Datenblatt Seite 180 (fast eins-zu-eins abgetipt)
Error:
STOP
Error-LED an
ergibt eine flackernde Error-Led.
Ne Idee?
So, hier mal noch eine leicht vereinfachte Version meines Quelltextes,
mit TWBR=0 und TWPS=0,die mehr oder weniger stabil lauft.
Mit den berechnete Werten läufts net!
Hab grad mal nen Mega16 probiert: Verhält sich ähnlich.
Warum funzts bei allen andern, nur bei mir net? heul
Bitte helft mir!
Ich hab vorgestern auch das erste mal meinen TWI angeschmissen
bekommen.. hab mir die Routinen aussem Datablatt abgeschaut:
twi_transmission:
out TWDR, temp1
ldi temp1, (1<<TWINT)|(1<<TWEN)
out TWCR, temp1
rjmp twi_wait
twi_read:
ldi temp1, (1<<TWINT)|(1<<TWEN)
out twcr, temp1
rjmp twi_wait
twi_start:
ldi temp1, (1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
out TWCR, temp1
rjmp twi_wait
twi_stop:
ldi temp1, (1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
out TWCR, temp1
ret
twi_wait:
push temp2
ldi temp2, 0xFF
twi_wait_2:
dec temp2
breq twi_wait_3
in temp1, TWCR
sbrs temp1, TWINT
rjmp twi_wait_2
in temp1, TWDR
pop temp2
ret
twi_wait_3:
ldi temp1, 99
pop temp2
ret
Bei twi_wait kann man natürlich das mit temp2 rauslassen, ist aber
deswegen, damit sich das Ding nicht aufhängt, wenn mal nen Sensor
spinnt.. bei mir wird dann halt "99°C" angezeigt und das is dann OK.
Geschmackssache.
Aber Thorsten wird auch Recht haben ...
Meine Init (@8Mhz):
; twi
ldi temp1, 32
out twbr, temp1
Die Formel ist:
CLK = Takt/(16+(2xTWBRx 4^TWPS))
Wenn TWPS = 0, dann ergibts sich für 4^TWPS = 1.. also
vernachlässigbar. Außerdem sollte man mit TWBR nicht niedriger als 10
gehen..
dave
Wie ich das sehe, du willst, statt mehere Byte an eine Device, ein Byte
an mehrere Device senden ?
ldi Adr,0xXX
rcall Senden
wenn einer dovon nicht vorhanden ist, gibt's kein MT_SLA_ACK zurück
!
Gruß
Thany
Ich kann dem Thorsten nur zustimmen!
Und auch deine Rechnung (Thany) ist meines Erachtens richtig.
Nur funktioniert das nicht!
Erst ein Wert zw 0 und 15 führt zu einer Datenübertragung (mehr oder
weniger stabil). Und um einen einigermasen funktionstüchtigen Quellcode
zu posten, hab ich die 0 ins TWBR geschrieben und als Kommentar die
berechneten Werte.
Die Frage ist halt, wo der Fehler liegt.
(Hätte ich ein Oszi, würd ich einfach messen, hab ich aber nich)
Ich habs übrigens auch schon in anderen Foren probiert, aber da bekam
ich weder so schnell noch so sachliche Antworten. Großes Lob an
euch!!!
Ich bin optimistisch dass wir das Problem in kürze lösen. Bitte weiter
so! Danke!
Also verwechsle bei meiner Rechnung:
CLK = Takt/(16+(2xTWBRx 4^TWPS))
Wenn TWPS = 0, dann ergibts sich für 4^TWPS = 1.. also
vernachlässigbar.
nicht PS mit BR...
Kannst ja mal umstellen:
CLK = TWclk
CLK = Takt/(16+(2xTWBR))
CLK * (16+(2xTWBR)) = Takt
(16+(2xTWBR)) = Takt/CLK
2xTWBR = (Takt/CLK) - 16
TWBR = (Takt/Clk -16)/2
bei 8Mhz und 100khz : (80/1 - 16)/2 = 32
und 16Mhz und 100khz: (160/1 - 16)/2 = 72
Also stimmt doch alles.. So, was funktioniert jetzt nicht?
Der Dave aussem Grab
Es fließen keine Daten wenn ich die (bewiesenermaßen) korekten Werte
einprogramiere (TWBR=72 & TWPS=0).
Erst wenn ich wesentlich kleiner Werte nehme "läuft" es .
Was ich aber nicht verstehe! Denn eine kleineres TWBR ist eine größeres
fSCL. Und ich glaube einfach nicht daran, dass ein Busstakt von 1MHz
(TWBR=0 & TWBS=0) so gut funktionieren kann!
@Dave: Du hast offensichtlich ein anderes Datenblatt als ich. Was ist
das?
LOL.. ich arbeite auch die ganze Zeit nur mit dem M32 (von Atmel g)
Was meinst du mit "Was ist das?"
Ich kapier genau so wenig, warum er das bei dir nicht macht.. bei 8Mhz
und Wert 32 klappts bei mir gut.
Gib mal deinen Quelltext rüber.
dave
Achso.. ja das ganz normale M32, welches ich runtergeladen habe..
Wow.. ich hab A...
Also bei mir sind die Routinen unter USING TWI
Und das is drin:
SCL frequency= CPU Clock frequency
16+2(TWBR)*4^TWPS
Ich lade mir jetzt mal schnell das G... aber was da anders sein soll..
dave
Neue Erkenntnisse:
Hab mal den Code von Dave nachvollzogen. Der 1. Unterschied ist die
Warteschleife. Und der 2. Unterschied ist die völlige Ignoranz des
Status-Registers.
Ich hab also seinen Code meinem Code angepasst und siehe da: ES GEHT!
Aber VIIIIEEEEL langsamer als meine Version. enttaüsch
Ich hab dann alle Hebel in bewegung gesetzt und mir doch noch ein Oszi
besorgt und die SCL gemessen.
Nur Interessehalber die Ergebnisse mit MEINEM Proggi:
TWBR SCL rech SCL mess Beschreibung
72 100000 100000 Nichts geht
12 400000 400000 alles Geht, kurz darauf FREEZ
10 444444 434782 2 von 8 PCFs gehen nicht
0 1000000 666666 alles geht (schnell)
Zurück zur Sachlichkeit:
Bei meinen Messungen hab ich gesehen, dass ein 5V Impuls doppelt so
lang ist wie alle anderen. (Der wievielte Impuls das ist hab ich
vergessen zu zählen). Bei Daves Prog trat das nicht auf.
Ich wäre euch sehr verbunden wenn ihr trotz der recht guten Ergebnisse
weiter meinen Code durchdenkt und mir meinen Fehler zeigen könntet. Mit
Daves Code ist das Arbeiten (in meinem Fall) viel komplizierter, was ich
vermeiden möchte. Danke trotzdem!
Also ich hab auch keinen Plan... die PCF machen ja nach Datasheet nur
100khz mit.
Etwas ist da noch komisch:
Quarz/Clock -16 = TWBR
16.000.000/666.666 = 24
24 - 16 = 8
Das hieße ja, dass TWBR in Realität 8 ist.. komisch komisch, vielleicht
ziehen die PCFs auch einfach den Clock runter.
Mein wait kannste auch einfach so ersetzten:
wait:
in r16,TWCR
sbrs r16,TWINT
rjmp wait
ret
Ich hab mir nur nicht die Mühe gemacht, meine Spezifizierung wieder
rückgänig zu machen.. Setz das nochmal ein, dann bleibt der delay mit
den 256 Takten weg.
Hat niemand anders ne Ahnung?
dave
Ich nehm auch an, dass die PCFs den Takt runterziehen. Die sind
eigentlich nur für 100kHz. So richtig rechteckig sah der Takt auch
nicht aus (bei 666 kHz) und unter dem Aspekt, dass schon im Datenblatt
des Mega32 ein TWBR von >10 gefordert wird, glaube ich dass es reiner
Zufall ist, dass das funktioniert.
Ich wünsche mir einen ganz normalen I2C-Bus mit 100kHz (auch wenn er
viieel langsamer ist)
Deine wait-Schleife hatte ich von Anfang an so geändert (Hey, ich bin
garnich so blöd wie ich aussehe. Aber ich seh verdammt blöd aus).
Stimmt ;) Unser Dirty-Harry sieht beschissen aus.. wie son Hund...
Und du bist dir sicher, dass bei 100khz nichts anderes reingespielt
hat? Vielleicht mal PS etwas höher setzten und dann in TWBR 18 reinhaun
oder ähnlich.
Also mein PCF (nur kurz zum Test-Zweck) hat schön bei 100khz
mitgespielt.
Isch nisch blicke
dave
Juhu! ich habs!
Also hier mal ne Fehlerbeschreibung.
Mein Prog löst eine START aus.
Dann wird gewartet bis die Hardware den START vollzogen hat.
Dann wird im Statusregister geguckt, ob der START gelungen ist(TWSR =
0x08). Ist dies nicht der Fall, wird die Error-Funftion aufgerufen.
Bei gelungenem START wird dann die Adresse und das Byte gesendet und
die ganze Sache mit nem STOP abgeschlossen. Es wird aber diesmal nicht
gewartet bis die Hardware mit dem STOP fertig ist!(Wozu auch?)
Da in meinen Prog hinternanderweg gesendet wird (rcall Senden ... rcall
Senden ...), wird die neue START-Kondition ausgelöst bevor überhaut ein
handfestes STOP am Bus anliegt. Dies kommt dann einem REPEATED-START
gleich und im Statusregister steht keine 0x08 sondern 0x10 (RESTART
gelungen), was natürlich zu unrecht die Error-Funktion aufruft. Ein
Aktzeptanz von TWSR=0x08 UND TWSR=0x10 nach dem START löst also mein
Problem.
Ich bedanke mich bei allen beteiligten!!!
Ohne euch würde ich immernoch an meinem TWBR zweifeln und hätte
bestimmt schon längst aufgegeben. Ihr seid die Größten!
Also Danke nochmal
ªpppµpµppppppppppµppª
ªªª¿¿ðUsUx2222UZÆÆg@L¿ªªª
ªp÷Ô2¾ ¾2/2/222222ZZ2@ ¾2Ô÷pª
¾2 ¿ ¾2/2/222222ZZ2@ ¿ 2¾
¿Ô¯ ¾2/2/222222ZZ2@ ¯Ô¿
¿Ô¯ ¾2/2/222222ZZ2@ ¯Ô¿
¿Ô¾2/2/222222ZZ2@Ô¿
ª¿ ¾ ¾2Yx22222ZZ2@ ¾ ¿ª
¿ªª¿ ¿Ô2Yx2SZUÔL ¿ªª¿
¿Ô22ZÔL
¾22Z@
¾22Z@
¾22Z@
ªªpp222SSggªª
ª¾¾¾ÔÔÔÔÔÔÔÔÔðððð¶¶¶ª