Forum: Compiler & IDEs Funktionsrumpf für Interrupt und neu setzen von Interrupt Vectoren


von T. B. (sleeperzzzzzz)


Lesenswert?

Hallo alle zusammen,

ich versuche jetzt schon seit einiger Zeit die Vektoren des Interrupt 
Bereichs während der Laufzeit zu überschreiben.

An sich keine schwere Sache wenn ich es über das Macro ISR(xxx) mache.
Nur damit bekomme ich statisch eine Funktion auf einen Vektor gelinkt.

Indem ich eine Struktur über die Interrupt Vektoren gelegt habe, kann 
ich diese jetzt einzeln und Gezielt abfragen und gegeben falls 
überschreiben.

Nur da kommt das nächste Problem!

Wie bekomme ich den Compiler dazu eine Beliebige Funktion mit dem 
Funktionsrumpf eines Interrupts zu versehen.
Es fehlen sonst so unwichtige dinge wie Stak aufräumen usw.

ISR(MyFunction) wirft Fehler aus

Das Macro ISR() ausgeschrieben mit direktem Eintrag des Funktionsnamens 
geht auch nicht (nicht das ich erwartet hätte dass das Funktioniert).

Also Daher die Frage was muss ich machen damit ein Code wie folgt dem 
Compiler sagt das es die Funktion normal anlegen soll, aber bitte schön 
den Rumpf eines Interrupts verwenden soll.
1
#define _MyInterDefinition(f_name)\
2
extern "C" void f_name (void) ???? ;
3
4
#define _MyInterDeclaration(f_name)\
5
extern "C" void f_name (void) 
6
7
_MyInterDefinition(f_IchKommSpaeter)
8
.
9
.
10
.
11
_MyInterDeclaration(f_IchKommSpaeter){
12
   return;
13
}
14
15
void main(void){
16
 pVectorList->vInterrupt = f_IchKommSpaeter;  // Überschreibe Vektor
17
}

von Bastler (Gast)


Lesenswert?

Welche Hardware?

von T. B. (sleeperzzzzzz)


Lesenswert?

Ich benutze einen Arduino UNO von Sunfounder mit einem ATmega328P, in 
Kombination Atmel Studio 6.2.1563 -Service Pack2.

Nur ich denke das ist kein Problem der Hardware.
Sondern der Compiler muss das Schlucken und umsetzen.

von Mike H. (Gast)


Lesenswert?

Es kommt darauf an ob du eine von Neumann Architektur mit gemeinsamen 
Progrmm und Datenspeicher (z.B. PC) oder eine Harvard-Architektur (z.B. 
ATMega µC) progrmmierst. Bei letzterer kann der Programmspeicher 
(Interruptvektor) durch das Programm selbst nicht geändert werden.

Die einfachste und universellste Möglichkeit ist eine Interruptroutine 
mit einer Fallunterscheidung mithilfe einer Variablen.

von T. B. (sleeperzzzzzz)


Lesenswert?

Hmm du hast recht,
aber wird nicht beim ATMega die Havard-Architektur ein wenig verbogen.
Sonst währen Konzepte wie Bootloader nicht möglich.

Ich habe bereits den Interrupt überschrieben mit einer anderen Funktion.
Zumindest glaube ich das, da der Interne Timer sich anschließen 
verabschiedete und alles andere auch.

Ich hab jetzt schon so einiges ausprobiert nur wirklich Land sehe ich 
bei dem Problem nicht.

Die Alternative ist wirklich jeden Interrupt eine Dummy-Funktion zu 
Verpassen und diese auf eine Struktur zu legen... und die zu 
überschreiben
1
#define _MyInterruptDirectDef_( vector , function )\
2
ISR((vector)){  \
3
  if(function)(function)(); \
4
  } 
5
6
7
typedef void (*volatile _pInterrupt_)(void);
8
9
10
11
typedef struct s_InterruptVectorList{
12
_pInterrupt_ vINT0;  // External Interrupt Request 0 */
13
_pInterrupt_ vINT1;  // External Interrupt Request 1 */
14
} s_IntVect, *ps_IntVect;
15
16
17
void Dummy (void){ return;}
18
19
s_IntVect sIntVectList;
20
21
22
_MyInterruptDirectDef_ ( TIMER0_COMPA_vect , sIntVectList.vINT0 )
23
24
void Main(void){
25
  memset((void*)sIntVectList,0,sizeof(sIntVectList));
26
  sIntVectList.vINT0 = Dummy;
27
    
28
}
(Bitte nicht an Details aufhängen ich hab das jetzt nicht nochmal durch 
den Compiler gejagt)
So Ähnlich hat es schon mal Funktioniert.
Nur ich find die Lösung unsauber.
Das muss einfacher gehen und direkt möglich sein.

von Uwe (de0508)


Lesenswert?

Guten Morgen Tobias,

ich frage mich für welche Anwendung benötigst Du das ?

Was immer geht packe einen Funktionspointer in die ISR und rufe dann 
deine "erweiterte" ISR darüber auf.

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Ich denke auch, dass die Variante mit Funktionszeiger die sauberste sein 
wird!

Unsauber ist das ganze schon deswegen, da Du führende Unterstriche für 
Deine Bezeichner verwendest! Wie kommt man eigentlich immer wieder auf 
die Idee?

: Bearbeitet durch User
von T. B. (sleeperzzzzzz)


Lesenswert?

Das sind eigentlich alles reine Fingerübungen.
Ich versuche mir Grade ein Interface aufzubauen, mit dem ich nicht immer 
den Compiler starten muss um kleine Softwareänderungen umzusetzen.
Die Geschwindigkeit ist erst einmal nicht so wichtig.

Vom Ansatz her wie CFC,SymadynD oder S7-KOP Abklatsch.

von Uwe (de0508)


Lesenswert?

Hi Tobias,

Softwareänderungen ohne Compiler - ist das ein Aprilscherz ?
Das kann doch nur auf binär Ebene geschehen.
Warum sollte man das machen? Da wird der gesamte Code nicht mehr wartbar 
!

Was Du eher willst, ist ein Interpreter schreiben, der dann diesen Code 
ausführen soll. Somit ist das schon etwas anders, aber warum das Rad neu 
erfinden.

Nimm Forth, hatte ich auf einem atmega32 installiert.

: Bearbeitet durch User
von T. B. (sleeperzzzzzz)


Lesenswert?

Ich bin kein Professioneller Programmiere und hab mich mal darauf 
festgelegt das ich #define mit einem Underline beginne Strukturen mit 
einem 's', Klassen mit einem 'c', Pointer mit einem 'p' usw...

Ich benutze diese Technik in CFC ebenfalls 'B_' für BOOL 'P_' für Puls, 
'PW_' für gepulste Bits in einem Datenword...

von Walter S. (avatar)


Lesenswert?

Tobias Bauer schrieb:
> Ich habe bereits den Interrupt überschrieben mit einer anderen Funktion.

dass du das zur Laufzeit gemacht hast traue ich dir nicht zu,
AVRs sind durch ihren Aufbau dazu nicht besonders gut geeignet

: Bearbeitet durch User
von T. B. (sleeperzzzzzz)


Lesenswert?

>Softwareänderungen ohne Compiler - ist das ein Aprilscherz ?
>Das kann doch nur auf binär Ebene geschehen.
>Warum sollte man das machen? Da wird der gesamte Code nicht mehr wartbar

@Uwe S.
Willkommen in der Realität fast alle Automatisierungssysteme basieren 
nicht ohne Grund auf ähnliche Konzepte.

>Was Du eher willst, ist ein Interpreter schreiben, der dann diesen Code
>ausführen soll. Somit ist das schon etwas anders, aber warum das Rad neu
>erfinden.

Nein!
Es ist ein unterschied ob du einen Interpreten benutzt oder ob du aktiv 
eine Programstruktur beeinflusst.
Ob das jetzt unter Interpreten zu definieren ist sei mal dahin gestellt.

Nur die eigentlich Frage geht grade verloren!
Ist es möglich eine Funktion zu deklarieren die den Funktionsrumpf eines 
Interrupts besitzt ohne gleich den Vektor des Interrupts zu Definieren.

von Mike H. (Gast)


Lesenswert?

Tobias Bauer schrieb:
> Das sind eigentlich alles reine Fingerübungen.

Mal ganz grundsätzlich zu solchen "Fingerübungen": Wenn du wirklich was 
lernen willst, dann befasse dich erstmal mit dem WAS du erreichen 
willst. Dann überleg dir, welche Konzepte in der Progrmmierung dafür 
existieren und dann befasse dich mit dem WIE der eigentlichen 
Progrmmiersprache.

Mal zum Vergleich: Wenn du ein Baumhaus bauen wilst, dann hämmerst du ja 
auch nicht als erstes ein bisschen auf einem Brett herum.

von Uwe (de0508)


Lesenswert?

Hallo Tobias,

wie wird durch Dich die Programstruktur beeinflusst ?

Das wird nicht klar, ich denke Du musst dich der Realität stellen.

von T. B. (sleeperzzzzzz)


Lesenswert?

Hey Leute,

lasst das doch meine Sorge sein!

Wenn ich über das Grundkonzept diskutieren wollte würde ich das in einem 
anderen Thread machen, schön mit PowerPoint wenn das einer Braucht.

Ist es zu viel verlangt Hilfestellung auf eine Einfache Frage zu 
bekommen?

von Uwe (de0508)


Lesenswert?

Hallo Tobias,

unsere Antwort war eindeutig: funktions pointer innerhalb der FESTEN 
ISR.

Der Flashspeicher ist halt nicht von sich selbst aus, ohne weiteres 
änderbar. Der GCC weis davon überhaupt nichts.
Nur Daten kann man im SRAM ablegen, Code kann dort nicht ausgeführt 
werden.

von Falk B. (falk)


Lesenswert?

@ Tobias Bauer (sleeperzzzzzz)

>ich versuche jetzt schon seit einiger Zeit die Vektoren des Interrupt
>Bereichs während der Laufzeit zu überschreiben.

Vergiss es. Die liegen im Flash, denn kann man nicht sinnvoll zu 
Laufzeit umprogrammieren. Du musst eine einfache Fallunterscheidung per 
Variable machen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Mike H. schrieb:
> Es kommt darauf an ob du eine von Neumann Architektur mit gemeinsamen
> Progrmm und Datenspeicher (z.B. PC) oder eine Harvard-Architektur (z.B.
> ATMega µC) progrmmierst.  Bei letzterer kann der Programmspeicher
> (Interruptvektor) durch das Programm selbst nicht geändert werden.

Das hat mit Harvard oder nicht grad garnix zu tun :-)

I.W. hängt eine Implementierung davon ab, ob die IRQ-Vektoren read-only 
sind wie z.B. bei AVR.  Evtl. spielt auch das OS eine Rolle, ob es 
entsprechende Funktionalität bereits implementiert.

Tobias Bauer schrieb:
> ich versuche jetzt schon seit einiger Zeit die Vektoren des
> Interrupt Bereichs während der Laufzeit zu überschreiben.

Vermutlich willst du die nicht zur Laufzeit per Bootloader 
überschreiben.

In dem Fall wird die ISR einen indirekten Sprung / Aufruf zur 
eigentlichen Funktion enthalten, etwa so:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
#define MAKE_VEC2(vec, disp)                \
5
    extern void (*disp)(void);              \
6
    extern void __bad_interrupt (void);     \
7
    void (*disp)(void) = __bad_interrupt;   \
8
                                            \
9
    ISR (vec)                               \
10
    {                                       \
11
        disp();                             \
12
    }
13
14
#define MAKE_VEC(vec)                       \
15
    MAKE_VEC2 (vec, vec ## _dispatch)
16
17
MAKE_VEC (PCINT1_vect)
18
19
static int volatile x;
20
21
static void fun (void)
22
{
23
    x = 1;
24
}
25
26
int main (void)
27
{
28
    PCINT1_vect_dispatch = fun;
29
    return 0;
30
}
Für die entsprechende ISR bedeutet das natürlich einiges an Overhead; 
wenn du den verringern willst kann die ISR in Assembler implementiert 
werden:

Z sichern, Z vom RAM laden, ICALL, Z restaurieren, RETI.  foo muss dann 
als ISR implementiert werden, was das Problem mit sich bringt, dass foo 
mit RETI endet und die Wrapper-ISR nach dem ICALL mit I = 0 fortsetzt.

von T. B. (sleeperzzzzzz)


Lesenswert?

Fazit die Umständliche Variante!

Als ich den Versuch den Pointer zu Überschreiben nochmal durch den 
Debugger gejagt habe ist klar warum das nicht funktioniert hat.
Ich hab irgendetwas überschrieben nur nicht den Pointer für den Vektor 
den ich erwartet hätte.

So besten Dank!

von T. B. (sleeperzzzzzz)


Lesenswert?

Johann L. schrieb:
> Für die entsprechende ISR bedeutet das natürlich einiges an Overhead;
> wenn du den verringern willst kann die ISR in Assembler implementiert
> werden:
>
> Z sichern, Z vom RAM laden, ICALL, Z restaurieren, RETI.  foo muss dann
> als ISR implementiert werden, was das Problem mit sich bringt, dass foo
> mit RETI endet und die Wrapper-ISR nach dem ICALL mit I = 0 fortsetzt.

Also käme ich an dem Punkt erst einmal nicht ohne Assembler aus.
Das hatte ich befürchtet, noch ein Grund mehr den Umständlichen weg 
einzuschlagen.
Das Bestätigt aber meinen Verdacht den ich auch schon hatte.
Danke für den Ansatz!

Fazit wäre dann ein Code der Etwa so aussieht!
1
// function pointer definition for interrupts
2
typedef void (*volatile _pInterrupt_)(void);
3
4
typedef struct s_InterruptVectorList{
5
_pInterrupt_ vReset;    // Reset Vector (not Used)
6
7
_pInterrupt_ vINT0;    // External Interrupt Request 0
8
_pInterrupt_ vINT1;    // External Interrupt Request 1
9
10
_pInterrupt_ vPCINT0;    // Pin Change Interrupt Request 0
11
_pInterrupt_ vPCINT1;    // Pin Change Interrupt Request 0
12
_pInterrupt_ vPCINT2;    // Pin Change Interrupt Request 1
13
.
14
.
15
.
16
} s_IntVect, *ps_IntVect;
17
18
s_IntVect sIntVectList;
19
20
#define _MyInterruptDirectDef_( vector , function )\
21
ISR((vector)){  \
22
  (function)(); \
23
  } 
24
25
_MyInterruptDirectDef_( INT0_vect , sIntVectList.vINT0)
26
_MyInterruptDirectDef_( INT1_vect , sIntVectList.vINT1)
27
_MyInterruptDirectDef_( PCINT0_vect , sIntVectList.vPCINT0)
28
_MyInterruptDirectDef_( PCINT1_vect , sIntVectList.vPCINT1)
29
_MyInterruptDirectDef_( PCINT2_vect , sIntVectList.vPCINT2)
30
.
31
.
32
.
33
34
void fDummy(void){ return;}
35
36
void Main(void){
37
  sIntVectList.vPCINT2 = fDummy;
38
  while(1){}
39
}

von Bernd K. (prof7bit)


Lesenswert?

Bitte bedenke auch daß der avr-gcc eine irrsinnige push-pop-Orgie 
veranstaltet sobald auch nur ein einziger Funktionsaufruf der nicht 
geinlined werden kann in einer ISR vorkommt.

Wenn Du mal einen Schritt zurücktrittst (mindestens bis zur 
Kaffeemaschine) und nochmal in Ruhe das konkrete Problem betrachtest 
das Du in diesem einen Fall zu lösen hast und dabei feststellst daß Du 
eigentlich nur bei einen oder zwei interrupts (und nicht bei allen) 
zwischen zwei oder drei Varianten (und nicht zwischen beliebigen) zu 
wählen hast dann könntest Du vielleicht ganz pragmatisch ein simples 
inline if else nehmen und einen ganzen Haufen unbenutzten Boilerplate 
vermeiden der nicht nur den Blick aufs Wesentliche versperrt sondern 
auch noch unnötig Flash, RAM und Taktzyklen kostet.

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Tobias Bauer schrieb:
> Ist es möglich eine Funktion zu deklarieren die den Funktionsrumpf eines
> Interrupts besitzt ohne gleich den Vektor des Interrupts zu Definieren.

Ja.

1)
1
__attribute__((__signal__,__used__))
bzw. __interrupt__, je nachdem, was du willst.

2) Funktionsprotoyp ist void(*)(void).

3) Funktionsname beginnt mit __vector_.

von T. B. (sleeperzzzzzz)


Lesenswert?

Bernd K. schrieb:
> Wenn Du mal einen Schritt zurücktrittst (mindestens bis zur
> Kaffeemaschine) und nochmal in Ruhe das konkrete Problem betrachtest
> das Du in diesem einen Fall zu lösen hast und dabei feststellst daß Du
> eigentlich nur bei einen oder zwei interrupts (und nicht bei allen)
> zwischen zwei oder drei Varianten (und nicht zwischen beliebigen) zu
> wählen hast dann könntest Du vielleicht ganz pragmatisch ein simples
> inline if else nehmen und einen ganzen Haufen unbenutzten Boilerplate
> vermeiden der nicht nur den Blick aufs Wesentliche versperrt sondern
> auch noch unnötig Flash, RAM und Taktzyklen kostet.

Bernd ich hab's mir schon vor ein bis zwei Wochen überlegt.
Ich setze erst einmal das gesamtpacket um und versuche dabei nicht 
gleich ein Baustelle nach dem anderen zu hinterlassen. Wenn ich das 
alles so flexibel wie möglich aufziehen möchte muss ich eben mit 
gewissen Verlusten rechnen. Optimiert wird nachher... sonst verstaubt 
alles wieder...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Tobias Bauer schrieb:
> Wenn ich das alles so flexibel wie möglich aufziehen möchte muss
> ich eben mit gewissen Verlusten rechnen. Optimiert wird nachher...

Die Frage ist: Warum reicht die Flexibilität, die ISRs zur Linkzeit 
festzulegen, nicht aus.  Soll das ein OS werden?

von T. B. (sleeperzzzzzz)


Lesenswert?

Ich möchte während der Laufzeit beliebig den Programablauf beeinflussen.
Ohne jedes mal den Compiler anschmeißen zu müssen.

Ziel ist es ein Kleines Interface aufzubauen mit dem ich Reihenfolge von 
Abarbeitung diverser "Bausteine" (Funktionen) verändern kann.
Bausteine werden Definiert mit eindeutigen übergabepunkten für 
n-Eingänge und n-Ausgängen. Eingänge können auf Ausgänge gelinkt werden 
usw. Kleine vorgefertigte Programm in einer Bibliothek...

So damit das alles auch Zeitgesteuert oder Ereignisorientiert passieren 
kann, muss ich gegeben Falls mal eine Interrupt auf einen anderen 
Einstiegspunkt Linken können. Damit ich mir nicht jedes mal einen Ast 
abbreche weil ich doch mal einen Vergessen habe, werden gleich all 
eingebunden.

Simatic TDC ist wohl kein begriff?
Das ist ein Automatisierungssystem mit dem ich seit einigen Jahren 
beruflich arbeite.
Hat leider den Nachteil das es Schweine Teuer ist aber dafür 
Zykluszeiten weit unterhalb 1ms möglich sind. Verwendung in 
Warmbandwerken, Gleichspannungshochspannungsanlagen, 
Hochspannungskompensationsanlagen usw.

So jetzt kommt der Grund für den Aufwand.
Es ist einfach und Flexibel und man Beeinflusst die Programmstruktur 
direkt, Ablaufreihenfolgen und die Punkte wo ein "Baustein" seine Daten 
abholt. Damit wird nur noch ein Funktion Aufgerufen die sich die Daten 
selbst holt. Wenn mich das nicht ganz täuscht, arbeiten da Interpreten 
ein wenig anders, da jedes mal ein Text oder vorher übersetzter Code 
schrittweise interpretiert wird.

Abgesehen davon sind das alles Fingerübungen...

von Bernd K. (prof7bit)


Lesenswert?

Für Code der sich zur Laufzeit mal eben selbst austauschen oder 
modifizieren können soll würde ich eher eine Von-Neumann-Architektur 
vorschlagen. Warum willst Du Dich mit für dieses Projekt mit einem 
ATmega rumquälen der sich aufgrund seiner Beschaffenheit natürlich (und 
zu Recht!) mit Leib und Seele dagegen wehrt in solch einer Weise 
verwendet zu werden?

von T. B. (sleeperzzzzzz)


Lesenswert?

Ganz einfach klappt es mit dem, funktioniert es auch mit anderen.
Die Übergabepunkte müssen nur angepasst und klar definiert sein.
Abgesehen davon hatte ich mir erst einmal einen Arduino Uno gekauft, um 
wieder mal einzusteigen und jetzt ist er eben da.

Hatte für einen Kollegen vor ein Paar Jahren ein Interface geschrieben 
gehabt für seine kleine Steuerung, zur online Datenerfassung. Ich frag 
mich immer noch wie er die Steuerung zum laufen bekommen hat ohne Daten 
auslesen zu können.

von Bernd K. (prof7bit)


Lesenswert?

Tobias Bauer schrieb:
> Ganz einfach klappt es mit dem, funktioniert es auch mit anderen.

Du wirst aber gewaltige Kompromisse machen müssen. Mal eben sowas wie 
eine ausgewachsene SPS von Siemens mit nur einem einzigen Arduino in 
angemessener Form in ihren wesentlichen Eigenschaften nachempfinden zu 
wollen halte ich für... sportlich.

von Falk B. (falk)


Lesenswert?

Schlaue Leute würde schlicht einen Controller wählen, welcher die 
Interruptvektoren im RAM liegen hat. Aber warum einfach, wenn es auch 
umständlich geht ;-)

von MWS (Gast)


Lesenswert?

Tobias Bauer schrieb:
> Abgesehen davon sind das alles Fingerübungen...

So, so, Fingerübungen, aber keinerlei Ahnung, dass Dein Klavier weiße 
und schwarze Tasten hat. LOL

von Walter S. (avatar)


Lesenswert?

Bernd K. schrieb:
> Für Code der sich zur Laufzeit mal eben selbst austauschen oder
> modifizieren können soll würde ich eher eine Von-Neumann-Architektur
> vorschlagen.

wurde ja schon erwähnt dass das nichts mit Neumann oder Harvard zu tun 
hat, sondern damit ob die Interruptvektoren einfach beschreibbar sind 
(z.B. wenn sie in einem RAM liegen)

von T. B. (sleeperzzzzzz)


Lesenswert?

Danke Leute für die Moralische Unterstützung.

Ja ich hab jetzt aber keine Von-Neumann-Architektur!

Also ist eben etwas umständlicher.

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.