Forum: Compiler & IDEs Kritischen Pfad für den Datenspeicher herausfinden?


von M. S. (elpaco)


Lesenswert?

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

von Oliver S. (oliverso)


Lesenswert?

Es gibt keine "Stelle". Programmierst du in C oder in Assembler?

Allerdings muß das ja ein sehr kleiner Tiny sein, den du da verwendest.

Oliver

von Peter D. (peda)


Lesenswert?

Im Map-File in der data Sektion.
Z.B.:
1
 .data          0x00800060        0x4 C:\WINDOWS\TEMP/ccik2v6G.o
2
                0x00800060                display_mem

Besagt, daß an Adresse 0x60 4 Byte als display_mem belegt sind.

von M. S. (elpaco)


Lesenswert?

Peter Dannegger schrieb:
> Im Map-File in der data Sektion.
> Z.B.:
>
1
>  .data          0x00800060        0x4 C:\WINDOWS\TEMP/ccik2v6G.o
2
>                 0x00800060                display_mem
3
>
>
> 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.

von Rolf M. (rmagnus)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

Stell das Mapfile mal hier rein.

von M. S. (elpaco)


Lesenswert?

Danke für die Antworten - ich habe zwischenzeitlich herausgefunden, 
welcher Teil des Codes das Problem verursacht hat.
1
    
2
switch(debounceIncrements())
3
{
4
  case 0:
5
    break;
6
  case 1:
7
    IncPlus();
8
    break;
9
  case 2:
10
    IncMinus();
11
    break;
12
  default:
13
    break;
14
}

Aus welchem Grund auch immer ein switch(uint8_t) so viel Arbeitsspeicher 
benötigt...

von holger (Gast)


Lesenswert?

>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.

von Oliver S. (oliverso)


Lesenswert?

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

: Bearbeitet durch User
von M. S. (elpaco)


Lesenswert?

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?

von Oliver S. (oliverso)


Lesenswert?

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

: Bearbeitet durch User
von Walter (Gast)


Lesenswert?

wenn Du dir helfen lassen willst bitte nicht immer irgendwelche 
Bröckchen präsentieren, sondern einfach das komplette Programm

von M. S. (elpaco)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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.

von M. S. (elpaco)


Lesenswert?

@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?

von ?!? (Gast)


Lesenswert?

M. S. schrieb:
> demnach auch nur höchstens 16 Zeichen an die Funktion übergebe,

17 Bytes (Nullbyte am Stringende beachten!)

von (prx) A. K. (prx)


Lesenswert?

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.

von Roland P. (pram)


Lesenswert?

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

von M. S. (elpaco)


Lesenswert?

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!

von Oliver S. (oliverso)


Lesenswert?

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

von Falk B. (falk)


Lesenswert?

@ 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.

von M. S. (elpaco)


Lesenswert?

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.

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.