Hallo zusammen,
ich verwende das TWI Interface eines mega128 zusammen mit dem avrgcc.
Die TWI ISR ist bisher so deklariert, das sie durch andere Interrupts
nicht unterbrochen werden kann. Nun möchte ich aber explizit andere
Interrupts während der TWI ISR Ausführung zulassen. Dabei habe ich
folgende Probleme:
1.) Wenn ich die TWI ISR durch folgendes avrgcc Macro unterbrechbar
mache:
void TWI_vect( void ) __attribute__( ( interrupt ) );
Habe ich das Problem, das die TWI ISR in einer Endlosschleife hängen
bleibt. D.d. sobald in die TWI ISR gesprungen wird, geht der
Controller wohl davon aus das schon wieder ein Interrupt eingetreten
ist und springt wieder in die TWI ISR. Das Verhalten scheint mir
plausibel da das TWINT Bit auch noch gesetzt ist.
2.) Wenn ich in der TWI ISR explizit den TWI Interrupt deaktiviere
( TWIE = 0 ) und darauf durch sei( ) die globalen Interrupts wieder
aktiviere so tritt das Problem von 1.) nicht mehr auf. Die TWI ISR
wird auch unterbrechbar. Jedoch überträgt das TWI interface nur noch
Müll.
Irgendwie komme ich überhaupt nicht weiter. Deshalb meine Frage an euch:
Wie bekomme ich es hin, das die TWI ISR des mega128 durch weitere
Interrupts unterbrechbar wird ? Habe ich irgendwas übersehen ?!
Edit: Mir ist noch folgendes aufgefallen: Sobald das TWIE Bit auf 0
gesetzt wird, wird implizit auch das TWSR Register auf 0 gesetzt. Das
Verhalten ist mir nicht klar ?!
Bei den AVRs sind Interrupts von Haus aus nicht unterbrechbar, das muss
man Softwaremäßig lösen (Interrupt-Freigabe mit SEI).
Abgesehen davon gibt es noch andere Probleme, z.B. Priorisierung (das
können die AVRs ebenfalls nicht). Der Müll könnte auch durch
Stack-Probleme zustande kommen - allerdings nur eine Vermutung.
Ich würde versuchen, ohne solche Klimmzüge auszukommen.
Interrupts allgemein werden so kurz wie möglich gehalten, keine
Warteschleifen etc. in Interrupts - wenn man das beherzigt, muss man
meist keinen Interrupt unterbrechbar machen.
Deswegen kann man mit dem genannten Macro auch explizit Interrupts in
ISR´s freischalten. Das Macro macht nichts anderes wie ein sei am Anfang
der ISR zu einzufügen. Bisher hatte ich nie solche Probleme und setze es
sehr häufig ein das ISR´s unterbrechbar sind. Nur das TWI Interface
scheint sich hier anders zu verhalten.
Tja, bei den AVRs ist es nicht schön gelöst mit den Interruptprioritäten
(es gibt sie leider nicht).
Und zu allem Übel löschen die Interrupts, die langsam sein dürfen, beim
Eintritt nicht ihr Interruptflag (UART, I2C, EEPROM).
Ich hab mir daher ne 2.Interruptpriorität in Software gebastelt und zwar
mit T0.
T0 läuft alle 256 Zyklen über und hält sich selbst an. Damit kann er
nicht mehr sich selbst unterbrechen. Er wird aber als ISR_NOBLOCK
definiert und ist damit unterbrechbar.
Dann pollt er alle low priority Interruptquellen und führt die Handler
aus.
Und zum Schluß startet er sich wieder.
Damit das funktioniert, müssen die high Priority Interrupts kürzer 256
Zyklen sein.
Und die low priority Interrupts werden bis zu 256 Zyklen verzögert
ausgeführt.
Ich hab das für ne 8-Kanal Software-PWM mit UART und I2C benötigt.
Funktioniert sogar.
Ich hätts ja lieber mit nem 8051 gemacht und mir den ganzen Aufwand
gespart, aber die funktional geeigneten NXP LPC9xx sind leider nicht 5V
kompatibel.
Peter
Mario wrote:
> Ja, so ähnlich habe ich das auch gemacht. Aber das hilft mir jetzt nicht> weiter.
Warum nicht?
> Keiner eine Idee wie ich die TWI ISR unterbrechbar mache ?
Wenn Dir die Idee nicht gefällt, denk Dir was anderes aus.
Ich sage ja nicht, daß dies die einzige Lösung ist.
Aber sie funktioniert und ist sauber.
Peter
P.S.:
Man muß einen Timerinterrupt opfern, weil nur diese ihr Flag automatisch
löschen und damit das SEI schnellstmöglichst ausgeführt werden kann.
Ich muss unmittelbar auf das TWI Interface reagieren und habe nicht die
Zeit eine gewisse Zeit später zu pollen ob ein Interrupt anliegt.
Gleichzeitig muss ich auf externe Interrupts horchen und darf dort
keinen "verschlucken".
Wenn du den TWI-Interrupt abschaltest, musst du darauf achten, dass du
das TWINT-Flag nicht aus versehen löschst, denn dann geht ja das TWI
wieder auf Sendung:
1
//also nicht:
2
TWCR&=~(1<<TWIE);
3
//sondern vl. so (nicht gestestet
4
TWCR&=~(1<<TWIE)|(1<<TWINT));
Wenn das erstmal nach totalem blödsinn klingt, schau(t) noch mal nach
wie man (die meisten) Interruptflags löscht...
hth. Jörg
Mario wrote:
> Ich muss unmittelbar auf das TWI Interface reagieren und habe nicht die> Zeit eine gewisse Zeit später zu pollen ob ein Interrupt anliegt.
Ich fürchte, dann hast Du das I2C gründlich mißverstanden.
Das I2C wartet immer auf den langsamsten Teilnehmer (SCL-Stretching).
Und wenn das HW-I2C richtig implementiert ist, kannst Du das auch nicht
verhindern.
Ich weiß, daß beim PIC das I2C nicht vollständig implementiert ist.
Wenn Du also den AVR mit nem PIC verheiraten willst, hast Du schlechte
Karten.
I2C von 8051, AVR, ARM7 verstehen sich aber prima (warten aufeinander).
Peter
Eine eigene Frage?
Dieser Thread ist über 18 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.