Forum: Mikrocontroller und Digitale Elektronik Mega128 + avrgcc + twi = Problem


von Mario (Gast)


Lesenswert?

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

von Mario (Gast)


Lesenswert?

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

von Marvin M. (Gast)


Lesenswert?

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.

von Mario (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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

von Mario (Gast)


Lesenswert?

Ja, so ähnlich habe ich das auch gemacht. Aber das hilft mir jetzt nicht 
weiter. Keiner eine Idee wie ich die TWI ISR unterbrechbar mache ?

von Peter D. (peda)


Lesenswert?

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.

von Mario (Gast)


Lesenswert?

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

von Jörg X. (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

von Mario (Gast)


Lesenswert?

@Jörg:
Genau DAS wars autsch. Vielen Dank für den Tip !

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.