Hi @ all, ich habe ein kleines Problem wo mir ein erfahrener AVR C Programmierer bestimmt weiter helfen kann. Ich rufe folgende Funktion... void gen_hl() { PORTD = 127; } ...mit... gen_hl(); ...auf. Solange man den Optimierungs-Schalter auf -O0 (Ohh null) läst geht das auch alles. Stellt man um auf -Os was ja empfohlen wird dann ist der Optimierer aber fleißig... zu fleißig, er ruft die Funktion erst garnicht mehr auf... warum? Gruß Frank
Moin! Es kann sein, dass du in der Klammer auch ein void setzen musst, sonst erkennt er es nicht als Funktion
1 | void gen_hl(void) { |
2 | PORTD = 127; |
3 | }
|
MfG
Hast du nachgesehen, ob die Funktion ge"inlined" wird?, d.h. der Compiler setzt die Anweisung in der Funktion direkt ins Programm ein, anstatt die Funktion aufzurufen.
Danke für die schnellen Antworten, also (void) bringt nichts, das "komische ist, es läst sich noch nicht einmal ein Breakpoint setzen. Deutet wohl darauf hin das er es völlig ignoriert. >> Hast du nachgesehen, ob die Funktion ge"inlined" wird?, d.h. der >> Compiler setzt die Anweisung in der Funktion direkt ins Programm ein, >> anstatt die Funktion aufzurufen Ähm ok, was bedeutet das? Wo würde man das sehen, was ist zu tun? Gruß Frank
> Ähm ok, was bedeutet das? wenn die Anweisung ausgeführt wird, die in der Funktion steht, ist es doch egal. > Wo würde man das sehen, was ist zu tun? Sieht man im list-file (da stehen die Assemblerbefehle drin, aus denen das Prog im Endeffekt besteht
Jo ok, also da sieht es tatsache nicht so aus als ob es angesprungen wird. Ich verstehe auch ASM, wollte aber nun ein Programm in C schreiben. Geht das nicht in C das man eben wiederkehrende Sachen in eine Funktion legt? Hmm hat noch jemand einen Tip warum es wohl wegoptimiert wird? Wie würdet ihr eine Funktion beschreiben? Das GCC Tour in dem Forum habe ich gesehen, das mache ich eigendlich so. Verwende AVR Studio und WinAVR. Gruß Frank'l
PORTD als volatile deklarieren? Wie geht denn das? ;) Und was "void" in den Klammern bringen soll, ist mir auch schleierhaft. Warum sollte er den Ausdruck nicht als Funktion erkennen? Woher nimmst du die Information, dass die Funktion nicht aufgerufen wird? PS: Schau doch mal in dem Listfile (*.lst) nach, ob die Funktion aufgerufen/inlined wird.
>> Hmm hat noch jemand einen Tip warum es wohl wegoptimiert wird?
weil der AUfruf (Rcall + push(evtl.) + ... pop + ret) länger
dauert("teurer ist") als die eigentlich Funktion (ldi + out), wenn du
eine längere Funktion schreibst oder die Funktion in eine andere
"compilation-Unit" (.c-Datei) auslagerst, wird die nicht ge-"inlined".
Da PORTD garantiert als "volatile" deklariert ist, wird es gcc mit Sicherheit nicht wegoptimieren. Wenn es Dir im ASM-Quelltext nicht über den Weg läuft, hast Du es bestimmt übersehen... Probiere doch einfach mal, so ein minimal-Programm zu flashen, um Dir dann den PORT über ein Oszi anzuschauen. Wenn es dann nicht geht, hat Dein uC vielleicht gar keinen PORTD (kommt gerne mal vor, daß soetwas übersehen wird)...
Inline bedeutet, dass anstatt "call gen_hl" der Inhalt von gen_hl() direkt an dieser Stelle ausgeführt wird. Macht bei einer so kleinen Funktion Sinn.
Hallo nun ich hab mal den Code auf ein Mininmum reduziert, wie gesagt die -O Option ist auf -Os um den "schnellsten" Code zu erzeugen. gen_off(); Wird nicht angesprungen... :-( µC ist ein ATmega16 auf'n STK500 mit AVR Studio und WinAVR.
1 | #include <stdlib.h> |
2 | #include <avr/io.h> |
3 | #include <avr/interrupt.h> |
4 | |
5 | volatile struct { |
6 | unsigned bGen:1; |
7 | unsigned bActLevel:1; |
8 | } fA1; |
9 | |
10 | |
11 | |
12 | ISR(TIMER0_OVF_vect) |
13 | {
|
14 | if bit_is_set (PORTB,PIN0) { PORTB &= ~(1 << PIN0);} |
15 | else { PORTB |= (1 << PIN0);} |
16 | }
|
17 | |
18 | |
19 | |
20 | void gen_off(void) { |
21 | PORTD = 127; |
22 | fA1.bGen = 0; |
23 | }
|
24 | |
25 | |
26 | |
27 | int main (void) { |
28 | //--- PORT B ---
|
29 | DDRB = 0xFF; // PortD Datenrichtung setzen |
30 | PINB = 0; // Pullups off |
31 | PORTB = 0xFF; |
32 | |
33 | //--- PORT D ---
|
34 | DDRD = 0xFF; // PortD Datenrichtung setzen |
35 | PIND = 0; // Pullups off |
36 | PORTD = 0xFF; |
37 | |
38 | //--- Timer 0 ----------------------------------------------------------------
|
39 | TIMSK |= (1 << TOIE0); // Interupt für Timer0 einschalten |
40 | TCCR0 |= (3<<CS00); // Vorteiler für T/C0 (3=CLOCK/64) |
41 | |
42 | gen_off(); |
43 | |
44 | sei(); |
45 | |
46 | while(1) { |
47 | }
|
48 | return 0; |
49 | }
|
Hallo digifloh, zeig doch mal die .lst-Datei. Bestimmt ist die Funktion in diesem Fall geinlined worden, weil es dann einfach schneller geht. Solange die Wirkung aber diesselbe ist, sollte es eigentlich egal sein, ob die Funktion angesprungen wird oder nicht. Übrigens: -0s erzeugt nicht den schnellsten sondern den kleinsten Code. -03 erzeugt den schnellsten Code, in den meisten Fällen aber auch den größten. MfG Mark
Meinst du nicht, dass das ein bischen an den Haaren herbeigezogen ist, das Programm, das du gepostet hast tut (im Simulator) genau was es soll, PORTD wird vorher schon gesetzt, und die struct wird extra gesetzt. Demnach meint der gcc dass sich der Aufruf nicht rechnet (da hat der sicher recht). Du hast eine bessere chance eine Funktion zu beobachten wenn diese Parameter übernimmt oder werte zurückgibt. (und es gibt ein no_inline_ oder so änhlich -attribute und enstprechende GCC-Parameter, um die zu nutzen müsstest du allerdings das GCC-Manual lesen ... hth. Jörg
Hallo! Ich weis zwar nicht was fuer ein Prozessor es ist, aber das kommt mit spanisch vor...... PINB = 0; // Pullups off Ich denke die Zeile tut nicht das was als Kommentar da steht.... gruß, Bjoern
Ich habe das letzte Programm mal durch den gcc gejagt. 'gen_off()' wird ge-inlined, die Funktion selbst ist aber da. Sie wird halt nur nicht aufgerufen. Die Funktion muß der Compiler auch erzeugen weil er nicht wissen kann ob sie nicht von einem anderen Modul aus aufgerufen wird. Mit 'static' deklariert nimmt er sie aber raus. Da habe ich gerade etwas dazugelernt: Ich dachte bisher immer das der gcc nur mit -O3 inlining benutzt - abgesehen von statischen Funktionen die nur einmal verwendet werden. Mit -O{0,1,2} wird die Funktion aufgerufen. - Michael
@Jorg X. Sicher ist es ein Programm was nur als Beispiel dient aber nicht unnöglich ist. Beim START möchte ich einmal die Funktion aufrufen, das ist alles, ich gehe mal davon aus das es total egal ist was man da reinschreibt in der Funktion. Ob nun 150 ein A über den UART ausgegeben wird oder einfach nur der Wert 127 am PortD. Kann es an meiner Timer Ini liegen? Die lss Datei hab ich mal angehangen... MfG Frank'l
Es ist nicht egal, was in der Funktion drinsteht, solange der Compiler das weiß! -> wenn du die Funktion in eine andere .c-Datei schreibst, wird die auch aufgerufen, weil der Compiler nicht inlinen kann, und glaub mir, wenn inlinen keine Vorteile bringt wird der compiler es auch ganz lassen. Können wir diese "Diskussion" fortsetzen, falls der GCC so inline't, dass das Programm nicht mehr funktioniert?
Hallo, @Joerg X. Ja war vlt. etwas übertrieben, ich wollte nur sagen das es für das Verständniss Funktionen halt egal wäre was im eigendlichen in ihr steht. Vielleicht wäre eine For Schleife besser... ;) Ok Knackpunkt ist das inline, das wußte ich nicht. Ich habe nun mal das prg Step für Step im Deassembler durchgeklickert... es macht inline wie du richtig angenommen hast... Also muß mein Fehler woanders liegen, ich hab was gelernt und sogar verstanden was :-D Das nächste mal wenn sich ein Punkt nicht anspringen läst schau ich hier als erstes nach. Dank euch... schönen Sonntag...
>Ok Knackpunkt ist das inline, das wußte ich nicht.
Der Knackpunkt ist nicht das inline, sondern, daß der gcc, genauso, wie
andere Compiler auch, bei eingschalteter Optimierung Code erzeugt, der
nicht mehr 1:1 rückwärts dem C-Quelltext zugeordnet werden kann. Das
macht der nicht nur durch inlining, da gibt es noch viele andere
"Schweinereien" :-)
Fazit:
Wenn du deinen Sourcecode Zeile für Zeile durchsteppen möchtest, geht
das nur mit -O0. Andere Compiler verbieten von vorherein, Debuginfos für
optimierte Programme zu erzeugen, der gcc ist da etwas großzügiger.
Oliver
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.