PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Problem mit ATMEGA32. Variablen spielen verrückt.....



Kaiser-F
08.05.2006, 01:52
Hallo,

Ab einer Bestimmten Menge an Programm spielen die Variablen verrückt!!!


Liegt das an einer Überschreitung der Größen?

Size after:
main.elf :
section size addr
.text 8960 0
.data 1932 8388704
.bss 143 8390636
.noinit 0 8390779
.eeprom 0 8454144
.stab 10140 0
.stabstr 3996 0
Total 25171


Ich weiß nicht mehr aus!

ogni42
08.05.2006, 09:03
Flash: Nee, ist doch noch genug Platz.

RAM: Ja, Dein Stack wird Dir Variablen überschreiben:

.data + .bss = 2075 Byte was mehr ist als die 2048 bytes RAM des Mega32.

PasstScho
08.05.2006, 15:55
Hi Kaiser-F,
Gibt diesem Thema doch bitte einen gescheiten Namen!
Jeder braucht dringend hilfe, sondst würde man ja nicht fragen.

MfG Alex

Kaiser-F
09.05.2006, 22:08
Flash: Nee, ist doch noch genug Platz.

RAM: Ja, Dein Stack wird Dir Variablen überschreiben:

.data + .bss = 2075 Byte was mehr ist als die 2048 bytes RAM des Mega32.

Hm, das würde also begründen, warum die Variablen verrückt spielen?





Gibt diesem Thema doch bitte einen gescheiten Namen!
Jeder braucht dringend hilfe, sondst würde man ja nicht fragen.

MfG Alex

Sorry, hab schon geändert. Stört mich selber auch immer.
War so verwirrt, da ist mir nichts anderes eingefallen....

Technikus
10.05.2006, 11:27
Wenn der Stack Variablen überschreibt, dann kommt es zu genau diesen absolut unvorhersehbaren Ergebnissen. Daran bin ich auch schonmal fast verzweifelt.

Weiterhin würde ich bei so starker Auslastung des SRAM auf die Addition von .data und .bss nichts mehr geben. Je nach dem wie tief die Funktionen verschachtelt sind, kommt es schon deutlich vorher zu Problemen.

Schau Dir unbedingt den Artikel Speicherverbrauch bestimmen mit avr-gcc (https://www.roboternetz.de/wissen/index.php/Speicherverbrauch_bestimmen_mit_avr-gcc) hier im RN an. Bei mir waren die Werte des Compilers bei rund 90% SRAM und durch die verschachtelten Funktionsaufrufe hat mir der Stack regelmäßig globale Variablen zerschossen.

Servus
Technikus

Kaiser-F
10.05.2006, 19:28
Interessanter Artikel... Vielen Dank!

Nur wie behebe ich mein Problem...?
Soo viele Variablen im SRAM habe ich ja garnicht...

10 oder 20. Jeweils 8 oder 16 Bit, halbe/halbe.

Und eine Schriftart, die als Array gespeichert ist. Die ist aber nich im SRAM. Hoffe ich.

Habt ihr Informationen, wie man die Speicherart festlegt. In meinem Buch ist das zu allgemein auf PC-Systeme bezogen. Jetzt weiß ich nicht genau, wie das bei AVR-GCC gilt....

Vielen Dank für eure Bemühungen

izaseba
10.05.2006, 21:28
Und eine Schriftart, die als Array gespeichert ist. Die ist aber nich im SRAM. Hoffe ich.

meinst Du vielleicht avr/pgmspace.h u. avr/eeprom.h ?

Gruß Sebastian

Kaiser-F
10.05.2006, 22:12
Ähm.... Sorry, kann dir gerade nicht folgen, welcher Bahnhof?

izaseba
10.05.2006, 22:37
ähm, sorry, es sollte so sein:



Die ist aber nich im SRAM. Hoffe ich.
#-o


Habt ihr Informationen, wie man die Speicherart festlegt.

meinst Du vielleicht avr/pgmspace.h u. avr/eeprom.h ?

so, ich hoffe, jetzt ist es verständlicher ...

Gruß Sebastian

Technikus
11.05.2006, 13:44
Und eine Schriftart, die als Array gespeichert ist. Die ist aber nich im SRAM. Hoffe ich.

Wenn Du einfach ein Array definiert hast, z.B.

char array[256] = {1, 2, 3, ....};

dann liegt das sowohl im Flash als auch im SRAM! Das ist sinnvoll, wenn Du dieses Array zur Laufzeit ändern willst. Wenn Du aber nur die Werte ausliest und nicht änderst, ist das eine grandiose Verschwendung von SRAM.

Du kannst den Compiler anweisen, ein Array (wie jede andere Variable) nicht ins SRAM zu kopieren, sondern nur im Flash (oder im EEPROM) abzulegen.
Variablen im Flash werden so definiert:

char array[5] PROGMEM = {1, 2, 3, 4, 5};

Damit das funktioniert, brauchst Du

#include <avr/pgmspace.h>

Allerdings kannst Du auf Variablen im Flash nicht transparent zugreifen. Du mußt sie vor Gebrauch in das SRAM umkopieren. Trotzdem spart man viel SRAM, denn Du must von einem großen Array meist nur ein einzelnes Element im SRAM haben und nicht das ganze Array, z.B. 100 Elemente. Der Zugriff auf Variablen im Flash erfolgt mit den Funktionen pgm_read_byte, pgm_read_word, memcpy_P und viele andere. Für weitere Infos lies mal das
Tutorial von mikrocontroller.net (http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial), da stehen nähere Infos dazu drin. Ansonsten schau Dir mal das "avr libc user manual" bezüglich avr/pgmspace.h an, das findest Du (wenn Du WinAVR installiert hast) im Startmenü unter WinAVR.

Servus
Technikus

Edit: Link repariert

Kaiser-F
11.05.2006, 14:52
Hallo,

Ich danke euch für die Informationen. Jetzt versteh ich auch was izaseba gemeint hat.

Ich habe ein

uint8_t FONT_6X8[659] = {....}

Dass man da das PROGMEM dazwischen schreiben muss hab ich nicht gewusst. Ich hab hier mal gelesen, dass Variablen erst im SRAM sind,
wenn sie innerhalb der main funktion deklariert werden. Das hat sich aber
schon anhand von versuchen wiedersprochen......

Man lernt halt nie aus! Und ich programmier ja erst seit nem Jahr :-( ^^

Wie man dann dieses array ausliest muss ich mir dann noch erarbeiten.
Ich danke euch erstmal vielmals für diese Informationen!

Habt ihr noch weitere Tipps auf Lager? denn ich weiß nicht wo die restlichen ~1300 Bytes herkommen.

Ich hab eigentlich nur eine billige menüführung.... Das sind echt nur ein paar wenige Variablen... zusammen höchstens 50Bytes...

Naja und die Funktionen, aber die sind auch nicht so krass.....

izaseba
11.05.2006, 17:03
Man lernt halt nie aus!
So ist es.

Habt ihr noch weitere Tipps auf Lager?
Ich denke, der eine oder andere könnte was helfen, aber dann müßtest Du das Programm posten :-)

Gruß Sebastian

SprinterSB
11.05.2006, 23:42
Schau mal im avr-gcc-Artikel, da hab ich was dazu geschrieben:
13 Optimierungen, Tipps & Tricks (https://www.roboternetz.de/wissen/index.php/Avr-gcc#Optimierungen.2C_Tipps_.26_Tricks)
11.3 SRAM, Flash, EEPROM: Datenablage am Beispiel Strings (https://www.roboternetz.de/wissen/index.php/Avr-gcc#SRAM.2C_Flash.2C_EEPROM:_Datenablage_am_Beispi el_Strings)

In Hallo Welt für AVR (LED blinken) (https://www.roboternetz.de/wissen/index.php/Hallo_Welt_f%C3%BCr_AVR_%28LED_blinken%29) gibt es einen Unterabschnitt "Mapfile erstellen". Im MapFile stehen alle Lokatierungs-Infos.

Kaiser-F
11.05.2006, 23:44
Okey, danke!

Da werd ich mich am Wochenende mal durchackern.

Dankeschön und Gute Nacht!

Kaiser-F
09.06.2006, 09:46
Hallo,

Hat doch ein bisschen länger gedauert, musste für ne Prüfung lernen...

Also wenn ich das richtig verstanden habe, dann muss ich das machen:


// Headerdatei inportieren
#include <avr/pgmspace.h>

// mein Array Definieren
const uint8_t FONT[] PROGMEM = { 1,2,3,4,5,6,7,8,9,10.... };

// Und so frägt man ein einzelnes Byte aus dem Array ab:
data = pgm_read_byte(&FONT[i]);


Kurze Fragen noch:
1. Frage
Bei einer Normalen Deklaration, definiert der AVR wenn er die
Deklaration durchläuft einfach eine Variable im RAM, und der bleibt dann da im Rahmen des Geltungsbereiches?

2. Frage
Muss bei der definition einer "Flashvariable" immer das const davor stehen?

3. Frage
Bei Funktionen wird man zwahr eher weniger solche festen Arrays und
daten definieren, aber ich würde gerne verstehen warum da dann static
davor steht. Werden die dann im Flash geschrieben, und nach der
Funktion wieder gelöscht?

4. Frage
Obiges warscheinlich nur wenn man was großes Bearbeiten möchte...


Danke schon im Voraus für eure Antworten!

SprinterSB
09.06.2006, 11:35
(ad 1)
Der Gültigkeitsbereich einer Variablen ist etwas anderes als ihre Lebensdauer! Die Lebensdauer bezieht sich auf ein Objekt (im Sinne von C), während "Gültigkeitsbereich" im Hinblick auf ein Symbol (über welches ein Objekt referenziert wird) zu verstehen ist.

(ad 2)
Ja.

(ad 3)
Nein. Im [wiki="C-Tutorial"] steht dazu was unter Speicherklassen bzw. Gültigkeitsbereich. Daß der Gültigkeitsbereich einer Variablen verlassen wird bedeutet nicht unbedingt, daß diese zerstört wird! Ebenso werden diese Variablen nicht vom Startup-Code ins Flash gelegt (wo sollten ihre Werte denn herkommen?) sondern in eine Section gelegt, die im Flash landet und eben nicht im RAM (oder im EEPROM). Das static kann gebraucht werden, wenn man lokale Labels in einer Flash-Tabelle halten will. Ein Beispiel findet sich am Ende der "State-Machine" im [wiki="Sourcevergleich"]

(ad 4) ???

Kaiser-F
10.06.2006, 10:56
Hallo,

Danke für deine Antworten! Übrigens, netter Artikel!

Eines wäre noch offen,

Ich speichere ja nun mein Font-Array in den Flash.
Um ein Zeichen darzustellen, benötige ich 7Bytes aus dem Array.
Das bedeutet, wenn ich einen Satz schreibe, greift er ziemlich oft auf
den Flash zu.

Frage:
Wie sieht das ganze dann zeitlich aus? Dauert es recht viel länger,
Bytes aus dem Flash zu lesen, als vom RAM?

Ich denke mal, dass es dann in meinem Fall sinnvoller ist, gleich das
ganze Zeichen aus dem Flash zu lesen (die 7Bytes), und nicht jedesmal
Einzelzugriffe zu machen.

Kaiser-F
10.06.2006, 16:43
section size addr
.text 900 0
.data 0 8388704
.bss 0 8388704
.noinit 0 8388704
.eeprom 0 8454144
.stab 1020 0
.stabstr 1940 0
Total 3860


data + bss = 0.... Ich würde sagen, Problem gelöst!

Danke vielmals für eure Hilfe!
Das 650Byte Font liegt jetzt schön brav im Flash!

FAZIT: Man lernt nie aus!

SprinterSB
11.06.2006, 12:41
Von der Zugriffszeit tun sich SRAM und Flash nicht viel, was etwas teurer sein kann ist die Adressberechnung und weil der Flash nur via Z-Reg gelesen werden kann.

Um aus dem Flash ein Byte zu lesen gibt es in avr/pgmspace.h das Makro
pgm_read_byte (addr)
in dem addr ein C-Ausdruck ist, der zu einer Adresse auswertet (bzw. unsigned int).
Beim Zugriff auf zwei aufeinanderfolgende Adressen muss die Adresse immer wieder neu berechnet werden. Ist die Adresse jedoch ein Lvalue, könnte sie im Z gehalten werden und der Zugriff dementsprechend effizienter gestaltet werden.


#include <avr/pgmspace.h>

#if defined (__AVR_ENHANCED__)

#define pgm_read_byte_inc(addr) \
({ \
uint8_t __result; \
__asm__ \
( \
"lpm %0, Z+" \
: "=r" (__result), "=z" (addr) \
: "1" (addr) \
); \
__result; \
})
#endif /* __AVR_ENHANCED__ */

uint8_t sram[7];
const uint8_t flash[10][7] PROGMEM =
{
};

void foo (uint8_t num)
{
uint8_t i;

for (i=0; i<7; i++)
sram[i] = pgm_read_byte (& flash[num][i]);
}

void foo2 (uint8_t num)
{
uint8_t i;

const void * addr = flash[num];

for (i=0; i<7; i++)
sram[i] = pgm_read_byte_inc (addr);
}

void foo3 (uint8_t num)
{
const void * addr = flash[num];

sram[0] = pgm_read_byte_inc (addr);
sram[1] = pgm_read_byte_inc (addr);
sram[2] = pgm_read_byte_inc (addr);
sram[3] = pgm_read_byte_inc (addr);
sram[4] = pgm_read_byte_inc (addr);
sram[5] = pgm_read_byte_inc (addr);
sram[6] = pgm_read_byte_inc (addr);
}


Ja kannst du dann wählen, was du haben willst: minimale Laufzeit oder kleinster Code:

.global flash
.section .progmem.data,"a",@progbits
.size flash, 70
flash:
.skip 70,0
/*************************************************/
.text
.global foo
foo:
ldi r25,lo8(7) ; tmp48,
mul r24,r25 ; num, tmp48
movw r30,r0 ; tmp54
clr r1
ldi r26,lo8(sram) ; tmp53,
ldi r27,hi8(sram) ; tmp53,
subi r30,lo8(-(flash)) ; tmp54,
sbci r31,hi8(-(flash)) ; tmp54,
ldi r25,lo8(6) ; i,
.L161:
lpm r24, Z ; __result
st X+,r24 ; sram, __result
subi r25,lo8(-(-1)) ; i,
adiw r30,1 ; tmp54,
sbrs r25,7 ; i,
rjmp .L161 ;
ret
/*************************************************/
.global foo2
foo2:
ldi r25,lo8(7) ; tmp45,
mul r24,r25 ; num, tmp45
movw r30,r0 ; addr
clr r1
subi r30,lo8(-(flash)) ; addr,
sbci r31,hi8(-(flash)) ; addr,
ldi r26,lo8(sram) ; tmp51,
ldi r27,hi8(sram) ; tmp51,
ldi r25,lo8(6) ; i,
.L168:
lpm r24, Z+ ; __result
st X+,r24 ; sram, __result
subi r25,lo8(-(-1)) ; i,
sbrs r25,7 ; i,
rjmp .L168 ;
ret
/*************************************************/
.global foo3
foo3:
ldi r25,lo8(7) ; tmp45,
mul r24,r25 ; num, tmp45
movw r30,r0 ; addr
clr r1
subi r30,lo8(-(flash)) ; addr,
sbci r31,hi8(-(flash)) ; addr,
lpm r24, Z+ ; __result
sts sram,r24 ; sram, __result
lpm r24, Z+ ; __result
sts sram+1,r24 ; sram, __result
lpm r24, Z+ ; __result
sts sram+2,r24 ; sram, __result
lpm r24, Z+ ; __result
sts sram+3,r24 ; sram, __result
lpm r24, Z+ ; __result
sts sram+4,r24 ; sram, __result
lpm r24, Z+ ; __result
sts sram+5,r24 ; sram, __result
lpm r24, Z+ ; __result
sts sram+6,r24 ; sram, __result
ret
/*************************************************/
sram:
.skip 7,0

Kaiser-F
12.06.2006, 07:49
Hallo,

erstmal besten Dank für Deine Bemühungen!

Ich werd gleich mal damit rumexperimentieren! Danke!

Kaiser-F
13.06.2006, 08:15
Hier bin ich nochmal,

Ich hätte noch eine Frage bezüglich der Speicherplatzverwaltung:

Ich habe in meinem Programm den Ausdruck:
LCD_FONT_6x8( 1, 4," Standby ");

Wo wird " Standby " abgespeichert?

Ich habe sehr viele solche Ausdrücke, und ich vermute, dass diese auch
im RAM gespeichert werden.... :-( .

Gibt es da auch eine elegante lösung?
Als String im Flash speichern?

SprinterSB
13.06.2006, 12:56
Ein Blick in den generierten Assembler beantwortet die Frage: Das Ding steht im Flash und wird vom StartUp ins SRAM kopiert. (Section .data wahrscheinlich).

Wie man die Strings im Flash lässt steht in [wiki="avr-gcc"]. Wo das Zeug landet kannst du sehen
-- im Assembler (Object-Sections bzw. wie es zugrgriffen wird
-- evtl. im Mapfile
-- evtl im Disassemble des Objects (auch .data disassemblen)
-- im Disassemble des elf
-- anzeigbar mit avr-nm, falls lokale Symbole nicht in der Tonne landen

Du schreibst die eine Funktion
void LCD_FONT_6x8_P (int, int, const char *)
die nichst aud dem SRAM liest, sondern aus dem Flash.

Aufruf:

#include <avr/pgmspace.h>

extern void LCD_FONT_6x8_P (int, int, const char *);

...
LCD_FONT_6x8_P (1, 2, PSTR ("Standby"));