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...
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.
> 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?
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.
>deine Indexvariable [i] ist 16bit deklariert.>schätzungsweise überspringt somit dein Array jede zweite Stelle.
Ja. Und an ungeraden Freitagen sogar Schäfchen. :-)
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).
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
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
intmain(void)
2
{
3
uint8_tdta[10000];
4
5
dta[0]=64;
6
dta[9999]=128;
7
}
compiliert problemlos, Speicherverbrauch:
1
AVRMemoryUsage
2
----------------
3
Device:atmega32
4
5
Program:172bytes(0.5%Full)
6
(.text+.data+.bootloader)
7
8
Data:0bytes(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.
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.
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.
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!
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.
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.
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.
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.
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.
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.