Forum: Mikrocontroller und Digitale Elektronik Interrupt von Hand aufrufen


von mh123 (Gast)


Lesenswert?

Hallo!

Gibt es einen "schönen" Befehl, um eine Interrupt-SR von Hand 
aufzurufen. Ich nutze avr-libc.

Vielen Dank

von holger (Gast)


Lesenswert?

Warum sollte man so einen Unsinn machen?

von antiholger (Gast)


Lesenswert?

Testzwecke?
Initialisierung?
Unbeschränkte Ideen?

von mh123 (Gast)


Lesenswert?

Klasse! In der ersten Antwort werde ich gleich mit "Unsinn" beschimpft!

Aber gut. Ich möchte die Funktionalität, die normalerweise von einem 
Interrupt ausgelöst wird, bei Programmstart einmalig von Hand 
aufrufen, damit alles in einem definierten Zustand ist.

Ja, ich könnte alles in eine Funktion packen, die ich dann immer von der 
ISR als auch einmalig von der main() aus aufrufe. Das macht mein 
Programm aber unnötig langsam, denn bei jedem Interrupt habe ich einen 
unnötigen Funktionsaufruf und Rücksprung. Also möchte ich einmalig die 
ISR von Hand aufrufen (von mir aus auch, indem ich das Interrupt-Bit 
setze).

von MWS (Gast)


Lesenswert?

Wenn Du das Datenblatt des AVR's Deiner Wahl lesen würdest, wüsstest Du 
daß man die Interrupt Flags nur löschen, aber nicht setzen kann.

Was man machen kann, ist z.B. einen Timer so zu setzen, daß er sofort 
überläuft und damit einen OVF Int auslöst, oder man kann einen ext. Int 
auslösen, indem man den Intpin als Ausgang definiert und entsprechend 
toggelt.

von holger (Gast)


Lesenswert?

Versuchs doch mit nem Call Interruptadresse in
Inline Assembler ;)

von looser (Gast)


Lesenswert?

um welche architektur handelt es sich denn?
es ist mithilfe von inline-asembler sicher möglich, das schön dreckig 
beim programmstart durchzuführen.

von Svenk (Gast)


Lesenswert?

Bei 8051 Derivaten kannst du die Interrupts durch setzen von bits in 
SFR-Registern erzwingen.

Ich meine das wäre das TCON Register bei 88h gewesen.

von Patrick M. (patrickmarkl)


Lesenswert?

Hi mh123,

Du baust eine ISR die nichts anderes macht als eine andere Funktion 
auzurufen, in der der eigentlich Code drin ist. Diese Funktion kannst Du 
dann direkt aus main aufrufen.

Gruß
Patrick

ISR(void)  -> Aufruf aus Vektortabelle
{
  MyIsr();
}

void MyIsr(void)
{
}


void main(void)
{
  MyIsr();
  ...
}

von Naja (Gast)


Lesenswert?

@ Patrick

Der Thread-Eröffner schrieb:

>Ja, ich könnte alles in eine Funktion packen, die ich dann immer von der
>ISR als auch einmalig von der main() aus aufrufe. Das macht mein
>Programm aber unnötig langsam, denn bei jedem Interrupt habe ich einen
>unnötigen Funktionsaufruf und Rücksprung.

von mh123 (Gast)


Lesenswert?

Dass das mit Assembler war mir klar. Deshalb habe ich nach einem schönen 
C-Befehl gefragt. Ich schrieb, dass ich avr-libc benutze.

Es ist ein AVR. Ich schrieb, dass ich avr-libc benutze. Und ich dachte, 
dass die avr-libc nur für AVRs geht.

Das mit der Extra-Funktion wusste ich auch schon. Das habe ich weiter 
oben schon beschrieben.

Leider ist es weder ein externer Pin noch ein Timer.


Da muss ich wohl doch einen der vielen möglichen Umwege nehmen. Da bin 
ich ein bisschen enttäuscht von avr-libc. Bin der sicherlich nicht der 
erste, der so eine Funktion gut gebrauchen kann.

von Michael (Gast)


Lesenswert?

Na wenn du noch genug Flash hast, musst du die Funktion zweimal 
schreiben, in der ISR und in der normalen Funktion.
Michael

von Patrick M. (patrickmarkl)


Lesenswert?

@naja,

okay :-)

von Naja (Gast)


Lesenswert?

>Da muss ich wohl doch einen der vielen möglichen Umwege nehmen. Da bin
>ich ein bisschen enttäuscht von avr-libc. Bin der sicherlich nicht der
>erste, der so eine Funktion gut gebrauchen kann.

Das sollte Dir eher ein Hinweis darauf sein, das es Gründe gibt, warum 
dies nicht implementiert wurde.

Im Grunde ist das nur notwendig, wenn Du absolut notwendig 
Programmspeicherplatz sparen musst. Ansonsten kanns Du eine C-Makro 
verwendenn. Der Code taucht dann nur einmal in Deinem Text auf. Du 
kannst das Makro dann in der ISR einsetzten und ein andermal in eine 
Funktion einfügen.

von mh123 (Gast)


Lesenswert?

Es geht doch! Ganz einfach sogar.

Einfach den Interruptnamen als Funktionszeiger aufrufen.
Also z. B. ADC_vect();

(Ich dachte zwar, ich hätte es schon erfolglos ausprobiert, aber da 
hatte ich mich wohl vertan.)

@naja: Und, was wären diese Gründe Deiner Meinung nach? ;-)

von (Gast) == (Gast)


Lesenswert?

Man kann doch eine ISR per Vector auf ne andere springen lassen. Der 
Overhead müsste überschaubar sein (ohne mich tiefer mit beschäftigt zu 
haben)
Bsp.

ISR(PCINT0_vect)
{
...
// Code to handle the event.
}

ISR(PCINT1_vect, ISR_ALIASOF(PCINT0_vect));

Quelle: avr-libc-user-manual.pdf


Also irgend nen ungenutzten Timer etc. auslösen lassen...

von Aahh (Gast)


Lesenswert?

Natuerlich kann man einen Interrupt von Hand aufrufen. Man braucht ja 
nur das passende Flag zu setzen. Um zB den timer0 Overflow Interrupt 
aufzurufen, braucht man das TOV0 im TIFR zu setzen

von Gast (Gast)


Lesenswert?

Hi,

geht prinzipiell bei der AVR Architektur nicht. Es ist z.B. nicht 
möglich ein Flag in einem Interruptregister zu setzen, da laut 
Datenblatt ein Schreiben einer 1 das Flag löscht.

Die einzige Möglichkeit wäre Deine Interruptroutine an den gewünschten 
Interruptvektor und an den SPM-Interrupt zu binden (wird meist in der 
Applikation nicht benötigt), dann kannst Du einmalig zur Initialisierung 
den SPM-Interrupt freigeben und danach gleich wieder sperren. Dadurch 
wird sofort Deine Interruptroutine einmal augeführt.

Von dem Funktionsaufruf aus der Interruptroutine kann ich nur abraten 
(es sei denn es ist eine inline/static Funktion im gleichen File), da 
sonst der Compiler einen vollen Interruptframe erzeugt, was die 
Ausführungszeit unnötigerweise erhöht.

Gruss

von Christian (Gast)


Lesenswert?

Hallo zusammen,

ich würde es mit etwas Inline-Assembler über einen indirekten Aufruf 
versuchen:

asm volatile (
"mov r30,0xHH\n\t"      //High-Adresse des Interruptvektors (meistens 0)
"mov r31,0xLL\n\t"      //Low-Adresse des Interruptvektors
"icall\n\t"::);         //Indirekter Aufruf der ISR


0xHH und 0xLL bitte mit den richtigen Hex-Werte ersetzen.
Die Methode funkt aber nur bis 64kWords/128kBytes Codegrösse.
Die Adressen der Interruptvektoren findet man im AVR Datenblatt im 
Kapitel Interrupts.

Würde mich über eine Anwort freuen ob es funktioniert.

von MWS (Gast)


Lesenswert?

mh123,

Du solltest nur das klitzekleine Detail beachten, daß der Compiler für 
das Ende einer ISR ein RETI erzeugt, während bei einer normalen Funktion 
ein RET steht.

Nicht daß Du Dich über merkwürdiges Verhalten wunderst :D

von lol^^ (Gast)


Lesenswert?

reti schaltet interrupts generell ein, also verwende ein cli gleich nach 
dem return (falls nötig!)!

von MWS (Gast)


Lesenswert?

>reti schaltet interrupts generell ein, also verwende ein cli
> gleich nach dem return (falls nötig!)

Genau das meinte ich, wollte aber dem TE das Erfolgserlebnis lassen, 
selbst draufgekommen zu sein, mennnooo... Alles wieder verraten ;-)

Wobei ich mir nicht sicher wäre, wenn zu diesem Zeitpunkt ein 
Interruptflag bereits gesetzt ist, ob dort nicht wieder sofort in die 
nächste ISR gesprungen, oder ob eben dieses CLI abgearbeitet würde.

von holger (Gast)


Lesenswert?

>Wobei ich mir nicht sicher wäre, wenn zu diesem Zeitpunkt ein
>Interruptflag bereits gesetzt ist, ob dort nicht wieder sofort in die
>nächste ISR gesprungen, oder ob eben dieses CLI abgearbeitet würde.

Ein Befehl vom Hauptprogramm wird dann noch abgearbeitet.
In dem Fall das CLI.

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.