Hallo, Ich habe das Problem, dass die hex-Datei für meinen µC zu groß wird. Optimierung habe ich schon auf "size" gesetzt. Könnt ihr mir ein paar Anhaltspunkte geben, was ich noch verbessern kann? Im Moment bin ich bei 103% Speicherbedarf. Zumal der Code ja auch noch nicht final ist (es fehlen noch ein paar kleine Funktionen). Aber z.B. bei der Entprell-Routine von Peter Dannegger kann ich wohl noch ein paar Routinen entfernen wie z.B. "get_key_rpt" und "get_key_short". Das wäre echt super, weil ich die µC für mein Projekt ja auch schon hier rumliegen habe in der Annahme, dass der Flash "schon reichen wird"... Gruß Hannes
Schmeiß das float Zeug raus und mach Festkomma-Arithmetik!! Grüße, egberto
Du hast noch nen Timer über, schreibe dir deine eigenen delay_us und delay_ms, da kannst du sicher auch noch einiges sparen da du ja nicht alles von delay.h brauchst.
M. K. schrieb: > Du hast noch nen Timer über, schreibe dir deine eigenen delay_us und > delay_ms, da kannst du sicher auch noch einiges sparen da du ja nicht > alles von delay.h brauchst. ob das etwas bringt? Das sind doch bloß makros die bis auf eine kleine schleife wegoptimiert werden.
egberto schrieb: > Schmeiß das float Zeug raus Benutzt du die passenden Float-Libraries (-lm )? Oder die riesigen, die der Compiler als Standard nimmt, wenn man nicht -lm angibt?
Hallo Tom, Nein diese Option kenne ich noch nicht und habe sie demnach wahrscheinlich auch nicht benutzt. Ich habe mich ein wenig in die Festkomma-arithmetik eingelesen, aber nun ist es ja so, dass ich die PWM-Werte erst logarithmisch umrechne, dann mit einem festen Wert addier und dann wieder exponentiell zurück rechne. Geht das alles auch mit Festkommazahlen?
Johannes H. schrieb: > aber nun > ist es ja so, dass ich die PWM-Werte erst logarithmisch umrechne, dann > mit einem festen Wert addier und dann wieder exponentiell zurück rechne. > Geht das alles auch mit Festkommazahlen? naja. Andere rechnen es einfach am PC aus und hinterlegen es als feste Tabelle.
Tom schrieb: > Benutzt du die passenden Float-Libraries (-lm )? Oder die riesigen, die > der Compiler als Standard nimmt, wenn man nicht -lm angibt? Das ist schon seit mindestens 5 Jahren kein Problem mehr, zudem wird -lm automatisch hinzugefügt.
Johannes H. schrieb: > Ich habe mich ein wenig in die Festkomma-arithmetik eingelesen, aber nun > ist es ja so, dass ich die PWM-Werte erst logarithmisch umrechne, dann > mit einem festen Wert addier und dann wieder exponentiell zurück rechne. > Geht das alles auch mit Festkommazahlen?
Ich habe jetzt deinen Code nicht, aber das was du beschreibst ist eine einfache Multiplikation .
:
Bearbeitet durch User
Gerald M. schrieb: > Ich habe jetzt deinen Code nicht, aber das was du beschreibst ist eine > einfache Multiplikation . Verräter. ;o)
Zu der Gammakorrektur gibts hier was: https://www.mikrocontroller.net/articles/LED-Fading Das lässt sich auch ins EEPROM prügeln wenn am flash gespart werden soll. Ansonsten hier wie man HSV nach RGB in Festkommaarithmetik hinbekommt: http://www.zabex.de/site/sofabeleuchtung.html Wenn alle Stricke reißen: Tiny85 pfeif
Hallo, Der Tiny85 ist leider keine Option, da ich die Tiny45 schon hier habe und der Code bis Mittwoch Abend fertig sein muss... Ich habe jetzt meinen Code auf Festkomma umgstrickt (betraf ja nur die ledmodes.c, siehe Anhang). Den Speicherbedarf konnte ich damit nur marginal um 3% auf 100,9% drücken... In diesem Tutorial(https://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung#Speicherverbrauch_nach_Funktionen_aufschl.C3.BCsseln) wird erwähnt, dass man sich den Speicherbedarf der einzelnen Module anzeigen lassen kann. Das habe ich mal gemacht, siehe Anhang. Allerding sagen mir diese Informationen nichts. Habe ich das Tool korrekt verwendet? Das sind im Weiteren die Parameter des Linkers: -Wl,-Map="$(OutputFileName).map" -Wl,-lm -mmcu=($DEVICE) ($MEMORY_SETTINGS)
Hallo Johannes, welche avr gcc Compileroptimierungen verwendest Du? Hier kann man immer etwas drehen und ein paar Byte einsparen. Zum attiny85 nun ja den kann man sich auch noch bis Dienstag besorgen ! Wie sieht die aktuelle Speicherbelegung Ram und Flash aus ?
Hallo, da Du weiterhin log() und exp() verwendest wird auch noch die float lib eingebunden. Hier sollte man auf eine Tabellen Repräsentation umstellen.
Noch eine Anmerkung, dein Abbildungsfunktion f(x) = calc_new_value(x) liefert Ergebnisse aus f(x) E {0,..,255} und die Argumente x sind ebenfalls aus der Menge {0,..,255}. Somit kann man sich einfach eine Funktionstabelle F(x) mit 256 Werten im Flash ablegen. Der Index entspricht dabei dem Wert von x.
Johannes H. schrieb: > Ich habe jetzt meinen Code auf Festkomma umgstrickt (betraf ja nur die > ledmodes.c, siehe Anhang). Kannst Du das Programm denn überhaupt testen, wenn es nicht in den µC passt? > Den Speicherbedarf konnte ich damit nur marginal um 3% auf 100,9% > drücken... Falls Du initialisierte Variablen/Texte verwendest, kann man die auch ins EEPROM schreiben und beim startup ins RAM kopieren.
Johannes H. schrieb: > Ich habe jetzt meinen Code auf Festkomma umgstrickt (betraf ja nur die > ledmodes.c, siehe Anhang). Nö, haste nicht. > #include <math.h> > value_brightness = 100*log(value_pwm * BASE / 255); Ausm avr gcc Doxygen zu log(): > double log (double __x) Hatte dir doch schon verlinkt wie man mit Festkomma und ner Tabelle nen RGB Fading macht. Fading im HSV Farbraum und das dann umrechnen nach RGB. Das passt sogar in ein tiny13 mit soft PWM rein!
Hast Du mal die Linkerschalter überprüft, ob -lm angegeben ist. 4kB für fast nix klingt stark nach der nicht optimierten Lib. Die verbraucht außerdem noch 264Byte SRAM.
@Uwe:Wenn ich das Projekt auf "Release" setze, kriege ich den selben Wert raus. @Peter: die Linkerparameter hatte ich weiter oben schon mal angegeben: -Wl,-Map="$(OutputFileName).map" -Wl,-lm -mmcu=($DEVICE) ($MEMORY_SETTINGS)
Mark S. schrieb: > Warum wechselst Du nicht einfach auf einen Attiny85? > Der Tiny85 ist leider keine Option, da ich die Tiny45 schon hier habe > und der Code bis Mittwoch Abend fertig sein muss... Was ist wohl einfacher? Den code ändern oder die Hardware ändern?
Peter II schrieb: > Was ist wohl einfacher? Den code ändern oder die Hardware ändern? In diesem Fall: Die Hardware ändern! Denn der Attiny85 ist praktisch identisch mit dem Attiny45 nur dass der Attiny85 einen größeren Flash, EEProm und RAM hat als der Attiny45 ;). Die Tipps zur Code-Optimierung (insbesondere auch der Tabellen-Spass) würde ich aber auch als erstes umsetzen.
M. K. schrieb: > auch der Tabellen-Spass Aber die sog. look-up-table (LUT) scheint er nicht zu wollen. Frisch berechnete Fließkommazahlen sind eben frisch berechnete Fließkommazahlen. Mal ganz abgesehen davon, dass die LUT nur ein paar CPU-Takte braucht, während die Multiplikation den ATTiny schon mal anhält. Tastenentprellung noch dazwischen…könnt' man vielleicht glatt die Multiplikation als _delay_ms benutzen.
was ich schon mal mache ist geeignete Variable nicht ins RAM zu legen, sondern dafür I/O Adressen zweckentfremdet zu benutzen, die du sonst nicht brauchst (zB das TCNTx oder OCRxy). Abgesehen von RAM-Ersparnis bringt das auch schon mal ein paar Bytes ROM. Nachteil ist klar: Wartbarkeit? Transportabilität? Aber wenn nur du dran frickelst und weisst was du tust... /sigma9
Ich hab jetzt die Look-Up-Variante genommen, da schrumpft der Speicherbedarf auf rund 50%. Ich habe ja 40 Tinys bestellt, deswegen tu ich mich schwer mit neu bestellen ;) Für Version 2.0 werde ich mal die Performance beider Varianten vergleichen und dann den entsprechenden µC auswählen.
Johannes H. schrieb: > Für Version 2.0 werde ich mal die Performance beider Varianten > vergleichen und dann den entsprechenden µC auswählen. was will man da noch vergleichen. Ob es 100 oder 1000 Fach schneller ist?
Johannes H. schrieb: > Ich habe ja 40 Tinys bestellt, deswegen tu ich mich schwer mit neu > bestellen ;) Der Tiny85 ist meistens billiger als T45, warum hast du uberhaupt T45 genommen ?
Johannes H. schrieb: > Ich hab jetzt die Look-Up-Variante genommen, da schrumpft der > Speicherbedarf auf rund 50%. Also als nächstes Tiny25 bestellen ;) ? Frisch berechnen is eben leider nicht immer vorteilhaft. Versuchs dochmal noch ins EEPROM zu werfen, dann wirds richtig klein im Flash.
Boris O. schrieb: > könnt' man vielleicht glatt > die Multiplikation als _delay_ms benutzen. Muss ich mal probieren... :D, ymmd
@Marc: Fuck, das habe ich jetzt auch gesehen... Selbst wenn's der selbe Preis gewesen wäre hätte es sich ja schon gelohnt! :D Naja, so lern ich wenigstens gleich noch ein paar Sachen, über die ich sonst wohl nicht gestolpert wäre :) @Peter2: nein aber ich kann ja bisher noch nicht abschätzen, ob durch die float-Geschichten die Performance der LED-Ansteuerung leidet oder so.
Johannes H. schrieb: > @Peter2: nein aber ich kann ja bisher noch nicht abschätzen, ob durch > die float-Geschichten die Performance der LED-Ansteuerung leidet oder > so. Kommt darauf an, was du überhaupt erwartest. Du hast für die 'main()' keine Zeitbasis. Ich könnte mir vorstellen, dass ein Überblenden der Helligkeiten/ Farben je nach Größe der zu berechnenden Werte völlig ungleichmäßig von statten geht. Zu erwartende Ausgaben: Die Datenübertragung dauert ~30µs. Die Berechnungen dauern unterschiedlich lange. Du hast eine 1ms-Pause in die 'main()' gebastelt. Auf Grund deiner gewählten Auflösung dauert der volle Helligkeitswechsel einer Farbe über 13..14s. Auszug aus 'led_modes.c':
1 | #define MAX 255
|
2 | #define BASE 10
|
3 | #define RESOLUTION 50 //number of steps to increment the brightness value
|
4 | |
5 | // [...]
|
6 | int16_t pwm_difference_red = 0; |
7 | // [...]
|
8 | float brightness_step_red = 0.0; |
9 | // [...]
|
10 | pwm_difference_red = LED_COLOR_new.r - LED_COLOR_old.r; // Either 0, +-127 or +-255 |
11 | // [...]
|
12 | brightness_step_red = 1/RESOLUTION * pwm_difference_red / MAX; // Speed is 0 for same, 1/2 for 127 and 1 for 255 as difference each in positive or negative direction. |
Was ich anders machen würde: - nur mit int16_t rechnen - dafür müssen allerdings der Wertebereich und die Berechnung des aktuellen Helligkeitswertes angepasst werden - Für 'RESOLUTION' 32 oder 64 nehmen - ordentliche Zeitbasis (z.B. 1ms) in main() über Timerinterupt (TIMER0_OVF), ohne irgendwelche 'Preload-Werte' - 'debounce' entsprechend seltener aufrufen (x8 oder x16). Was nicht funktioniert: - 'brightness_step_red' ist immer 0. (Integerberechnung von 1/50)
Ralf G. schrieb: > brightness_step_red = 1/RESOLUTION * pwm_difference_red / MAX; Diese Zeile solltest du noch einmal überdenken. Im Sinne des defensiven Programmierens würde ich Klammern setzen. Du verlässt dich darauf, dass der Compiler stur von links nach rechts die Zeile abarbeitet.
Johannes H. schrieb: > Den Speicherbedarf konnte ich damit nur marginal um 3% auf 100,9% > drücken... Na, es wird kaum der Speicherbedarf von ledmodes.o sein der dein Programm aufbläht, sondern die notwendigen hinzugeladenen Funktionen aus der Library um float zu implementieren.
Georg G. schrieb: > Ralf G. schrieb: >> brightness_step_red = 1/RESOLUTION * pwm_difference_red / MAX; > > Diese Zeile solltest du noch einmal überdenken. Im Sinne des defensiven > Programmierens würde ich Klammern setzen. Du verlässt dich darauf, dass > der Compiler stur von links nach rechts die Zeile abarbeitet. Der Compiler ist nicht "stur", sondern hält sich an den Sprachstandard. Wer die Sprache nicht kennt, der ist ziemlich schnell am Ende der Fahnenstange — egal ob mit "defensiver" Programmierung oder ohne.
1 | LED_COLOR_new.r = Colors(random_color_value).r; |
2 | LED_COLOR_new.g = Colors(random_color_value).g; |
3 | LED_COLOR_new.b = Colors(random_color_value).b; |
Diese Sache ist auch recht umständlich. Warum die Funktion 3* aufrufen? Und deren Implementierung auch. Statt der tonnenweise Einzelzuweisungen wäre ein memcpy eines Flasharrays deutlich codesparender. Wird COLORS[14] überhaupt je geändert? Ich seh da in Deinem Code eh nicht durch. Er sieht mir sehr umständlich aus. Erfahrene Programmierer mögen keine Großschriftunterscheidungen, wie COLORS,Colors.
Keine Ahnung, was du als Compiler benutzt. Ich bekomme mit einem GCC 4.7.2 schon Code, der in den ATtiny45 passt:
1 | $ avr-gcc -DF_CPU=8000000 -mmcu=attiny45 -Os -o test.elf -I includes *.c -lm |
2 | main.c:14:9: warning: built-in function ‘index’ declared as non-function [enabled by default] |
3 | $ avr-size *elf |
4 | text data bss dec hex filename |
5 | 3888 20 44 3952 f70 test.elf |
Die Warnung bekommt man los, indem man nicht den GNU-Modus, sondern strikten Standardmodus benutzt. Allerdings muss „asm“ dann „__asm“ heißen:
1 | $ avr-gcc -DF_CPU=8000000 -Dasm=__asm -mmcu=attiny45 -std=c99 -Os -o test.elf -I includes *.c -lm |
2 | $ avr-size *elf |
3 | text data bss dec hex filename |
4 | 3888 20 44 3952 f70 test.elf |
GCC 5.3.0 spart noch ein paar Bytes ein:
1 | $ avr-gcc -DF_CPU=8000000 -Dasm=__asm -std=c99 -mmcu=attiny45 -Os -o test.elf -I includes *.c -lm |
2 | $ avr-size *.elf |
3 | text data bss dec hex filename |
4 | 3792 20 44 3856 f10 test.elf |
Danke, Johann, für deine kontinuierliche Verbesserungsarbeit! :)
Hallo, Also das ist ja Code den ich noch nie testen konnte. Und auf jeden Fall gibt's da noch einiges zu optimieren. @Ralf Das mit dem 1ms-delay würde ich spätestens merken, wenn's denn mal laufen würde ;) Was ist mit int16_t der Vorteil? Aha also wenn, dann müsste es "1.0/Resolution" heißen, oder? @Peter D. Ja ich habe dann auch gemerkt, dass man die Farbe auch in einer Anweisung zuweisen kann. Auch die Benamsung is noch nicht final. Es kommt mal was dazu, es fliegt was weg. Saubergemacht wird zum Schluss. Generell: C-mäßig bin ich noch irgendwo zwischen Anfänger und Fortgeschrittener also bitte nicht zu sehr drauf rumhacken... ;)
Johannes H. schrieb: > Was ist mit int16_t der Vorteil? Deine Zwischenergebnisse in float haben jetzt eine Genauigkeit von 7..8 Stellen. (Wenn ich mich nicht irre.) Mit int16_t hast du einen Wertebereich von +/-32767 und somit erstmal 5 Stellen. Wenn du die Faktorenberechnung nicht in dem Bereich von +/-1.0 (float) machst, sondern z.B. im Bereich von +/-1024 (int), sparst du dir die aufwendigen Fließkommaberechnungen. Bei einer Ausgabe von 8Bit sollte das locker für Zwischenergebnisse an Genauigkeit reichen. > Aha also wenn, dann müsste es "1.0/Resolution" heißen, oder? Genau! ;-)
Johannes H. schrieb: > Also das ist ja Code den ich noch nie testen konnte. Offenbar, denn der Code schreibt fleißig nach Adresse 0 (via LED_OUTPUT): *main.c*
1 | ...
|
2 | struct cRGB *LED_OUTPUT; |
3 | ...
|
4 | int main(void){ |
5 | |
6 | /**** Set Timer & Buttons for Debounce Functionality ****/
|
7 | KEY_DDR &= ~ALL_KEYS; |
8 | KEY_PORT |= ALL_KEYS; |
9 | |
10 | TCCR0B = (1<<CS02)|(1<<CS00); // divide by 1024 |
11 | TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5); // preload for 10ms |
12 | TIMSK |= 1<<TOIE0; // enable timer interrupt |
13 | |
14 | sei(); // Enable global interrupts |
15 | |
16 | *LED_OUTPUT = Colors(13); |
17 | ws2812_setleds(LED_OUTPUT,1); |
18 | ...
|
Johannes H. schrieb: > Saubergemacht wird zum Schluss. nie, Code der zu 90% funktioniert bleibt bei 90% und nichts ist dauerhafter als ein Provisorium
Johann L. schrieb: > Wer die Sprache nicht kennt, der ist ziemlich schnell am Ende Wir hatten auch mal einen genialen Programmierer, der topfit in C war. Er schrieb die kürzesten Programme (Quelltext Zeilen). Leider waren die so gut wie unwartbar. Nicht umsonst gibt es bei fast allen Compilern die Warnung "Klammern werden empfohlen ..." ein zu schalten. IOCCC ist ja nett, aber im täglichen Leben sollte man anders programmieren.
Johann L. schrieb: > Johannes H. schrieb: >> Also das ist ja Code den ich noch nie testen konnte. > > Offenbar, denn der Code schreibt fleißig nach Adresse 0 (via Und im Gegensatz zu PC's bekommt man dafür keine "Exception", sondern überschreibt sich die CPU-Register von R0 aufsteigend, abhängig von der Größe der geschriebenen Daten. [Ironie] Kann man als "Codeprotection" benutzen, oder wenn man lustige Fehler mag. [/Ironie]
Georg G. schrieb: > Leider waren die so gut wie unwartbar. Wenn C-Programme wie Lisp aussehen, weil der Programmierer keine Ahnung hat und „vorsichtshalber“ alles klammert, sind sie aber auch unwartbar …
Johannes H. schrieb: > @Uwe:Wenn ich das Projekt auf "Release" setze, kriege ich den selben > Wert raus. Wundert mich, beim mir hat es funktioniert. Was auch viel Speicher benötigt ist "DELAY". Ich habe mal die beiden _delay_ms(500); in der Main-Routine entfernt. Das hat 100 Byte gebracht und war mit "DEBUG" klein genug.
Uwe K. schrieb: > Ich habe mal die beiden _delay_ms(500); in der Main-Routine entfernt. > Das hat 100 Byte gebracht Aber nur, wenn man die Optimierung ausschaltet – was man bei den delay-Routinen aber grundsätzlich nicht tun darf. Gibt auch eine Warnung, und die sich ergebenden Verzögerungen sind um mehr als eine Größenordnung daneben. Ansonsten dampfen die Delays (wie schon geschrieben wurde) zu wenigen Befehlen zusammen. Aber wer weiß, was für eine altertümliche Compilerversion der TE überhaupt benutzt. Ich schrieb ja weiter oben schon, dass sein originaler Code mit einem halbwegs aktuellen Compiler ohne jegliche Änderungen problemlos in seinen ATtiny45 passen würde.
:
Bearbeitet durch Moderator
Hallo Jörg, Leider hatte ich Deinen ersten Post nur überflogen, denn tatsächlich habe ich im AVR-Studio 5.1 noch die alte GCC-Version 3.3.1.27... Aber hm, wie update ich denn den Compiler? Die Suchmaschinen geben mir grad hinsichtlich Anleitungen nix Vernünftiges. Ersetze ich einfach den Ordnerinhalt in ...\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27?
Hallo, am einfachsten wäre es deinen Rechner aufzurüsten und anstatt des alten AVR-Studio 5.1 das mächtige AVR-Studio 7.x zu installieren http://www.atmel.com/Microsite/atmel-studio/ Ein Uprade der CPU, Ram und Harddisk ist dann selbstverständlich.
Die Toolchain ist ziemlich unabhängig von der IDE. Allerdings kommt die alte AVR Studio 5 IDE dank ihres offenbar nur mit trial&error statt nach dem DWARF-Standard entworfenen DWARF-Parsers mit dem Debug-Output aktuellerer Compiler nicht mehr ohne weiteres zurecht. Man müsste dann manuell -gstrict-dwarf in die Optionen für den Compiler einfügen. Johannes H. schrieb: > GCC-Version 3.3.1.27 Sowas gibt es nicht. Es gab vielleicht einen GCC 3.3.1, aber keine IP-Adress-ähnliche microsoftartige Nummerierung … Diese hat sich Atmel einfallen lassen, und das Herausfinden, welche tatsächlichen Versionen der einzelnen Tools dahinter verstecken, bleibt dem Leser überlassen. Dennoch ist der darunter befindliche Compiler (dürfte ein GCC 4.3 bis 4.5 sein) mittlerweile schon sehr betagt. Den sollte man, wenn's auf das letzte Byte ankommt, nicht mehr nehmen, denn Johanns AVR-spezifische Verbesserungen haben vor allem ab GCC 4.7 gegriffen.
:
Bearbeitet durch Moderator
Ich habe mal ein bisschen herumgepfuscht, zur Anregung ;-) WARNUNG: nicht kompiliert und ungetestet! EDIT: Entschuldige das Einrückungschaos - Notepad++ hat Leerzeichen und TABs gemischt.
:
Bearbeitet durch User
Hallo, wo bekommt man includes/light_ws2812.h und includes/light_ws2812.c her ?
Karl M. schrieb: > wo bekommt man includes/light_ws2812.h und includes/light_ws2812.c her ? Also, ich würde diese beiden Begriffe mal bei Google eingeben. Und würde dann ganz schnell was dazu finden...
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.