Ich habe bisher schon verschiedene AVRs aus der ATMega-Reihe eingesetzt und für ein neues Projekt möchte ich den ATMega2560 einsetzen, da ich 3 UARTs, 1 x TWI und 1 x SPI als Slave benötige. Durch die Außenbeschaltung bedingt kann ich ihn nur mit 3,3V versorgen und somit stehen mir max. nur ca. 8 MHz zur Verfügung. Auf der SPI-Schnittstelle ist der AVR Slave und die wird mit 100kHz betrieben, die Wartezeit zwischen zwei Bytes beträgt vom Master aus im Moment 30us. D.h. nach 80us ist ein komplettes Byte angekommen, das einen SPI-Interrupt im AVR auslöst, um das Zeichen dort zu sichern und das Antwortzeichen für den Master auszugeben. Der Master wartet 30us bis er den Clock wieder aktiviert und das nächste Byte schickt. Innerhalb diesen 30us muss der AVR in den SPI-Interrupt springen, das Zeichen ablegen und das Antwortzeichen in den Sendepuffer eintragen. Das funktioniert mit dem ersten Prototypen auch recht gut, sofern die anderen (höherprioren) Interrupts deaktiviert sind! Da der AVR für andere interne Verarbeitungen aber auch noch einige Timerinterrupts aktiv geschaltet benötigt, werden zuerst diese abgearbeitet, sofern eines der Timerinterruptflags aktiv gesetzt ist. Die Timerinterrupts sind alle recht kurz, aber da sie völlig asynchron und unabhängig voneinander sind, kann es durchaus vorkommen, dass er einen Timerinterrupt abarbeitet und während der Abarbeitung das INT-Flag eines anderen Timerinterrupts gesetzt wird und er erst noch diesen abarbeitet, bis er in den SPI-Interrupt kommt. Falls der AVR es nun nicht schafft das Antwortzeichen in den SPI-Sendepuffer zu schreiben bevor der Master nach den 30us den Clock für das weitere Byte wieder aktiviert, erhält der Master auf der Leitung ein fehlerhaftes Zeichen und ich eine Kollission im SPI-Interrupt. Die Interruptprioritäten sind im AVR ja fest vorgegeben, daher kann ich die Priorität für SPI-Interrupts auch nicht anheben. Nun die Frage, ist es möglich in den höherprioren Interrupts das Interruptflag für die SPI-Schnittstelle abzufragen und falls es gesetzt ist die Interruptverarbeitung des SPI-Schnittstelleninterrupts vom Timerinterrupts aus aufzurufen? Falls ja, wie genau? Wer hat hiermit schon Erfahrungen gesammelt oder fällt Euch eine andere Lösungsmöglichkeit hierfür ein? Freue mich auf Eure Rückmeldungen :-)
Vielleicht reicht es einfach, in den Timer-ISRs gleich am Anfang die Interrupts wieder freizugeben?
Ich würde ein Handshake nehmen: Der Master setzt ja /SS auf low, um den Slave zu adressieren und nach dem Byte wieder high. Statt high würde ich nun auf Eingang schalten und nen Pullup draußen dran. Hat der Slave nun das neue Byte in den Puffer geschrieben, macht er auf der /SS-Leitung einen H-L-H Impuls. Der Master nimmt für die /SS-Steuerung einen externen Interrupt und kriegt diesen Impuls als externen Interrupt zurück. Nun weiß der Master, daß er weiter machen kann. Peter
Hallo Jörg: >> Vielleicht reicht es einfach, in den Timer-ISRs gleich >> am Anfang die Interrupts wieder freizugeben? Das Problem ist ja, dass die Timerinterrupts eine höhere Priorität besitzen, wenn ich nun im Timerinterrupt die Interrupts wieder freischalte kann er ja nur durch einen höherprioren verdrängt werden, der SPI-Interrupt besitzt jedoch eine geringere Priorität. Hallo Peter: Auf dieser SPI-Schnittstelle sitzt nicht nur der AVR sondern auch noch einige andere SPI-Slaves wie Dataflash, EEPROM, AD-Wandler... Von daher muss sich der AVR auf dieser SPI-Schnittstelle konform verhalten. Sobald die /SS-Leitung auf low geht, wird das SPI-Interface im AVR aktiv und erhält je nach Telegramm bis zu ca. 32 Bytes an Nutzdaten, bis /SS wieder auf high geht. Technisch ist ein Handshakeverfahren mit einer weiteren Leitung außer den 4en für SPI (MOSI, MISO, SCLK und CS) nicht möglich, da der Master keinen Pin mehr für solche Zwecke zur Verfügung hat und die /SS immer aktiv treibt. Trotzdem Danke für Eure Vorschläge bisher und ich bin mal gespannt, was Euch oder den anderen noch so einfällt um dieses Problem zu lösen :-)
> Das Problem ist ja, dass die Timerinterrupts eine höhere Priorität > besitzen, wenn ich nun im Timerinterrupt die Interrupts wieder > freischalte kann er ja nur durch einen höherprioren verdrängt > werden, ... Nein, das ist kein 8051. Interruptprioritäten haben nur Bedeutung bei der Annahme des Interrupts, wenn mehrere Requests gleichzeitig anliegen. Wenn du innerhalb einer ISR die Interrupts wieder freigibst, kann sie durch jeden weiteren Interrupt unterbrochen werden (einschließlich des eigenen, falls die Bedingung noch anhängig ist -- daher ist es keine gute Idee, z. B. in einer UART-ISR die Interrupts gleich am Anfang erneut freizuschalten...).
Es wird Dir zwar nichts nützen, aber die neuen AT89LP4052 haben ein gepuffertes SPI, d.h. der Slave kann gleich 2 Byte in den Sendepuffer schreiben und kriegt nach dem 1.Byte den Interrupt, um ein nächstes Byte reinzupacken. Er hat also ein volles Byte Zeit um den Interrupt zu bedienen. Und er hat auch 4 echte Interruptprioritäten, d.h. dem SPI könnte man die höchste Priorität zuweisen. Und mit 20MIPS ist er auch nicht langsam. Ist aber eben ne andere Architecktur. Peter
Hallo Jörg, würdest Du dann empfehlen in den entsprechenden höherprioreren ISRs die Interrupts wieder freizugeben, damit der SPI-Interrupt schneller "dran kommt"? Wäre es auch möglich oder geschickter das SPI-Interruptflag in den anderen Interrupts abzufragen und den SPI-Interrupt aufrufen, falls es gesetzt ist? Fall ja, wie? Michi
> würdest Du dann empfehlen in den entsprechenden höherprioreren ISRs > die Interrupts wieder freizugeben, damit der SPI-Interrupt schneller > "dran kommt"? Ja, wobei du natürlich das Timing ordentlich nachvollziehen musst (worst case Betrachtung). > Wäre es auch möglich oder geschickter das SPI-Interruptflag in den > anderen Interrupts abzufragen und den SPI-Interrupt aufrufen, falls > es gesetzt ist? Ich denke nicht. Der Aufruf einer anderen Funktion kostet so viel mehr Zeit (da der Compiler dann alle per ABI als `caller-saved' markierten Register rettet), dass das nicht lohnt. Man müsste das dann sorgfältig mit der Hand feilen. Sofern die geschachtelten Interrupts funktionieren, würde ich diese bevorzugen.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.