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.
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.
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.
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 )\
(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.
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.
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?
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.
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.
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...
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
>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.
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.
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?
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.
@ 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.
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
staticintvolatilex;
20
21
staticvoidfun(void)
22
{
23
x=1;
24
}
25
26
intmain(void)
27
{
28
PCINT1_vect_dispatch=fun;
29
return0;
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.
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!
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!
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.
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_.
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...
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?
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...
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?
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.
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.
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 ;-)
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
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)