Hallo Zusammen!
Ich möchte einen ATMega zum Ansteuern eines direkt daran angeschlossenen
Motors verwenden. Dieser ATMega bekommt von einem anderen
Mikrocontroller über die SPI Schnittstelle die Anweisung die Motor
Drehrichtung zu setzen, oder Auskunft zu geben an den Mikrocontroller
über die aktuelle Drehrichtung.
Um im Interrupt auf Variablen zuzugreifen müssen diese ja als Volatile
deklariert werden. Wie ist das, wenn ich mit settern und gettern
arbeiten möchte wie hier die beiden Funktionen in motor.h
Müssen die dann ebenfalls VOLATILE sein?
Sind Funktionsaufrufe im Interrupt grundsätzlich OK oder kann es
Probleme geben, vielleicht wegen des Stacks?
Beste Grüße
Stephan
// ---------- motor.h --------------------
VOLATILE uint8_t get_motor_direction();
void set_motor_direction(VOLATILE uint8_t dir);
// ------------- motor.c ------------------
uint8_t motor_direction = 0;
volatile uint8_t get_motor_direction()
{
return motor_direction;
}
void set_motor_direction(volatile uint8_t dir)
{
motor_direction = dir;
}
// ------------ main.c ----------------------
ISR(SPI_STC_vect)
{
uint8_t SPI_received_byte = SPDR; // Zeichen von SPI einlesen
switch (SPI_received_byte)
{
case 1 :
do
{
SPDR = get_motor_direction();
} while (SPSR & (1<<WCOL));
break;
case 2 :
set_motor_direction(100);
}
}
Gast
#2769781
Variablen die NUR im Interrupt verwendet werden müssen nicht als volatile deklariert werden. Bei Variablen die im Interrupt und in der main verwendet werden muss der Zugriff atomar erfolgen und die Variablen als volatile gekennzeichnet werden. Funktionsaufrufe im Interrupt sind grundsätzlich OK.
Hallo ausfüllen, vielen Dank für deine hilfreiche Antwort! Weiß vielleicht noch jemand, ob es erforlich ist die setter- und getter- Funktionen mit VOLATILE zu kennzeichnen?
Stephan R. schrieb: > Weiß vielleicht noch jemand, ob es erforlich ist die setter- und getter- > Funktionen mit VOLATILE zu kennzeichnen? Dir scheint nicht klar zu sein, worin die Bedeutung des Schlüsselwortes 'volatile' liegt. http://www.mikrocontroller.net/articles/FAQ#Was_hat_es_mit_volatile_auf_sich Sobald dir das klar ist UND du verstanden hast, dass ein C Compiler nicht einfach mir nichts dir nichts Funktionsaufrufe wegoptimieren kann/darf sollte sich deine Frage ganz von alleine beantworten. NB: Es gibt nicht mal eine Syntax, mit der man Funktionen als volatile markieren könnt.
Karl Heinz Buchegger schrieb: > Sobald dir das klar ist UND du verstanden hast, dass ein C Compiler > nicht einfach mir nichts dir nichts Funktionsaufrufe wegoptimieren > kann/darf Wenn der Compiler den Inhalt einer Funktion kennt, oder sie als frei von Seiteneffekten deklariert ist (C++, in C evtl. nur bei gcc möglich), dann darf er. Funktionen sind Code wie jeder andere auch. Wenn er Code als überflüssig erkennt, kann er ihn wegoptimieren, auch wenn er durch einen Funktionaufruf eingerahmt ist.
Karl Heinz Buchegger schrieb: > NB: Es gibt nicht mal eine Syntax, mit der man Funktionen als volatile > markieren könnt. Freilich geht das! Wir sind ja hier im GCC-Forum :-)
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
Allerdings will der TO die damit verbundene Semantik keinesfalls haben... Ergo: Ein volatile zu viel kann echt übel sein.
Gast
#2769985
A. K. schrieb: > Wenn der Compiler den Inhalt einer Funktion kennt, oder sie als frei von > Seiteneffekten deklariert ist (C++, in C evtl. nur bei gcc möglich), > dann darf er. Das gilt aber nur für statische Funktionen. Oliver
Gast
#2769989
ausfüllen schrieb: > Funktionsaufrufe im Interrupt sind grundsätzlich OK. aber langsam. Sobalt man eine Funktion in der Prozedur aufruft werden alle Register auf den Stack gesichter. Kosten zeit und speicher. Wenn man schon mehre funktionsaufrufe hat, dann ist es egal ob man noch ein paar mein reinschriebt.
Karl Heinz Buchegger schrieb: > NB: Es gibt nicht mal eine Syntax, mit der man Funktionen als volatile > markieren könnt. Wenn ich es auf den Punkt bringe ist meine Frage, ob man die folgenden 4 zur Unterscheidung großgeschriebenen "VOLATILE" auch weglassen könnte, oder ob dann die volatile-Eigenschaft verloren geht. Der Compiler erzeugt zumindest gleichlangen Code im AVR Studio, wenn ich einen oder alle dieser 4 "VOLATILE" entferne und gibt keine Warnungen aus. Weiß der Compiler also auch bei Weglassen der 4 "VOLATILE" nachher beim Funktionsaufruf in der ISR, dass der Zugriff auf die Variable volatile erfolgen soll? _______________________________________________________________ // ---------- motor.h -------------------- VOLATILE uint8_t get_motor_direction(); void set_motor_direction(VOLATILE uint8_t dir); // ------------- motor.c ------------------ volatile uint8_t motor_direction = 0; VOLATILE uint8_t get_motor_direction() { return motor_direction; } void set_motor_direction(VOLATILE uint8_t dir) { motor_direction = dir; }
volatile ist sinnvoll bei globale Variablen. Keine der von dir markierten Stellen bezieht sich auf eine globale Variable. Lass es einfach weg an den 4 genannten Stellen.
A. K. schrieb: > Karl Heinz Buchegger schrieb: >> Sobald dir das klar ist UND du verstanden hast, dass ein C Compiler >> nicht einfach mir nichts dir nichts Funktionsaufrufe wegoptimieren >> kann/darf > > Wenn der Compiler den Inhalt einer Funktion kennt, oder sie als frei von > Seiteneffekten deklariert ist (C++, in C evtl. nur bei gcc möglich), Wie deklarierst du eine Funktion als 'frei von Seiteneffekten'? Und gcc Erweiterungen lass ich da erst mal nicht zu. Reines ANSI-C > dann darf er. Funktionen sind Code wie jeder andere auch. Wenn er Code > als überflüssig erkennt, kann er ihn wegoptimieren, auch wenn er durch > einen Funktionaufruf eingerahmt ist. Aber erst mal muss er den Funktionskörper inlinen. Erst dann kann der Optimizer daran gehen und unnötigen Code eliminieren. D.h. der Funktionsaufruf findet konzeptionell immer statt - selbst dann, wenn er durchs inlinen eben 'physisch' nicht mehr statt findet.
Stephan R. schrieb: > Weiß der Compiler also auch bei Weglassen der 4 "VOLATILE" nachher beim > Funktionsaufruf in der ISR, dass der Zugriff auf die Variable volatile > erfolgen soll? Hast du den Link in die FAQ gelesen? volatile ist der Hinweis an den Optimizer, dass er es bei Zugriff auf Variablen nicht übertreiben darf. Wenn also überhaupt, dann macht es erst mal nur Sinn, sich den Kopf über die volatile Markierung von Variablen zu zerbrechen. Denn letzten Endes kommt es darauf an! Du willst in manchen Situationen einen garantierten Variablenzugriff erzwingen. Wo, in welcher Funktion der steht, ist völlig wurscht - du willst den Zugriff. Und wenn der Compiler die Funktion durch inlining auflöst, dann willst du immer noch den Zugriff erzwingen.
Oliver schrieb: > Das gilt aber nur für statische Funktionen. Nein. Es ist heute nicht selten, dass der einzelne Compilerlauf die Funktionen lediglich vorkompiliert und die Codeerzeugung im Linker erfolgt (link time code generation). Dort sind, was die Optimierung angeht, dann externe Funktionen mit statischen Funktionen ungefähr vergleichbar.
Karl Heinz Buchegger schrieb: > Aber erst mal muss er den Funktionskörper inlinen. Erst dann kann der > Optimizer daran gehen und unnötigen Code eliminieren. > D.h. der Funktionsaufruf findet konzeptionell immer statt - selbst dann, > wenn er durchs inlinen eben 'physisch' nicht mehr statt findet. Yep, und im Ergebnis verschwindet der Code dann u.U. ganz. Das ist wie mit Variablen und ihre Zugriffe. Die verschwinden u.U. auch ganz, obwohl der Zugriff formal im Quellcode stattfindet, grad wie der Funktionsaufruf formal im Quellcode statfindet. Ohne volatile kann aber der Variablenzugriff genauso verschwinden wie der komplette Code eines Funktionsaufrufs.
Karl Heinz Buchegger schrieb: > Und gcc Erweiterungen lass ich da erst mal nicht zu. Reines ANSI-C Was glaubst du wohl, warum ich "in C evtl. nur bei gcc möglich" reingeschrieben hatte? ;-)
Karl Heinz Buchegger schrieb: > D.h. der Funktionsaufruf findet konzeptionell immer statt - selbst dann, > wenn er durchs inlinen eben 'physisch' nicht mehr statt findet. Der Unterschied liegt anderswo: Funktionen haben im Sprachkonzept von C keinen Zustand, der sich irgendwie ohne Kenntnis des Compilers ändern könnte - bei Variablen hingegen ist das prinzipiell möglich und vorgesehen (nicht nur bei volatile, auch Aliasing geht in diese Richtung). Erst wenn man ein Szenario betrachtet, in dem der Code einer Funktion sich ohne Kenntnis des Compilers ad hoc ändern kann, wird volatile relevant. Sowas gibts natürlich, z.B. in Betriebssystemen, aber nicht direkt in C.
Gast
#2770067
Das Problem ist, das viele denken das volatile ändert irgendetwas im verhalten der ISR. Das ist aber nicht wirklich richtig. Der Code in der ISR ist auch ohne volatile korrekt und richtig. Ein Volatil erzeugt nur schlechtern Code und bringt hier eigentlich nur Nachteile. Damit sollte auch klar sein, das eine volatile funktion in der ISR überhaupt keinen sinn macht. Das Problem ist die Mainschleife, hier optimiert der compiler weil er nicht weiss das sich eine Variable ändert. Es reicht also vollkommen aus in der main auf die Variablen mit volatile zuzugreifen. (cast). Dieser code zieht zwar nicht schön aus, ist aber sogar effizenter. Das ganze gilt nur unter der Bedingung das man in der ISR kein SEI aufruft.
Peter II schrieb: > Es reicht also vollkommen aus > in der main auf die Variablen mit volatile zuzugreifen. (cast). Dieser > code zieht zwar nicht schön aus, ist aber sogar effizenter. Hey, super Idee! Scheint aber nicht zu funktionieren:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
Übersetzt sich so:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
Hier ist die Welt noch in Ordnung: x wird immer neu gelesen. Jetzt das Ganze mit Casting - so wie Du vorgeschlagen hast:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
Ausgabe:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
Hier wird x NICHT neu gelesen, sondern lediglich auf das Register r24 wiederholt zugegriffen. Oder mache ich was falsch? Gruß, Frank
Frank M. schrieb: > Oder mache ich was falsch? Ja. Du kannst volatile nicht einfach so casten. Was geht ist sowas:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
Ergebnis:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
Gast
#2770118
Frank M. schrieb: > Hier wird x NICHT neu gelesen, sondern lediglich auf das Register r24 > wiederholt zugegriffen. scheinbar lebt x nur im Register nicht im RAM damit ist das doch ok lege mal ein ISR mit zugriff auf X an, dann sollte sie im RAM liegen. Ich habe den cast so in der art gemacht if ((volatile uint8_t)x)
Gast
#2770120
ja Jörg Wunsch hat den richtige Cast - wusste auch nicht mehr genau wie der aussah. Am besten in einem Makro verstecken.
Jörg Wunsch schrieb: > Ja. Du kannst volatile nicht einfach so casten. So hatte ich Peter aber verstanden ;-) > Was geht ist sowas: > if (*(volatile uint8_t *)&x) Wunderbar, gerade selbst getestet - klappt! Das erspart mir an vielen Stellen innerhalb von ISRs das Kopieren von volatile-Variablen in lokale Variablen, um den Zugriff zu optimieren. Tatsächlich muss man lediglich ausserhalb der ISR "suboptimieren" ;-) Gruß und Dank, Frank
Peter II schrieb: > Am besten in einem Makro verstecken. Du meinst, sowas hier? ;-)
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
Gast
#2770146
Jörg Wunsch schrieb: > Du meinst, sowas hier? ;-) ja danke, ganz vergessen das so soetwas wie typeof in C ja auch gibt.
Jörg Wunsch schrieb: > Du meinst, sowas hier? ;-) >
1 | |
2 | |
Sehr schön, nur "x" ist hier speziell als Makro-Argument verwirrend, weil die Variable x den gleichen Namen hat. Besser also:
1 | |
Gast
#2770157
jetzt stellt sich aber noch die Frage was bei
1 | |
2 | |
3 | |
passiert. kann es passierne das die änderung an X noch nicht im Ram landen?
Peter II schrieb: > jetzt stellt sich aber noch die Frage was bei > >
1 | |
2 | |
3 | |
4 | |
> > passiert. kann es passierne das die änderung an X noch nicht im Ram > landen? Scheint zu klappen:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
Der Wert von x wird im Ram zurückgespeichert. Aber ob man sich darauf verlassen kann?
Jörg Wunsch schrieb: > #define MAKEVOLATILE(x) (*(volatile typeof(x) *)&(x)) Ich freue mich sehr über die vielen kompetenten Antworten und Ideen. Danke! Grüße, Stephan
Frank M. schrieb: > Der Wert von x wird im Ram zurückgespeichert. Aber ob man sich darauf > verlassen kann? Der x++-Zugriff ist nicht volatile und das alles hat zudem das Problem, daß es nicht atomar ist. Und m.E. sind solche Casts purer Hack den man vermeiden sollte. Für jede Formulierung mit diesem Hack gibt es auch eine saubere Formulierung ohne.
Gast
#2770193
Eine Variable, die an sich nicht volatile ist, an gewissen Stellen per cast volatile zu machen, ist nicht die feine Art. Das habe ich so noch nicht gesehen. Manchmal ist man halt der Gnade des Compilers ausgeliefert oder man hat irgend etwas falsch gemacht.
Gast
#2770232
Coder schrieb: > Eine Variable, die an sich nicht volatile ist, an gewissen Stellen per > cast volatile zu machen, ist nicht die feine Art. Das habe ich so noch > nicht gesehen. das liegt aber nur daran das es nichts besseres in C gibt. Und speziell auf dem AVRs wo man schon ein wenig auf CPU leistung achten sollte finde ich diese sehr sinnvoll. Warum alle zugriffe auf eine Variabel volatile machen und damit wesentlich schlechteren code erzeugen, wenn du eine davon stelle davon ausreichen würde. Das Kopieren in Temp variabel ist doch auch nur eine krücke.
Johann L. schrieb: > Der x++-Zugriff ist nicht volatile und das alles hat zudem das Problem, > daß es nicht atomar ist. Das ist mir klar. Er ist aber auch nicht atomar, wenn man die Variable von vornherein als volatile definiert. > Und m.E. sind solche Casts purer Hack den man vermeiden sollte. Also doch lieber volatile-Variablen auch volatile definieren und in der ISR dann die volatile-Variable, die u.U. mehrfach in dieser ISR benötigt werden, in eine lokale Variable kopieren (und gegegebenenfalls am Ende zurückkopieren) - so wie es überall gepredigt wird?
Gast
#2770242
Ich finde diese Tatsache auch sehr interessant. Hab bisher auch Variablen als volatile markiert (ohne gezielten Cast) weil ich nicht wusste dass eine ISR eine Variable immer neu lädt und schreibt. Kann man das Makro denn noch erweitern, um den Zugriff in der Main atomar durchzuführen? Da (zumindest beim AVR) im normalfall eine ISR nicht durch eine weitere unterbrochen wird wäre der Zugriff in der ISR automatisch atomar und müsste nur in der main gezielt "atomar gecastet" werden.
Frank M. schrieb: > Johann L. schrieb: >> Und m.E. sind solche Casts purer Hack den man vermeiden sollte. > > Also doch lieber volatile-Variablen auch volatile definieren und in der > ISR dann die volatile-Variable, die u.U. mehrfach in dieser ISR benötigt > werden, in eine lokale Variable kopieren (und gegegebenenfalls am Ende > zurückkopieren) - so wie es überall gepredigt wird? Ja; zumindest ist das mein Favorit. Der Code wird dadurch u.U. sogar besser als mir dem volatile-Cast, etwa wenn Aliasing ins Spiel kommt. Zudem wird der volatile-Cast noch hässlicher, wenn man mit Zeigern hantiert, über die auf die Variable(n) zugegriffen wird.
@ Peter II (Gast) >> Eine Variable, die an sich nicht volatile ist, an gewissen Stellen per >> cast volatile zu machen, ist nicht die feine Art. Das habe ich so noch >> nicht gesehen. Ist auch Schrott. >das liegt aber nur daran das es nichts besseres in C gibt. Doch. Mach es einfach wie der Rest der Welt. Die Variable als volatile deklarieren. > Und speziell >auf dem AVRs wo man schon ein wenig auf CPU leistung achten sollte finde >ich diese sehr sinnvoll. Keine Sekunde. >Warum alle zugriffe auf eine Variabel volatile machen und damit >wesentlich schlechteren code erzeugen, Unsinn. > wenn du eine davon stelle davon >ausreichen würde. Unsinn die 2. Denn dann kann an einigen Stellen lokal optimiert werden und nichtvolatile zugegriffen werden, und dein "Konzept" geht baden. Nur weil es manchmal funktioniert, ist es noch lange nicht richtig. >Das Kopieren in Temp variabel ist doch auch nur eine >krücke. Nö, das ist solide. Und gängige Praxis. Wenn man die Grundlagen beim Thema Interrupt verstanden hat, löst sich dieses "Problem" in Luft auf. Dann hat man nämlich ein Minimum an Variablen, welche zwischen ISR und main kommunizieren und gut. Und das "verschwendet" auch keine CPU-Leistung sondern ist schlicht notwendig. Und bei dem richtigen Konzept auch kein Thema. Denn HIER liegt das eigentliche Problem des OP. Sein Konzept mit den Funktionen in der ISR und der SPI-Datenaufnahme und Verarbeitung ist schlecht. MfG Falk
@ Karlo (Gast) >Ich finde diese Tatsache auch sehr interessant. Hab bisher auch >Variablen als volatile markiert (ohne gezielten Cast) weil ich nicht >wusste dass eine ISR eine Variable immer neu lädt und schreibt. Das tut sie NICHT!
Gast
#2770359
Falk Brunner schrieb: > Das tut sie NICHT! klar tut sie das immer. eine ISR kann sich nichts in Registern merken. > >auf dem AVRs wo man schon ein wenig auf CPU leistung achten sollte finde > >ich diese sehr sinnvoll. > > Keine Sekunde. ohne tmp Variabel auf jeden Fall. volatile uint8_t x; if ( x == 12 ) { ... } if ( x == 14 ) { ... } if ( x == 18 ) { ... } if ( x == 20 ) { ... } das ist viel weniger code ohne volatile, und damit auch schneller. Klar ein Temp variable hilft hier. Aber ohne volatile spare ich mir die tmp variable.
Peter II schrieb: > Falk Brunner schrieb: >> Das tut sie NICHT! > > klar tut sie das immer. eine ISR kann sich nichts in Registern merken. Natürlich kann sie das. Falks Antwort bezog sich auf beliebige Variablen, nicht speziell auf volatiles.
Gast
#2770383
Frank M. schrieb: > Peter II schrieb: >> Falk Brunner schrieb: >>> Das tut sie NICHT! >> >> klar tut sie das immer. eine ISR kann sich nichts in Registern merken. > > Natürlich kann sie das. Falks Antwort bezog sich auf beliebige > Variablen, nicht speziell auf volatiles. Noch mal: Eine ISR kann sich "außerhalb" ihres aufrufes nichts in Register merken. Egal welche art von Variablen. Die ISR muss jeden Variabel aus dem Ram laden und damit auch am ende wieder in den Ram schreiben, wenn sie die variabel geändert hat.
Falk Brunner schrieb: > Denn HIER liegt das eigentliche Problem des OP. Sein Konzept mit den > Funktionen in der ISR und der SPI-Datenaufnahme und Verarbeitung ist > schlecht. Ich habe bisher im Interrupt nur die SPI-Daten angenommen und dann wie du vorschlägst für das Hauptprogramm ein Flag gesetzt, das die empfangenen Daten auswertet. Bei SPI Kommunikation ist es nun so, dass ich den uC für den Motor als SPI Slave betreibe. Dann kann er selber die Daten nicht aktiv verschicken sondern muß sehr schnell die Daten bereitstellen, so dass der Master mit seiner Clock Leitung die Daten "heraustakten" kann. Eine zusätzliche Interruptleitung zwischen SPI Master und dem "Motor-Slave-uC" gibt es nicht, daher wartet der Master einige uSec bis er die Daten vom Slave heraustaktet. Wenn der Slave die Daten nicht rechtzeitig bereitstellt merkt der Master gar nicht, dass er nur Müll empfangen hat. Um das zu verhindern will ich sofort im Interrupt antworten. Einzige Alternative die ich sehe wäre noch den Slave auf Master umzuschalten und die Daten aktiv zu senden. Ich bin mir noch nicht sicher ob das eine gute Idee ist, weil noch mehr Slaves an der SPI Schnittstele hängen.
Peter II schrieb: > Noch mal: > > Eine ISR kann sich "außerhalb" ihres aufrufes nichts in Register merken. > Egal welche art von Variablen. Die ISR muss jeden Variabel aus dem Ram > laden und damit auch am ende wieder in den Ram schreiben, wenn sie die > variabel geändert hat. Das ist natürlich selbstverständlich, das kann auch keine andere stinknormale Funktion in C. Karlo schrieb aber was anderes: >Ich finde diese Tatsache auch sehr interessant. Hab bisher auch >Variablen als volatile markiert (ohne gezielten Cast) weil ich nicht >wusste dass eine ISR eine Variable immer neu lädt und schreibt. Das liest sich so, als ob speziell in ISRs Variablen vom Compiler prinzipiell wie volatiles behandelt werden würden: "immer neu lädt und schreibt" ^^^^^ (also bei jedem Zugriff) Diese generelle Aussage stimmt so nicht.
Peter II schrieb: > ja danke, ganz vergessen das so soetwas wie typeof in C ja auch gibt. In Standard-C gibts das auch nicht. Aber in GCC.
Gast
#2770422
Frank M. schrieb: > Das ist natürlich selbstverständlich, das kann auch keine andere > stinknormale Funktion in C. main ist auch eine normale funktion - aber diese wird halt nicht verlassen. Damit kann sich der compieler die Freiheit nehmen variablen in Registern vorzuhalten, das ganze betrifft dann auch unterfunktionen von main, denn hier kann er sie inlinen und damit auch den zugriff auf den Ram sparen.
@ Peter II (Gast) >Eine ISR kann sich "außerhalb" ihres aufrufes nichts in Register merken. >Egal welche art von Variablen. Falsch. Lokale Variablen, welche static sind ;-)
Gast
#2770459
Falk Brunner schrieb: > Falsch. Lokale Variablen, welche static sind ;-) wie soll ich das nun wieder verstehen? Dir ist doch bestimmt klar das sie auch nur im Ram liegen.
Peter II schrieb: > volatile uint8_t x; > > if ( x == 12 ) { ... } > if ( x == 14 ) { ... } > if ( x == 18 ) { ... } > if ( x == 20 ) { ... } > > das ist viel weniger code ohne volatile, und damit auch schneller. Klar > ein Temp variable hilft hier. Aber ohne volatile spare ich mir die tmp > variable. Das spart dir noch viel mehr Quellcode:
1 | |
Wozu das ganze Leerzeichen-Geraffel??? Kost nur Zeit beim Tippen!
Gast
#2770465
Johann L. schrieb: > Wozu das ganze Leerzeichen-Geraffel??? > Kost nur Zeit beim Tippen! Sache die nur einmal gemacht werden( tippen) müssen nicht schnell gehen, bei dingen die sicher oft wiederholen (ausführung) sollte man schon darauf achten.
@ Stephan R. (stero) >Ich habe bisher im Interrupt nur die SPI-Daten angenommen und dann wie >du vorschlägst für das Hauptprogramm ein Flag gesetzt, das die >empfangenen Daten auswertet. Schon mal gut. >Bei SPI Kommunikation ist es nun so, dass ich den uC für den Motor als >SPI Slave betreibe. Dann kann er selber die Daten nicht aktiv >verschicken sondern muß sehr schnell die Daten bereitstellen, Dass der AVR als SPI-Slave nicht so toll ist, ist bekannt. >"Motor-Slave-uC" gibt es nicht, daher wartet der Master einige uSec bis >er die Daten vom Slave heraustaktet. OK. > Wenn der Slave die Daten nicht >rechtzeitig bereitstellt merkt der Master gar nicht, dass er nur Müll >empfangen hat. Um das zu verhindern will ich sofort im Interrupt >antworten. Dein 1. Interrupt bekommt ja auch ein paar µS vom Master, warum nicht bei den nachfolgenden Bytes? Ausserdem scheint mir in deinem geposteten Coebesipiel dennoch deutlich mehr las nur die reine Datenübertragung drin zu sein. Funktionsaufrufe in ISRs sind beim AVR auch nicht so toll, wegen der Performance (der GCC sichert sehr viele Register). >Einzige Alternative die ich sehe wäre noch den Slave auf Master >umzuschalten und die Daten aktiv zu senden. Das ist Murks. Bei SPI gibt es nur einen Master, und der ist fest vorgegeben.
@ Peter II (Gast) >wie soll ich das nun wieder verstehen? Dir ist doch bestimmt klar das >sie auch nur im Ram liegen. Praktisch schon, zwingend aber nicht. Ein Compiler kann die auch in Registern halten, auch wenn das real fast nie passiert. Es ist auch selten sinnvoll, als C-Programmierer derartig spezifische Annahmen über die Umsetzung des Compilers zu machen. Die Regeln und der Sinn von volatile sind klar definiert, die diversen Vorschläge sind nur Hackertricks mit vielen Nachteilen und wenigen Vorteilen.
Gast
#2770532
Falk Brunner schrieb: > Praktisch schon, zwingend aber nicht. was aber auch egal ist, dann man kann eh nicht von außen auf sie zugreifen. > Die Regeln und der Sinn von > volatile sind klar definiert, die diversen Vorschläge sind nur > Hackertricks mit vielen Nachteilen und wenigen Vorteilen. nachteil das ich ein Makro verwenden muss? sonst sehen ich keinen nachteil. Oder meinst du als nachteil das es ziemlich GCC und Atmega spezifisch ist, wenn ja kann ich gut damit leben. Ich sehe die Hauptverwendung von volatile bei den IO-Register dort muss jeder zugriff auf die register sofort gemacht werden, bei variablen entscheide ich im einzelfall wie ich es mache.
Peter II schrieb: > Johann L. schrieb: >> Wozu das ganze Leerzeichen-Geraffel??? >> Kost nur Zeit beim Tippen! > > Sache die nur einmal gemacht werden (tippen) müssen nicht schnell gehen, > bei dingen die sicher oft wiederholen (ausführung) sollte man schon > darauf achten. Genau wie bei volatile-Hack auch. Der Spart Tipparbeit, denn: Johann L. schrieb: > Für jede Formulierung mit diesem Hack gibt es auch eine saubere > Formulierung ohne. Und noch präziser: Für jede Formulierung mit diesem Hack gibt es auch eine saubere Formulierung ohne, die zudem mindestens genauso effizient ist. Es geht nur darum ein paar Zeilen Tipparbeit zu sparen.
Gast
#2770584
Peter II schrieb: > Warum alle zugriffe auf eine Variabel volatile machen und damit > wesentlich schlechteren code erzeugen, wenn du eine davon stelle davon > ausreichen würde. Das Kopieren in Temp variabel ist doch auch nur eine > krücke. Mit einer Kopie zu Arbeiten ist sprachlich sauberer. Ich persönlich überlasse es dem Compiler optimalen Code zu erzeugen, denn der Compiler ist meist besser als ich. Zum Anderen finde ich aus konzeptioneller unlogisch eine normale Variable zu einem volatile Typ zu casten. Tipparbeit sollte man sich nicht ersparen, denn solche Kniffe holen irgendwann mal einen ein.
Falk Brunner schrieb: > Dein 1. Interrupt bekommt ja auch ein paar µS vom Master, warum nicht > bei den nachfolgenden Bytes? Ich bin mir nicht ganz sicher ob ich dich richtig verstehe. Wenn ich die Antworten an den Master erst aus dem Hauptprogramm verschicken würde, nachdem dort Flag-gesteuert der Kommandointerpreter ausgeführt wird, dann vergeht evtl. ziemlich viel Zeit. Mehr als ein paar uSec. Der Master müßte profilaktisch solange warten, wie maximal ein Hauptprogramm Schleifendurchlauf dauert. Gut jetzt könnte man auf dem Master per Timer warten und pauschal z.B. 20mSec verstreichen lassen, bevor der Master das Byte abholt... Im Moment sehe ich vor, vom Master ein Kommando an den Motor-Slave zu senden, der dann ein Byte innerhalb weniger uSec zurückgibt. Wenn die Daten sofort im Interrupt über z.B. get_motor_direction() beschafft werden können, dann kann ich sie auch sofort noch im Interrupt wegschicken und bin mir sicher, dass nicht mehr als ein paar uSec verstrichen sind. Nachteilig ist dabei, das eben viele Variablen als Volatile gekennzeichnet werden müssen. Wie ich oben gelernt habe müssen aber wenigstens nicht die Funktionen auch noch mit volatile gekennzeichnet werden, das erleichtert das Ändern der Motor-Bibliothek. > Ausserdem scheint mir in deinem geposteten > Codebeispiel dennoch deutlich mehr als nur die reine Datenübertragung > drin zu sein. Funktionsaufrufe in ISRs sind beim AVR auch nicht so toll, > wegen der Performance (der GCC sichert sehr viele Register). Ja wahrscheinlich ist es besser auf die getter und setter Funktionen der Motor-Bibliothek zu verzichten und direkt z.B. die Variable für die Motordrehrichtung zu schreiben. Die muß dann natürlich auch in Volatile geändert werden und mittels extern noch veröffentlich werden. Ich könnte auch einen Hybrid machen, dass ich in der Interruptfunktion nur Rückgabewerte an den Master sofort bearbeite und alle anderen Befehle per Flag im Hauptprogramm. Da ich für das Senden der Infos zum Master sowieso fast alle Variablen als Volatile deklarieren muß, kann ich aber auch gleich die Befehle ohne Rückangwort an den Master im Interrupt ausführen. >>Einzige Alternative die ich sehe wäre noch den Slave auf Master >>umzuschalten und die Daten aktiv zu senden. > Das ist Murks. Bei SPI gibt es nur einen Master, und der ist fest > vorgegeben. OK, dann werde ich das auch wohl sein lassen :) Wäre das so eine ordentliche Lösung?
Gast
#2770592
Coder schrieb: > Mit einer Kopie zu Arbeiten ist sprachlich sauberer. Ich persönlich > überlasse es dem Compiler optimalen Code zu erzeugen, denn der Compiler > ist meist besser als ich. das ist doch ein wiederspruch in sich. Wenn der compiler optimalen code erzeugen würden, dann bräuchte man keine hilfsvariable, sonder könnte es schreiben wie ich es will. > Tipparbeit sollte man sich nicht ersparen, denn solche Kniffe holen > irgendwann mal einen ein. bis jetzt hat noch niemand einen wirklichen nachteil dieser Lösung genannt.
Gast
#2770632
Peter II schrieb: > das ist doch ein wiederspruch in sich. Wenn der compiler optimalen code > erzeugen würden, dann bräuchte man keine hilfsvariable, sonder könnte es > schreiben wie ich es will. Ich möchte gar nicht abstreiten, dass die oben genannte Lösung in deiner Konstellation schnelleren Code liefert. Und ich habe auch kein Problem damit, den Inhalt einer volatile-Variable in einer Hilfvariable zu kopieren. Das ist Formal sauber. Aber ich denke, dass meine Aussage ist kein Widerspruch ist. Es eine Frage wie man die Sprache einsetzt und seine Funktionen programmiert. Denn die Leute, die den Compiler programmiert haben, sind ganz bestimmt besser als Ich (man muss die Optimierungen natürlich einschalten). IMHO deklariert man eine Variable so, wie man sie verwenden möchte; Also sie entweder volatile oder nicht.
Gast
#2770642
Coder schrieb: > Aber ich denke, dass meine Aussage ist kein Widerspruch ist. Es eine > Frage wie man die Sprache einsetzt und seine Funktionen programmiert. > Denn die Leute, die den Compiler programmiert haben, sind ganz bestimmt > besser als Ich (man muss die Optimierungen natürlich einschalten). leider stimmt das so nicht immer. schönes Beispiel:
1 | |
2 | |
3 | |
hier verwendet der compiler einen float vergleich - schön langsam auf einem AVR. > IMHO deklariert man eine Variable so, wie man sie verwenden möchte; Also > sie entweder volatile oder nicht. ich will ja nicht das er in der ISR die variabel als volatile ansieht, das ist ja das Problem. Eventuell könnte man ja die ISR in eine extra C datei auslagern und die variabel in der main als volatile deklarieren. Also 2 verschiende deklarationen für die gleiche Variable.
Gast
#2770668
Also floats sind auf jedem uC immer langsam, die nativ keine Fließkommazahlen können! (1) Also Variablen, die Du in deiner ISR verwendest UND "parallel" zur ISR-Context von deiner main verwendet werden, müssen als volatile deklariert werden. (2) Wenn Du in deiner main() auf Variablen zugreifst die auch die ISR verwendet, solltest Du indirekt darauf zugreifen, z.B. über die Get- und Set-Routinen. Weil in den Get- und Set-Routinen muss sichergestellt werden, dass während des Zugriff in der main die ISR zuschlägt und ausgerechnet die Variable ändert, die Du gerade bearbeitest. (3) Wenn Du natürlich die gesamte Ansteuerung des Motor über die ISR machst, benötigst Du kein volatile. Dann sollte aber alles in einem modul sein.
Coder schrieb: > (2) Wenn Du in deiner main() auf Variablen zugreifst die auch die ISR > verwendet, solltest Du indirekt darauf zugreifen, z.B. über die Get- und > Set-Routinen. Weil in den Get- und Set-Routinen muss sichergestellt > werden, dass während des Zugriff in der main die ISR zuschlägt und > ausgerechnet die Variable ändert, die Du gerade bearbeitest. 16 Bit Variablen werde ich dann mit ATOMIC_BLOCK in der Bibliothek und im Hauptprogramm schützen. Bei den 8-Bit Werten kann ich vorraussichtlich darauf verzichten. Ich weiß, dass man auch bei 8-Bit aufpassen muß z.B. bei &= und |= Operationen. > (3) Wenn Du natürlich die gesamte Ansteuerung des Motor über die ISR > machst, benötigst Du kein volatile. Dann sollte aber alles in einem > modul sein. Der Motor ist ein Brushless-Typ. Die Treibersoftware erstreckt sich über viele verschiedene Files. Also leider nichts, was so in die ISR passen würde.
Gast
#2770715
Abschließend mal ganz was anderes. Wie wäre es alternativ mit einer Commando Queue, also einer FIFO über die dein Program mit deinem Treiber kommuniziert? Könnte der "Rest" deiner Motor-Treiber-Firmware dann so funktionieren, dass das Ergebnis über die "Commando-Queue" weitergibt, so dass die Steueralgorhitmen nicht auf den Motor-Hardware direkt zugreift? Ansonsten habe ich auch keine Idee mehr.
Coder schrieb: > Wie wäre es alternativ mit einer Commando Queue, also einer FIFO über > die dein Program mit deinem Treiber kommuniziert? Könnte der "Rest" > deiner Motor-Treiber-Firmware dann so funktionieren, dass das Ergebnis > über die "Commando-Queue" weitergibt, so dass die Steueralgorhitmen > nicht auf den Motor-Hardware direkt zugreift? Wenn die schnelle Variante im Interrupt nicht sauber funktioniert, wäre das noch eine Alternative.
Peter II schrieb: > Falk Brunner schrieb: >> Praktisch schon, zwingend aber nicht. > > was aber auch egal ist, dann man kann eh nicht von außen auf sie > zugreifen. > >> Die Regeln und der Sinn von >> volatile sind klar definiert, die diversen Vorschläge sind nur >> Hackertricks mit vielen Nachteilen und wenigen Vorteilen. > > nachteil das ich ein Makro verwenden muss? sonst sehen ich keinen > nachteil. Der Nachteil ist, dass du den Einsatz des Makros vergessen kannst. Mit entsprechenden Auswirkungen auf das Programm. Vergisst du in der Umkehrung das Umkopieren in eine temporäre Variable, dann ist das Programm immer noch korrekt, wenn auch ein wenig langsamer. Im Sinne der defensiven Programmierung nehme ich lieber die Variante, die mir einen Fehler verzeiht bzw. die Variante, bei der ich weniger schwerwiegende Fehler machen kann.
Gast
#2770852
Karl Heinz Buchegger schrieb: > Der Nachteil ist, dass du den Einsatz des Makros vergessen kannst. > Mit entsprechenden Auswirkungen auf das Programm man kann auch das volatile vergessen. Davor warnt einem auch niemand, als Programmieren sollte man halt schon ein wenig wissen was man macht.
Gast
#2770905
Peter II schrieb: > man kann auch das volatile vergessen. > > Davor warnt einem auch niemand, als Programmieren sollte man halt schon > ein wenig wissen was man macht. Man kann sich auch vorher Gedanken, von welchen Typ die Variable sein sollte. Je weniger typecasts man machen muss, desto besser. Und defensives Programmieren ist nicht immer langsamer. Ich kann nur nochmal betonen: die Optimierer der Compiler i.d.R. besser sind , als man selbst. Man muss seinen Code so schreiben, dass der Compiler Optimierungsstrategien anwenden kann. Und bevor man anfängt wild zu optimieren, sollte das Programm erstmal funktionieren.
Gast
#2770932
Coder schrieb: > Und bevor man anfängt wild zu > optimieren, sollte das Programm erstmal funktionieren. ob ich nun schreibe
1 | |
2 | |
3 | |
4 | |
oder gleich schreibe
1 | |
2 | |
3 | |
4 | |
5 | |
ist der gleiche aufwand und gleich stark optimiert. Beides läuft (hoffentlich) fehlfrei. Nur weil ich ein I7 habe mache ich immer noch gedanken über die Programmlaufzeit. Jeder Optimiert bei der Programmierung, die frage ist nur auf welchen Level.
Gast
#2771285
Peter II schrieb: > Jeder Optimiert bei der Programmierung, die frage ist nur auf welchen > Level. Ja natürlich. Und abschließend Wenn der Optimierer aktiv ist, liefern folgende Beispiele
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
sowie
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
denselben Asssembler Code. Für den übersetzten Code macht es nichts, ob man eine Temp Variable verwendet. Es ist aber sprachlich sauber und vorzuziehen. Der volatile-cast-hack ist absolut unnötigt und ist fehlerträchtig. Aber das muss du für Dich entscheiden. Einen schönen Tag noch.
Gast
#2771301
Coder schrieb: > denselben Asssembler Code. Für den übersetzten Code macht es nichts, ob > man eine Temp Variable verwendet. Es ist aber sprachlich sauber und > vorzuziehen. Der volatile-cast-hack ist absolut unnötigt und ist > fehlerträchtig. noch einmal, es geht mir nicht um die main! Mich stört die volatile zugriff in der ISR, wenn ich die Variabel als voltile kennzeichne. Um das zu umgehen muss ich dort mit einer Tmp variable arbeiten. Damit hat das beispiel leider das thema verfehlt. Ich möchte die globale variable in der ISR normal haben und in allen andere funktionen volatile.
@Coder: Gib's einfach auf. Wer nix dazulernen will, der will eben nix dazulernen...
Gast
#2771453
Hm. Habe ich mich wirklich so schlecht ausgedrückt? Habe ich das wirklich falsch verstanden? 1) Dem Threadersteller hatte ich kurz und knapp geschrieben, wie man meines Erachtens mit volatile deklarierten Variablen umgeht. Also wie man Variablen verfahren sollte, die sich eine ISR-Context und Main-Context bzw. mehrere Threads teilen. Wenn jemand eine andere bessere Lösung hat, darf er diese gerne mitteilen. 2) Peter II sagt in seinen vorhergehenden Postings Peter II schrieb: > Warum alle zugriffe auf eine Variabel volatile machen und damit > wesentlich schlechteren code erzeugen, wenn du eine davon stelle davon > ausreichen würde. Das Kopieren in Temp variabel ist doch auch nur eine > krücke. a)Also vermute ich, er möchte deswegen wohl in seiner ISR seine Variablen per default nicht als volatile deklarieren , weil er befürchtet es sei zu langsam, zu schlechter? Diese Variablen braucht er aber in anderen Funktionen (oder Module?) als volatile? b)Hatte ich ich nicht geschrieben, dass meines Erachtens eine Variable entweder immer volatile ist oder nicht volatile ist, und dass das ein ganz schlechtes Konzept ist? Und ich stattdessen zu einer Lösung wie 1) tendiere. c)Hatte ich Peter II mit meinem Beispiel nicht versucht zu überzeugen, dass im Zweifel eine punktuelle Optimierung der Compiler durchaus selber hinkriegt, wenn die Optimierungen eingeschaltet sind?
Gast
#2771473
Coder schrieb: > Hatte ich Peter II mit meinem Beispiel nicht versucht zu überzeugen, > dass im Zweifel eine punktuelle Optimierung der Compiler durchaus selber > hinkriegt, wenn die Optimierungen eingeschaltet sind? das Beispiel war unsinn, das hier das gleich rauskommt ist absolut klar. > Hatte ich ich nicht geschrieben, dass meines Erachtens eine Variable > entweder immer volatile ist oder nicht volatile ist, und dass das ein > ganz schlechtes Konzept ist? Und ich stattdessen zu einer Lösung wie 1) > tendiere. ja geschrieben haben wir alles viel, aber das sagt nicht das es immer das richtige ist. Fakt ist das man das volatile nicht in der ISR braucht und es dort (ohne die zustätzelichen Temp Variablen ) zu schlechter optimierten code führt. Fakt ist auch das man ein volatile zugriff in alles anderen funktionen braucht. Damit hat man die Möglichkeiten: - die variable als volatile kennzeichen und Perfomance verlust in kauf nehmen. - die variabel als voaltile kennzeichen und Temp variabel einführen und damit eine doppelete Datenhaltung haben - was auch zu fehler führen kann. - variable nicht volatile machen und einen cast in den NICHT-isr funktionen machen. (darf man nur nicht vergessen) Ich habe alles schon verwendet, weil es verschiedene Anforderungen gibt. Die erste lösung ist die "schönste" aber halt nicht die schnellste, und dafür gibt es ebend 2 alternativen.
Gast
#2771475
Belassen wir es einfach.
Peter II schrieb: > - die variable als volatile kennzeichen und Perfomance verlust in kauf > nehmen. Bleibt die Frage bestehen, ob diese Performanceverluste auch nur in irgendeiner Weise relevant sind - was natürlich davon abhängt, wie oft die ISR so typischerweise aufgerufen wird und wie schnell in der ISR auf irgendwas reagiert werden soll. Um mehr als eine Handvoll Takte wird es jedenfalls nicht gehen.
Coder schrieb: > Hm. Habe ich mich wirklich so schlecht ausgedrückt? Nö. > Habe ich das wirklich falsch verstanden? Ja. Ich meinte nicht dich, sondern deinen Kommunikationspartner. Und das es offenbar nicht lohnt, sich die Finger fusselich zu tippen, wenn eh alles abperlt. > 1) Dem Threadersteller hatte ich kurz und knapp geschrieben, wie man > meines Erachtens mit volatile deklarierten Variablen umgeht. Also wie > man Variablen verfahren sollte, die sich eine ISR-Context und > Main-Context bzw. mehrere Threads teilen. Wenn jemand eine andere > bessere Lösung hat, darf er diese gerne mitteilen. > > 2) Peter II sagt in seinen vorhergehenden Postings > > Peter II schrieb: >> Warum alle zugriffe auf eine Variabel volatile machen und damit >> wesentlich schlechteren code erzeugen, wenn du eine davon stelle davon >> ausreichen würde. Das Kopieren in Temp variabel ist doch auch nur eine >> krücke. > > a)Also vermute ich, er möchte deswegen wohl in seiner ISR seine > Variablen per default nicht als volatile deklarieren, weil er > befürchtet es sei zu langsam, zu schlechter? Diese Variablen braucht er > aber in anderen Funktionen (oder Module?) als volatile? Ja. Eine Variable ist entweder volatile oder nicht volatile. Wenn einem die 1 Zeile zum Anlegen einer lokalen Variable zu viel ist, dann machen manche eben lieber einen Hack[tm] mit dem Pointer-Cast, der • Schlechter Stil ist, z.B. im Hinblick auf Wartbarkeit und passive Programmierung • Keine bessere Performance hat als die saubere Lösung • U.u. sogar schlechtere Performance hat, siehe die Anmerkung zu Aliasing • Noch wüstere Makros erfordert wenn man mit Zeigern hantiert – und mit dem Cast dann mit Zeigern auf Zeigern und irgendwo das volatile reinfutscheln muss • Kein Standard-C ist sondern eine GNU-Erweiterung (typeof) • Ohne typeof sieht der Code noch "expertiger" aus • Der Performance-Verlust wahrscheinlich eh schnuppe ist, nach dem Motto "Herr Compiler, ich weiß da was besser und machn Experten-Hack" d.h. die Optimierung fällt in die Kategorie "Pyschologische Optimierung" bzw. "Angstoptimierung". > b)Hatte ich ich nicht geschrieben, dass meines Erachtens eine Variable > entweder immer volatile ist oder nicht volatile ist, und dass das ein > ganz schlechtes Konzept ist? > Und ich stattdessen zu einer Lösung wie 1) tendiere. Seh ich auch so. > c)Hatte ich Peter II mit meinem Beispiel nicht versucht zu überzeugen, > dass im Zweifel eine punktuelle Optimierung der Compiler durchaus selber > hinkriegt, wenn die Optimierungen eingeschaltet sind? Versucht schon...
Gast
#2771570
Johann L. schrieb: > Wenn einem die 1 Zeile zum Anlegen einer lokalen Variable zu viel ist dann habe ich 2 Variabelen dir irgendwie gleich sind aber dann doch nicht. > Der Performance-Verlust wahrscheinlich eh schnuppe ist, nach dem > Motto "Herr Compiler, ich weiß da was besser und machn Experten-Hack" > d.h. die Optimierung fällt in die Kategorie "Pyschologische > Optimierung" bzw. "Angstoptimierung". es zwingt euch niemand es so zu machen. Und ich bin wirklich nicht überzeugt von der Qualtität der optimierung des compilers (ich könnte aber auch keinen besseren schreiben!) und schaue mit kritische codesequenzen gerne im ASM code an und versuche dann die code so zu umzuschreiben das es der compiler es begreift.
Johann L. schrieb: > Ja. Ich meinte nicht dich, sondern deinen Kommunikationspartner. Und das > es offenbar nicht lohnt, sich die Finger fusselich zu tippen, wenn eh > alles abperlt. Dann hör lieber auch auf damit. Ich habs schon gestern aufgegeben. Peter weiß es immer besser und schreibt auch jedesmal eine neue Antwort darauf, wo immer dasselbe drin steht. Beton bleibt Beton.
Gast
#2771621
Frank M. schrieb: > Ich habs schon gestern aufgegeben. Peter > weiß es immer besser und schreibt auch jedesmal eine neue Antwort > darauf, wo immer dasselbe drin steht. als ob eure Argumente sich ändern würden. Ich sehen wenigsten ein das es mehre wege zum Ziel gibt.
So, die Motorsteuerung läuft jetzt einwandfrei gesteuert aus dem SPI-Interrupt heraus. Im Interrupt rufe ich nun die Setter und Getter des Motortreibers auf. Die Variablen, auf die die Setter und Getter zugreifen sind jetzt alle als Volatile deklariert. Die Antworten an den SPI-Master gehen auch sauber raus. Ich habe im Master erstmal eine Wartezeit von 10uSec auf den Slave eingestellt, sicher geht auch noch weniger. Das Makro hätte mir auch keine Änderung am Motortreiber erspart, deswegen nehme ich solange es die Performance zuläßt die althergebrachte Lösung. Wenn es performancekritisch wird, werde ich mich sicher an das Cast-Macro erinnern. Umkopieren der Volatile Variablen mit mehreren Zugriffen im Interrupt mit dem Ziel, das der Compiler schnell darauf zugreifen kann, ist wohl immer eine gute Idee, wenn Performance nicht völlig unwichtig ist.
Peter II schrieb: > Und ich bin wirklich nicht überzeugt von der Qualtität der optimierung > des compilers Weder bei der Cast-Variante noch bei der Variante mit der temporär-Variable handelt es sich um eine Optimierung, die ein Compiler ausführt, denn beide ändern die Semantik des Programms. Der Compiler ist natärlich and die Semantik der Sprachspezifikation gebunden — ansonsten wäre er ziemlich sinnfrei. Für Optimierungen, die die Semantik des Programmes ändern, ist also der Programmierer verantwortlich. Anderes Beispiel wäre die Auswahl eines Sortieralgorithmus': Verlangt man vom Compiler ein qsort, wird er ein qsort einbauen. Wenn man einen anderen Algorithmus möchte, muss man selbst Hand anlegen an den Code. Und zwar an den Code der Anwendung, nicht an den des Compilers. Und beim Handanlegen hat eben jeder unterschiedliche Qualitätsmaßstäbe und daran wie der resultierende Code formal aussehen sollte — auch wenn er wie beim obigen Beispiel zum gleichen Binärcode führt (modulo Aliasing). Falls du dich auf Optimerungen in Reichweite des Compilers beziehst: GCC is Free Software. Anybody can contribute. Patches welcome.
Johann L. schrieb: > Für Optimierungen, die die Semantik des Programmes ändern, ist also der > Programmierer verantwortlich. Manchmal aber dann doch auch der des Compiler. Immerhin ist schon Benchmark-Beschiss aufgeflogen, bei denen der Compiler klammheimlich den Algorithmus "modifiziert" hat, weil er das Pattern des Benchmarks erkannte und den Code passend durch eine schnellere Variante ersetzte.
Gast
#2771762
Johann L. schrieb: > Für Optimierungen, die die Semantik des Programmes ändern, ist also der > Programmierer verantwortlich. warum optimiert er dann nicht [c] int a; if ( a > 0.1 ) { }; [\c] laut C muss er den vergleich mit float machen. Aber wenn der sicherstellen kann das das ergebniss gleich ist darf er optimieren. Damit könnte er hier ein int vergleich machen - tut er aber nicht weil es ein dummer compiler ist.
A. K. schrieb: > Johann L. schrieb: >> Für Optimierungen, die die Semantik des Programmes ändern, ist also der >> Programmierer verantwortlich. > > Manchmal aber dann doch auch der des Compiler. Immerhin ist schon > Benchmark-Beschiss aufgeflogen, bei denen der Compiler klammheimlich den > Algorithmus "modifiziert" hat, weil er das Pattern des Benchmarks > erkannte und den Code passend durch eine schnellere Variante ersetzte. GCC?
Gast
#2771778
@Peter II Na weil a sich zur Laufzeit ändert. Und das kann kein Compiler. @Stephan R. Schön zu hören dass es funktioniert. @Johann Ich habs' nicht auf mich bezogen. Die Fragen waren eher rhetorisch, weil Peter II mich mit seinen "Optimierungen" zum verzweifeln bringt (ich bin bestimmt kein C-Guru und verzapfe auch viel Mist)
Gast
#2771789
Coder schrieb: > @Peter II > Na weil a sich zur Laufzeit ändert. Und das kann kein Compiler. nein der code ändert sich nicht zu laufzeit!
1 | |
2 | |
er sollte selber auf die idee kommen:
1 | |
2 | |
Peter II schrieb: > Johann L. schrieb: >> Für Optimierungen, die die Semantik des Programmes ändern, ist also der >> Programmierer verantwortlich. > > warum optimiert er dann nicht >
1 | |
2 | |
> laut C muss er den vergleich mit float machen. Aber wenn der > sicherstellen kann das das ergebniss gleich ist darf er optimieren. > > Damit könnte er hier ein int vergleich machen - tut er aber nicht weil > es ein dummer compiler ist. Dann nimm einen anderen Compiler. Oder verbessere den vorliegenden Compiler. GCC ist wie gesagt Freie Software, zu der jeder beitragen kann. Und Beträge kommen von demjenigen, der sich darum kümmert. Wie ist übrigens die Bug-Nummer zum obigen Code? Die Grundvoraussetzung für das Beheben eines Problems ist, daß das Problem mitgeteilt wird. Und möglicherweise hat sich auch noch keiner drum gekümmert, weil jeder, den die fehlende Optimierung an dieser Stelle stört, die triviale, naheliegende Änderung an seinem Code macht, die den Vergleich auf int-Ebene ausführt. Wenn du wiklich wissen willst, warum die Optimierung nicht in GCC drinne ist, dann frag die GCC-Entwicker in der dafür vorgesehenen Mailing-Liste gcc-help@gcc.gnu.org
Gast
#2771802
@Peter II Nicht der Code der Inhalt! Woher weiss der Compiler was in der Variable a ist? Und nein er initalisiert das nicht und eigentlich sollte dein Compiler eine Warnung erzeugen, dass a nicht initialisiert ist. was wird wohl aus einem (int)0.1? Ganz blödes beispiel. Feierabend.
Gast
#2771805
Johann L. schrieb: > die triviale, > naheliegende Änderung an seinem Code macht, die den Vergleich auf > int-Ebene ausführt. erstaunlich was alles naheliegend ist - hättest du es denn gewussst? Und ein harter cast ist ja wohl keine lösung, du du uns oben bei dem volatile schon erklärt hast.
Gast
#2771814
Coder schrieb: > Woher weiss der Compiler was in der Variable a ist? aus der Deklaration? Wie auch bei jeder anderen Variable. > Und nein er > initalisiert das nicht und eigentlich sollte dein Compiler eine Warnung > erzeugen, dass a nicht initialisiert ist. es spielt keine rolle was in a drin steht, irgendein wert zwischen INT_MIN und INT_MAX > was wird wohl aus einem (int)0.1? Ganz blödes beispiel. wo ist das Problem mit dem Beispiel? Es geht ja darum das in a keine konstante ist, sonst hätte ich sie ja hingeschrieben. Es soll eine ganz normale variabel sein die jeden möglichen inhalt aus ihren wertebereich annehmen kann. Aber für dich noch mal ohne warnung:
1 | |
2 | |
3 | |
Johann L. schrieb: > GCC? Nein.
Peter II schrieb: > warum optimiert er dann nicht > > int a; > if ( a > 0.1 ) { }; > > laut C muss er den vergleich mit float machen. Aber wenn der > sicherstellen kann das das ergebniss gleich ist darf er optimieren. Wenn ich Code schreiben würde, in dem eine Integer-Variable mit einer nichtganzzahligen Konstante verglichen wird, wäre das 150%ig garantiert keine Absicht, sondern ein Fehler. Dieser Fehler muss vom Compiler nicht auch noch optimiert werden. Wenn ich überhaupt eine spezielle Behandlung dieses Falls erwarten würde, dann allenfalls eine 3 Meter hohe Warnmel- dung in knalligstem Rot :)
Peter II schrieb: > Johann L. schrieb: >> die triviale, naheliegende Änderung an seinem Code macht, >> die den Vergleich auf int-Ebene ausführt. > > erstaunlich was alles naheliegend ist - hättest du es denn gewussst? Ja. > Und ein harter cast ist ja wohl keine lösung, du du uns oben bei dem > volatile schon erklärt hast. Der volatile-Cast ist nochmal eine ganz andere Liga, denn er ist zum einen ein Pointer-Case und zum anderen fuhrwerkt er mit Qualifiern rum. Nochmal zu dem float-Beispiel: Welche Bugnummer hat das im GCC-Bugzilla? Dein Beispielcode ist übrigens weder gültiges C, noch zeigt er den von dir beschriebenen Effekt — zumindest wenn man deinen hingeschlunzten Zeilen zu einen gültigen Testfall ergänzt, der einen Compile-Lauf übersteht ohne zig Syntax-Fehlern zu produzieren.
Gast
#2771875
Johann L. schrieb: > Nochmal zu dem float-Beispiel: > > Welche Bugnummer hat das im GCC-Bugzilla? keine Ahnung ich habe keinen angelegt. (ich habe es einmal bei PHP versucht und dann aufgegen) > Dein Beispielcode ist übrigens weder gültiges C, noch zeigt er den von > dir beschriebenen Effekt — zumindest wenn man deinen hingeschlunzten > Zeilen zu einen gültigen Testfall ergänzt, der einen Compile-Lauf > übersteht ohne zig Syntax-Fehlern zu produzieren. so hier ein beispiel, damit du es auch nachvollziehen kannst:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
erzeugt folgenden code:
gcc -Wall -O2 -S test3.cpp
main:
.LFB19:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $32, %esp
call rand
movl %eax, 28(%esp)
fildl 28(%esp)
fldl .LC0
fxch %st(1)
fucompp
fnstsw %ax
sahf
jbe .L2
movl $.LC1, (%esp)
call puts
.L2:
xorl %eax, %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE19:
.size main, .-main
.section .rodata.cst8,"aM",@progbits,8
.align 8
.LC0:
.long -1717986918
.long 1069128089
.ident "GCC: (Debian 4.7.1-2) 4.7.1"
.section .note.GNU-stack,"",@progbits
Peter II schrieb: > Johann L. schrieb: >> Nochmal zu dem float-Beispiel: >> >> Welche Bugnummer hat das im GCC-Bugzilla? > keine Ahnung ich habe keinen angelegt. Na dann leg ein Bugreport an! Anstatt GCC-Entwickler als dumm zu bezeichnen und hellseherische Fähigkeiten zu erwarten. Dich hier darüber aufzuregen bringt rein garnix. Eine erwachsener Umgang damit ist, bei GCC-Entwicklern nachzufragen, warum das so ist, selber das Problem zu beheben — immerhin bist du ja nicht dumm — oder eben zumindest einen aussagekräftigen Bugreport zu schreiben. Und überleg dir, ob die Optimierung wirklich zulässig ist, etwa wenn int nicht exakt durch double darstellbar ist, bevor es peinlich wird. Und daß die ganzen Typumwandlungen dabei unabhängig vom eingestellten Rounding-Mode sind.
Gast
#2772127
Johann L. schrieb: > Anstatt GCC-Entwickler als dumm zu bezeichnen und hellseherische > Fähigkeiten zu erwarten. was soll das jetzt? Ich habe keinmal schlecht über die entwickler gesprochen. Habe überhaupt keine Grund dazu. Ich wollte nur zeigen das man nicht jeden code dem compiler vorwerfen kann und hoffen das er schon optimiert. du hast doch geschieben: > Der Performance-Verlust wahrscheinlich eh schnuppe ist, nach dem > Motto "Herr Compiler, ich weiß da was besser und machn Experten-Hack" > d.h. die Optimierung fällt in die Kategorie "Pyschologische > Optimierung" bzw. "Angstoptimierung". ich habe dir nur ein einfaches beispiel gezeigt wo das nicht stimmt. > Dich hier darüber aufzuregen bringt rein garnix. ich rege mich überhaupt nicht auf, es war nur als bespiel gedacht das man auch noch selber denken sollte. > Und überleg dir, ob die Optimierung wirklich zulässig ist, etwa wenn int > nicht exakt durch double darstellbar ist, bevor es peinlich wird. jetzt hast du aber lange gesucht um noch etwas zu finden. Dann schreib doch gleich mal hin in welchen fall das nicht stimmt. > Eine erwachsener Umgang damit ist, bei GCC-Entwicklern nachzufragen, > warum das so ist, selber das Problem zu beheben — immerhin bist du ja > nicht dumm — oder eben zumindest einen aussagekräftigen Bugreport zu > schreiben. ist denn eine nicht vorhanden optimierung ein Bug? Müsste man das nicht als Feature Request einreichen?
Peter II schrieb: > Johann L. schrieb: >> Und überleg dir, ob die Optimierung wirklich zulässig ist, etwa wenn int >> nicht exakt durch double darstellbar ist, bevor es peinlich wird. > jetzt hast du aber lange gesucht um noch etwas zu finden. Dann schreib > doch gleich mal hin in welchen fall das nicht stimmt. Ist n_f der float, der aus dem int n hervorgeht, dann ist
mit ε=0 falls n exakt darstellbar ist und ε≠0 sonst. Das hängt u.a. davon ab, wie die Implementierung den Integer repräsentiert, wie den Floating-Typ, und wie groß n ist. Weil die Optimierung die Semantik des Programms nicht verändern darf, muss sichergestellt sein, daß der Vergleich das gleiche Ergebnis liefert, wenn n durch n+ε erstetzt wird. Dies ist nicht für alle denkbaren Implementierungen und Vergleiche der Fall. > ist denn eine nicht vorhanden optimierung ein Bug? Müsste man das nicht > als Feature Request einreichen? Die Bug-Nummern in GCC bzw. binutils bugzilla beginnen auf PR, kurz für "Problem Report". Dazu zählen auch die "missed-optimization" in Feld Keywords. Und wähle eine populäres Target wie x86 anstatt avr. Den aktuellen Compiler hast du ja. Ausserdem wird http://gcc.gnu.org/bugs/#need gerne gelesen.
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.