Forum: Mikrocontroller und Digitale Elektronik ATtiny24 - Codegröße, Flashgrenze erreicht


von Harald X. (harald1976)


Lesenswert?

Hallo,

ich habe für einen ATtiny24 ein C-Programm mit AVR Studio geschrieben. 
Nun habe ich das Problem, dass ich bereits an der Flashgrenze von 2kByte 
angelangt bin.

Ich vermute um die Funktionalität fertigzustellen wird die Codegröße in 
C bei 2,5 -3 kByte liegen.

Ich habe schon einige Optimierungen gemacht: keine FloatingPoint, Zeiger 
auf Strukturen...

Vermutlich kann man es nur noch mit Assembler in die Flashgrenze 
bekommen.

Ich habe keine Erfahrung mit Assembler. Wie könnte man vorgehen um das 
Programm teilweise in Assembler umzuschreiben.

Würdet ich auch so vorgehen:

1) Programm in C fertigstellen ( mit 3kB)

2) Teile des Programms in C umschreiben, bis 2kB Größe erreicht.


Wird das Programm wirklich kleiner wenn man C direkt in Assembler 
übersetzt? Oder muss man mehr Kniffe anwenden.

Wie schnell kann man sich in Assembler hineindenken, wenn man bisher 
noch kein Assemblerprogramm erstellt hat.

Wo findet man gute Assembler Beispielprogramme?

Ich weiß, dass man hier zu dem Thema schon viel findet. Vielleicht könnt 
Ihr mir einige gute Links geben.

Gruß
Harald

von (prx) A. K. (prx)


Lesenswert?

Einfacher: ATtiny44 verwenden.

von Harald X. (harald1976)


Lesenswert?

Bin leider gezwungen den ATtiny24 zu verwenden, da dieser auf Lager ist.

von Harald X. (harald1976)


Lesenswert?

Ich meine das Programm hat schon eine Größe, aber das in C die 2kByte so 
schnell verbraten werden, dachte ich nicht.

Jedes mal wenn ich eine Codezeilen hinzufügte waren wieder 100Byte weg.

Gruß
Harald

von Harald X. (harald1976)


Lesenswert?

einige Codezeilen

von Mehmet K. (mkmk)


Lesenswert?

Ich würde auch das raten, was A.K. geraten hat.
In einer aehnlicher Situation, wobei der zusaetzlich benötigte 
Speicherplatzt nicht so gross war wie bei Dir, hatte ich alle 
String-Konstanten ins Eeeprom ausgelagert und mir so Platz im Flash 
geschaffen.
Aber das war ein Atmega8 mit 512Bytes Eeprom.

von (prx) A. K. (prx)


Lesenswert?

Zeig mal was du da machst, d.h. den Code. Gibt Dinge die übel ausgehen.

von Bernd N. (Gast)


Lesenswert?

Wenn du den Code nicht herzeigen kannst, dann beschreibe mal was du für 
eine Aufgabe hast. Ohne Code oder Codebeschreibung ist das ein 
Ratespiel.

von Alter Hase (Gast)


Lesenswert?

Ich hatte schon mal ein ähnliches Problem, ist aber einige Jahre her.
War damals ein Keil Compiler für 8051.
Ich habe mir den Compiler-Ouput als Assembler Listing ausgeben lassen.
Dann "sinnlose" Befehle bei Bit-Opreationen, die generell über das
Carry statt über das adressierbare! Bit gemacht wurden eliminiert,
und ähnliches.
Würde mich aber schon wundern, wenn ein moderner optimierender 
Compiler-Code
um ca. 30% gekürzt werden kann, einem Assembler-Guru mag das noch
gelingen.

Fragt sich nur ob sich der ganze Aufwand rechnet.
Der nächst größere Tiny kostet kaum mehr, und Argumente wie "Tiny 24
liegt am Lager, der Tiny44 nicht" würden mich als Entwickler erst mal
nicht stören.
Es ist ein Rechenexempel:
Was kostet die Einführung/Lagerhaltung etc. eines neuen µP?
Was kostet die (nur einmal nötige) Schrumpfung des Programms, wenn es 
denn geht?
Oder gleich auf den Tiny44 umstellen, der dann vielleicht sogar 
günstiger
wird?

Mit dieser Vorgehensweise hatte ich bisher immer Erfolg.

von Purzel H. (hacky)


Lesenswert?

Ein Tiny24 kostet 1.15Euro, ein Tiny44 kostet 1.55Euro. Dh bei pro 100 
stueck spart man 40 Euro beim kleineren, aequivalent einer 
Arbeitsstunde. Dh ein Tag Mehrarbeit frist die Minderkosten von 1000 
Stueck auf.
Bei wieviel 10'000 stueck liegt denn dieses Projekt ?

von Oliver (Gast)


Lesenswert?

Harald X. schrieb:
> Wird das Programm wirklich kleiner wenn man C direkt in Assembler
> übersetzt? Oder muss man mehr Kniffe anwenden.

Die selbe Funktionalität in Assembler oder C macht kaum einen 
Größenunterschied -  wenn du Assembler kannst. 30% weniger 
Platzverbrauch ist nicht möglich.

Wenn dein Programm 3kB Codegröße hat, du keine Böcke drin hast, dann ist 
es 3kB groß. Das passt einfach nicht auf einen Tiny24.

Oliver

von Michael H. (overthere)


Lesenswert?

Iwo, ich habe mal für den Tiny22A und Tiny44A ein Angebot eingeholt, 
unterschied waren knapp 7 ct (bei 1000 Stück) (war glaube ich so bei 89 
ct dann)
Wenn man richtig billig werden will, würde ich die MSP430G Series 
anschauen, da kann man richtig sparen. (So um die 50ct/Stück!) zudem hat 
man noch einen sparsameren 16bitter. Nachteile: Schlechterer 
Community-Support, Unübersichtliche Datenblätter, und weniger Timer (nur 
einen). Vorteil: DMA, und verdammt schneller ADC. 200kSamples (sec).
Edit: Gerade nochmal nachgeschaut: Es waren 90ct, unterschied 7 ct. 
Anyway, ich steig gerade auf MSP430 um...

von Purzel H. (hacky)


Lesenswert?

Die Einsparung von ASM kann doch gross sein. Die Compiler sind nicht so 
gut wie sie sein koennten. Die groesste einsparung sind die angepassten 
Datentypen. Da muss man sich bei jeder Variable ueberlegen, was man 
wirklich braucht.

von Michael H. (overthere)


Lesenswert?

Das Problem bei ASM ist aber, dass man sich viel zu viel im Detail 
verliert und damit auch die Übersicht. (Ist jedenfalls bei mir so). ASM 
macht nur im Inline Assembler sinn, und dann auch nur, wenn der Compiler 
deftigen Mist baut. Wegen einem unnötigen mov auf 100 andere Befehle 
schreibe ich den Mist nicht nochmal in ASM.
Fazit: Man kann was sparen, aber 30%. No Way. Schau dir lieber mal das 
Listing durch, wo der Compiler mist baut.
Noch einen Tipp: Man kann in ISR gut Platz sparen...

von Falk B. (falk)


Lesenswert?


von Oliver (Gast)


Lesenswert?

Hey noch Was schrieb:
> Die groesste einsparung sind die angepassten
> Datentypen. Da muss man sich bei jeder Variable ueberlegen, was man
> wirklich braucht.

Ein Byte ist ein Byte ist ein Byte ist ein Byte. Egal, ob in Assembler, 
oder C.

Oliver

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

Oliver schrieb:
> Hey noch Was schrieb:
>> Die groesste einsparung sind die angepassten
>> Datentypen. Da muss man sich bei jeder Variable ueberlegen, was man
>> wirklich braucht.
>
> Ein Byte ist ein Byte ist ein Byte ist ein Byte. Egal, ob in Assembler,
> oder C.

Nein. Es kommt noch auf andere Faktoren an. Z.B. wo sich dieses Byte 
befindet. Liegt es im SRAM, dann kann es nur benutzt (damit gearbeitet) 
werden, wenn man es vorher holt und hinterher zurückschafft. Bei 
kleineren Programmen kann es aber durchaus hilfreich sein, oft 
gebrauchten Variablen Exklusivregister zu spendieren, die Bytes also in 
Registern zu halten. Dies wäre ein Argument für ASM.

Oft reicht es aber, die verwendeten Algorithmen nochmal zu überdenken. 
Denn oft wird in C sehr ressourcenverschwendend progrmmiert, besonders 
wenn der Programmierer seine Erfahrungen mit PC-Programmierung gemacht 
hat, wo ressourcensparendes Programmieren ja ein Fremdwort ist.

Oft reicht es auch, auf C-Bibliotheken zu verzichten und sich seine 
Funktionen selbst zu schreiben, und zwar so, dass sie exakt das können, 
was auch gebraucht wird und kein bissel mehr. Das kann erheblichen 
Speicherplatz sparen, den viele C-Funktionen sind eierlegende 
Wollmilchsäue und verbraten viel Speicherplatz für Funktionalität, die 
im speziellen Fall gar nicht gebraucht wird.

>
> Oliver

von Harald X. (harald1976)


Lesenswert?

Ich habe jetzt ein neues Projekt mit einer leeren Main Funktion 
angelegt.

int main(void)
{

}


Dieses belegt bereits 58 Bytes.
58 bytes (2.8% Full)
(.text + .data + .bootloader)

Wozu wird der bootloader benötigt bzw. kann man hier noch etwas 
optimieren?

Gruß
Harald

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

Harald X. schrieb:
> Ich habe jetzt ein neues Projekt mit einer leeren Main Funktion
> angelegt.
>
> int main(void)
> {
>
> }
>
>
> Dieses belegt bereits 58 Bytes.

Naja, Interrupt-Sprungtabelle und Handler für unbenutzte Interrupts 
brauchen auch ihren Flash. Dazu die Mainloop, 29 Adressen sind da 
schnell belegt.

> 58 bytes (2.8% Full)
> (.text + .data + .bootloader)
>
> Wozu wird der bootloader benötigt bzw. kann man hier noch etwas
> optimieren?

Schau Dir den erzeugten ASM-Code an, alles Andere ist Kaffesatzleserei.

>
> Gruß
> Harald

von Peter D. (peda)


Lesenswert?

Harald X. schrieb:
> Ich meine das Programm hat schon eine Größe, aber das in C die 2kByte so
> schnell verbraten werden, dachte ich nicht.

In 2kB paßt schon ne Menge, wenn man sorgfältig programmiert.
Ein häufiger Anfängerfehler ist, für alles "int" zu nehmen, das bläht 
den Code auf.
Besser nimmt man uint8_t und nur da, wo wirklich notwendig uint16_t.

Strukturen sollten möglichst flach sein, d.h. möglichst wenig Pointer 
auf Pointer auf Pointer ....


> Jedes mal wenn ich eine Codezeilen hinzufügte waren wieder 100Byte weg.

Versuche mal, modular zu programmieren, d.h. ähnliche Programmteile in 
Funktionen zusammen zu fassen..
Oftmals sieht man Copy&Paste Monstercode, z.B. um Menüs zu erstellen. 
Jedes Menü wird als komplettes Programm hintereinander geklatscht.
Besser, man macht eine Menüfunktion, und der wird nur der Pointer auf 
den Formatstring, auf die Parameterliste, auf die Tastenliste übergeben.

Es gibt noch weitere Optimierungen (Compilerschalter) und oftmals hilft 
auch eine Überarbeitung des Programmablaufplans, bzw. erstmal die 
Erstellung eines solchen.


Peter

von Oliver (Gast)


Lesenswert?

Harald X. schrieb:
> Wozu wird der bootloader benötigt bzw. kann man hier noch etwas
> optimieren?

Mal eine ganz andere Frage: Die Optimierung -Os hast du aber aktiviert, 
oder?

Und nein, am bootloader kannst du nichts optimieren, es gibt da nämlich 
keinen.

Oliver

von Ulrich (Gast)


Lesenswert?

Wieviel man mit ASM sparen kann hängt ganz vom Problem ab. Es gibt Fälle 
da kreigt man es ASM kaum so kurz hin wie GCC es schaft, aber es gibt 
auch welche, da kommt man mit 1/4 des Platzes aus. Für einige der 
Einsparungen hilft es aber nicht C mis ASM zu mischen, die kommen erst 
zum Tragen wenn man ganz auf ASM umstellt. Ohne Code, oder wenigstens 
eine BEschreibung worum es geht, ist das aber ein Stochern im Nebel.  Es 
wäre auch mögloch das mand en C Code so weit hinkriegt dass man noch in 
die 2 KB reinpaßt.

von O. D. (odbs)


Lesenswert?

Die Einsparmöglichkeiten in Assembler sind oft gigantisch, wenn man sie 
denn nutzt. Eine Pauschalaussage wie "mehr als 30% sind nicht drin", ist 
Mumpitz.

Der C-Compiler tut sein bestes, ja. Wenn du also von einem Listing 
ausgehst, das von einem C-Compiler erzeugt wurde, und manuell darin nach 
Einsparmöglichkeiten suchst, dann mögen die 30% hinkommen. Aber wenn du 
das Problem in C formuliert hast, hast du schon alleine dadurch eine 
Menge Einsparmöglichkeiten vertan, von denen der beste Compiler nichts 
wissen kann.

Wenn du alleine vom Pflichtenheft ausgehst und das Programm von Grund 
neu in Assembler erstellst, wirst du erstaunt sein, wie effizient man 
mit kleinen Controllern arbeiten kann. Das erfordert allerdings 
Erfahrung und viel vorbereitende Handarbeit.

Schreib doch mal mehr dazu, was dein Programm können muß.

von gagosoft (Gast)


Lesenswert?

Ich denke auch, dass Du Dir den C-Code ganz gründlich ansehen solltest.
Oft kann mit einer anderen Herangehensweise an ein Problem ein viel 
schlankerer Algorithmus gefunden werden.
Hast Du viele Macros in deinem Code (=Codekopien)?
Tief verschachtelte Funktionsaufrufe?
Viele globale Variablen?

Bei ASM ist meist nicht viel drinnen!
Ich hab meist mehr Erfolg den C-Code und speziell den Algorithmus zu 
optimieren!

Hmm was programmierts Du da, nur grob umrissen?

[ ]User-Interface
[ ]Signalverarbeitung (ADC->rechnen->PWM)
[ ]rechenintensives Zeug
[ ]timing-lastiges Zeug
[ ]top secret (dann kann Dir keiner wirklich helfen)
[ ]ganz was anderes

...bitte ankreuzen ;)

von Purzel H. (hacky)


Lesenswert?

Was macht der Bootloader eines C programmes ?

zB die vordefinierten Variablen initialisieren.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Harald X. schrieb:

> [...] Zeiger auf Strukturen...

Zweischneidige Sache das...
1
typedef struct ... data_t;
2
3
data_t data;
4
5
void foo ()
6
{
7
    data_t d = &data;
8
    d->a = d->a + 1;
9
}

Sowas führ nur zu kleinerem Code, wenn der Compiler (hier geht's wohl um 
avr-gcc) die Zugriffsadresse zur Compilezeit nicht kennt. ANsonsten 
macht er gerne absoluten Zugriff und Code wie für
1
void foo ()
2
{
3
    data.a = data.a + 1;
4
}

Bei mehreren Strukturen und wenn GCC die Adressen nicht kennt, ist man 
evtl. auch nicht besser:

1
void bar (data_t *d1, data_t *d2, 1data_t *d3, ...)
2
{
3
    ...
4
}

AVR hat nur wenige Pointer-Register. Daher legt er d1, d2, d3 nicht 
unbedingt in diesen an, sondern in anderen GPRs oder sogar im Frame. 
Selbst wenner sie in GPRs anlegt, braucht er für einen Zugriff 4 Byte: 2 
Byte, um den Zeigen in ein Pointer-Register zu bekommen und (mindestens) 
2 Byte für den indirekten Zugriff. Man ist dann nicht besser als mit 
absoluten Adressen -- dafür langsamer.

Um solche Features zu verwenden, um kleinen Code zu bekommen, sind 
Pauschaltipps oft unbrauchbar. Man muss schon recht gut wissen, wie GCC 
arbeitet, um den Code klenier zu bekommen, wenn er denn unnötig groß 
ist. Und es ist natürlich abhäbngig vom Code und von der GCC-Version.

Wenn man wirklich sowas machen muss, weil es von "oben" vorgegeben ist, 
dann erst man das Listfile überfliegen und checken, ob der Compiler 
guten Code macht oder mies arbeitet, und warum. Bei 2k ist das gut 
machbar.

Aber ohne was von dem Code zu sehen und was avr-gcc draus macht, kann 
man wie gesagt kaum verwertbare Tipps geben (ausser triviale wie kein 
float zu nehmen; das ist in 2k Flash eh obsolet).

von Harald X. (harald1976)


Lesenswert?

Hallo,

es handelt sich um ein spez. Akkuladegerät und unterbrechungsfreie 
Stromversorgung

1) Dabei werden mehrere Spannungen im Viertelsekundentakt gemessen und 
ausgewertet. U.a. die Temperatur der Akkus.
Mit ADC-ISR und sleepmode

2) Eine zwei-farbige Leuchtdiode dient dabei als Zustandsanzeige. Dabei 
sollen auch Blinkfolgen ausgegeben werden können.
Einlegen der Akkus 3 x grün, Entnahme der Akkus 3 x rot, Laden langsam 
grün blinkend, Schnell-Entladen schnell grün blinkend, Akkus schwach 
rot, Akkus in gutem Ladezustand dauernd grün

3) Da das Gerät keine Tasten zur Eingabe hat soll mit dem Schalter der 
Versorgungsspg. über eine Art Morsecode einfache Einstellungen und 
Ausgaben Systemzustand (Gib Status) durchgeführt werden können. Das wäre 
aber mehr Schön-zu-haben.

4) Watchdog

===

5) Reduzierter Ladestrom (über MOSFET toggeln), falls Last am Ausgang 
sehr groß.

6) Timerinterrupt mit sleep_mode() anstatt delay_ms


Punkte 1-4 habe ich umgesetzt, wobei 3) nur teilweise. Ab hier bin ich 
an der Flashgrenze.

Mir fehlen also teilweise Punkt 3) sowie 5) und 6)

Gruß
Harald

von Oliver (Gast)


Lesenswert?

Jetzt zeig doch mal den Code. Sonst wird das nix.

Falk Brunner schrieb:
> AVR-GCC-Codeoptimierung

Hast du das Schritt für Schritt durchgearbeitet? Welche Einstellung hat 
was gebracht, welche nicht?

Oliver

von O. D. (odbs)


Lesenswert?

Hallo Harald,

deine Anforderungen sind leicht in Assembler zu erfüllen und passen ganz 
sicher locker in die 2k. Da bleibt sogar noch jede Menge Platz frei.

Da du nicht viel rechnen, nicht viele Daten zwischenspeichern musst und 
kein kompliziertes User-Interface brauchst (Display mit Formatierung der 
Daten etc.), bietet sich Assembler sogar an.

Wenn du dir vorher das Programm im Pseudocode auf Papier überlegst, wird 
die Umsetzung auch nicht schwer.

Deinen Punkt 6) verstehe ich nicht.

Poste deinen Code!

von MarioT (Gast)


Lesenswert?

Hallo,  Harald X.
Das klinkt jetzt aber nicht gerade viel. Ich könnte mir vorstellen alles 
drauf zu bekommen.

Harald X. schrieb:
> gemessen und
> ausgewertet

Durch geschicktes Anordnen der Rechenoperationen und Formeln oder auch 
eine komplette andere Vorgehensweise läßt sich da manchmal sehr viel 
rausholen. Es ist wirklich nur eine Spekulatuion ohne Code.

von Peter D. (peda)


Lesenswert?

Harald X. schrieb:
> 1) Dabei werden mehrere Spannungen im Viertelsekundentakt gemessen und
> ausgewertet. U.a. die Temperatur der Akkus.
> Mit ADC-ISR und sleepmode
> ... usw.

Das klingt alles nicht aufwendig, sollte spielend in 2kB passen.


> Dabei
> sollen auch Blinkfolgen ausgegeben werden können.
...
> 3) Da das Gerät keine Tasten zur Eingabe hat soll mit dem Schalter der
> Versorgungsspg. über eine Art Morsecode ...

Soll das nur für Dich sein?
Bedenke, daß ein anderer Benutzer nicht die Zeit hat, erstmal einen 
Bedienungslehrgang zu absolvieren.
Also LEDs und Tasten maximal mit 2 Funktionen belegen, sonst gebe ich 
Dir für Ergonomie (Benutzbarkeit) ne glatte 6-Minus.



> 6) Timerinterrupt mit sleep_mode() anstatt delay_ms

Das klingt schon verdächtig nach unüberlegtem Spaghetticode, sowas hat 
die Tendenz zu explodieren und unübersichtlich zu werden.
Deutlich effizienter ist es, Du programmierst ne Statemachine.


Peter

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?


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
Noch kein Account? Hier anmelden.