www.mikrocontroller.net

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


Autor: mr.chip (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jens B. (sio2)
Datum:

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

Autor: mr.chip (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: mr.chip (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast du
sei()
aufgerufen?

Grüße
Walter

Autor: mr.chip (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)?

Autor: Andreas Kramer (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Hauke Radtki (lafkaschar) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: mr.chip (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: mr.chip (Gast)
Datum:

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

Autor: Bernhard S. (bernhard)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: mr.chip (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Bernhard S. (bernhard)
Datum:

Bewertung
0 lesenswert
nicht 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


Autor: mr.chip (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Bernhard S. (bernhard)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Bernhard S. (bernhard)
Datum:

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

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

Autor: mr.chip (Gast)
Datum:

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

Autor: Jan Krause (jeangonzales)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jacob R. (jaykopf)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin,
//Prescaler setzen
TWSR = 0x02;

//Bit-Rate setzen
//für ~100kHz : 0x05 bei Prescaler = 2
TWBR = 0x05;

//Start senden
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
// Setzte Daten 
TWDR = data;
  
//starte Übertragung
TWCR = (1<<TWINT) || (1<<TWEN) || (1<<TWIE);
damit kann man zuerst den slave adressieren und dann daten senden.
//Stop senden
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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.