Sehr seltsames Verhalten von Arrays

OP #2434711
Lesenswert?

Hallo,

Ich weiß nicht was gerade das Problem ist, aber ich kann keine Arrays 
mehr benutzen...

Folgendes habe ich geschrieben:
1
uint8_t data []= {128,128,128,128,139,128,128,196,128,128,244,128,128,248,128,128,210,128};
2
for (uint16_t i = 0; i < 18; i++)
3
  write8(data[i]);
Das gibt allerdings sehr seltsame Ergebnisse aus (genau kann ich es 
nicht sagen, da ich kein LCD o.ä. habe, um mir Daten auszugeben.

Auf jeden Fall macht dieser Code auf keinen Fall das gleiche wie:
1
write8(128);
2
write8(128);
3
write8(128);
4
write8(128);
5
write8(139);
6
...

Die Funktion, die ich aufrufe, ist folgende: void write8(uint8_t d)

Ich hoffe ihr seht, wo mein Denkfehler ist...

Das ganze läuft auf einem ATmega16.

Viele Grüße,
Manuel

PS: Kann ich auf diese Weise eigentlich auch Arrays aus 7000 Elementen 
ansprechen? Da der ATmega16 nur 1K-Ram hat, kann das Array ja auf jeden 
Fall nicht vollständig in den RAM geladen werden...
Gast #2434714
Lesenswert?

Gebt mir ein: D
Gebt mir ein: E
Gebt mir ein: B
Gebt mir ein: U
Gebt mir ein: G
Gebt mir noch ein: G
Gebt mir wieder ein: E
Gebt mir ein: R

Vielleicht sollte der Gedankengang, alles ist korrekt bis auf diese paar 
Zeilen, noch einmal überdacht werden, da die scheinbar nicht vorhandene 
Ausgabe ja fundiert auf einen Fehler in diesen Zeilen hinweist.
#2434730
Lesenswert?

Manuel Vossel schrieb:

> Folgendes habe ich geschrieben:
>
1
uint8_t data []=
2
> {128,128,128,128,139,128,128,196,128,128,244,128,128,248,128,128,210,128};
3
> for (uint16_t i = 0; i < 18; i++)
4
>   write8(data[i]);
> Das gibt allerdings sehr seltsame Ergebnisse aus (genau kann ich es
> nicht sagen, da ich kein LCD o.ä. habe, um mir Daten auszugeben.
>
> Auf jeden Fall macht dieser Code auf keinen Fall das gleiche wie:
>
1
write8(128);
2
> write8(128);
3
> write8(128);
4
> write8(128);
5
> write8(139);
6
> ...
7
>

Das Timing ist ein klein wenig anders, aber ansonsten sind sie 
gleichwertig.


> PS: Kann ich auf diese Weise eigentlich auch Arrays aus 7000 Elementen
> ansprechen? Da der ATmega16 nur 1K-Ram hat, kann das Array ja auf jeden
> Fall nicht vollständig in den RAM geladen werden...

Und wie willst du in einen Speicher mit einer definierten Maximalgröße 
Daten reinpferchen, die größer sind. Harry Potter Modus?
Gast #2434736
Lesenswert?

Wenn du C++/C99 verwendest sollte die Funktion write8 korrekt aufgerufen 
werden. Was dort geschieht kann hier keiner sehen.

Da du 16Kb an Flash hast, könntest du das Array immer aus den Flash 
lesen (vorausgesetzt du willst es nur lesen) ohne es in den RAM zu 
laden.
OP #2434820
Lesenswert?

Habe das Problem jetzt mehr durch Zufall gefunden.
Ich hatte besagtes 7000k-Array vorher schon definiert, und das hat dem 
wohl im RAM alles durcheinander gebracht...
Debuggen hatte ich schon versucht, allerdings hat der die for-Schleife 
immer übersprungen (auch bei Step Into, nicht nur bei Step Over) - ich 
benutze AVR Studio.

Kast schrieb:
> Da du 16Kb an Flash hast, könntest du das Array immer aus den Flash
> lesen (vorausgesetzt du willst es nur lesen) ohne es in den RAM zu
> laden.

Ja, ich will das nur lesen.
Allerdings müsste ich das erstellen des Arrays dann wahrscheinlich in 
der .hex-Datei machen?! Oder gibts da eine andere Möglichkeit, dass das 
schon im Flash liegt, wenn der µC startet?
Ich müsste im 40ms-Takt daraus jeweils 96 Byte lesen und per write8 
schreiben.

Aber falls das jetzt zu kompliziert ist, mach ich mir die Mühe nicht. Im 
Endeffekt liegen die Daten sowieso auf einer SD-Karte, weil das ung. 8MB 
werden, von denen ich pro 40ms 576byte lesen muss und rausschicke (das 
ganze wird eine Animation auf einem digitalen RGB-Strip).
#2434830
Lesenswert?

Manuel Vossel schrieb:
> Habe das Problem jetzt mehr durch Zufall gefunden.
> Ich hatte besagtes 7000k-Array vorher schon definiert, und das hat dem
> wohl im RAM alles durcheinander gebracht...

Genau deswegen gibt doch die Toolchain im AVR-Studio eine 
Speicherverbrauchsstatistik aus (zumindest in AVR-Studio 4, wie das bei 
5 ist weiß ich nicht). Ist der SRAM Verbauch bei den kleineren 
Prozessoren bei 80 bis 85%, wirds meistens schönb langsam kritisch.


> Allerdings müsste ich das erstellen des Arrays dann wahrscheinlich in
> der .hex-Datei machen?!

Nö.
Du musst das nur richtig definieren und anders aufs Array zugreifen.

> Oder gibts da eine andere Möglichkeit, dass das
> schon im Flash liegt, wenn der µC startet?

Das liegt sowieso im Flash. Wo soll es denn sonst herkommen?


> Ich müsste im 40ms-Takt daraus jeweils 96 Byte lesen und per write8
> schreiben.
>
> Aber falls das jetzt zu kompliziert ist, mach ich mir die Mühe nicht. Im
> Endeffekt liegen die Daten sowieso auf einer SD-Karte,

und du machst dir Sorgen, ob das Lesen aus dem Flash schnell genug ist?

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Programmspeicher_.28Flash.29
Gast #2434849
Lesenswert?

Karl Heinz Buchegger schrieb:
> Genau deswegen gibt doch die Toolchain im AVR-Studio eine
> Speicherverbrauchsstatistik aus (zumindest in AVR-Studio 4, wie das bei
> 5 ist weiß ich nicht).

Naja, die Idee 7000 Bytes in in 1k SRam reinklopfen zu wollen, ist schon 
absurd, wobei das wieder beweist, dass es Nerds gelingt selbst den 
unwahrscheinlichsten Fehler zu machen.

Jedoch:

ATM32
AVR-Studio 4.18
WinAVR-20090313
Optimierung: -O0
1
int main (void)
2
{
3
uint8_t dta[10000];
4

5
dta[0] = 64;
6
dta[9999] = 128;
7
}
compiliert problemlos, Speicherverbrauch:
1
AVR Memory Usage
2
----------------
3
Device: atmega32
4

5
Program:     172 bytes (0.5% Full)
6
(.text + .data + .bootloader)
7

8
Data:          0 bytes (0.0% Full)
9
(.data + .bss + .noinit)
Da sollte wenigstens eine Warnung kommen.

Das Disassemblat zeigt, dass ein rechter Unsinn daraus erzeugt wird:
1
9:        dta[0] = 64;
2
+00000041:   E480        LDI       R24,0x40
3
+00000042:   8389        STD       Y+1,R24 
4
10:       dta[9999] = 128;
5
+00000043:   01FE        MOVW      R30,R28 
6
+00000044:   5FE0        SUBI      R30,0xF0
7
+00000045:   4DF8        SBCI      R31,0xD8
8
+00000046:   E880        LDI       R24,0x80
9
+00000047:   8380        STD       Z+0,R24
Es wird versucht die Zellen im SRam per Y auf 0xE14C (57676) und per Z 
auf 0x085B (2139) zu beschreiben.
Persönliche Seite #2434856
Lesenswert?

MWS schrieb:
> Da sollte wenigstens eine Warnung kommen.

Schwierig, denn dann müsste der Compiler zur Übersetzungszeit in der 
Lage sein, den Gebrauch des Stacks zu überprüfen. Bei einem so einfachen 
Beispiel wie Deinem ist das noch recht einfach (Größenprüfung 
automatischer Variablen), aber was ist, wenn ein µC 1 k Speicher hat, 
aber acht Funktionen verwendet werden, die jeweils eine automatische 
Variable von 256 Byte Größe verwenden? Ist das ein Fehler oder ist das 
in Ordnung? Die Antwort lautet: Je nachdem.
#2434863
Lesenswert?

Rufus Τ. Firefly schrieb:
> MWS schrieb:
>> Da sollte wenigstens eine Warnung kommen.
>
> Schwierig,

In dem krassen Fall ginge das natürlich. Auch in einer Funktion kann ich 
nicht mehr Daten allokieren, als der µC überhaupt Speicher hat.

Ob man das in den gcc integrieren könnte, weiß ich nicht.

Aber ich gebe was anderes zu bedenken:
Warnungen tenideren dazu als "Sicherheitsnetz" misbraucht zu werden: Der 
Compiler hat nicht gewarnt, also ist alles in Ordnung.
Solange der Compiler nicht tatsächlich alle Fälle eindeutig erkennen 
kann, bin ich normalerweise ein Gegner solcher Warnungen. Und damit bin 
ich wieder bei dir, da du unmissverständlich zeigst, dass das im 
Allgemeinen für jedes Programm und jede Allokierung nicht feststellbar 
ist, feststellbar sein kann.
OP #2434876
Lesenswert?

MWS schrieb:
> Naja, die Idee 7000 Bytes in in 1k SRam reinklopfen zu wollen, ist schon
> absurd, wobei das wieder beweist, dass es Nerds gelingt selbst den
> unwahrscheinlichsten Fehler zu machen.

Nö, das hatte ich nicht vor, ich wollte nur Arrays aus 7k ansprechen, wo 
die liegen, ist mir schnurz.
Und das funktioniert mit dem Link von kbuchegg auch problemlos, danke!


Karl Heinz Buchegger schrieb:
> Genau deswegen gibt doch die Toolchain im AVR-Studio eine
> Speicherverbrauchsstatistik aus (zumindest in AVR-Studio 4, wie das bei
> 5 ist weiß ich nicht). Ist der SRAM Verbauch bei den kleineren
> Prozessoren bei 80 bis 85%, wirds meistens schönb langsam kritisch.

Das habe ich jetzt gerade auch entdeckt, danke!
Gast #2434903
Lesenswert?

Rufus Τ. Firefly schrieb:
> Schwierig, denn dann müsste der Compiler zur Übersetzungszeit in der
> Lage sein, den Gebrauch des Stacks zu überprüfen.

Da geb' ich Dir in begrenztem Umfang recht, denn es ist zur 
Übersetzungszeit problemlos möglich zu prüfen ob 10000 x 1Byte im SRam 
Platz haben. Zumindest grobe Schnitzer wären zu entdecken.

Eine vor main() deklarierte Variable wird richtig mit einem 
Speicherverbrauch von 488.3% angegeben, allerdings keine Warnung. 
Innerhalb von main() ist, sobald der Stack verwendet wird, die 
Prozentangabe falsch, wird nur durch ein vorgesetztes static korrekt 
angezeigt, welches die Variable in den Standardadressbereich mappt und 
nicht mehr in den Stack. Auch hier keine Warnung, was aber nun gar kein 
Problem wäre. Da geht mir die Logik ein wenig ab, was aber der 
Standardisierung von C geschuldet sein mag.

Wohin soll den main() auf einem µC zurückkehren ? Geht nicht, also 
sollte eine innerhalb main() stehende Allokation prinzipiell keinen 
Unterschied zur globalen Allokation machen, ist aber trotzdem so.

Karl Heinz Buchegger schrieb:
> bin ich normalerweise ein Gegner solcher Warnungen.

Das ist jetzt keine schlüssige Argumentation, da jedem mit 
Programmproblemen empfohlen wird, sich die Warnungen des Compilers 
anzusehen. Wer das tut und eine Warnung findet "Bereichsüberschreitung 
bei Variablendeklaration", hat die Chance zu korrigieren und sei's nur 
ein Vertipper.

> Und damit bin
> ich wieder bei dir, da du unmissverständlich zeigst, dass das im
> Allgemeinen für jedes Programm und jede Allokierung nicht feststellbar
> ist, feststellbar sein kann.

Selbstverständlich ist das nicht allgemeingültig möglich, eine 
Bereichsüberschreitung geht immer, nur bei solch einem offensichtlichen 
Fehler wäre es sinnvoll wenn der Compiler meckert. Wie Du siehst, hätte 
es in diesem Fall geholfen, es würde sogar dann helfen, wenn jemand 
absichtlich ein Array im Flash anlegen möchte, das Schlüsselwort aber 
vergisst. Es wäre m.E. sogar gerechtfertigt statt einer Warnung einen 
Fehler zu melden.

Manuel Vossel schrieb:
> Nö, das hatte ich nicht vor, ich wollte nur Arrays aus 7k ansprechen, wo
> die liegen, ist mir schnurz.

Ehm, ja, aber das Programmieren von µC's setzt voraus, die Hardware des 
µC zu kennen und spätestens dann sollte klar sein, daß keine 7k in 1k 
SRam reingehen. Und bezüglich "ansprechen": lesen aus dem Flash ist ok, 
aber schreiben vergleichbar mit dem SRam kannst Du da nicht.
#2434911
Lesenswert?

MWS schrieb:

> Karl Heinz Buchegger schrieb:
>> bin ich normalerweise ein Gegner solcher Warnungen.
>
> Das ist jetzt keine schlüssige Argumentation, da jedem mit
> Programmproblemen empfohlen wird, sich die Warnungen des Compilers
> anzusehen.

Natürlich tun wir das.
Wir sehen aber auch immer wieder die Umkehrung: Der Compiler hat nicht 
gewarnt, also ist alles in Ordnung.
Darauf zielen meine Bedenken ab: Auf das Misverständnis, dass Warnungen 
ein 100% Sicherheitsnetz wären.
Gast #2434941
Lesenswert?

Karl Heinz Buchegger schrieb:
> Wir sehen aber auch immer wieder die Umkehrung: Der Compiler hat nicht
> gewarnt, also ist alles in Ordnung.

Also beim Lesen der "Hilfe, mein Programm geht nicht"-Posts gewann ich 
stets den Eindruck, dass warnungsfreie Compilierung in Verbindung mit 
nicht funktionierendem Programm eher zur Ausnahme zählt.

Meist läuft's so ab:
TO: Mein Programm geht nicht.
A: Wo ist der Code ?
TO: Hab's jetzt mit angehängt.
A: Was geht nicht ?
TO: Es macht nicht was es soll.
A: Hast Du Warnungen vom Compiler ?
TO: Ja, aber es waren zu viele.
Oder alternativ:
TO: Ja, aber dabei hab' ich mir nichts gedacht.

> Darauf zielen meine Bedenken ab: Auf das Misverständnis, dass Warnungen
> ein 100% Sicherheitsnetz wären.

Würd's eher als Komfortfunktion verstehen, wenn ein Compiler bei 
offensichtlichen Fehlern sich bemerkbar macht.
Persönliche Seite #2435118
Lesenswert?

Sicher, wenn in einem Rutsch mehr automatische Variablen deklariert 
werden, als überhaupt auf dem Stack verfügbar sein kann, dann könnte der 
Compiler meckern, sobald aber die Speichernutzung etwas verteilter (und 
damit realistischer) ist, geht's eben nicht.

Und da genügt das einfache von mir erwähnte Beispiel

> was ist, wenn ein µC 1 k Speicher hat,
> aber acht Funktionen verwendet werden,
> die jeweils eine automatische Variable
> von 256 Byte Größe verwenden?
> Ist das ein Fehler oder ist das in Ordnung?

Hinzu kommt, daß der Compiler nur einzelne Module bei der Übersetzung zu 
Gesicht bekommt, sobald ein Programm aus mehreren Modulen besteht, ist 
eine Stackverbrauchsanalyse nicht mehr möglich.

Die kann erst in der Linkphase erfolgen, der Linker aber weiß nichts von 
automatischen Variablen.

Und --um auf mein Beispiel zurückzukommen--, selbst wenn die Summe aller 
in allen Funktionen und Modulen deklarierten automatischen Variablen den 
Stack um ein mehrfaches sprengt, muss das kein Fehler sein. Obige 
Funktionen können ja nacheinander aufgerufen werden, was vollkommen 
legitim ist. Erst, wenn diese Funktionen sich gegenseitig aufrufen, 
knallt es.
Da genügt sogar eine Funktion, die sich rekursiv aufruft, was, sofern 
es nicht zu oft geschieht, auch vollkommen legitim ist. Geschieht es 
aber zu oft, knallt es -- selbst wenn die Funktion gar keine 
automatischen Variablen verwendet.

Hier helfen nur sehr aufwendige Codeanalyseprogramme, oder Erfahrung und 
der Gebrauch eines Debuggers.
Gast #2435129
Lesenswert?

Rufus Τ. Firefly schrieb:
> Und da genügt das einfache von mir erwähnte Beispiel
>
>> was ist, wenn ein µC 1 k Speicher hat,
>> aber acht Funktionen verwendet werden,
>> die jeweils eine automatische Variable
>> von 256 Byte Größe verwenden?
>> Ist das ein Fehler oder ist das in Ordnung?

Könnte sein, dass wir da unterschiedliche Vorstellungen um den 
Funktionsumfang solch einer Prüfung haben.

Meine wäre bei offensichtlichen Fehlern zu warnen und nicht zu versuchen 
alles zu erschlagen. Denn das geht, wie mir auch klar ist, nur höchst 
schwierig, oder ist quasi unmöglich.

Sobald also der reservierte Bereich innerhalb einer Funktion die Menge 
des tatsächlich verfügbaren SRams übersteigt, wäre ein Fehler 
auszugeben.

Auch da kann man sich natürlich wieder um den Nutzwert streiten, aber 
wie hier am Beispiel des TOs gesehen hätt's etwas geholfen.
Gast #2435187
Lesenswert?

Bastler schrieb:
> deine Indexvariable [i] ist 16bit deklariert.
>
> schätzungsweise überspringt somit dein Array jede zweite Stelle.

Also mit Verlaub, das ist aber vollkommener Blödsinn. Der Index wird zur 
Basisadresse addiert. Dabei ist es vollkommen belanglos, ob die Zahl 1 
nun 4, 8 oder 16 bit Darstellung hat. Die Adresse als Ergebnis ist 
dieselbe.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren