Hallo,
ich habe ein recht vollgestopften Flash durch mein Programm, bin bei 93%
auf einem ATMega8. Ich kommuniziere über UART und SPI, frage einen ADC
über SPI ab und schicke die Daten an einen CAN Controller über SPI.
Jetzt möchte ich gerne die Daten vom ADC von counts nach Volt wandeln
und muss dazu folgende Formel anwenden:
Wenn ich das nun in den Code einpflege wird der sofort um ca 500Byte
größer und sprengt mir somit den Flash. Ich habe durch Probieren
rausbekommen, dass es an der Multiplikation von ADC_[counts] mit dem
Rest hängt. Nehme ich die raus, stehe ich bei 96%. ADC_[counts] ist eine
uint32_t Variable, der Rest float. Ich wollte daher einen Cast machen
nach float.
Was kann ich machen oder umstricken, ohne dass ich den Rest des
Programms rausschmeißen muss?
Danke euch.
Grüße
Hi,
ich befürchte da kann man wenig machen. Das Rechnen mit einer 32-bit
Float-Variable ist verständlicherweise sehr Programmintensiv. Du
solltest überlegen, ob du wirklich mit float rechnen musst, oder ob ein
normaler Ganzzahlwert ausreicht.
Ansonsten ist der Atmega168 (glaube ich) Pin-kompatibel und bietet
doppelt so viel Flash.
Wo siehst Du eine Multiplikation?
0.5 = rechtsshift um 1
1/(2^23-1) = ca. rechtsshift um 23
VRef/Gain = vermutlich auch links- oder rechtsshift mit glattem Wert
Auch ich würde gänzlich auf float verzichten und alles mit uint32_t
rechnen. (dafür alles in mV, falls dies von der Auflösung aussreicht!)
Venwendest Du die Math-Lib für AVR? (Linker Option: -lm), die ist für
AVR optimirt und wesentlich schlanker als die generische GCC Math-Lib
(welche unsinnigerweise meistens defaultmässig dazugelinkt wird)
Gunther schrieb:
> Wo siehst Du eine Multiplikation?>> 0.5 = rechtsshift um 1> 1/(2^23-1) = ca. rechtsshift um 23> VRef/Gain = vermutlich auch links- oder rechtsshift mit glattem Wert
Vermutlich float VRef;
float Gain;
und damit sind deine ganzen Shiftereien nur noch Makulatur.
Wenn er den ganzen Code (ohne die SPI / UART Funktionen, bei denen kann
man gar nicht so viel Speicher verbrauchen) herzeigen würde, dann könnte
man sich das alles mal ansehen und nicht nur generische Vorschläge
machen. Aber wahrscheinlich ist das wieder mal ein Geheimprojekt :-)
Bevor ich auf fix-und-fertig Berechnungen umstelle, würde ich lieber den
Euro für einen 'dickeren' Prozessor spendieren und 'float' anstatt
Tränen fließen lassen :-)
> Vermutlich float VRef;> float Gain;>> und damit sind deine ganzen Shiftereien nur noch Makulatur.
Wäre es bei mir nicht unbedingt, da ich bei der Hardwaredefinition auch
die Software im Blick habe (und natürlich umgekehrt).
Gunther schrieb:
>> Vermutlich float VRef;>> float Gain;>>>> und damit sind deine ganzen Shiftereien nur noch Makulatur.>> Wäre es bei mir nicht unbedingt, da ich bei der Hardwaredefinition auch> die Software im Blick habe (und natürlich umgekehrt).
Das passiert des öfteren, wenn Leute float blauäugig einsetzen.
So nach dem Muster: Da denk ich gar nicht lange nach - float muss her.
Besonders interessant wird es dann, wenn der float sich über mehrere
Berechnungsstufen hinzieht. 6 signifikante Stellen sind nicht viel und
sind schnell aufgebraucht. Ab dann hätte man geausogut auch würfeln
können :-)
// wir sind ab hier wieder mit dem CAN Bus verbunden
114
115
PRINT("Versuche die Nachricht per CAN zu verschicken\n");
116
117
// Versuche nochmal die Nachricht zu verschicken, diesmal per CAN
118
if(mcp2515_send_message(&message)){
119
PRINT("Nachricht wurde in die Puffer geschrieben\n\n");
120
}
121
else{
122
PRINT("Fehler: konnte die Nachricht nicht senden\n\n");
123
}
124
125
PRINT("Warte auf den Empfang von Nachrichten\n\n");
126
127
128
/* For CAN board carrying ADS1234 only
129
*/
130
PRINT("================ \n");
131
PRINT("Schalte jetzt Pins durch...\n");
132
PRINT("ADS1234: set gain factor to %3d... ",1);
133
if(ADS1234_setGain(1))
134
PRINT("[done]\n");
135
else
136
PRINT("[failed]\n");
137
138
PRINT("ADS1234: set channel to %2d... ",4);
139
if(ADS1234_setChannel(4))
140
PRINT("[done]\n");
141
else
142
PRINT("[failed]\n");
143
144
PRINT("ADS1234: set speed to %2d... ",10);
145
if(ADS1234_setSpeed(10))
146
PRINT("[done]\n");
147
else
148
PRINT("[failed]\n");
149
150
PRINT("ADS1234: calibrating... ");
151
if(ADS1234_calibrate())
152
PRINT("[done]\n");
153
else
154
PRINT("[failed]\n");
155
PRINT("SetUp beendet.\n==============\n\n");
156
157
//Let's get us a variable to hold latest data
158
int32_tAData=0;
159
intcount=0;
160
charstr[9];
161
162
while(1){
163
164
// warten bis wir eine Nachricht empfangen
165
if(mcp2515_check_message())
166
{
167
PRINT("Nachricht empfangen!\n");
168
169
// Lese die Nachricht aus dem Puffern des MCP2515
170
if(mcp2515_get_message(&message)){
171
print_can_message(&message);
172
PRINT("\n");
173
}
174
else{
175
PRINT("Kann die Nachricht nicht auslesen\n\n");
176
}
177
}
178
179
180
/* For CAN board carrying ADS1234 only
181
*/
182
if(ADS1234_checkDrdy())
183
{
184
185
PRINT("Data waiting ...");
186
187
if(ADS1234_getData(&AData))
188
{
189
PRINT("count: %i Value:",count);
190
floatVData=counts2voltage(AData);
191
ltoa(VData,str,10);
192
PRINT("%f V\n",VData);
193
194
}
195
else
196
PRINT("Could not acquire data!\n");
197
}
198
199
count+=1;
200
_delay_ms(500);
201
}
202
return0;
203
}
Das ist mein gesamtes Programm, ich nutze einen ADS1234 ADC von TI und
einen MCP2515 für den CAN Bus. Für den CAN Bus nutze ich die Bibliothek
von Fabian Greif, für den ADC habe ich selbst eine geschrieben.
@Peter: Deine Idee finde ich äußerst interessant. Habe gerade mal mit
der Linker Option -lm gearbeitet, aber der erzeugte Code scheint genauso
groß zu sein. Wie kann ich die Anbindung der GCC-Mathe Bibliothek
unterbinden? Ich habe ja gar keine math.h an sich eingebunden...Aber ich
sehe grade, dass WinAVR standardmäßig anscheinend -lm schon nutzt.
Ich würde wohl mal die Festarithmetrik ausprobieren, aber es
interessiert mich schon wieso und vor allem wo die 500Bytes hingehen.
Hatte lediglich erwartet, dass es eben lange dauert - die Float
Geschichte...
Grüße
MPPT schrieb:
> da er kein progmem nutzt, sind die eigentlich nicht im Flash
Ohne PROGMEM wären sie im Ram UND im Flash. Denn irgend woher muss der
RAM ja initialisiert werden. :)
Klaus schrieb:
> wow, dein Flash ist ja zur Hälfte mit Textstrings voll oO
OK, hab ich mir noch gar keine Gedanken drüber gemacht, aber ich habe
gerade mit folgender Version eine 87%ige Auslastung des Speichers
erreicht:
Das Programm sieht nicht sonderlich groß aus.
Die Flashfresser werden in dem nicht geposteten Code liegen.
Wenn Du es mit den fehlenden *.c und *.h zippen würdest, könnte man es
mal optimiert compilieren.
Peter
S. G. schrieb:
Ich würde wohl mal die Festarithmetrik ausprobieren, aber es
> interessiert mich schon wieso und vor allem wo die 500Bytes hingehen.> Hatte lediglich erwartet, dass es eben lange dauert - die Float> Geschichte...
Na ja.
Die halbe Floating Point Libarry ist dann schon mal ein Wummer.
Dazu dann noch der ganze stream Überbau, den du dir mit der sorglosen
Verwendung von printf einhandelts, obwohl du ihn nirgend wo wirklich
brauchst oder auch nur annähernd in seinen Fähigkeiten ausnutzt. Eine
puts Funktion zusammen mit einer puti (für Integer Ausgaben) hätte es
auch getan.
S. G. schrieb:
> Dann versuch ich mal die PRINTs durch uart_puts zu ersetzen. Wie gut> oder schlecht is die Nutzung von itoa() im Sinne des Speichers?
itoa ist klein.
printf, sprintf, fprintf als eierlegende Wollmilchsäue mit x
verschiedenen Möglichkeiten zur Zahlenformatierung im Formatstring, sind
schon nicht ohne.
Sinn macht es allerdings nur, wenn du ALLE printf ersetzt!
Karl heinz Buchegger schrieb:
> Sinn macht es allerdings nur, wenn du ALLE printf ersetzt!
Also ich habe das von mir zuerst gepostete Programm genommen und
folgendes gemacht:
Karl heinz Buchegger schrieb:
> Ach ja.> Wenn du genauer wissen willst, wie sich der Flash aufteilt: lass dir ein> Map-File erzeugen. Da stehts genau aufgeschlüsselt drinnen.
Jetzt muss ich wieder mit Unvermögen prahlen... wie krieg ich das hin?
S. G. schrieb:
> Karl heinz Buchegger schrieb:>> Ach ja.>> Wenn du genauer wissen willst, wie sich der Flash aufteilt: lass dir ein>> Map-File erzeugen. Da stehts genau aufgeschlüsselt drinnen.>> Jetzt muss ich wieder mit Unvermögen prahlen... wie krieg ich das hin?AVR-Studio?
Bei den Prjekt Einstellungen gibt es Häkchen für Listfile und für Map.
Die Print-Geschichte isses nicht, Platz kostet immer nur der erste
Aufruf.
Das Programm müßte bequem in 4kB passen.
Der Flashfresser liegt woanders!
Peter
dann sucht dir der Compiler raus, wo du nicht einfach einen printf
ersetzen kannst, sondern noch mehr eingreifen musst.
> ersetzt und komme auf 95% Auslastung, was für mich reicht. Ich muss> überlegen, ob ich dennoch mit der Festkommaarithmetik weiter komme.
Auf jeden Fall.
Lass dir nicht Volt ausrechnen sondern Millivolt. Oder von mir aus 10-er
Einheiten von Millivolt (wozu hat men denn sonst einen ADC mit sovielen
Bits, so dass es höchst fragwürdig ist, ob das nach der 5ten
Nachkommastelle überhaupt noch in irgendeiner Weise mit der zu messenden
Spannung korreliert :-)
Peter Dannegger schrieb:
> Die Print-Geschichte isses nicht, Platz kostet immer nur der erste> Aufruf.
Bischen was ist es auch.
Mit dem ganzen stream Überbau, printf ist auch nicht gerade Schmalhans.
> Das Programm müßte bequem in 4kB passen.
Ähm. Da fällt mir noch was ein.
Nachdem der TO die Projekt Einstellungen anscheinend nicht kennt:
Die Optimierung ist aber eingeschaltet?
Ich kenn schon die Projekteinstellungen, so ist es nicht. Aber ich hab
mir eben noch nie eine Memory Map vom AVR anschauen müssen. Die Häkchen
sind übrigens standardmäßig gesetzt.
Ich habe die Optimierung überprüft, steht auf "-Os".
Ich habe zusätzlich mal libm.a dazugelinkt und auf einmal habe ich trotz
Nutzung von printf jetzt wieder nur noch 70% Auslastung.
S. G. schrieb:
> Ich habe zusätzlich mal libm.a dazugelinkt und auf einmal habe ich trotz> Nutzung von printf jetzt wieder nur noch 70% Auslastung.
Fehler: ich habe zusätzlich noch die -libprintf_min dazugelinkt und
dadurch wurde das Programm so klein, konnte allerdings keine float
Variablen mehr
im printf Befehl darstellen -> "?"
Also hab ichs rausgenommen und bin wieder bei meinen knappen 100% wenn
ich den einen oder anderen String auskommentiere und konsequent auf
uart_puts() + ltoa() vertraue.
S. G. schrieb:
> S. G. schrieb:>> Ich habe zusätzlich mal libm.a dazugelinkt und auf einmal habe ich trotz>> Nutzung von printf jetzt wieder nur noch 70% Auslastung.> Fehler: ich habe zusätzlich noch die -libprintf_min dazugelinkt und> dadurch wurde das Programm so klein, konnte allerdings keine float> Variablen mehr> im printf Befehl darstellen -> "?"
Das ist klar.
Ein Punkt für das 'Minimalversion' in liblrpintf_min ist es eben, dass
die floating point Unterstützung herausoperiert wurde.
jop! Hab ich verstanden. Jetzt versuche ich mal die
Festkommegeschichte...
Karl heinz, hast du noch einen Tipp für mich, wie ich Strings im EEPROM
ablegen kann und dann einfach zur "Anzeige" bringe über UART? Danke dir
S. G. schrieb:
> jop! Hab ich verstanden. Jetzt versuche ich mal die> Festkommegeschichte...>> Karl heinz, hast du noch einen Tipp für mich, wie ich Strings im EEPROM> ablegen kann und dann einfach zur "Anzeige" bringe über UART? Danke dir
Da gibts nicht sehr viel an Tipps.
String im EEPROM ablegen. Mit den EEPROM Funktionen auslesen und ab zur
UART damit. Alles straightforward.
Aber ehe du dich da jetzt ins Unglück stürzt: Denk mal darüber nach, ob
deine Texte wirklich so geschwätzig sein müssen.
Ich meine ...
1
if(!mcp2515_init()){
2
PRINT("Fehler: kann den MCP2515 nicht ansprechen!\n");
3
for(;;);
4
}
... liest sich natürlich wunderbar. Aber ein simples
1
if(!mcp2515_init()){
2
PRINT("Fehler: MCP2515 nicht gefunden!\n");
3
for(;;);
4
}
oder
1
if(!mcp2515_init()){
2
PRINT("Error: MCP2515 not found!\n");
3
for(;;);
4
}
tut's auch. Und in Summe sinds dann auch ein paar Bytes. Ein paar Bytes
hier, ein paar Bytes da und schon sind wieder 100 oder 200 Bytes
beisammen.
Hm...Da hast du Recht Karl Heinz.
Werds mal eindampfen und dann mal schauen, ob ich noch Platz brauche,
dann ggf. ins EEPROM auslagern.
Dane euch für die Hilfe.
Grüße