Forum: Mikrocontroller und Digitale Elektronik ATmega48 Programmspeicher zu klein?


von Kai S. (luxell)


Angehängte Dateien:

Lesenswert?

Auf die Schnelle habe ich mir ein Programm geschrieben, was die ADCs des 
ATmega48 liest und die PWMs steuert. Im Prinzip keine große Sache und 
auch nicht wirklich viel Programmtext. Nur leider scheint das für den 
ATmega48 doch zu viel zu sein. Dieser hat nur 4 kBytes 
Programmierspeicher. Und das AVR-Studio sagt, dass der Programmspeicher 
zu 120% voll ist.
Nun meine Frage: Habe ich in meinen Programm irgendein Fehler verbockt 
oder unnötig Speicherplatz verbraucht?
Ich kann mir nicht vorstellen, dass man so schnell ein µC voll bekommt. 
Oder habe ich vielleicht falsche Einstellung beim AVR-Studio, so dass 
dieser das Programm falsch kompiliert?

Bootloader verwende ich auch nicht.

Danke schon Mal im Voraus.

von Cyblord -. (cyblord)


Lesenswert?

Deine ganzen FLOAT Berechnungen blähen deinen Code auf. Vergiss Float 
und mach direkt Festkomma mit Ints.

gruß cyblord

von Conny G. (conny_g)


Lesenswert?

Die float-Library ist riesig:
1
return (((float) ADCW)/1024); // auf 5 Volt normieren

Baue es um, das zu vermeiden und es sind nur noch 200 Bytes :-)

von Kai S. (luxell)


Lesenswert?

Danke für die schnelle Antwort.

Conny G. schrieb:
> Baue es um, das zu vermeiden und es sind nur noch 200 Bytes :-)

Aber wie meinst du das genau?
Soll ich statt float lieber short int verwenden, weil ADCW auch nur 2 
Byte groß ist?
Muss ich dann noch die float-Library ausbinden?

Wenn es das ist was du meinst, macht das den so ein großen Unterschied, 
wenn ich statt float (4 Byte) besser short int(2 Byte) nutze?

von avr (Gast)


Lesenswert?

Kai S. schrieb:
> Wenn es das ist was du meinst, macht das den so ein großen Unterschied,
> wenn ich statt float (4 Byte) besser short int(2 Byte) nutze?

nein, die zwei Bytes sind dem avr egal. Der Unterschied besteht darin, 
dass float ein komplexer Datentyp ist und der avr nur über große Umwege 
damit rechnen kann.

von avr (Gast)


Lesenswert?

und natürlich macht es dadurch einen riesen Unterschied!

von Amateur (Gast)


Lesenswert?

>Soll ich statt float lieber short int verwenden, weil ADCW auch nur 2
>Byte groß ist?

Es lebe der Extremismus.

Im Grunde geht es nicht um die Größe (in Bytes) der Variablen sondern um 
eine riesige Bibliothek, die hinzugelinkt wird.
Wenn Du glaubst zu Ungenau zu werden, so nimm Doppelworte, schiebe deine 
Basiswerte um 8 bis 16 Bit nach rechts, mach Dein Ding und schiebe den 
Kram kurz vor der Übergabe wieder um die 8 bis 16 Bit zurück.
Die verwendeten Multiplikations- und Divisionsroutinen brauchen nicht 
viel Platz.
Tust Du nur die Kern- oder Rechenvariablen auf ein größeres Format 
erweitern, flippt Dir auch die Speicherverwaltung nicht aus.

von Conny G. (conny_g)


Lesenswert?

Kai S. schrieb:
> Danke für die schnelle Antwort.
>
> Conny G. schrieb:
>> Baue es um, das zu vermeiden und es sind nur noch 200 Bytes :-)
>
> Aber wie meinst du das genau?
> Soll ich statt float lieber short int verwenden, weil ADCW auch nur 2
> Byte groß ist?
> Muss ich dann noch die float-Library ausbinden?
>
> Wenn es das ist was du meinst, macht das den so ein großen Unterschied,
> wenn ich statt float (4 Byte) besser short int(2 Byte) nutze?

Am besten Du stellst auf Festkomma-Arithmetik um.

Also Du lässt den ADC-Wert so wie er ist:
1
// Die Spannung am Eingang mit der Nummer (chan) messen:
2
float ADC_Read(uint8_t chan){        //Kanal 0 bis 7
3
  
4
  static uint8_t mux;
5
6
  if ( mux == chan ){        // Normalerweise kein Kanalwechsel
7
    ADCSRA |= (1<<ADSC);    // eine ADC-Wandlung starten
8
    while ( ADCSRA & (1<<ADSC) );  // auf Abschluss warten 
9
10
    return ADCW;  //!! der ist jetzt 1024 = 10 bits nach links verschoben
11
12
  }else{
13
    mux = chan & 0x07;    // Beim Kanalwechsel:
14
    ADMUX = ( ADMUX & 0b11111000) | mux; // Kanal neu
15
    ADC_Read(mux);        // 1 Dummy-Readout
16
    return (ADC_Read(mux));    // gültige Messung durchführen
17
  }
18
}

und änderst dann alle Rechnungen
1
    }else{
2
        OCR2B = (unsigned char)(102*((poti-0.1)/0.9)+153);  //Lüfter von Poti steuern
3
      }
so ab, dass deine Bits rechts die Nachkommastellen sind und Du nur mit 
Ganzzahlen rechnest.
Müssen auch nicht alle 10 Bits sein, kann auch weniger sein.

Hier gibt's mehr Info:
http://www.mikrocontroller.net/articles/Festkommaarithmetik

So ein kleiner uC kann keine Flieskommarechnung von der CPU aus, wenn 
man das tut, dann bindet der Compiler automatisch Bibliotheken ein, die 
die Fliesskommarechnungen mit einem Heidenaufwand durchführen.
Und wie Du merktest ist der Aufwand größer als ein uC ihn leisten kann.

Deshalb muss man hier eine andere Taktik fahren um dem Generell aus dem 
Weg zu gehen.
Sobald Du den Compiler nicht mehr zu Zahlen mit Nachkommastellen 
zwingst, braucht er auch die Lib dafür nicht mehr und lässt sie weg.

von Peter D. (peda)


Lesenswert?

Kai S. schrieb:
> Und das AVR-Studio sagt, dass der Programmspeicher
> zu 120% voll ist.

Dann hast Du die falsch Math-Lib gelinkt oder Optimierung aus.
Ich komme mit WINAVR auf:
1
4.3.3
2
AVR Memory Usage
3
----------------
4
Device: atmega48
5
6
Program:    2024 bytes (49.4% Full)
7
(.text + .data + .bootloader)
8
9
Data:          1 bytes (0.2% Full)
10
(.data + .bss + .noinit)

Die float Lib belegt einmalig 1kB, man muß vor float also keine Angst 
haben.
Früher mag das anders gewesen sein, daher haben viele immer noch 
Vorbehalte.

: Bearbeitet durch User
von Kai S. (luxell)


Lesenswert?

Erst mal ein großes Dankeschön an alle für eure nützlichen Tipps.
Nun habe ich alle Kommarechnungen raus genommen und siehe da, das 
Programm ist mal gerade 776 Bytes groß. Was für ein Wunder! Wenn man 
zuvor mit so etwas noch nie Probleme hatte ist das schon sehr 
überraschend.

Peter Dannegger schrieb:
> Dann hast Du die falsch Math-Lib gelinkt oder Optimierung aus.

Das bei dir nur 49.4% belegt sind ist sehr wunderlich. Wie kann ich den 
überprüfen welche Math-Lib ich gelinkt habe bzw. wie kann ich sie dann 
ändern?

Mit der Optimierung habe ich auch schon rumgespielt. Brachte aber kaum 
Erfolg. Daran kann es nicht liegen.

von Uwe (de0508)


Lesenswert?

Kai S. ,

zeige uns doch bitte Dein Makefile, das steht alles drin..

von Cyblord -. (cyblord)


Lesenswert?

Uwe S. schrieb:
> Kai S. ,
>
> zeige uns doch bitte Dein Makefile, das steht alles drin..

Wo soll der herkommen bei Atmel Studio? Da gibts keinen makefile. Was 
soll diese Frage? Er hat die Math Lib nicht gelinkt, fertig. Da muss man 
keinen makefile zu sehen.

@Kai:
Die Mathe lib heißt eigentlich "libm.a". Bei den Linkeroptionen trägt 
man lediglich "m" ein, da das "lib" und die Endung bereits vom linker so 
erwartet werden. Wo man genau im Atmel Studio weitere libs für den 
Linker angibt, weiß ich leider nicht, da ich Eclipse nutze.

gruß cyblord

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Welches AVR-Studio benutzt Du denn?
In den Compileroptionen muß ein -lm stehen.
Die Optimierung sollte -Os sein.

von m.n. (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Die float Lib belegt einmalig 1kB, man muß vor float also keine Angst
> haben.
> Früher mag das anders gewesen sein, daher haben viele immer noch
> Vorbehalte.

Das kann ich voll bestätigen. Und float auf dem AVR ist recht schnell!
Ich habe eher den Verdacht, dass delay_ms(5000) zumindest gefühlt allein 
schon 5kB braucht :-)

von Karl H. (kbuchegg)


Lesenswert?

m.n. schrieb:
> Peter Dannegger schrieb:
>> Die float Lib belegt einmalig 1kB, man muß vor float also keine Angst
>> haben.
>> Früher mag das anders gewesen sein, daher haben viele immer noch
>> Vorbehalte.
>
> Das kann ich voll bestätigen. Und float auf dem AVR ist recht schnell!


Ich geb dir in der Sache recht.

Aber bei ihm ist es auch kein Beinbruch, wenn er in der ADC_Read 
Funktion dann eben nicht Floating Point durch 1024 dividiert und dafür 
hier in der Verwendung
1
    poti = ADC_Read(0);                  //prozentuiere die Spannung an ADC0
2
    if(poti < 0.1){                      //Bei unter 10% des Potis
3
...
4
    }else{                          //Bei größer gleich 10% des Potis
5
...
6
        OCR0A = (unsigned char)(102*((poti-0.1)/0.9)+153);  //Lüfter von Poti steuern
an 2 Stellen ein wenig umstellt. Und um mehr geht es in diesem Programm 
nicht.
Wo du natürlich recht hast: Für nicht benutzten Flash gibt es kein Geld 
zurück und in dieser Applikation ist die Laufzeit auch nicht das 
Problem.

Trotzdem würde mich interessieren, was er gemacht hat, damit er den 
Flash angefüllt hat. Selbst mit der Floating Lib sollte das doch alles 
locker rein passen.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

cyblord ---- schrieb:
> Wo soll der herkommen bei Atmel Studio? Da gibts keinen makefile. Was
> soll diese Frage?

Selbstverständlich gibt es da ein makefile. Das Studion ompiliert nicht 
selber, das ruft auch nur make auf. Das makeflie dafür wird vom Studio 
automatisch erzeugt, und ist leicht zu finden.

Oliver

von m.n. (Gast)


Lesenswert?

Karl Heinz schrieb:
> Trotzdem würde mich interessieren, was er gemacht hat, damit er den
> Flash angefüllt hat. Selbst mit der Floating Lib sollte das doch alles
> locker rein passen.

Wenn er das Listing vom Linker zeigen würde, könnte man es sofort sehen, 
ohne lange auf Irrwegen (Abblockkondensatoren, usw.... :-) 
herumzulaufen.

von Karl H. (kbuchegg)


Lesenswert?

m.n. schrieb:
> Karl Heinz schrieb:
>> Trotzdem würde mich interessieren, was er gemacht hat, damit er den
>> Flash angefüllt hat. Selbst mit der Floating Lib sollte das doch alles
>> locker rein passen.
>
> Wenn er das Listing vom Linker zeigen würde, könnte man es sofort sehen,
> ohne lange auf Irrwegen (Abblockkondensatoren, usw.... :-)
> herumzulaufen.

Ich hab noch so dunkel in Erinnerung, dass im 4-er Studio die -lm nicht 
standardmässig angegeben war und dann die generischen Floating Routinen 
eingebunden wurden, die größer sein sollen.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:
> m.n. schrieb:
>> Karl Heinz schrieb:
>>> Trotzdem würde mich interessieren, was er gemacht hat, damit er den
>>> Flash angefüllt hat. Selbst mit der Floating Lib sollte das doch alles
>>> locker rein passen.
>>
>> Wenn er das Listing vom Linker zeigen würde, könnte man es sofort sehen,
>> ohne lange auf Irrwegen (Abblockkondensatoren, usw.... :-)
>> herumzulaufen.
>
> Ich hab noch so dunkel in Erinnerung, dass im 4-er Studio die -lm nicht
> standardmässig angegeben war und dann die generischen Floating Routinen
> eingebunden wurden, die größer sein sollen.


Yep. Das scheint es zu sein.
Mach ich ein Testprojekt für den M48 und geb keine libm.a in den 
Linkeroptionen an, dann binn ich trotz -Os bei 113%
Mit libm.a geht es runter auf 49%

von m.n. (Gast)


Lesenswert?

Karl Heinz schrieb:
> Ich hab noch so dunkel in Erinnerung, dass im 4-er Studio die -lm nicht
> standardmässig angegeben war und dann die generischen Floating Routinen
> eingebunden wurden, die größer sein sollen.

Das ist richtig; die waren übel groß. Beim 4.19 Studio muß ich dem 
Linker auch immer noch explizit Bescheid geben. Aber dann geht's los!
Vielleicht sollten wir abwarten, bis der TO aufgestanden ist und 
gefrühstückt hat.

von Tipp (Gast)


Lesenswert?

Machs in Asm... Macht die Sache deutlich kleiner, schneller, einfacher. 
Irgendwelche Compileroptionen gibts auch nicht zu beachten.

von Kai S. (luxell)


Lesenswert?

Guten morgen. Oder eher Mittag!
Danke für das Warten ...

m.n. schrieb:
> bis der TO aufgestanden ist und
> gefrühstückt hat.

Hier hat sich ja einiges getan. Ich habe nun auch beim AVR-Studio 4.18 
(- AVR Studio was den AT90USB1287 noch simuliert und ein Studio was ich 
überhaupt auf meinen Rechner zum Laufen bekommen hab ... bisher) libm.a 
eingefügt und siehe da. Das Programm ist trotz float und 
Gleitkommarechnung nur 49.4% groß. Was für ein Wunder. Und schon wider 
überrascht es mich, weil ich mit so einem Problem bisher noch nichts zu 
tun hatte. Geschweige denn, dass ich bei den Linkeroptionen etwas 
zufügen musste.

Wenn ich es jetzt richtig verstehe, kann ich ob unnötig oder nicht mit 
float und Gleitkommarechnungen programmieren, da dank der libm.a dies 
keine großen Auswirkungen hat? Oder sollte ich mir nun doch angewöhnen 
möglichst ohne float und auf jeden Fall ohne Gleitkommazahlen zu 
rechnen?

Wenn bei meinen AVR-Studio schon libm.a fehlt, kann es sein, dass mir 
auch noch andere wichtige Linkeroptionen fehlen?

Uwe S. schrieb:
> zeige uns doch bitte Dein Makefile, das steht alles drin..

Da das Problem gefunden wurden ist, hat sich das erledigt.

m.n. schrieb:
> Ich habe eher den Verdacht, dass delay_ms(5000) zumindest gefühlt allein
> schon 5kB braucht :-)

Das hatte ich auch als erstes im Verdacht. Aber selbst wenn ich delay 
entfernt hatte, war das Programm noch zu groß.

von Karl H. (kbuchegg)


Lesenswert?

Kai S. schrieb:

> Wenn ich es jetzt richtig verstehe, kann ich ob unnötig oder nicht mit
> float und Gleitkommarechnungen programmieren, da dank der libm.a dies
> keine großen Auswirkungen hat? Oder sollte ich mir nun doch angewöhnen
> möglichst ohne float und auf jeden Fall ohne Gleitkommazahlen zu
> rechnen?

In der Allgemeinheit ist so eine Frage schwierig zu beantworten. Wenn es 
dein Programm einfach macht, dann benutze Floating Point.
Aber sei gewarnt: Floating Point ist auch nicht die Lösung aller 
Probleme.

In deinem konkretem Programm würde ich mir die Frage stellen, ob es 
tatsächlich und wirklich notwendig ist, die gemessene Spannung 
tatsächlich in Form von Volt zur Verfügung zu haben. Bringt mir das was, 
wird dadurch irgendetwas klarer?
IMHO nein. Der ADC stellt einen Wert fest. Ob der jetzt von 0.0 bis 5.0 
läuft oder von 0 bis 1023, das ist nur ein anderer Zahlenwert. 
Entscheidend ist doch: je weiter verdreht das Poti ist, desto größer ist 
der Wert. Rechnen kann ich mit dem einen genausogut wie mit dem anderen. 
Zumal es mir dann auch bewusst macht, dass ich mit
1
   if (adc_wert_integer < 50)
eben sowieso nicht EXAKT 0.1V als Grenze haben werde, selbst dann nicht 
wenn ich Floating Point anwende und der Vergleich
1
   if (adc_wert_float < 0.1)
hier etwas suggeriert, das nicht vorhanden ist, weil ja der float Wert 
eben nicht kontuinuierlich alle Zahlenwerte annehmen kann, sondern da ja 
immer noch die Diskretisierung auf 1024 mögliche Werte durch den ADC 
drinnen steckt.

Die Umrechnung in den OCR Wert gestaltet sich dann eben so, dass nicht 
mehr der Bereich 0.0-5.0 auf den gewünschten OCR Bereich umgemappt wird, 
sondern ein Bereich 0-1023. Das heißt, das ist Jacke wie Hose, ein 
Zahlenbereich wird linear in einen anderen Zahlenbereich transformiert. 
Man hätte genausogut die ADC Werte nicht in eine Spannung sondern in 
einen Winkel von 0 bis 360 umrechnen können und mit dem dann weiter 
rechnen können. Das alles sind nur andere Zahlenwerte, ändert aber am 
Prinzip nichts.
D.h. ich brauch hier in Wirklichkeit die Spannung an sich ja gar nicht. 
D.h ich könnte mir diese ganze Flaoting Point Rechnerei auch sparen.

Daher würde ich hier kein Floating Point benutzen. Ich seh da keinen 
Vorteil drinnen, sie zu haben. Denn eigentlich interessiert mich ja die 
Spannung nicht. Was mich interessiert ist der Verdrehwinkel des Potis. 
Der wird nicht besser oder schlechter dadurch ausgedrückt, dass ich ihn 
in Volt ausdrücke als durch einen fiktiven Wert, der von 0 bis 1023 
geht.

Was anderes wäre es, wenn man zb mittels GPS Koordinaten Arithmetik am 
Grosskreis betreibt. Da wäre man "verrückt", wenn man das ohne Floating 
Point rechnen will.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Muss mich entschuldigen.
Du rechnest dir ja die Spannung gar nicht explizit aus, sondern 
normierst den ADC Bereich auf 0.0 bis 1.0. Jetzt weiß ich auch wieder, 
warum mir die ganze Zeit 10% im Kopf rumgespukt sind. Das sieht man 
nämlich auch hier recht oft, dass das Ergebnis vom ADC auf Biegen und 
Brechen erst mal in eine SPannung umgerechnet wird, nur um dann mit 
einer weiteren Umrechnung die Spannung wieder in einen anderen Wert 
umzurechnen.

Ist aber vom Prinzip her egal. Letzten Endes ist es einfach nur ein 
Skalierfaktor, mit dem du das ADC Ergebnis beaufschlagst und der dich 
dazu zwingt Floating Point zu benutzen. Kann man machen, muss man nicht 
machen, für nicht verbrauchten Flash und eingesparte Laufzeit kriegt man 
kein Geld zurück.

von Conny G. (conny_g)


Lesenswert?

Ich verwende möglichst kein Float, denn Prigramme werden von alleine 
immer größer und dann hat man mal von vorne herein 1k mehr.
In den meisten Fällen kommt man um float auch einfach herum, warum dann 
1k und Rechenzeit verschwenden?
Da verwendest mal unbedacht in einem Timer INT ein float und wunderst 
dich, dass es seltsame Timing Probleme gibt etc.
Float ist einfach relativ teuer und hat m.E. In einem 4k, paar MHz uC 
nichts verloren.

von m.n. (Gast)


Lesenswert?

Conny G. schrieb:
> und Rechenzeit verschwenden?

Das verstehe ich nicht. Von welcher Rechenzeit reden wir denn hier - 
10µs oder 10ms?
Kannst Du konkrete Beispiele liefern?

von Conny G. (conny_g)


Lesenswert?

m.n. schrieb:
> Conny G. schrieb:
>> und Rechenzeit verschwenden?
>
> Das verstehe ich nicht. Von welcher Rechenzeit reden wir denn hier -
> 10µs oder 10ms?
> Kannst Du konkrete Beispiele liefern?

Nein und ich will hier keinen Glaubenskrieg anfangen - ich mag das halt 
nicht und mach das so.
Wer meint, er muss auf den Minigurken unbedingt mit Float rechnen, der 
soll es halt machen :-)

von m.n. (Gast)


Lesenswert?

Conny G. schrieb:
> Nein und ich will hier keinen Glaubenskrieg anfangen - ich mag das halt
> nicht und mach das so.
> Wer meint, er muss auf den Minigurken unbedingt mit Float rechnen, der
> soll es halt machen :-)

Na schön; es hätte mich auch gewundert, wenn Du für Deine vorlauten 
Behauptungen irgendwelche Beweise gehabt hättest.

von Cyblord -. (cyblord)


Lesenswert?

Es spricht nichts gegen float, aber man sollte wissen was man tut. Ist 
man sich der Probleme bewusst, ist alles ok. Es ist nur schlecht, wenn 
man völlig unreflektiert floats in ein Programm reinschmeißt, so als 
säße man an einer 3 GHz Kiste mit 8 GB Ram.
Man sollte sich eben klar machen dass float eben empfindlich flash 
kostet (1kb ist viel, manche avr haben nicht gar nicht mehr), und 
natürlich auch zusätzliche Takte bei der Berechnung.

Bewusster Umgang, dann ist alles ok.

gruß cyblord

von Svenska (Gast)


Lesenswert?

Für ein Uni-Projekt (Roboter mit ARM7) gab mir der Dozent den Tipp, 
double für alle Koordinaten zu verwenden. Das war das beste, was er 
hätte tun können. Die Bewegungsformeln brauchte ich dann nur noch 
hinschreiben und es tat schnell genug, was es sollte. Außerdem konnte 
ich die meisten internen Werte fürs Debugging gleich auf eine reale 
Größe beziehen.

Wenn man nicht mit komplizierten Formeln zu tun hat, tut es 
Festkommaarithmetik aber besser. Vor allem erspart man sich damit auch 
Probleme mit der numerischen Stabilität.

von Conny G. (conny_g)


Lesenswert?

m.n. schrieb:
> Conny G. schrieb:
>> Nein und ich will hier keinen Glaubenskrieg anfangen - ich mag das halt
>> nicht und mach das so.
>> Wer meint, er muss auf den Minigurken unbedingt mit Float rechnen, der
>> soll es halt machen :-)
>
> Na schön; es hätte mich auch gewundert, wenn Du für Deine vorlauten
> Behauptungen irgendwelche Beweise gehabt hättest.

Wahnsinn, dass hier immer gleich rumgepöbelt werden muss. Schade.
Würdest Du doch im echten Leben auch nicht machen.

von m.n. (Gast)


Lesenswert?

Conny G. schrieb:
> Wahnsinn, dass hier immer gleich rumgepöbelt werden muss. Schade.
> Würdest Du doch im echten Leben auch nicht machen.

Wenn ich herumgepöbelt hätte, hättest Du Dich nicht mehr gemeldet.
Wir sind hier in einem Technikforum, und nicht bei der dt. 
Bischofskonferenz in Münster. Für Glaubensfragen bist Du dort sicher 
besser aufgehoben, wenn es darum geht, gläubige Anhänger zu finden.

Hier muß man seine Behauptungen belegen; und dem verweigerst Du Dich.

Die Tage hat es mich sehr gefreut, dass ein sich ein TO trotz seiner 
anfänglichen Skepsis einmal die Zeit genommen hat, um seine float bzw. 
integer Berechnungen zu vergleichen. In der Ausführungszeit gab es 
keinen signifikanten Unterschied.

von San L. (zwillingsfreunde)


Lesenswert?

Mam Man Man ... richtiger Popcorn tread.

Wundert mich dass hier noch kein ASM vs C krieg angefangen hat, vonwegen 
Leute die ASM kennen würden wissen was Float berechnungen in einem 
Controller anstellen.

von Conny G. (conny_g)


Lesenswert?

m.n. schrieb:
> Conny G. schrieb:
>> Wahnsinn, dass hier immer gleich rumgepöbelt werden muss. Schade.
>> Würdest Du doch im echten Leben auch nicht machen.
>
> Wenn ich herumgepöbelt hätte, hättest Du Dich nicht mehr gemeldet.
> Wir sind hier in einem Technikforum, und nicht bei der dt.
> Bischofskonferenz in Münster. Für Glaubensfragen bist Du dort sicher
> besser aufgehoben, wenn es darum geht, gläubige Anhänger zu finden.
>
> Hier muß man seine Behauptungen belegen; und dem verweigerst Du Dich.
>
> Die Tage hat es mich sehr gefreut, dass ein sich ein TO trotz seiner
> anfänglichen Skepsis einmal die Zeit genommen hat, um seine float bzw.
> integer Berechnungen zu vergleichen. In der Ausführungszeit gab es
> keinen signifikanten Unterschied.

Ich führte aber auch keine wissenschaftliche Diskussion, ich stellte 
keine Behauptung auf, sondern äusserte eine Meinung, dass ich float auf 
uC nicht präferiere, wenn ich es vermeiden kann. So, Ende jetzt.

von m.n. (Gast)


Lesenswert?

San Lue schrieb:
> Mam Man Man ... richtiger Popcorn tread.

Halte Dich zurück, dann wird es auch keiner.

Svenska schrieb:
> Für ein Uni-Projekt (Roboter mit ARM7) gab mir der Dozent den Tipp,
> double für alle Koordinaten zu verwenden. Das war das beste, was er
> hätte tun können. Die Bewegungsformeln brauchte ich dann nur noch
> hinschreiben und es tat schnell genug, was es sollte. Außerdem konnte
> ich die meisten internen Werte fürs Debugging gleich auf eine reale
> Größe beziehen.

Dein Fazit: es war sinnvoll und richtig mit double zu rechnen. Soweit, 
so gut. Lieben Gruß an Deinen Dozenten :-)

> Wenn man nicht mit komplizierten Formeln zu tun hat, tut es
> Festkommaarithmetik aber besser. Vor allem erspart man sich damit auch
> Probleme mit der numerischen Stabilität.

Und jetzt auf einmal: doch besser nicht.
Dabei gehe ich davon aus, dass Du keine Probleme mit "numerischer 
Stabilität" hattest, sondern diese nur als "vages Gefühl" äusserst.
Wie, bitte schön, hättest Du denn Deine double-Berechnungen mit long 
oder longlong erschlagen können?
Ich gehe davon aus, dass dann die "numerische Stabilität" ein Problem 
gewesen wäre.

von Oliver S. (oliverso)


Lesenswert?

m.n. schrieb:
> Die Tage hat es mich sehr gefreut, dass ein sich ein TO trotz seiner
> anfänglichen Skepsis einmal die Zeit genommen hat, um seine float bzw.
> integer Berechnungen zu vergleichen. In der Ausführungszeit gab es
> keinen signifikanten Unterschied.

Da verwechselst du wohl signifikant mit relevant.

Oliver

von Karl H. (kbuchegg)


Lesenswert?

m.n. schrieb:

> Dabei gehe ich davon aus, dass Du keine Probleme mit "numerischer
> Stabilität" hattest, sondern diese nur als "vages Gefühl" äusserst.

Ich geh davon aus, dass er von seiner Roboter-Anwendung gesprochen hat.
In dem Moment, in dem sich Berechnungen über mehrere Formeln hinziehen 
und vor allen Dingen iterativ Werte mitgeführt werden, wie das bei 
Roboter-Anwendungen schon vorkommt, ist numerische Stabilität ein Thema. 
Hatte ich auch schon, das sich in einer Roboter-Simulation nach der 
20-ten Matrixmultiplikation die Matrix immer mehr denormalisiert hat. 
Und ja, das ist ein echtes Problem. 1000 Stück aufsummierte 0.001 
ergeben nun mal nicht 1.0. Und nach 360 mal sich um 1° weiterdrehen 
(ausgedrückt als Matrixmultiplikation) hat man sich eben nicht exakt 1 
mal im Kreis gedreht. Danach hat noch nicht mal der Einheitskreis mehr 
einen Radius von 1.0

Den Tip mit double kann man verallgemeinern: Auf einem PC bzw. auf einem 
ARM aufwärts, gibt es kaum einen Grund float zu verwenden.

Aber:
Das alles ist hier in diesem Beispiel kein Thema. Hier geht es um eine 
Normalisierung und daraus abgeleitet einen int-Wert zu berechnen. 
Numerische Stabilität ist da sicherlich kein Thema.

Das Fazit kann nur lauten: Man muss im jeweiligen Fall abwägen. So etwas 
wie 'one size fits all' gibt es nun mal in der Programmierung nur höchst 
selten. Genauso falsch ist es allerdings auch, generell einen 
Persil-Schein für Floating Point auszustellen. Speziell dann, wenn man 
nur 4 Byte float zur Verfügung hat.

: Bearbeitet durch User
von doppelschwarz (Gast)


Lesenswert?

Conny G. schrieb:
> So, Ende jetzt.

Ich habe dann doch noch eine Frage:
Wie sieht es mit RAM-Verbrauch aus? Und Stack-Größe? Ich könnte mir 
vorstellen, dass man von beidem mehr benötigt. Und da ich hier auch 
schon an der Grenze war (in dem Fall 1 kB), sollte man das auch 
berücksichtigen.

von Svenska (Gast)


Lesenswert?

Hallo,

> Wie, bitte schön, hättest Du denn Deine double-Berechnungen mit long
> oder longlong erschlagen können?
> Ich gehe davon aus, dass dann die "numerische Stabilität" ein Problem
> gewesen wäre.

sämtliche höheren Funktionen wurden mit Matlab verarbeitet (nicht meine 
Baustelle), und dort war die Basiseinheit ein Millimeter, keine 
Nachkommastellen. Das hätte ich auf dem Roboter auch machen können.

Was die numerische Stabilität angeht: Wenn da erstmal ein NaN drin 
steht, kriegt man das so schnell nicht mehr raus. Sanity checks hatte 
ich überall drin, aber das kam dann doch sehr überraschend (v.a. weil 
alle Befehle relativ waren, um Funklatenzen auszugleichen).

Gruß,
Svenska

von Amateur (Gast)


Lesenswert?

Ich habe mal das alte Studio 4 angeworfen und folgendes Codestückchen 
durchlaufen lassen.
Settings: Für ATMega16; Os; libm
1
uint32_t IRes;
2
uint32_t IAccu;
3
uint32_t IAdd;
4
double   FRes;
5
double   FAccu;
6
double   FAdd;
7
8
int main ( void ) {
9
  IAccu = 1000;
10
  IAdd  = 1000;
11
  FAccu = 1000.0;
12
  FAdd  = 1000.0;
13
                       // Cycle Counter
14
  IRes = IAccu + IAdd; // Bei Bearbeitung dieser Zeile 24 Takte
15
  FRes = FAccu + FAdd; // Bei Bearbeitung dieser Zeile 108 Takte
16
17
  if ( IRes == 12 ) IAccu = 0;     // Damit Os nicht
18
  if ( FRes == 12.0 )FAccu = 0.0;  // alles herausschmeißt
19
20
  IRes += IAccu;                   // Damit Os nicht
21
  FRes += FAccu;                   // alles herausschmeißt
Ich denke, abseits von allen Glaubensrichtungen ist dies, ein recht 
eindeutiges Ergebnis.
Dieses "Nichts" belegt ca. 1024 Bytes...

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Beim TO wird diese Bilanz sogar noch schlimmer ausfallen. Denn wenn er 
auf Floating Point verzichtet, fallen ihm einige Teile weg.

aus
1
float ADC_Read( .. )
2
    ...
3
    return ADCW / 1024.0;
4
5
...
6
7
   res = ADC_Read(0);
8
9
   if( res < 0.1 )
10
    ...

wird
1
uint16_t ADC_Read( .. )
2
    ...
3
    return ADCW;
4
5
   res = ADC_Read(0);
6
7
   if( res < 102 )
8
     ...
wodurch die komplette Konvertierung in float samt Division wegfällt und 
der Vergleich zum Pipifax für den µC wird.

Aber darum gehts doch gar nicht.
Er hat den Speicher und er hat die Laufzeit.

Bitte, bitte, bitte. Lasst ab von diesen Dogmen. Floating Point hat 
seine Berechtigung. Und trotzdem ist es gut, wenn man in der Lage ist, 
sich davon zu lösen falls man mal den Speicher und/oder die Laufzeit 
braucht.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Das hast du aber nicht mit -Os kompiliert.

Das übliche Problem solcher Tivial-Testprogramme ist, daß sich das alles 
zur Compilezeit berechnen lässt. Was der Compiler auch in diesem Fall 
gnadelos tut. Das erzeugte Programm besteht nur noch aus ldi- und 
sts-Befehlen (die er allerdinga auch noch komplett hätte wegoptimieren 
können. War ihm wahrscheinlich nur zu blöd)

Size after:
AVR Memory Usage
----------------
Device: atmega16

Program:     262 bytes (1.6% Full)
(.text + .data + .bootloader)

Data:         24 bytes (2.3% Full)
(.data + .bss + .noinit)


Oliver

: Bearbeitet durch User
von Amateur (Gast)


Lesenswert?

>Bitte, bitte, bitte. Lasst ab von diesen Dogmen. Floating Point hat
>seine Berechtigung.

@Karl Heinz
Um Himmels Wilhelm!
Natürlich hat die Fließkommaarithmetik ihre Daseinsberechtigung.

Ich wollte nur mal die Verhältnisse aufzeigen.
108/24 Takte ist ganz schön ziemlich. Vor allem wenn es, in Schleifen, 
rund geht.

>Das hast du aber nicht mit -Os kompiliert.
@Oliver
Stimmt, mit Os hat er gemerkt, dass er den ganzen Code auf den Müll 
schmeißen kann. Da lässt es sich schlecht testen.

von m.n. (Gast)


Lesenswert?

Amateur schrieb:
> Ich wollte nur mal die Verhältnisse aufzeigen.

Da Du das Rahmenprogramm schon hast, rechne doch bitte einmal mit 
6-stell. Auflösung: 95107*900113/773115
einmal mit int32_t und einmal mit float und zähle dafür die Takte.

von Amateur (Gast)


Lesenswert?

>Da Du das Rahmenprogramm schon hast, rechne doch bitte einmal mit
>6-stell.

@m.n.
Ganz sicher nicht.

Markieren und einfügen. Ich schätze mal dass Du dann den gleichen Code 
hast.
Das einzige, was Dir dann noch fehlt sind die Includes am Anfang und die 
abschließende Klammer am Ende. Müsste sich eigentlich machen lassen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

doppelschwarz schrieb:

> Ich habe dann doch noch eine Frage:
> Wie sieht es mit RAM-Verbrauch aus? Und Stack-Größe? Ich könnte mir
> vorstellen, dass man von beidem mehr benötigt. Und da ich hier auch
> schon an der Grenze war (in dem Fall 1 kB), sollte man das auch
> berücksichtigen.

Um ne Hausnummer zu nennen:
1
    Some software metrics for the AVR binary compiled as above:
2
    
3
    Program Size:  Less than 2000 of 2048 bytes
4
5
    RAM Usage:
6
        Static storage     :    0 bytes
7
        Static stack usage : ~ 50 bytes
8
        Dynamic            :    0 bytes
9
        Total              : 40% of 128 bytes

Das ist aus folgendem Projekt:

4000 Stellen von Pi mit ATtiny2313

und verwendet folgende float-Routinen:

Addition, Subtraktion, Multiplikation, Division, lrintf, Vergleiche (<=, 
>=) sowie int <--> float Konvertierungen.

Gerade der Stack-Verbrauch hängt aber auch nicht unwesentlich von der 
Verschachtelungstiefe der Funktionen ab.  Und natürlich auch was ISRs 
schlucken (die obiges Projekt nicht verwendet).

Aber immerhin hat der ATtiny2313 gerade mal 128 Bytes an RAM.

Das Demo-Projekt zeigt also schon ganz klar, daß float kein Teufelswerk 
ist.

Bei dem Code vom OP würde ich aber nicht auf float zurückgreifen, das 
ist dann doch zu viel Kanonen auf arme Spatzen geschossen.  Und außer 
bei dem "4000 Stellen von Pi" hab ich noch nie float auf nem AVR 
verwendet.  Ich war selbst überrscht was geht and hatte viel mehr 
Vorbehalte.

Im Rahmen der fixed-point Implementierung im avr-gcc ab 4.8 (IEC ISO/DTR 
18037 aka. "Embedded C") hab ich mich etwas näher mit der Umsetzung 
transzendenter Funktionen auseinandergesetzt wie z.B. sin oder arcsin. 
Man muß schon höllisch auf Bereichsüberläufe aufpassen, einfach eine 
Taylor-Entwicklung hinschreiben ist nicht. Taylor ist da eh komplett 
unbrauchbar.

Eine fixed-point Implementierung erreicht also rasch ihre Grenzen, und 
saturierte Operationen sind auch nicht wirklich hilfreich.  Vielleicht 
für Regler-Implementierungen, aber bei komlexeren Sachen ist's einfach 
fies, wenn Addition nicht nichmal mehr assoziativ ist.

Und von Rundungsfehlern bei verschachtelten Funktionsaufrufen will ich 
garnicht reden.

Manchmal sieht man auch hausbackene fixed-point Implementierungen, die 
den Code mit einem Schwall von Makros überziehen. Wirklich gut wartbar 
ist das auch nicht... Das sind dann eher Insel-Lösungen mit von Fall zu 
Fall angepasster Genauigkeit, Stelle des Dezimalpunkts, etc.

Ist hier also wie bei vielen Sachen: 'nen Königsweg gibt's nicht, und 
jeder wird nach eigener Facon glücklich -- oder unglücklich.

von m.n. (Gast)


Lesenswert?

Amateur schrieb:
>>Da Du das Rahmenprogramm schon hast, rechne doch bitte einmal mit
>>6-stell.
>
> @m.n.
> Ganz sicher nicht.

Amateur schrieb:
> Ich denke, abseits von allen Glaubensrichtungen ist dies, ein recht
> eindeutiges Ergebnis.

Ach so!

Johann L. schrieb:
> Ich war selbst überrscht was geht and hatte viel mehr Vorbehalte.

Das ist der Punkt, um den es mir geht. Aber dazu muß man erst die 
Vorurteile überwinden und kann dann je nach Aufgabe sachgerecht 
entscheiden.
Erst, wenn man weiß, dass in der Hölle immer gut geheizt ist, verliert 
sie ihren Schrecken :-)

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.