Moin, ich würde gerne eine Interrupt Routine auf meinem ATmega2560 per Hand aufrufen. Konkret geht es um den Transmit Complete interrupt, welchen ich gerne einmal per Hand auslösen würde.
Gruß Justus
|
Anzeige
|
Interrupt aus main aufrufen AVR
Gast
#7338699
Moin, ich würde gerne eine Interrupt Routine auf meinem ATmega2560 per Hand aufrufen. Konkret geht es um den Transmit Complete interrupt, welchen ich gerne einmal per Hand auslösen würde. Gruß Justus
Das ist wenig sinnvoll. Wenn, dann musst du die Funktion im Interruopt in eine normale Funktion packen, die man dann aus der ISR oder dem normalen Programm heraus aufrufen kann. Das hat in der ISR den kleinen Nachteill, daß dort realtiv viele Register gesichert werden müssen, so um die 10. Das macht die ISR etwas langsamer. Wenn man das vermeiden will, muss man die Funktionalität der ISR und der normalen Funktion kopieren, sprich, doppelter Code an zwei Stellen im Quelltext. Nicht schön, aber OK.
Gast
#7338708
Such mal nach "Software Interrupt"
Gast
#7338710
cli rcall <symbolischer Name des Vectors, z.B.: UTXC0addr> Das ruft natürlich wirklich nur die ISR auf, ändert nichts am Status der Hardware.
Warum setzt Du nicht das entsprechende Interrupt-Flag?
Weil die nur die Hardware setzen kann. Die CPU kann sie nur löschen! "Bit 6 – TXCn: USART Transmit Complete This flag bit is set when the entire frame in the Transmit Shift Register has been shifted out and there are no new data currently present in the transmit buffer (UDRn). The TXCn Flag bit is automatically cleared when a transmit complete interrupt is executed, or it can be cleared by writing a one to its bit location. The TXCn Flag can generate a Transmit Complete interrupt (see description of the TXCIEn bit)."
Dann erkläre bitte mal, warum das bei einem Bit gehen soll und beim anderen Bit nicht: • Bit 7 – RXCn: USART Receive Complete This flag bit is set when there are unread data in the receive buffer and cleared when the receive buffer is empty (that is, does not contain any unread data). If the Receiver is disabled, the receive buffer will be flushed and consequently the RXCn bit will become zero. The RXCn Flag can be used to generate a Receive Complete interrupt (see description of the RXCIEn bit). • Bit 6 – TXCn: USART Transmit Complete This flag bit is set when the entire frame in the Transmit Shift Register has been shifted out and there are no new data currently present in the transmit buffer (UDRn). The TXCn Flag bit is automatically cleared when a transmit complete interrupt is executed, or it can be cleared by writing a one to its bit location. The TXCn Flag can generate a Transmit Complete interrupt (see description of the TXCIEn bit). Soll das nur am "Sprachgefüge" liegen? Wenn ich Spaß dran habe probiere ich es mal aus :-)
Gast
#7338773
Can be used heisst, dass das Bit intern mit der Interrupt-Einrichtung verkabelt ist und es 'can' ein Interrupt-Enable-Bit gesetzt werden, sodass jenes Bit den Interrupt ausloest.
Gast
#7338797
Bei 8 Bit AVR macht der RETI Befehl genau das gleiche, wie RET. Deswegen kann man theoretisch Interrupthandler wie ganz normale Funktionen aufrufen. Ich habe allerdings nicht herausgefunden, wie man das in C anstellt.
Falsch. RETI setzt das I-Bit und ermöglicht weitere Interrupts. RET tut das nicht.
Gast
#7338831
? RETI behaves differently in AVRe, AVRxm, and AVRxt devices. In the AVRe series of devices, the Global Interrupt Enable bit is cleared by hardware once an interrupt occurs, and this bit is set when RETI is executed. In the AVRxm and AVRxt devices, RETI will not modify the Global Interrupt Enable bit in SREG since it is not cleared by hardware while entering ISR. This bit should be modified using SEI and CLI instructions when needed.
Erklär mal, wie du das Bit setzen willst, wenn es heißt "The TXCn Flag bit is automatically cleared when a transmit complete interrupt is executed, or it can be cleared by writing a one to its bit location."
Gast
#7338844
Hugo Hurtig schrieb:
Wäre nicht das umgekehrte Vorgehen angebracht - wenn man sich unsicher ist, erst ausprobieren, und danach sich hier äußern?
Gast
#7338852
Da hast du jetzt ein paar spezielle AVR Serien genannt, die ich dabei nicht im Sinn hatte. Ehrlich gesagt sagen mir diese drei Abkürzungen nichts. Wo hast du die her, dass ich da mal nachlesen kann? Ob durch den Funktionsaufruf das globale I Flag gesetzt wird, spielt bei dem angefragten Anwendungsfall keine Rolle. Denn es war vorher an und soll auch nachher an sein (nehme ich an). Die Screenshots stammen aus https://ww1.microchip.com/downloads/en/devicedoc/atmel-0856-avr-instruction-set-manual.pdf
Gast
#7338865
? AVRe sind die 'normalen von früher', AVRxt die 'neuen' - was ist an denen "speziell"?
Ganz einfach:
Der Funktionsname ist derselbe, der auch in der Definition der ISR an das ISR-Makro übergeben wird. Vor dem Aufruf sperrt man sinnvollerweise die Interrupts, wie dies auch beim Auslösen eines echten Interrupts automatisch getan wird. Durch den RETI am Ende der ISR werden die Interrupts wieder freigeschaltet, was hier vermutlich auch gewünscht wird.
Gast
#7338876
AVRs kennen keine Software Interrupts!
Auf ein kaputtes Konzept, einen solchen Flicken setzen zu wollen, ist 99.999% der Fälle eine dumme Idee. Mein Rat: Mindestens 2 Schritte zurück gehen und neu nachdenken.
Gast
#7338914
Das habe ich probiert, aber zumindest im Simulator klappt das nicht. Dann habe ich zum ATmega328p gewechselt, aber auch damit klappte es nicht. Siehe Screenshot. Wenn ich dort noch einen schritt weiter debugge, beginnt das Programm wieder am Anfang von main(). Offenbar springt er an die falsche Adresse. Man sieht das auch im *.lss:
Anstatt "call 0x7c" würde ich hier "call 0x80" erwarten. Ich habe mit -O1 compiliert.
Das mag der Compiler nicht 8-0
Gast
#7338958
Du musst die ISR vor main() platzieren.
Gast
#7338963
Auf die Auflösung dieses Rätsels bin ich gespannt. LG, Sebastian
Gast
#7338972
Also bei mir stimmt es im .lss-File. Zu meiner C-Umgebung kann ich aber leider nichts sagen, die ist irgendwie zusammengestoppelt.
Gast
#7338987
Ich habe unter Linux den gleichen Fehler:
Ahhhh! Manchmal ist es so einfach!
Passt. Die ISR liegt auf Adresse 0x80, und der rcall ruft sie auf. Ganz normal. Es wird NICHT der Interruptvektor __vector_20 auf Adresse 0x50 aufgerufen! In ASM kann man das machen, bringt aber auch nix extra.
Ja - hätte ich mal besser gemacht. Ich gelobe Besserung :-)
Gast
#7338990
Warum zum Teufel geht das bei dir, und bei mir nicht?
Gast
#7338992
Genau - funktioniert hier realiter.
Da fehlt das #include "avr/interrupt.h"
Gast
#7338997
Oh Mann, ja genau das war bei mir der Fehler. Also halten wir fest: ISR kann man einfach wie normale Funktionen aufrufen.
Gast
#7339005
Stefan Frings schrieb:
Merkwürdig: bei mir hier bringt der Compiler drei Warnungen, wenn ich das '#include <avr/interrupt.h>' weglasse - bei Ihnen nicht? Warum nicht einfach "normalen" Code schreiben?
Falls "machwas" in der ISR nicht geinlinet werden soll, dann einfach flatten weglassen.
Gast
#7339027
Siehe Stefan F. schrieb im Beitrag #7338987: Ausgaben des Compilers Ich habe die Warnungen schon gesehen, aber nicht erkannt, was deren Ursache ist.
Gast
#7339031
Da ich ausschließlich unter Windows arbeite, hatte ich mir Ihre Linux-Version gar nicht erst angeschaut.
Gast
#7339117
Man kann auch im 10.Stock aus dem Fenster springen. Ratsam ist beides nicht. Mal ganz deutlich gesagt: Interrupt-Services sind NICHT dafür gemacht, im Programm von irgendwo her aufgerufen zu werden - auch wenn es formal gehen sollte. Und wer da meint, daß er es dennoch braucht, der hat an anderer Stelle etwas ganz verkehrt gemacht. W.S.
Gast
#7339245
Ja. Sinnvoll ist das aber praktisch nie. I.d.R. hantieren ISRs ja irgendwie mit der Hardware, die den Interrupt ausgelöst hat. Und deren Status passt halt nicht. D.h.: es ist relativ wahrscheinlich, dass die ISR "anders" läuft, als im echten Interruptfall. Früher (TM) hätte man eine Rücksprungadresse auf den Stack gelegt und dann einen Sprung auf die Interrupt-Routine gemacht. Aber das waren noch 6502-Tricksereien.
Gast
#7339272
Nichts anderes passiert beim direkten Aufruf in C.
Die Frage ist, warum man sowas überhaupt machen sollte. Er wird doch nur benötigt, um bei RS-485 die Richtung des Transceivers umzuschalten. Initial läßt man den Transceiver erstmal auf Empfang. Für das Senden selber nimmt man ja den USART Data Register Empty Interrupt.
Gast
#7339309
[TXC-Interrupt]
Das mag die einzige nützliche Anwendung sein, die DU kennst, aber es gibt noch etliche mehr...
Gast
#7339339
Sei froh, daß es sich hier um einen AVR handelt. Bei anderen Architekturen sieht sowas völlig anders aus, da wird ggf. auch der Stack gewechselt, der Programmlevel von User auf System oder Supervisor gewechselt, beim ARM7 ggf. auch Code (Arm/Thumb) und einige Register (Schattenregister) gewechselt usw. Von wegen nichts ... Eben genau deshalb gibt es eine Reihe von Randbedingungen bei der Verwendung von C, die eine saubere Trennung zwischen dem Grundprogramm und den ISR erfordern. Und bei kleineren Plattformen (PIC, 8051 usw.) hat man oftmals keine reentranten Funktionen, weil lokale Variablen eben NICHT auf dem Stack stehen und RAM nur sehr begrenzt vorhanden ist, da sollte man sowas auch besser bleiben lassen. Und Leute, die offenbar mit den AVR aufgewachsen sind, haben sich dann solche schlechten Manieren angewöhnt. Ja auch das ubiquitäre Verwenden von DI/EI gehört dazu. W.S.
Gast
#7339362
Ich weiss. Deswegen hatte ich das (siehe oben) extra nochmal ausprobiert, bevor ich hier Blödsinn verzapfe. Manche Dinge sind eben Hardware spezifisch. Man kann nicht alles völlig generisch programmieren.
Gast
#7339418
Das allerdings ist, was die nixwissenden C-Apologeten immer wieder versprechen, also inbesondere die, die nie nahe an der Hardware programmieren... Die richtigen C-Programmierer wissen natürlich sehr wohl, dass es da eine Grenze gibt, die sich auch in C nicht wirklich überwinden läßt. Es läuft dann halt auf die allseits beliebten #ifdef-Orgien hinaus, wenn man nahe an der Hardware irgendwas "portabel" programmieren will. Ich halte diese Art der "Portabilität" allerdings sowieso für einen ziemlichen Euphemismus. Wie wohl jeder, der beim Kompilieren solchen Codes in den #else-Zweig dieser #ifdef-Orgien gelangt... Antwort schreibenBitte melde dich an, um einen Beitrag zu schreiben. |
Anzeige
|