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);
}
}
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
typedefvoidF(void);
2
3
volatilecharx;
4
5
staticvoidf(void)
6
{
7
x++;
8
}
9
10
voidbar(void)
11
{
12
volatileF*vf=(volatileF*)f;
13
vf();
14
x++;
15
}
Allerdings will der TO die damit verbundene Semantik keinesfalls
haben...
Ergo: Ein volatile zu viel kann echt übel sein.
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
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.
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
#include<stdint.h>
2
#include<avr/io.h>
3
4
volatileuint8_tx;
5
6
intmain()
7
{
8
while(1)
9
{
10
if(x)
11
{
12
PORTD=0x01;
13
}
14
}
15
}
Übersetzt sich so:
1
00000048 <main>:
2
{
3
while (1)
4
{
5
if (x)
6
{
7
PORTD = 0x01;
8
48: 91 e0 ldi r25, 0x01 ; 1
9
10
int main ()
11
{
12
while (1)
13
{
14
if (x)
15
4a: 80 91 60 00 lds r24, 0x0060
16
4e: 88 23 and r24, r24
17
50: e1 f3 breq .-8 ; 0x4a <main+0x2>
18
{
19
PORTD = 0x01;
20
52: 92 bb out 0x12, r25 ; 18
21
54: fa cf rjmp .-12 ; 0x4a <main+0x2>
22
23
00000056 <_exit>:
24
56: f8 94 cli
25
26
00000058 <__stop_program>:
27
58: ff cf rjmp .-2 ; 0x58 <__stop_program>
Hier ist die Welt noch in Ordnung: x wird immer neu gelesen.
Jetzt das Ganze mit Casting - so wie Du vorgeschlagen hast:
1
#include<stdint.h>
2
#include<avr/io.h>
3
4
uint8_tx;
5
6
intmain()
7
{
8
while(1)
9
{
10
if((volatile)x)
11
{
12
PORTD=0x01;
13
}
14
}
15
}
Ausgabe:
1
00000048 <main>:
2
3
int main ()
4
{
5
while (1)
6
{
7
if ((volatile) x)
8
48: 80 91 60 00 lds r24, 0x0060
9
{
10
PORTD = 0x01;
11
4c: 91 e0 ldi r25, 0x01 ; 1
12
13
int main ()
14
{
15
while (1)
16
{
17
if ((volatile) x)
18
4e: 88 23 and r24, r24
19
50: 11 f0 breq .+4 ; 0x56 <main+0xe>
20
{
21
PORTD = 0x01;
22
52: 92 bb out 0x12, r25 ; 18
23
54: fc cf rjmp .-8 ; 0x4e <main+0x6>
24
56: ff cf rjmp .-2 ; 0x56 <main+0xe>
25
26
00000058 <_exit>:
27
58: f8 94 cli
28
29
0000005a <__stop_program>:
30
5a: ff cf rjmp .-2 ; 0x5a <__stop_program>
Hier wird x NICHT neu gelesen, sondern lediglich auf das Register r24
wiederholt zugegriffen.
Oder mache ich was falsch?
Gruß,
Frank
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)
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
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.
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.
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?
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!
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.
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.
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 ;-)
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:
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.
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.
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?
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.
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.
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
intx;
2
if(x>0.1){
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.
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.
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.
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.
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.
Coder schrieb:> Und bevor man anfängt wild zu> optimieren, sollte das Programm erstmal funktionieren.
ob ich nun schreibe
1
char*s
2
for(intx=0;x<strlen(s);x++){
3
s[x]=uppper(s[x]);
4
}
oder gleich schreibe
1
char*s
2
char*c=s;
3
while(*c){
4
*c=uppper(*c);
5
++c;
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.
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
#include<stdint.h>
2
3
volatileuint8_tVolatileVar;
4
5
voidmain(void)
6
{
7
uint8_tTemp;
8
while(1)
9
{
10
Temp=VolatileVar;
11
if(Temp==1U)
12
{
13
++VolatileVar;
14
}
15
}
16
}
sowie
1
#include<stdint.h>
2
3
volatileuint8_tVolatileVar;
4
5
voidmain(void)
6
{
7
while(1)
8
{
9
if(VolatileVar==1U)
10
{
11
++VolatileVar;
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.
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.
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?
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.
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...
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.
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.
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?
@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)
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
inta;
2
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.>> 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
@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.
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.
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:
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.
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:
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.
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.