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
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 .
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.
@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_tpwm_difference_red=0;
7
// [...]
8
floatbrightness_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.
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.
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
structcRGB*LED_OUTPUT;
3
...
4
intmain(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
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.
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.
Ich habe mal ein bisschen herumgepfuscht, zur Anregung ;-)
WARNUNG: nicht kompiliert und ungetestet!
EDIT: Entschuldige das Einrückungschaos - Notepad++ hat Leerzeichen und
TABs gemischt.
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...