Bin Einsteiger in AVR GCC (sonst arbeite ich mit ASM) und habe heute das
erste C Programm mit AVR GCC geschrieben. Hatte keine Probleme mit dem
Compiler, läuft alles super, aaaaber im Build-Fenster steht:
2316 bytes (7.1% full)
(.text + .data + .bootloader)
Das kann doch wohl nicht sein, dass diese popelige Progrämmle (siehe
unten)bereits 7% von einem ATmega32 auffrist.
Kann mir da einer weiterhelfen, was ich hier definitiv falsch gemacht
habe.
Beste Grüße
Manni
/**************************************************************
Test Routine for fast atan2 function
**************************************************************/
#include "main.h"
double fast_atan2 (double y, double x);
#define PIBY2 M_PI / 2
int main( void )
{
double u, x, y, z1, z2;
x = 1.25678;
y = 1.25678;
z1 = atan2 (y, x);
z2 = fast_atan2 (y, x);
}
/**************************************************************
Here's another atan2 function, based on a 50-year old atan
approximation due to Hastings.
It has an |error| < 0.005, and is 3-5x faster than atan2.
**************************************************************/
double fast_atan2 (double y, double x)
{
double atan;
double z;
if (x == 0.0f)
{
if (y > 0.0) return PIBY2;
if (y == 0.0) return 0.0;
return -PIBY2;
}
z = y/x;
if (fabs(z) < 1.0f)
{
atan = z/(1.0 + 0.28*z*z);
if (x < 0.0)
{
if (y < 0.0) return atan - M_PI;
return atan + M_PI;
}
}
else
{
atan = PIBY2 - z/(z*z + 0.28);
if (y < 0.0) return atan - M_PI;
}
return atan;
}
Manni wrote:
> Das kann doch wohl nicht sein, dass diese popelige Progrämmle (siehe> unten)bereits 7% von einem ATmega32 auffrist.
Na dann möchte ich Dich mal sehen, wie Du Dir in Assembler einen mit
Floating Point Zahlen abbrichst.
Wenn Du auf weniger Code kommst und auch alles richtig rechnet, dann
kann ich nur sagen "Hut ab !".
Peter
Hallo Peter,
ja das ist ja der Grund, warum ich für diesen Fall den Assembler
verlassen hab, weil ich mir diesen Hut nicht anziehen will (hab'
gelegentlich auch noch was anderes zu tun).
Aber erklären kann ich mir noch nicht. Wenn ich den Disassembler
einschalte/ansehe, sind nur ca. 5% des Codes auf das Programm bezogen.
Nach der Anweisung:
return atan
folgen noch 95% code mit der bemerkung: -----No Source-------------
Hier unten eine kurze Kopie. Habe ich etwa die ganze libm.a
miteingebunden ?
57: return atan;
+000001DB: 8589 LDD R24,Y+9 Load indirect with
displacement
+000001DC: 859A LDD R25,Y+10 Load indirect with
displacement
+000001DD: 85AB LDD R26,Y+11 Load indirect with
displacement
+000001DE: 85BC LDD R27,Y+12 Load indirect with
displacement
+000001DF: 8B89 STD Y+17,R24 Store indirect with
displacement
+000001E0: 8B9A STD Y+18,R25 Store indirect with
displacement
+000001E1: 8BAB STD Y+19,R26 Store indirect with
displacement
+000001E2: 8BBC STD Y+20,R27 Store indirect with
displacement
58: }
+000001E3: 8969 LDD R22,Y+17 Load indirect with
displacement
+000001E4: 897A LDD R23,Y+18 Load indirect with
displacement
+000001E5: 898B LDD R24,Y+19 Load indirect with
displacement
+000001E6: 899C LDD R25,Y+20 Load indirect with
displacement
+000001E7: 9664 ADIW R28,0x14 Add immediate to word
+000001E8: B60F IN R0,0x3F In from I/O location
+000001E9: 94F8 CLI Global Interrupt
Disable
+000001EA: BFDE OUT 0x3E,R29 Out to I/O location
+000001EB: BE0F OUT 0x3F,R0 Out to I/O location
+000001EC: BFCD OUT 0x3D,R28 Out to I/O location
+000001ED: 91DF POP R29 Pop register from
stack
+000001EE: 91CF POP R28 Pop register from
stack
+000001EF: 9508 RET Subroutine return
+000001F0: 5850 SUBI R21,0x80 Subtract immediate
+000001F1: 2E19 MOV R1,R25 Copy register
+000001F2: D103 RCALL PC+0x0104 Relative call
subroutine
+000001F3: D001 RCALL PC+0x0002 Relative call
subroutine
+000001F4: C0E6 RJMP PC+0x00E7 Relative jump
+000001F5: 17BA CP R27,R26 Compare
+000001F6: 0762 CPC R22,R18 Compare with carry
+000001F7: 0773 CPC R23,R19 Compare with carry
+000001F8: 0784 CPC R24,R20 Compare with carry
+000001F9: 0795 CPC R25,R21 Compare with carry
+000001FA: F1B1 BREQ PC+0x37 Branch if equal
+000001FB: F488 BRCC PC+0x12 Branch if carry
cleared
+000001FC: F40E BRTC PC+0x02 Branch if T flag
cleared
+000001FD: 9410 COM R1 One's complement
+000001FE: 2E0B MOV R0,R27 Copy register
+000001FF: 2FBA MOV R27,R26 Copy register
+00000200: 2DA0 MOV R26,R0 Copy register
+00000201: 2E06 MOV R0,R22 Copy register
---- No Source
------------------------------------------------------------------------
------------
+00000202: 2F62 MOV R22,R18 Copy register
+00000203: 2D20
und hier kommen noch ca. 1800 bytes.
OK, verstehe ich !
Dann muss ich mal weiter forschen, wie ich das atan2 Problem anders
lösen lösen kann. Hab's mittlerweile auch im Disassembler gesehen, eben
die Gleitkommabibliothek.
Danke Dir !
Wie Peter schon schrieb, wird es dir sicher schwer fallen, Gleitkomma-
arithmetik in anderer Form mit wesentlich weniger Speicherverbrauch zu
implementieren.
Eventuell beschreibst du ja lieber mal dein Problem.
Ja, DL8DTL ist das Afu-Rufzeichen. Suffixe mit 1 Ziffer und 3
Buchstaben sind doch durchaus gängig, und waren praktisch die
einzigen, die sie uns seinerzeit hier in Neufünfland übergeholfen
haben, als wir unsere Y2-Calls abgeben mussten (obwohl die BRD ja nach
wie vor auf dem Block Y2-Y9 gluckt -- man hätte sie also auch
,,biologisch ausklingen'' lassen können, wenn man gewollt hätte).
Suffixe mit nur zwei Buchstaben oder das Rückerlangen alter DM-Calls
wurden erst später möglich. Aber letzteres hatte ich (gerade so)
ohnehin nicht mehr besessen, und außerdem hätte es noch einen Wechsel
des Calls bedeutet, das macht man nicht freiwillig.
Wenn du jetzt noch deine Fliesskommazahlen über uart per printf
ausgibst, kommt nochmals ein dicker Speicherhappen dazu. Das war es dann
aber auch. Alles, was du dann noch anstellst, wird die Codegröße
ungefähr linear anwachsen lassen, und das auch im erwarteten Rahmen. Da
ist noch viel Platz im Flash.
Das Compilerflag -Os ist aber immer hilfreich.
Oliver
@Oliver:
na das hat's ja ordentlich gebracht: ca. 47% weniger Programm-Bytes.
Habe aber noch nicht ausprobiert, was der Einfluß auf's Timing ist:
Zitat User Manual: "... at the possible expense of code execution
speed".
@Jörg:
Danke dir für die Eräuterungen zu deinem Rufzeichen. Bin ein bischen aus
der Übung gekommen weil mein 3-Element Beam nach dem Umzug in 2004 noch
immer im Keller liegt. Diesen Sommer kommt sie aber wieder auf's Dach.
Gruß DK4GL
"... at the possible expense of code execution speed". Das mag im
PC-Umfeld, im Vergleich zu der Optimierungsstufe -O3 stimmen.
Das schöne bei den Atmels ist, daß ein Befehl nur einen Takt dauert (die
allermeisten jedenfalls). Weniger Befehle => schneller. Und zwar fast so
viel, wie der Code kleiner wird.
Oliver
Naja, -O3 macht zuweilen durch loop unrolling, function inlining und
solche Dinge wirklich ein paar Takte gut trotz größeren Codes, aber
in der Tendenz stimmt es schon: beim AVR ist kleinerer Code oftmals
auch schneller.
@Jörg:
"Eventuell beschreibst du ja lieber mal dein Problem."
Anbei das "Problem", was aber eigentlich gar keines ist, bzw. sein
sollte. Nix aufregendes mit einer Abtastrate von ca. 1 Hz.
Phasenauflösung soll so bei einem Grad liegen. Da kann man noch vieles
nebenbei rechnen lassen. Lookup-Table wäre auch möglich mit 2*360 10bit
Werten (also 720 bytes). Hab ich aber noch nicht weiter verfolgt.
Vielleicht ist das ja die einfachste Lösung.
"-O3": Bei allen verfügbaren compiler flags -O1 bis -Os kommt ungefähr
immer die gleiche Codelänge raus, d.h. 40-50% weniger als bei -O0.
Ja, Lookup-Tabelle oder stützpunktbasierte Interpolation, das Ganze
möglichst im Integer-Bereich.
Andererseits ist die Frequenz wahrscheinlich wirklich gering genug,
dass du alle Zeit der Welt zum Rechnen hast, und Programmspeicher
hast du auch noch reichlich. Wenn's die Entwicklung des Prototypen
schneller macht, ist also die Gleitkommarechnung vielleicht gar nicht
so fehl am Platz. Wenn sie's am Ende ohne Einschränkung tut, warum
solltest du sie nicht auch einfach benutzen? Schließlich wirst du
von Atmel kein Geld zurück bekommen, wenn du Teile des ROMs nicht
benutzt. ;-)