Ein erster Ansatz ist es mal in das .map File zu sehen. Normalerweise steht da drin welche globale Variable wie viel Speicher braucht.
Hallo RoboterNetz-Gemeinde,
ich bin vor kurzem bei einem Projekt eingestiegen, bei dem wir auf Basis der AT90CAN128 von Atmel entwickeln. Die haben 4kb SRAM. Da das Projekt schon etwas umfangreicher ist und ich nicht den vollen Überblick habe, Suche ich nach einer Möglichkeit herauszufinden, an welchen Stellen im Code viel Arbeitsspeicher statisch belegt wird. Denn schon zur Compile-Zeit ist Data zu 90% voll, da bleibt nicht mehr viel übrig für dynamische Speicherbedarfe.
Gibt es ein Programm, das einem dabei hilft oder wie macht ihr das?
Ein erster Ansatz ist es mal in das .map File zu sehen. Normalerweise steht da drin welche globale Variable wie viel Speicher braucht.
Zeigt die die Größen aller Symbole.Code:avr-nm --size-sort -S xxx.elf
Disclaimer: none. Sue me.
@SprinterSB wo muss man das obige eingeben?
Habe nämlich ein ähnliches Problem, bei mir ist der Speicher des ATmega8 mit folgendem Code schon zu 47% voll:
Code:#include <avr/io.h> #ifndef F_CPU /* Definiere F_CPU, wenn F_CPU nicht bereits vorher definiert (z.B. durch Übergabe als Parameter zum Compiler innerhalb des Makefiles). Zusätzlich Ausgabe einer Warnung, die auf die "nachträgliche" Definition hinweist */ #warning "F_CPU war noch nicht definiert, wird nun mit 1000000 definiert" #define F_CPU 1000000 /* Quarz mit 1 Mhz */ #endif #include <util/delay.h> /* in älteren avr-libc Versionen <avr/delay.h> */ #define TEMPO 1800 #define TEMPO2 2000 int main (void) { DDRC = 0xFF; int ba=0; int const _A[] = {0b00001, 0b10110, 0b10110, 0b00001}; int const _H[] = {0b00000, 0b11011, 0b11011, 0b00000}; int const _L[] = {0b00000, 0b01111, 0b01111, 0b01111}; int const _O[] = {0b10001, 0b01110, 0b01110, 0b10001}; void B (int bb[]) { PORTC = bb[0]; _delay_us(TEMPO); PORTC = bb[1]; _delay_us(TEMPO); PORTC = bb[2]; _delay_us(TEMPO); PORTC = bb[3]; _delay_us(TEMPO); PORTC = 0b11111; _delay_us(TEMPO2); ba += 8; } while(1) { B(_H); B(_A); B(_L); B(_L); B(_O); _delay_ms(157 - ba); ba = 0; } return 0; }
Roboter, CNC Fräse, Elektronik und Basteleien stelle ich auf meiner Website vor...
@Jacob2:
Deine Konstanten belegen schon 128 Byte!
Eine Möglichkeit ist die Variablentypen immer so zu wählen, dass der Wert gerade rein passt, also die kleinst mögliche Variable. Bei 6 Bit wäre das unsigned char, der Speicherbedarf würde um Faktor 4 auf 32 Byte sinken.
Bei Variablen für Berechnungsergebnisse musst du gucken, dass das größtmögliche Ergebnis auch noch rein passt.
Oder gleich fest definieren, dann brauchst du dafür überhaupt keinen Speicherplatz.
Grus
Lorcan
wie fest definieren? mit #define? als int const?
ich habs doch gefunden, aber mir sagt das nichts was da steht!
Roboter, CNC Fräse, Elektronik und Basteleien stelle ich auf meiner Website vor...
Ich habs jetzt so umgeschrieben:
allerdings hat mir das höchstens 1% gebrachtCode:const unsigned char _A[] = {0b00001, 0b10110, 0b10110, 0b00001}; const unsigned char _H[] = {0b00000, 0b11011, 0b11011, 0b00000}; const unsigned char _L[] = {0b00000, 0b01111, 0b01111, 0b01111}; const unsigned char _O[] = {0b10001, 0b01110, 0b01110, 0b10001};
Roboter, CNC Fräse, Elektronik und Basteleien stelle ich auf meiner Website vor...
In einer shell/Konsole/Eingabeaufforderung.Zitat von Jacob2
Du kannst aber auch ein neues Target im Makefile hinzufügen, wenn du lieber mit make arbeitest.
Disclaimer: none. Sue me.
Das Problem ist jetzt, dass ich noch 22 weitere solcher Variablen unterzubringen hätte! Ich hab leider keinen anderen Controller zur Hand
Der Speicherstand sieht momentan so aus:
Program: 3830 bytes (46.8% Full)
(.text + .data + .bootloader)
Data: 280 bytes (27.3% Full)
(.data + .bss + .noinit)
Wie könnte man noch Platz sparen?
Roboter, CNC Fräse, Elektronik und Basteleien stelle ich auf meiner Website vor...
Hi!
Was auch sehr viel Platz braucht, sind Funktionsaufrufe, wenn die Aufruftiefe größer ist. Jeder Funktionsaufruf muss Register und die Rücksprungadresse auf dem Stack sichern.
Für die nächsten beiden Vorschläge werden mich meine Kollegen der Softwareentwicklung gleich steinigen, weil Code unleserlich wird oder böse Stolperfallen bereits halten kann:
1. Kleine Funktionen als Präprozessor-Makros schreiben. Ist für Funktionen gut, die z.B. Ports setzen oder auswerten. Ergebnis: Mehr Speicherbedarf durch Code, aber weniger durch Stack.
2. Funktionen, die nur zum Strukturieren des Codes eingeführt wurden rauswerfen und alles als einen Codeblock schreiben. Ergebnis: Etwas weniger Code, da Aufrufe wegfallen, weniger Stackbedarf. Der Code wird jedoch schwerer lesbar.
Auf die beiden Methoden greife ich bei meinen Projekten jedoch nur zurück, wenn's wirklich nicht mehr anders geht. Lieber greife ich zu einem größeren Controller.
Gruß,
Markus
Lesezeichen