Hallo,
gestern wollte ich ein kleines Programmchen für einen 2313 (2kB Flash,
128B RAM) mit AVR-GCC schreiben. Obwohl mein Programmchen wirklich klein
war (nur ein Modul, ~500 Zeilen mit defines und Kommentaren), kam die
Fehlermeldung, daß sowohl Flash als auch RAM voll sind.
Ist das normal??
Kann man dem Compiler vielleicht irgendwie sagen, er soll auf
"Speicherplatz" optimieren??
Danke,
Sebastian
Ich habe ähnliches vor:
Um die Eignung der AVR für meine Anwendungen im industriellen Umfeld zu
testen, will ich einen AT89C2051 durch einen AT90S2313 ersetzen, d.h.
ohne eine neue Platine machen zu müssen.
Das 2051-Programm ist in C geschrieben und belegt etwa 1,6kB des Flash.
Es sind nur wenige Zeilen, aber es benutzt float Variablen.
Meine Frage:
Hat schon mal jemand float auf nem 2313 verwendet oder ist das
illusorisch ?
Peter
@Sebastian:
Welche Features benutzt Du denn alles so?
Ich habe mal ein kleines meiner Projekte herausgewühlt,
das vom Codeumfang vergleichbar ist. Das kommt für 2 x
je ca. 400 Zeilen Quellcode auf 1 KB Flash-Nutzung.
Allerdings hängt das von den benutzten Bibliotheksfunktionen
etc. pp. mit ab. Wenn Du printf() benutzt, genügt schon
eine einzige Zeile Programmcode, daß alles nicht mehr in
einen AT90S2313 hineinpaßt. ;-)
Die RAM-Nutzung hast Du natürlich komplett mit Deinen
Variablen selbst in der Hand. Denk dran, daß Du auch
RAM für den Stack brauchst.
@Peter:
float auf dem 2313 wird sicher knapp. Solange Du nur
addieren und subtrahieren willst, geht es vielleicht
gerade noch so, Multiplikation oder gar Division ziehen
aber vermutlich schon so viel mit rein, daß das nicht
mehr praktikabel ist. Und Ein-/Ausgaben wirst Du ja
vielleicht auch noch machen wollen...
Ich habe Gleitkomma erfolgreich auf einem AT90S8535
benutzt, allerdings wäre für printf() kein Platz mehr
gewesen (hatte ich damals sowieso noch nicht), und zusammen
mit bißchen Debug-Code und sowas habe ich am Ende den
Flash dieses Teils auch vollbekommen (fast jedenfalls).
Vielleicht wäre ja scaled integer eher was für Dich?
@Peter:
Vielleicht hast Du schon mein Frequenzmeßgerät gesehen
www.mino-elektronik.de/fmeter/fmeterx.htm. Hier wird float auf Basis
eines IAR-Compilers ICCA90 (V1.x) verwendet. Die Codegröße für fadd,
fsub, fmul, fdiv, die Konvertierungen float2long, long2float, ... und
die Rundungen beträgt unter 900Byte. Verglichen mit ImageCraft-AVR,
GCCAVR und Codevision-AVR ist das sehr kompakt. Printf ist allerdings
bei keinem der Compiler anzuraten, da auch viele Routinen gelinkt
werden, die nicht gebraucht werden.
Ohne Geld auszugeben, kann man eine Demo von IAR bekommen, eine c-Quelle
mit float schreiben und 'debuggen'; so bekommt man den versteckten Code
der Libs zu sehen und könnte ihn auch abtippen. Zur weiteren Anwendung
gibt es einen kostenlosen AA90 Assembler (www.atmel.com). Bei mir (s.o.)
gibt es auch ein Beispielprogramm 'fm.c', welches auch float benötigt
und trotz reiner C-Quelle in den 2313 paßt.
Ich hatte seinerzeit meine ersten Versuche mit dem 2313 gemacht, der
genau wie bei Dir den 2051 ersetzen sollte. Der Code für einen
Tastatudekoder + LCD-Treiber + ser.Multiprozessorschnittstelle auf dem
2051 war mit 2k gerade passend, für den 2313 wollte der C-Compiler
zunächst 3k erzeugen. Durch Optimierung und teilweise Codierung in
Assembler (wie auch schon beim 2051) passte der Code dann auch in den
2313. So macht man seine Erfahrungen. Die Vorteile waren für mich das
interne EEPROM und die Programmierung verschiedener Versionen auf der
Leiterplatte. Die serielle Ausgabe (über 4094) aufs LC-Display wurde so
schnell, daß bei 62,5kBd keine Warteschleifen mehr eingefügt werden
mussten.
Ich will hier keine Werbung machen, aber der aktuelle IAR ICCAVR erzeugt
sehr guten Code und nutzt bei den ATmega auch die neuen Befehle; das
Teil kostet aber auch richtig Knete! Ich rufe die Compiler aus der
Kommandozeile auf, was für mich sehr wichtig ist.
Ich kann Dir anbieten, Deine Quelle 'mal durch den Compiler zu nudeln
und Dir den Output schicken.
Michael
Mein Programmchen benutzt gar keine C-Library. Auch keine floats oder
solche Sachen. Allerdings eine größere Schachtelungstiefe von
if/switch/for etc.
Die Variablen, die ich benutze, machen zusammen 20 bis 30 Bytes.
Ich habe den GCC in Verdacht, ziemlich resourcenhungrigen Code zu
erzeugen?!
Grüße,
Sebastian
@Michael,
900 Byte klingt gut, beim 2051 sinds 979 Byte.
Vielleicht hat doch noch jemand dazu Vergleichszahlen für den AVRGCC ?
printf() nehme ich nicht, da ich ja 7-Segment-Kode brauche und kein
ASCII.
Dein Frequenzmesser sieht interessant aus, ähnelt vom Meßprinzip her
meinem mit dem 2051 aufgebautem.
Eine Frage, ist das Programm dazu nun in C (wegen float) oder in
Assembler ?
Das mit den 0,0025 Hz ist aber ein Druckfehler, das wären ja 7 Minuten
Meßzeit.
Meiner geht von 0,5Hz ... 125MHz, die Auflösung ist 4 Digits bzw.
0,001Hz, die Meßzeit beträgt 0,5s ab >2Hz und erhöht sich bis auf 2s bei
0,5Hz.
Als Vorverstärker bzw. Trigger nehme ich den AD8009 und den LT1720.
Bei Interesse kann ich mehr dazu auf meine Webseite stellen.
Peter
@Peter:
'fm.c' ist reine C-Quelle; Du kannst Dir den .hex-Code ja 'mal auf einen
2313 programmieren.
Bei fmeter.htm sind 0,0025Hz kein Druckfehler. Bei 1Hz Eingangsfrequenz
bekommt man 7-stellige Ergebnisse: jede Sekunde ein neues! Ich gleiche
damit z.B. PCF8583 Uhren ab. Der Vorteiler für 50MHz wird automatisch
selektiert.
Hier habe ich die Steuerung und Auswertung in C, die Interruptroutinen
und Optimierungen (interne Registerverwendung) in Assembler gemacht.
Ebenso ist der startup abgemagert - einige Konstanten liegen im EEPROM.
Michael
> Ich will hier keine Werbung machen, aber der aktuelle IAR ICCAVR erzeugt sehr
guten Code ...
Ich will ja hier keine Werbung machen, aber da schmeisst mal wieder
jemand Äpfel und Tomaten durcheinander! Was hat denn die Firma IAR
Systems mit der Firma Imagecraft zu tun?? ICCAVR stammt von der Firma
Imagecraft und nicht von IAR, wie man am Namen schon unschwer erkennen
kann (Imagecraft C-Compiler). Und zwischen den Produkten von Imagecraft
und denen von IAR Systems liegen Welten.
Vielleicht entscheidest du dich erst mal, wofür du hier
(Schleich-)werbung machen willst.
> Ich habe den GCC in Verdacht, ziemlich resourcenhungrigen Code zu erzeugen?!
Auch mal wieder so eine Fehlannahme! Ich würde erst mal schauen welches
Flieskommaformat bzw. welche Präzision die Routinen haben, bevor ich
anfange die erzeugte Codegrösse zu vergleichen. Wenn ich die Präzision
und den Zahlenbereich einer Fliesskommavariablen entsprechend reduziere,
bekomme ich naturgemäss auch kompaktere Routinen und damit kompakteren
Code (siehe z.B. CodeVision & Konsorten). Wenn man allerdings volle IEEE
754-Präzision haben möchte (float = 4 Byte, double = 8 Byte und long
double = 10 Byte), so kostet das natürlich entsprechenden Platz. Leider
schreibt der ANSI-Standard hier nichts vor, so dass Hersteller
kommerzielle Compiler mit verkrüppelten Fliesskommaroutinen trotzdem
noch dieses Schildchen auf den Karton pappen dürfen, was mir persönlich
sehr missfällt.
Notker
Der avr-gcc unterstützt ohnehin nur 4-Byte floats, double
ist identisch zu diesem. Viel mehr erscheint mir persönlich
auch kaum sinnvoll; zwei 4-Byte floats als Argumente einer
Funktion belegen bereits den kompletten Satz an scratch
registers, die definiert sind, also ab 3 Parametern müßte
man schon auf den Stack.
Anyway, wichtig beim avr-gcc ist, welche Optimierungsoptionen
benutzt werden. Wer gedankenlos -O3 schreibt (oder gar
sinnloserweise noch größere Zahlen, weil er das Manual nicht
gelesen hat und nicht weiß, daß es gar nichts höheres gibt ;-),
der wird bestraft. -O3 wird ja vielleicht noch ein bissel
schneller als die kleineren Zahlen, aber kleiner wird es
absolut nicht, sondern vielmehr recht aufgebläht. Am kleinsten
fallen -Os (wie der Name sagt ;-) und -O1 aus, und sie sind
bestenfalls nur geringfügig langsamer als die Optimierungsstufen
mit der größeren Zahl (d. h. weniger als 10 % selbst bei
rechenkritischen Operationen).
Vielleicht ist meine Frage ja ganz dumm ...:
Sind im Makefile die linker flags richtig ?
#linker flags
LDFLAGS = -Wl,-Map=$(TRG).map,--cref -lm
Das Fehlen des -lm switches erzeugt Fehlermeldungen über volles flash.
@notker:
'iccavr.exe' ist auch von IAR. Wie man am Namen unschwer erkennen kann
kommt ICC von Iar-C-Compiler. Die Version davor hieß 'icca90.exe'.
Vielleicht liest Du die Sätze 'mal komplett, ohne gleich loszuwettern.
Ich habe noch einmal nachgesehen: float-basisroutinen bei IAR brauchen
638 Byte (gleicher Wert bei zwei verschiedenen Projekten). Internes
Format 4 Byte, wie nicht anders zu erwarten.
ftp://ftp.imagecraft.com/pub/pub/iccavrdem.exe
Also der ist doch wohl zweifelsohne von Imagecraft, oder? (das "dem"
steht übrigens dafür, dass es die Demoversion ist, die Vollversion
heisst iccavr.exe.
Ich habe den Satz schon richtig gelesen, danke für den Hinweis!
Notker
> Der avr-gcc unterstützt ohnehin nur 4-Byte floats, double
ist identisch zu diesem.
Das halte ich aber für ein Gerücht! Aber ein kurzes Debugging mit dem
AVR-Studio an einem Beispielprogramm wird dies schnell klären.
> Wer gedankenlos -O3 schreibt (oder gar
sinnloserweise noch größere Zahlen, weil er das Manual nicht
gelesen hat und nicht weiß, daß es gar nichts höheres gibt ;-),
der wird bestraft.
Womit denn? Mit Freiheitsstrafe nicht unter 2 Jahren? ;-)
Naja, beim "normalen!" gcc gibt es hier schon höhere Zahlen.
Notker
> Das halte ich aber für ein Gerücht!
Kannst Du gern. Um wieviel möchtest Du wetten?
RTFDoc hilft hier übrigens auch, es ist sehr eindeutig
beschrieben, daß er nur 32-bit floats kennt. Aber ich
gebe zu, wetten wäre unfair, ich habe Heimvorteil.
> Naja, beim "normalen!" gcc gibt es hier schon höhere> Zahlen.
Woher hast Du denn diese Weisheit? Aus dem Manual oder
dem Sourcecode des gcc bestimmt nicht. Vielleicht aus
abergläubischen Linux-Makefiles, die von Unwissenden
geschrieben worden sind, die sich einbilden, das bloße
Aufschreiben von -O99 würde die gcc-Geister beschwören,
besseren Code zu produzieren... gcc selbst ignoriert es
geflissentlich und nimmt einfach stattdessen mal -O3 an,
bis die Leute ja dann vielleicht doch noch RTFM'ed haben...
>Woher hast Du denn diese Weisheit? Aus dem Manual oder>dem Sourcecode des gcc bestimmt nicht. Vielleicht aus>abergläubischen Linux-Makefiles, die von Unwissenden>geschrieben worden sind, die sich einbilden, das bloße>Aufschreiben von -O99 würde die gcc-Geister beschwören,>besseren Code zu produzieren...
Sag mal, du trägst hier aber ganz schön dick auf!
Also das, was hier drin steht ist also falsch?
http://www.fokus.gmd.de/linux/HOWTO/pdf/Assembly-HOWTO.pdf
Ich könnte ja jetzt noch in den Sourcen des gcc solange rumsuchen, bis
ich etwas gefunden habe, aber ehrlich gesagt, ich finde es langsam etwas
müssig, jede fragwürdige Behauptung, die hier gemacht wird, genauer zu
untersuchen. Wer es also genau wissen will, soll selbst nachsehen.
Notker
Wasichnochsagenwollte:
Mit WinAVR hab ich jetzt mein Programmchen problemlos in den A2313
bekommen. Scheint wirklich ein Fortschritt gegenüber V3.0.2 zu sein!!
Grüße,
Sebastian
@Notker:
> Sag mal, du trägst hier aber ganz schön dick auf!
Zumindest habe ich die Doku gelesen. ;-) Diese nennt
eindeutig nur -O0 (ist identisch zum Weglassen von -O),
-O alias -O1, -O2 und -O3.
> Also das, was hier drin steht ist also falsch?
Ja, zumindest für einen unverpfuschten gcc. Allerdings
ist innerhalb des gcc die Variable "optimize" global,
und diese bekommt in der Tat die Zahl nach -O zugewiesen,
so daß ein einzelner Codegenerator von anderen Levels
Gebrauch machen könnte. Der ungepatchte gcc benutzt
aber als höchsten Vergleich "optimize >= 2", und genau
so ist es auch dokumentiert. UTSL.
> Zumindest habe ich die Doku gelesen. ;-) Diese nennt> eindeutig nur -O0 (ist identisch zum Weglassen von -O),> -O alias -O1, -O2 und -O3.
Sorry, -Os habe ich unterschlagen.
Also hier mal ein Codeauszug aus der Source des gcc 3.2:
------------------schnipp--------------------------------
else if (argv[i][0] == '-' && argv[i][1] == 'O')
{
/* Handle -Os, -O2, -O3, -O69, ... */
<--------!!!!
char *p = &argv[i][2];
if ((p[0] == 's') && (p[1] == 0))
{
optimize_size = 1;
/* Optimizing for size forces optimize to be 2. */
optimize = 2;
}
------------------schnapp-----------------------------------
Also irgendwie scheinen dort ja doch Levels höher als 3 erkannt und
ausgewertet zu werden, oder habe ich heute abend etwas an den Augen???
Level -O6 habe ich im Unix-Bereich schon des öfteren in Sourcen
namhafter und renommierter GPL-Software gesehen.
Notker
Wenn Du bis dorthin vorgedrungen bist, dann untersuche
einfach noch, an welchen Stellen die Variable
"optimzize" auch wirklich benutzt wird. Du wirst
zu Deinem Erstaunen feststellen, dass der hoechste
Vergleich, der irgendwo auftritt, optimize >= 2
ist -- was exakt der Manpage entspricht.
Was anderes habe ich auch nicht geschrieben: die
Zahl nach -O wird zwar noch geparst, aber alles
ab -O3 wird identisch behandelt.
Ob mehr oder weniger namhafte ,,Experten'' im Glauben
an den Gott der Optimierung dann -O6 schreiben, ist
mir egal. Sie werden jedenfalls damit nicht mehr
als mit -O3 erreichen, und um auf den Anfang
zurueckzukommen, fuer die meisten AVR-Applikationen
kann -O3 zu einer massiven Platzverschwendung bei
bestenfalls marginaler Verbesserung der Laufzeit
fuehren. Siehe Doku, meine Mini-Benchmark-Ergebnisse
habe ich dokumentiert.
> Du wirst zu Deinem Erstaunen feststellen, dass der hoechste> Vergleich, der irgendwo auftritt, optimize >= 2> ist -- was exakt der Manpage entspricht.
Nun, dann schauen wir doch mal etwas weiter unten (toplev.c) ...
------------------------schnipp-------------------------------
flag_delete_null_pointer_checks = 1;
flag_reorder_blocks = 1;
}
if (optimize >= 3) <---------------!!!
{
flag_inline_functions = 1;
flag_rename_registers = 1;
-----------------------schnapp-------------------------------
Nun, ich denke, dass DU besser mal einen Blick vorher hier
hineingeworfen hättest. Mein lieber Jörg Wunsch, so langsam wird die
Sache langweilig. Ich glaube, du suchst dir besser ein anderes Forum mit
leichtgläubigerem Publikum aus, wo du dein "Expertenwissen" zum Besten
geben kannst. Die Behauptung hier ist wohl auch mal wieder heisse Luft.
Notker
Na gut, dann halt >=3, was Jörg wahrscheinlich auch gemeint hat ("...was
exakt der Manpage entspricht"), aber größere Werte als 3 machen beim GCC
definitiv keinen Unterschied.
BTW: Er ist auf dem Gebiet wohl der letzte, in dessen Zusammenhang es
angebracht ist "Expertenwissen" in Anführungszeichen zu schreiben...
> BTW: Er ist auf dem Gebiet wohl der letzte, in dessen Zusammenhang es
angebracht ist "Expertenwissen" in Anführungszeichen zu schreiben...
Mag ja alles sein, allerdings finde ich seine Art wenig souverän. Als
tatsächlicher Experte sollte man schon seine Hausaufgaben gemacht haben
und ein etwas diplomatischerer Umgang mit anderen Menschen wäre kein
Luxus.
Notker
Nun, die Hausaufgaben habe ich gemacht. Siehe Andreas'
Hinweis, das war ein simpler Schreibfehler -- der Effekt
ist exakt der, den ich beschrieben habe: -O3 ist der
höchste ,,aus der Dose raus'' unterstützte Level. Daß
man dafür natürlich entweder >= 3 oder > 2 schreiben muß,
ja klar. Ich hatte meine Hausaufgabe schon vor einer
Woche gemacht und daher aus dem Gedächtnis zitiert.
Ich wehre mich vor allem gegen diese ,,weil es im HOWTO xyz
steht, muß es richtig sein'' Mentalität. Alles spricht
dagegen, daß es -O levels > 3 wirklich gibt (die Manpages,
der Sourcecode), aber der Glaube an den Gott der Optimierung
wirkt stärker... Dabei ist in der Doku zum gcc wirklich
recht detailliert beschrieben, welche Stufe welche Optimierungen
einschließt. Im Gegensatz zu irgendeinem Howto stammt diese
aber von den Autoren/Maintainern.