Hallo,
habe folgendes Problem bei meinen ersten Versuchen mit TWI / I²C:
Benutzte AVR Studio (aktuellste Version) und kann nicht auf die
TWI-Register (TWBR, TWSR, TWCR, TWDR) mit in / out zugreifen; der
Assembler gibt immer den Fehler "Operand out of range" aus.
µC ist ein ATMega644P-20PU.
Habe die Assembler Routinen aus einem altem Thread
(Beitrag "AVR-TWI-ASM EEPROM Ansteuerung") von Bastler (Gast) für mich
ein wenig angepasst, hier meine Datei twi-routines.asm:
1
;
2
; Two-Wire-Interface Routinen
3
;
4
5
6
;Initialisierung
7
twi_init:
8
ldi temp1, 0x32
9
out TWBR, temp1
10
ldi temp1, 0x01
11
out TWSR, temp1
12
13
14
; Start senden
15
16
twi_start:
17
ldi temp1,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
18
out TWCR,temp1 ;Start Condition senden
19
twi100:
20
in temp1,TWCR ;Status holen
21
sbrs temp1,TWINT ;Kommando ausgeführt?
22
rjmp twi100 ;nein -> warten
23
ret
24
25
26
; TWI Write
27
; Zu sendendes Byte in temp1
28
29
twi_write:
30
out TWDR,temp1 ;Byte in Ausgaberegister
31
ldi temp1,(1<<TWINT)|(1<<TWEN)
32
out TWCR,temp1 ;Byte senden
33
rjmp twi100 ;Warten bis ausgeführt
34
35
36
; TWI Read mit Ack.
37
; Empfangenes Byte in temp1
38
39
twi_read:
40
ldi temp1,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
41
out TWCR,temp1 ;Flags setzen
42
twi200:
43
in temp1,TWCR ;Status holen
44
sbrs temp1,TWINT ;Kommando ausgeführt?
45
rjmp twi200 ;nein -> warten
46
in temp1,TWDR ;Daten sind da
47
ret
48
49
50
; TWI Read ohne Ack.
51
; Empfangenes Byte in temp1
52
53
twi_readna:
54
ldi temp1,(1<<TWINT)|(1<<TWEN)|(0<<TWEA)
55
out TWCR,temp1 ;Flags setzen
56
twi201:
57
in temp1,TWCR ;Status holen
58
sbrs temp1,TWINT ;Kommando ausgeführt?
59
rjmp twi201 ;nein -> warten
60
in temp1,TWDR ;Daten sind da
61
ret
62
63
64
; TWI Stop Condition
65
66
twi_stop:
67
ldi temp1,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
68
out TWCR,temp1 ;Stop Condition senden
69
rjmp twi100 ;Warten bis ausgeführt
Der Assembler meckert z.B. bei "out TWBR, temp1" mit folgendem Text:
error: Operand 1 out of range: 0xb8
0xb8 stimmt mit der Position von TWBR aus m644Pdef.inc überein.
Mach ich einen Fehler oder AVR Studio?
Edit: Habe gerade die Lösung des Problems gefunden (glaube ich
zumindest).
>Alle Register, deren SRAM-Adresse größer ist als 0x3f(->SREG), können>nicht mehr mit den ASM-Befehlen IN und OUT angesprochen werden und>haben folglich keine IO-Adresse.
Also muss ich anscheinend mit LDS und STS statt IN / OUT auf die
Register zugreifen; mal sehen, ob das funktioniert.
Hi
>Der Assembler meckert z.B. bei "out TWBR, temp1" mit folgendem Text:>error: Operand 1 out of range: 0xb8
Du must 'sts TWBR, temp1' benutzen. Und beim Lesen 'lds ....'. Die
Register sind mit 'in/out' nicht erreichbar.
MfG Spess
danke für die Antwort.
Der Assembler meckert jetzt nicht mehr, aber der Buszugriff scheint noch
nicht richtig zu funktionieren.
Ich habe einen DS1337 (RTC) an den AVR gehängt und versuche erstmal,
dessen Statusregister auszulesen:
1
rcall twi_init ; TWI Initialisieren
2
3
rcall twi_start ; Start-Condition setzen
4
5
ldi temp1, 0xD0 ; Schreibzugriff auf DS1337 (Adresse ist 1101000)
6
rcall twi_write
7
8
ldi temp1, 0x0E ; Statusregister anwählen
9
rcall twi_write
10
11
rcall twi_start ; Repeated Start
12
13
ldi temp1, 0xD1 ; DS1337 lesen
14
rcall twi_write
15
16
rcall twi_readna ; Statusregister lesen (kein ACK, da nur ein Byte gelesen werden soll)
17
18
rcall twi_stop ; Transfer beenden
Das Programm hängt beim ersten twi_read. Das Interrupt-Flag im
Control-Register wird nicht gesetzt; bis auf das TWI Enable Bit sind
alle Werte des Registers 0, SCL steht auf LOW-Pegel.
Habe schon diverse Busgeschwindigkeiten durchprobiert, aber ohne Erfolg.
Kann es sein, dass der DS1337 nicht reagiert (kein ACK sendet)?
Wie kann ich feststellen, ob er überhaupt aktiv ist und am Bus horcht?
Danke+Gruß
Ladde
Hallo gtf,
da hatte ich schonmal flüchtig drüber geguckt, fand das ganze aber etwas
unübersichtlich und hatte deshalb die Routinen von Bastler aus
Beitrag "AVR-TWI-ASM EEPROM Ansteuerung" verwendet. Laut dem DS1337
Datenblatt http://datasheets.maxim-ic.com/en/ds/DS1337-DS1337C.pdf
sollten sich die Register ja einfach lesen lassen (Seite 13/14).
Das Problem scheint aber grundlegender zu sein. Ich erhalte genau den
gleichen Fehler (Programm hängt, da TWCR = 0x04) wenn die RTC gar nicht
am Bus hängt.
Werde mir morgen nochmal deinen Link und etwas TWI-Grundlagen angucken,
hoffentlich komme ich dann auf den Fehler.
Gute Nacht
Ladde
Mal ne andere Frage: Da das Code-Beispiel im Datenblatt offsichtlich
fehlerhaft ist (Registerzugriff mit in / out), könnte man Atmel ja mal
darauf hinweisen. Weiß da wer ne Email-Adresse / Formular?
> Da das Code-Beispiel im Datenblatt offsichtlich fehlerhaft ist...
Das Code-Beispiel ist nicht fehlerhaft, nur benutzt Du einen AVR Typ,
dessen TWI Register oberhalb des IO Bereiches bis 0x3F liegen, In/Out
ist laut Instruction Set nur bis 0x3F zulässig.
Bei anderen Typen, beispielsweise ATM32 liegen die TWI Register dagegen
bei 0x20-23.
Da musst Du schon selber mitdenken, das Instruction Set genau lesen und
das Code-Beispiel halt entsprechend anpassen.
> könnte man Atmel ja mal darauf hinweisen.
Dann mach das mal, dann haben die bei Atmel gleich ein wenig Spass :D
Mir ist schon klar, dass Atmel den Code wohl nur einmal für alle
Controller(familien) geschrieben hat, und dass er für viele korrekt ist.
Das ändert aber nichts daran, dass der Code, der im Datenblatt für diese
Controllerfamilie steht fehlerhaft ist.
Im gleichen Datenblatt steht ja auch die Registerübersicht mit der
entsprechenden Adresse im SRAM-Bereich.
Wenn man sich am Datenblatt orientiert (wie oft hört bzw. liest man
schließlich "steht doch im Datenblatt"), werden einem hier echte
Stolpersteine in den Weg gelegt.
Habe mich mal über das Technical Support Formular an Atmel gewandt, mal
sehen, ob die darauf reagieren.
Grüße
Ladde
> Wenn man sich am Datenblatt orientiert (wie oft hört bzw. liest man> schließlich "steht doch im Datenblatt"), werden einem hier echte> Stolpersteine in den Weg gelegt.
Das ist ein typischer Anfängerfehler, jeder der sich nur ein wenig in
die Materie eingearbeitet hat und mit Assembler arbeitet, weis was er zu
tun hat.
Programmieren ist nicht copy/paste und hat etwas mit Mitdenken zu tun,
also In/Out Befehl anschauen, Adresse des TWI Interfaces anschauen und
feststellen, daß es so nicht geht. Wenn Dir das zuviel ist, nimm eine
Hochsprache, da sucht der Compiler die passenden Befehle für Dich raus.
Zumindest ich denke nicht, daß Atmel jeden kleinen Pups für den
Programmierer erledigen, also Standardbeispiele auf die jeweiligen
Controller anpassen muss.
Solche Kleinigkeiten kann man vom Programmierer erwarten.
>Das ist ein typischer Anfängerfehler, jeder der sich nur ein wenig in>die Materie eingearbeitet hat und mit Assembler arbeitet, weis was er zu>tun hat.
Es mag pedantisch sein, aber gerade als Anfänger erwarte ich doch
konsitente Informationen im Datenblatt als wichtigste
Informationsquelle.
Für zukünfitge Projekte weiß ich jetzt, wo der Fehler lag und wie ich
auf Register korrekt zugreife, habe hier ja schnell die passenden Infos
bekommen.
>Programmieren ist nicht copy/paste und hat etwas mit Mitdenken zu tun,>also In/Out Befehl anschauen, Adresse des TWI Interfaces anschauen und>feststellen, daß es so nicht geht. Wenn Dir das zuviel ist, nimm eine>Hochsprache, da sucht der Compiler die passenden Befehle für Dich raus.
Ich hatte ja auch gar nicht den Code aus dem Datenblatt kopiert, sondern
die Routinen, die ich an anderer Stelle im Forum gefunden hatte,
nachvollzogen und an mein Projekt angepasst. Da dabei ein Fehler auftrat
habe ich eben zunächst mit dem Datenblatt abgeeglichen. Da ich anhand
des TWI-Abschnittes den Fehler nicht klären konnte, habe ich hier im
Forum gepostet und gesucht.
Ich denke daher, dass dein Kommentar, der mangelnden Einssatz
meinerseits nahelegt, unangebracht ist.
>Zumindest ich denke nicht, daß Atmel jeden kleinen Pups für den>Programmierer erledigen, also Standardbeispiele auf die jeweiligen>Controller anpassen muss.
Es geht mir - wie beschrieben - nicht darum, fertige Code-Segmente von
Atmel zu bekommen ("jeden kleinen Pups") sondern darum, dass die
Dokumentation möglichst keine Fehler enthält (eben auch kleine).
Mag pedantisch erscheinen, aber wenn schon ein Code-Beispiel dabei ist,
dann sollte es meiner Meinung nach auch in sich stimmig sein.
Grüße
Ladde
> Ich denke daher, dass dein Kommentar, der mangelnden Einssatz> meinerseits nahelegt, unangebracht ist.
Da ist nix unangebracht, Du hast Deine Hausfagaben einfach nicht gut
genug gemacht, denn Du kannst Beides nachschauen, im Instruction Set Pdf
findest Du:
OUT A,Rr 0 ... 0 ≤ A ≤ 63
A steht für den I/O Adressbereich
Im ATM644 DB:
(0xBD) TWAMR
(0xBC) TWCR
(0xBB) TWDR
(0xBA) TWAR
(0xB9) TWSR
(0xB8) TWBR
Dann solltest Du noch verstanden haben daß ≤ 63 die dezimale Notation
für 0x3F ist und schon hast Du alle benötigte Information. Du bist doch
auch in der Lage ein "2-wire Serial Interface", wie im ATM644 DB
angegeben, als "I2C" zu identifizieren, warum so borniert hier ?
Kann's nicht eher sein, daß Dich der gemachte Fehler aufgrund eigener
mangelnder Kenntnisse so aufregt, so daß Du nun einen Schuldigen für
Deine Unkenntnis suchst ?
Nochmal: Ich persönlich erwarte, daß ein Programmierer solch einfache
Dinge selbst anzupassen versteht. Wenn bereits so 'ne Kleinigkeit Dir
Probleme bereitet, so daß Du nach dem Support rufen musst, dann wird das
noch eine ziemlich interessante Programmiererkarriere :D
@ ladde,
Ist nichts neues, das mal im Datenblatt was fehlt. Atmels AVR
Datenblätter find ich sogar sehr gut beschrieben. Schau doch mal ins DS
von RFM12 :- )
Oder guck mal ein XMEGA Datenblatt an, da gibt’s gar keine Beispiele.
Und die Registernamen haben’s auch in sich.
Geheimtipp:
;******************************************
AVR315: Using the TWI module as I2C master
Alternative für Slave
AVR311: Using the TWI module as I2C slave
;******************************************
Du musst nur die Programmablaufpläne in Code umsetzen, und schon
schwingt deine Mühle.
Ich find’s in der Regel einfacher aus einem PAP ein Source zu erstellen,
statt den Source von jemanden nachzuvollziehen.
Bis meine IIC- Kommunikation lief, hatte ich mehr wie 2 Wochen an
Datenblättern und Spezifikationen rumstudiert.
Viel spaß
@MWS
Bist du ein Rechtsverdreher? Die beziehen sich auch immer auf
Unterparagraphen die dann wieder irgendwelche neuen Verweise bringt. Ich
muss hier Ladde Recht geben. Wenn man schon ein Beispiel bringt, muss es
auch zum Controller/Datasheet passen!
Und aus so mancher Kleinigkeit wurden schon mal Tage zur Fehlersuche.
Und nur weil man davon ausgeht, dass ein Datasheet informieren sollte
und nicht verwirren..
@Steffen H.,
> Bist du ein Rechtsverdreher? Die beziehen sich auch immer auf> Unterparagraphen die dann wieder irgendwelche neuen Verweise bringt.
Nein, ganz sicher nicht. Mein Argument ist, wer sich mit µC's
erfolgreich auseinandersetzen will, muss flexibel sein und das eine oder
andere Problem durch Nachdenken und auch Lernen der Basics zu
umschiffen.
> ...wurden schon mal Tage zur Fehlersuche.
Wenn ein Programmierer mit der eindeutigen Fehlermeldung "Operand 1 out
of range: 0xb8" Tage sucht, dann sollte über eine weniger hirnintensive
Tätigkeit nachgedacht werden.
Und ich rechtfertige nicht, daß Atmel ein Beispiel reinschreibt, das
wahrscheinlich das Standardbeispiel in allen Datenblättern ist, ich
halte es lediglich für einen verzeihlichen Umstand, da es den Ablauf des
TWI ausreichend erklärt.
Jeder mittelmäßig begabte Programmierer sollte dieses Beispiel anpassen
können. Dazu muss sich besagter Programmierer aber erst einmal
ausreichend mit der Materie beschäftigen, was der TE offensichtlich
nicht getan hat.
Seine Hausaufgaben nicht machen, dafür aber Erbsen zählen und sich
sofort beschweren ist so eine richtig deutsche Eigenschaft, dafür sind
wir berühmt in aller Welt :D
MWS schrieb:
>Jeder mittelmäßig begabte Programmierer sollte dieses Beispiel anpassen>können. Dazu muss sich besagter Programmierer aber erst einmal>ausreichend mit der Materie beschäftigen, was der TE offensichtlich>nicht getan hat.> Seine Hausaufgaben nicht machen, dafür aber Erbsen zählen und sich> sofort beschweren ist so eine richtig deutsche Eigenschaft, dafür sind> wir berühmt in aller Welt :D
Jetzt verdrehst du aber das passierte. Nachdem der Fehler auftauchte
habe ich selbstständig nach der Lösung gesucht und sie gefunden (siehe
zweiter Post in diesem Topic). Und Atmel auf den Fehler / die
Ungenauigkeit (nenne es, wie du magst) hinzuweisen, damit in Zukunft
Ungereimtheiten vermieden werden können, ist meiner Meinung nach kein
meckern sondern ein gut gemeinter Verbesserungsvorschlag.
@gtf
Danke für die Hinweise. Habe inzwischen reichlich Informationen zu TWI /
I²C (unter anderem die von dir genannten App-Notes) und werde mal sehen,
wie weit ich damit komme.
Danke + Gruß
Ladde
L. K. (ladde),
ich hab' mich eher gewundert, wie solch ein, imho Pippifax, überhaupt
den Weg in's Forum findet.
Denn selbst wenn man noch nie mit "größeren" µC's gearbeitet hat deren
IO über 0x3F hinausgeht, und solch eine eindeutige Meldung bekommt, dann
schaut man halt den Befehl nach, merkt der geht nur bis 0x3F, das muss
anders adressiert werden und gut ist's, im Hirn ab dann abgehakt.
Es ist immer noch meine Meinung, daß der Fall hier absolut geringfügig
ist und ganz sicher keinen Fehlerreport wert.
Aber schaun wir mal, vielleicht bekommst Du Antwort, Dear Sir, many
thanks for the report of this dangergous bug, we immediately corrected
it and rewrote all our 32000 datasheets...
Oder Du bekommst 'nen Tiny zum selber zusammenstecken als kleines
Dankeschön ;-)
So, der Bus läuft endlich!!
Auch wenns für mich etwas beschämend ist hier der Fehler:
Habe mich heute intensiv mit Datenblättern, App-Notes, Literatur usw.
beschäftigt, konnte dabei aber keinen Fehler in den Routinen finden.
Als ich die TWI-Frequenz soweit wie irgendmöglich reduziert hatte
(Prescaler 3, Bitrate-Register 255, CKDIV8-Fuse gesetzt) und nur START
gesendet hatte, fiel mir auf, dass der die LED am SDA-Pullup verdächtig
lange flackert.
Eignetlich dürfte sie ja nur einmal (sehr) kurz aufleuchten. Habe aber
das "ret" für twi_init vergessen (siehe Ursprungspost), so dass schon
beim Init ein Start gesendet wird. Das nächste Start verursacht deshalb
einen Fehler und die weiteren Buszugriffe schlagen natürlich auch fehl.
Tja, nächstes Mal den eigenen Quelltext nochmal aufmerksam von Anfang
bis Ende lesen, dann bleibt einem ne Menge Ärger erspart.
Grüße
Lasse
PS: Wenn ich von Atmel ne Nachricht bekomme, werde ich diese hier
posten.