Hallo
Ich versuche gerade, mit folgendem Code den TWI-Interrupt des Mega32 zu
starten, leider vergeblich.
ISR(TWI_vect){
...
}
void twi_init(){
TWAR = (TWI_ADDRESS << 1) | (0 << TWGCE);
TWCR = (0 << TWINT) | (1<<TWEA) | (1<<TWEN) | (1 << TWIE);
TWSR = (2 << TWPS0);
TWBR = 4;
}
void twi_transmit(){
TWCR |= (0 << TWINT) | (1 << TWEN) | (1 << TWSTA);
}
Es werden lediglich diese beiden Funktionen nacheinander aufgerufen,
mehr mache ich am TWI nicht.
Leider wird der Interrupt nie aufgerufen. Woran könnte das liegen? (Ich
beziehe mich jetzt nur auf die Simulation in AVR-Studio!) Auch das
TWINT-Flag wird nie gesetzt.
Gruss
Michael
> 0 << XXX heisst das nicht, das die zahl "0" um XXX stellen geschoben> wird? solltest ne 1 nehmen afaik
Das sollte eigentlich nicht das Problem sein, da die 0 schon korrekt
gesetzt wird (jedenfalls insofern wie ich mir das vorstelle).
Hi,
ich weiss ja nicht, was du sonst so hast, aber ads mit dem (0<<TWINT)
macht grundsätzlich gar nichts mit dem Flag. Du veroderst naemlich dann
die Stelle von TWINT mit 0. Heisst konkret, wenn 0 drinne steht, wird
wieder eine 0 drin sein, wenn 1 drin steht, wieder eine 1.
Um das korrekt zu löschen, musst du das mit einer 0 verunden.
Beispiel hier:
TWCR &= ~(1 << TWINT);
Du schiebst die 1 an die richtige stelle und negierst dann alles. An der
Stelle mit TWINT steht nun eine 0, der Rest hat eine 1. Dann wird diese
0, bzw die anderen 1en mit dem aktuellen Registerstand verundet. Die
TWINT-Stelle ist in jedem Fall 0, da es ja mit 0 verundet wird, der Rest
behaelt den Wert, wegen Verundung mit 1.
Ich hoffe die Erklärung war verändlich.
Gruss, Sebastian
Hallo Sebastian
Danke für deine ausführliche Antwort. Ich muss aber nochmals
klarstellen: Was logisch mit diesen Registern gemacht wird, ist schon
korrekt. D.h., die Bits die ich auf 0 haben will gehen auf 0 und die,
die ich auf 1 haben will, gehen auf 1.
Ich frage mich eher, ob ich die richtigen Bits auf den richtigen Wert
setze. Der Fehler ist sozusagen eine Ebene höher zu suchen, vermute ich
;-)
Gruss
Michael
Jepp.
Hmm...ich versteh echt nicht, wieso das nicht geht. Hab alles
durchgecheckt etc. Hätte mir vielleicht jemand ein funktionierendes
Beispiel mit TWI-Interrupts (Master-Transmit)?
Kann es sein das das hier vieleicht nen Fehler verursacht ? :
TWSR = (2 << TWPS0);
Also die 2 darin.Ich bin zwar erst Anfänger, aber ich denke das dürfte
doch unmöglich sein in ein bit eine 2 zu schreiben ^^. Interesse an so
einem Code hätte ich zum vergleichen auch.
Gruß Andreas
> TWSR = (2 << TWPS0);
Das ist so schon korrekt, wenn auch etwas gewöhnungsbedürftig. Es gibt
eine Reihe indizierte Steuerbits, die in den entsprechenden Registern
direkt hintereinander stehen (z.B. auch die Clock-Select (CS)-Bits in
den Timer-Steuerregistern und eben die TWPS-Bits), die dann mit 0, 1,
...usw. indiziert werden. Wenn man die nicht alle einzeln schreiben
will, dann setzt man in der Maske das Bitmuster, das die Bits haben
sollen (in diesem Falle sind es zwei Bits, TWPS0 und TWPS1, die das
Bitmuster "10" haben sollen) und schiebt es um die Anzahl stellen des
niederwertigsten Bits nach links. Dann steht das Bitmuster genau da, wo
es hinsoll.
...Übrigens, das mit dem "Nullen-Schieben" ("0 << irgendwas") ist
wirklich Blödsinn (wie weiter oben schon mal angesprochen). In einer
ODER-Verknüpfung bringt das überhaupt nix und sollte deshalb weggelassen
werden...
Ja, ich weiss, es ist Blödsinn. Es würde nicht mal etwas bringen, wenn
dort ne 1 stehen würde, jedenfalls mit |=.
Aber nochmals: Die Bits werden so gesetzt, wie ich es will. Die Frage
ist jetzt: Setze ich die richtigen Bits für ein funktionierendes TWI?
"Übrigens, das mit dem "Nullen-Schieben" ("0 << irgendwas") ist
wirklich Blödsinn"
Nein.
Es hat zwar keine Wirkung, ist aber grad an solcher Stelle auch kein
Blödsinn. Letztlich hat es die Bedeutung eines Kommentars. Es erleichert
die Fehlersuche ("habe ich das Steuerbit XYZ einzustellen vergessen?")
und vereinfacht zudem spätere Änderungen an den Einstellungen (0=>1
statt "wie heisst das vermaledeite Bit grad wieder?").
Über die Effizientz des Codes braucht man sich keine Gedanken zu machen,
das kriegt der Compiler schon selber spitz.
Hallo Bernhard
Eben leider nicht - dieses Beispiel verwendet keine Interrupts, ich habe
es mir schon angesehen. Das Problem bei mir ist ja effektiv nur, dass
kein Interrupt aufgerufen wird. (Wobei ich jeztt nachsehen müsste, ob
das TWINT-Flag überhaupt gesetzt wird; ich meine nicht. Dann könnte man
nämlich durchaus das Interrupt-freie Beispiel nehmen.)
Gruss
Michael
Hallo Michael
>Ich beziehe mich jetzt nur auf die Simulation in AVR-Studio!AVR-Studio simuliert kein TWI !!
>dieses Beispiel verwendet keine Interrupts
Doch, der Slave besitzt eine Interrupt Routine
reti ;rjmp ANA_COMP ; Analog Comparator Handler
rjmp TWSI ; Two-wire Serial Interface Handler
reti ;rjmp SPM_RDY ; Store Program Memory Ready Handler
; #############
; TWI INTERRUPPT-Routine
TWSI:
....
reti
Gruß
Bernhard
Hallo
Gar kein TWI? Mir ist schon klar, dass AVR-Studio nicht simulieren
kann, was auf dem TWI passiert, aber zumindest sollte doch der Interrupt
aufgerufen werden, wenn eine Aktion ohne jede äusserne Zusammenhänge
ausgeführt wurde (nämlich das Start-Kommando - der Interrupt wird beim
ausführen von Start so oder so aufgerufen, egal was die Peripherie dazu
meint)
Nun - wie mach ich das am besten? Gibt es Plugins, welche TWI können?
Weil so ganz ohne Simulator etwas zu proggen ist schon heftig, vorallem
wenn man sich damit noch nicht soo auskennt und die Interpretation des
Datenblattes durch tüfteln unterstützen muss.
Gruss
Michael
> Gar kein TWI? Mir ist schon klar, dass AVR-Studio nicht simulieren> kann, was auf dem TWI passiert,
In dem Fall könnte dich das hier interessieren:
http://www.helmix.at/hapsim/#hapsimtermtut
Hallo Michael,
>nämlich das Start-Kommando - der Interrupt wird beim>ausführen von Start so oder so aufgerufen, egal was die Peripherie dazu>meint
Wir müssen uns aber einigen, ob wir von einem Slave oder Master
sprechen.
Beim Slave gibt es kein Start-Interrupt. Ein Interrupt wird im Slave nur
aktiviert, wenn gewisse BUS-Zustände aufgetreten sind.
(Bus-Error, ein Byte wurde empfangen usw)
Im Masterbetrieb tritt eigentlich kein Interrupt auf, warum auch?
Eine Start-Prozedur wid gnadenlos gesendet:
; START
ldi temp, (1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
out TWCR, temp
Anschließend wartet der µC geduldig, bist das INT-Flag gesetzt ist und
nun wertet man den Status aus (war der Start erfolgreich)
In diesem Beispiel wird bewusst der Interrupt deaktiviert, würde auch
nerven, wenn jedesmal die Interrupt-Routine aufgerufen wird.
Übrigens, logisch "1" löscht paradoxer Weise das INT-Flag (1<<TWINT)
Gruß
Bernhard
Hallo Mr. Chip,
klappts inzwischen mit dem Interrupt?
Ich habe nämlich genau dasselbe Problem - allerdings nicht im Simulator
sondern auf einem echten Mega32.
Wenn ich synchron Programmiere (ohne Interrupt) klappt alles wie es soll
(das INT-Flag, welches ich polle wird auch gesetzt). Wenn ich nun noch
bei jedem Schreiben des TWCR-Registers das TWIE-Bit setze, wird aber
trotzdem kein einziger TWI-Interrupt ausgelöst... Ich stehe vor einem
Rätsel. Ich finde auch weit und breit kein Beispiel, das bei TWI mit
Interrupts arbeitet.
@Bernhard Schulz:
>Im Masterbetrieb tritt eigentlich kein Interrupt auf, warum auch?
Aber natürlich treten da Interrupt auf. Nach dem Senden einer
Startcondition, nach dem Senden des Adressbytes, nach dem Senden eines
Datenbytes, ...
Gruß, Jan
damit sollte eine Start-Condition gesendet werden und
nun sollte nachdem das start erfolgreich gesendet wurde der
TWI-Interrupt ausgelöst werden und der Statuscode 0x08 ausgelesen werden
können
1
// Setzte Daten
2
TWDR=data;
3
4
//starte Übertragung
5
TWCR=(1<<TWINT)||(1<<TWEN)||(1<<TWIE);
damit kann man zuerst den slave adressieren und dann daten senden.
damit wird halt eine Stop-Condition gesendet.
wichtig ist es halt TWINT auf '1' zu setzen, damit die TWI-HW anfängt zu
senden. Das TWINT-Flag wird laut Datenblatt nicht automatisch
zurückgesetzt wird wenn die ISR ausgeführt wird, also muss man sich
darum noch kümmern!!!
Bei mir geht er ohne Probleme in die TWI-ISR.
MfG Jay-Kopf