Forum: Mikrocontroller und Digitale Elektronik TWI-Interrupt wird nicht aufgerufen


von mr.chip (Gast)


Lesenswert?

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

von Jens B. (sio2)


Lesenswert?

0 << XXX  heisst das nicht, das die zahl "0" um XXX stellen geschoben 
wird? solltest ne 1 nehmen afaik

von mr.chip (Gast)


Lesenswert?

> 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).

von Sebastian (Gast)


Lesenswert?

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

von mr.chip (Gast)


Lesenswert?

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

von Walter (Gast)


Lesenswert?

Hast du
sei()
aufgerufen?

Grüße
Walter

von mr.chip (Gast)


Lesenswert?

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)?

von Andreas Kramer (Gast)


Lesenswert?

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

von Hauke R. (lafkaschar) Benutzerseite


Lesenswert?

Hab ja auch nich so viel ahnung, aber die 2 sollte dann doch die 
bitfolge 10 ergeben, also kommt das bit eine stelle weiter links an, als 
TWPS0

von johnny.m (Gast)


Lesenswert?

> 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.

von johnny.m (Gast)


Lesenswert?

...Ü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...

von mr.chip (Gast)


Lesenswert?

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?

von A.K. (Gast)


Lesenswert?

"Ü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.

von mr.chip (Gast)


Lesenswert?

@A.K.: Genau so ist es, so habe ich es auch vorgesehen ;-)

von Bernhard S. (bernhard)


Lesenswert?


von mr.chip (Gast)


Lesenswert?

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

von Bernhard S. (bernhard)


Lesenswert?

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


von mr.chip (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

> 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

von Bernhard S. (bernhard)


Lesenswert?

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

von Bernhard S. (bernhard)


Lesenswert?

Hiermit könnte man "per Hand" den TWI-BUS steuern und experimentieren:

Beitrag "RS232 <-> TWI / I2C INTERFACE (Assembler) ATmega8"

von mr.chip (Gast)


Lesenswert?

Danke schonmal für die Antworten! Langsam sehe ich doch noch Hoffnung, 
das ganze hinzukriegen.

von Jan K. (jeangonzales)


Lesenswert?

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

von Jacob R. (jaykopf)


Lesenswert?

Moin,
1
//Prescaler setzen
2
TWSR = 0x02;
3
4
//Bit-Rate setzen
5
//für ~100kHz : 0x05 bei Prescaler = 2
6
TWBR = 0x05;
7
8
//Start senden
9
TWCR = (1<<TWINT) || (1<<TWSTA) || (1<<TWEN) || (1<<TWIE);
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.
1
//Stop senden
2
TWCR = (1<<TWINT) || (1<<TWSTO) || (1<<TWEN) || (1<<TWIE);
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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.