Hallo zusammen,
ich bekomme momentan folgende Fehlermeldung:
Data Memory Usage : 162 bytes 126,6 % Full (Memory Overflow)
Nun hätte ich gerne herausgefunden, an welcher Stelle denn mein
Datenspeicher nicht ausreicht. Ich benutze Atme-Studio 6.2. Weiß jemand,
ob es dort eine Möglichkeit gibt, anzeigen zu lassen an welcher Stelle
dieser Fehler auftritt?
Folgendes habe ich schon versucht, ohne, dass sich die Zahlen geändert
hätten:
- Funktionen zusammengeführt um Variabeln zu sparen und den Stack zu
verkleinern
- Funktionen und Variabeln testweise ganz auskommentiert
>> Besagt, daß an Adresse 0x60 4 Byte als display_mem belegt sind.
1
.data 0x00800060 0x9a load address 0x000003f6
2
0x00800060 PROVIDE (__data_start, .)
Das wären ja schon mal 154 byte. Aber woher die jetzt kommen wird mir
daraus leider nicht ersichtlich. Meine im Programm verwendeten Variabeln
finde ich nirgends wieder.
@Oliver: Es ist ein AtTiny2313A, ich möchte daran ein Display betreiben
und per Inkrementalgeber eine Zahl zwischen 1 und 16.000.000 einstellen,
welche auf dem Display angezeigt wird. Ursprünglich dachte ich, dass die
dafür verwendete uint32_t daran schuld wäre, das erwähnte
auskommentieren dieser Zahl und auch der Umweg über drei uint8_t haben
leider nichts bewirkt.
M. S. schrieb:> Hallo zusammen,>> ich bekomme momentan folgende Fehlermeldung:>> Data Memory Usage : 162 bytes 126,6 % Full (Memory Overflow)>> Nun hätte ich gerne herausgefunden, an welcher Stelle denn mein> Datenspeicher nicht ausreicht.
Was meinst du mit "an welcher Stelle"? An welcher Stelle genau ist ein
Eimer zu klein für das Wasser, das du reinschüttest?
> Folgendes habe ich schon versucht, ohne, dass sich die Zahlen geändert> hätten:>> - Funktionen zusammengeführt um Variabeln zu sparen und den Stack zu> verkleinern
Der Stack ist in der oben angegebenen Anzeige gar nicht enthalten. Der
kommt also noch oben drauf. Dessen Größe ist dem Linker nicht bekannt,
da sie sich erst zur Laufzeit ergibt, deshalb kann sie dort nicht
angezeigt werden.
> - Funktionen und Variabeln testweise ganz auskommentiert
Funktionen brauchen Codespeicher, nicht Datenspeicher.
M. S. schrieb:> Das wären ja schon mal 154 byte. Aber woher die jetzt kommen wird mir> daraus leider nicht ersichtlich. Meine im Programm verwendeten Variabeln> finde ich nirgends wieder.
avr-objdump -t <ELF-Datei> sollte dir eine Liste aller Symbole mit Name
und Größe angeben.
M. S. schrieb:> Ursprünglich dachte ich, dass die> dafür verwendete uint32_t daran schuld wäre, das erwähnte> auskommentieren dieser Zahl und auch der Umweg über drei uint8_t haben> leider nichts bewirkt.
Ein uint32_t braucht vier Bytes. Drei uint8_t brauchen stattdessen drei
Bytes. Ist also nicht sehr verwunderlich, wenn sich dadurch nicht viel
ändert.
>Aus welchem Grund auch immer ein switch(uint8_t) so viel Arbeitsspeicher>benötigt...
Sach mal gehts noch? Da sind drei unbekannte Funktionen drin.
Man könnte ja glatt von selber auf die Idee kommen das die das
Problem sind.
M. S. schrieb:> Aus welchem Grund auch immer ein switch(uint8_t) so viel Arbeitsspeicher> benötigt...
Aus welchem Grund auch immer du darauf kommst, das ist es nicht.
Wie weiter oben schon steht, steht Code im Programmspeicher, nicht im
Sram.
Daher, wie immer: Code zeigen, und zwar komplett.
Oliver
Ja, dass die Funktionen nicht hier drin sind ist mir auch klar, ich
dachte dass es an dem "switch" liegt und wollte das mitteilen. Bin nun
aber durch weiteres ausprobieren darauf gekommen, dass es auf
"lcd_string()" zurückzuführen ist, das aus der hier auf µC.net zu
findenden lib verwendet wird:
1
void lcd_string( const char *data )
2
{
3
while( *data != '\0' )
4
lcd_data( *data++ );
5
}
mit
1
void lcd_data( uint8_t data )
2
{
3
LCD_PORT |= (1<<LCD_RS); // RS auf 1 setzen
4
5
lcd_out( data ); // zuerst die oberen,
6
lcd_out( data<<4 ); // dann die unteren 4 Bit senden
7
8
_delay_us( LCD_WRITEDATA_US );
9
}
und
1
static void lcd_out( uint8_t data )
2
{
3
data &= 0xF0; // obere 4 Bit maskieren
4
5
LCD_PORT &= ~(0xF0>>(4-LCD_DB)); // Maske löschen
6
LCD_PORT |= (data>>(4-LCD_DB)); // Bits setzen
7
lcd_enable();
8
}
Der verwendete Speicher ist dabei proportional zur länge des Strings,
konnte es dadurch umgehen, dass jedes Zeichen einzeln gesendet wird via
lcd_data. Hat der Tiny2313A einfach extrem wenig Arbeitsspeicher?
Auch die gezeigten Funktionen sind es nicht.
Der von AVR-size ausgegebene Wert umfasst nur globale und statische
Variablen. Die gibt es in den von dir gezeigten Codeabschnitten aber gar
nicht.
Und die Frage, ob ein Attiny2313a extrem wenig Arbeitspeixher hat, ist
ja wohl nicht ernst gemeint, oder?
Oliver
Es hängt auch vom Inhalt des Strings, d.h. ob Sonderzeichen enthalten
sind ab. Aber wie gesagt führt das heraus nehmen dieser Funktion dazu,
dass das Problem verschwindet. Anders herum führt das Einfügen eines
Aufrufs von lcd_string() an einer beliebigen Stelle dazu, dass die
Auslastung wieder extrem ansteigt. Ich habe exakt die Funktionen aus
https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung
verwendet. Dabei hängt die Auslastung auch vom Inhalt des Strings ab,
bspw. ein Sonderzeichen, hier "^" benötigt mehr Speicher.
M. S. schrieb:> Der verwendete Speicher ist dabei proportional zur länge des Strings,
Richtig. Die Zeile
lcd_string("123456789");
braucht 10 Bytes RAM um der String zu speichern. Jede solche String im
Code landet von Haus aus im RAM.
@Walter: Es geht mir darum, zu erfahren, wie ich allgemein die
Auslastung des Arbeitsspeichers verringern kann, da mir dadurch, dass
hier im konkreten Einzelfall etwas optimiert wird nicht für die Zukunft
geholfen ist.
@A.K.: Demnach dürften aber, da ich ein 16-Zeichen-Display verwende und
demnach auch nur höchstens 16 Zeichen an die Funktion übergebe,
höchstens 16 Bytes RAM verwendet werden, oder?
M. S. schrieb:> @A.K.: Demnach dürften aber, da ich ein 16-Zeichen-Display verwende und> demnach auch nur höchstens 16 Zeichen an die Funktion übergebe,> höchstens 16 Bytes RAM verwendet werden, oder?
Nein. Nicht die Funktion ist verantwortlich, sondern das "123456789".
Das muss irgendwo stehen, und da AVRs architekturbedingt das Flash nicht
mit einem const char * ansprechen können ist das eben RAM. Steht zwar
zusätzlich auch im ROM, wird aber beim Start ins RAM kopiert.
Schreib die Funktion als lcd_string(const __flash char *) und ruf sie
mit lcd_string(PSTR("123456789")) auf. Nun bleibt der String im Flash
und braucht kein RAM.
Der GCC legt Strings per default im SRAM ab und nicht im
Programmspeicher.
Schau mal ob deine LCD Bibliothek Funktionen anbietet, die direkt aus
dem Programmspeicher lesen.
( meist sb lcd_stringP( PSTR("Hallo"));)
Gruß Roland
Danke, der Tip hört sich gut an. Die Funktion ist so noch nicht in der
lib vorhanden, ich werde hoffentlich morgen dazu kommen, das
auszuprobieren und gebe dann Rückmeldung!
Ganz generell ist C-Programmierung auf einem Tiny mit nur 128 Byte Sram
sportlich. Da sollte man schon einen Überblich behalten, was da genau
verbraucht wird. Insofern ist da die unreflektierte Nutzung von libs aus
dem Netz nicht unbedingt der richtige Ansatz.
Oliver
@ Oliver S. (oliverso)
>Ganz generell ist C-Programmierung auf einem Tiny mit nur 128 Byte Sram>sportlich.
Naja. Für eine einfache Anzeige einer 24 Bit Zahl und bisser
Drehgeberauswertung reicht es allemal.
Am Ende sind es nur die typischen Anfängerfehler, welche unnötig
Resourcen verballern.
@ M. S. (elpaco)
Poste deine VOLLSTÄNDIGEN Quelltext oder gar das ganze Projekt als
Anhang. Dann kann man dir in 5 Minuten sagen, wo das Problem liegt.
Siehe Netiquette.
Hallo zusammen, danke nochmals für den Tip mit dem Flash. Ich habe die
Funktion ersetzt und kann nun auch lcd_stringP verwenden, ohne dass der
RAM dabei voll wird.
Ich verstehe die Einwände hier, dass in der Regel der komplette Code für
die Lösung eines Problems nötig ist. Jedoch konnte ich hier bereits die
verantwortliche Funktion selbst heraus finden, so dass die Funktionen
zum auswerten des Inkrementalgebers hier weg gelassen worden sind.
Problem gelöst, darf geschlossen werden.