Code zu groß für AtTiny45

OP #4633047
Lesenswert?

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
Angehängte Dateien:
Gast #4633284
Lesenswert?

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.
OP #4633709
Lesenswert?

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?
Gast #4633712
Lesenswert?

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.
#4633770
Lesenswert?

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 .
OP #4634965
Lesenswert?

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)
Angehängte Dateien:
Gast #4635043
Lesenswert?

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 ?
Gast #4635048
Lesenswert?

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.
Gast #4635059
Lesenswert?

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.
(Firma: fritzler-avr.de) #4635084
Lesenswert?

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!
#4636145
Lesenswert?

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.
Persönliche Seite #4636181
Lesenswert?

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.
Gast #4636194
Lesenswert?

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
OP #4636441
Lesenswert?

@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.
#4636577
Lesenswert?

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)
Persönliche Seite #4636631
Lesenswert?

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.
#4636645
Lesenswert?

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.
Moderator Persönliche Seite #4636649
Lesenswert?

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! :)
OP #4636698
Lesenswert?

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... ;)
#4636712
Lesenswert?

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! ;-)
Persönliche Seite #4636798
Lesenswert?

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
...
#4636870
Lesenswert?

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.
#4636906
Lesenswert?

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]
Moderator Persönliche Seite #4639596
Lesenswert?

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.
OP #4639677
Lesenswert?

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?
Moderator Persönliche Seite #4639743
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren