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
Bin leider gezwungen den ATtiny24 zu verwenden, da dieser auf Lager ist.
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
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.
Zeig mal was du da machst, d.h. den Code. Gibt Dinge die übel ausgehen.
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.
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.
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 ?
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
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...
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.
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...
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
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
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
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
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
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
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.
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ß.
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 ;)
Was macht der Bootloader eines C programmes ? zB die vordefinierten Variablen initialisieren.
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).
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
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
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!
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.
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
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.