Uuuups! Das verblüfft mich nun total. Wie kann man dann noch
unterscheiden, ob eine Variable im SRAM oder im Flash liegt?
Das kapiere ich überhaupt nicht.
Wilhelm K. schrieb:> Uuuups! Das verblüfft mich nun total. Wie kann man dann noch> unterscheiden, ob eine Variable im SRAM oder im Flash liegt?
Bei einem Pointer entscheidet die Art des Zugriffs darüber, ob er ins
Flash oder RAM zeigt:
*Pointer -> Pointer ins RAM
pgm_read_XXXX(Pointer) -> Pointer ins Flash
Wilhelm K. schrieb:> Uuuups! Das verblüfft mich nun total. Wie kann man dann noch> unterscheiden, ob eine Variable im SRAM oder im Flash liegt?>> Das kapiere ich überhaupt nicht.
Du hattest hier einen Sonderfall.
Das hier ist ein Pointer. Ein Pointer ist aber nichts anderes als ein
Verweis auf einen anderen Speicher.
D.h. bei einem Pointer musst du unterscheiden: Was genau liegt den
eigentlich im Flash? Der Pointer selber, oder das worauf er zeigt?
Pointer
+-------+ +---+---+---+---+---+
| o--------------------------->| | | | | |
+-------+ +---+---+---+---+---+
Bei
const prog_char * String_im_Flash;
liegt nicht der Pointer (mit Namen String_im_Flash) im Flash (der linke
Teil der Grafik), sondern die Character (der rechte Teil der Grafik).
Die Deklaration liest sich so
String_im_Flash da ist eine Variable
* String_im_Flash und diese Variable ist ein
Pointer
prog_char * String_im_Flash das worauf er zeigt, liegt im
Flash ...
char prog_char * String_im_Flash ... und zwar sind das Character
> Wie kann man dann noch unterscheiden, ob eine Variable> im SRAM oder im Flash liegt?
Schau dir die Deklaration der Variablen an
int i PROGMEM;
Das ist eine Variable i und die liegt im Flash
int * pI;
Da ist ein Pointer und dieser Pointer zeigt auf einen int
int * pJ PROGMEM;
Noch ein Pointer. Aber diesmal liegt die Pointervariable
selbst im Flash.
Wie schon gesagt: das prog_char war kosmetischer Natur. Effektiv hat es
nichts bewirkt ausser der (eher zweifelhaften) Dokumentation, dass ein
Pointer auf etwas zeigt, was im Flash liegt. Das ist aber etwas, was du
sowieso wissen musst. Ob pI auf einen Integer im SRAM oder im Flash
zeigt, musst du selbst wissen, da kann dich der Compiler nicht
unterstützen.
Martin 567 schrieb:> gibt es nicht die möglichkeit im Studio 6 etwas umzustellen?
Du willst alse explizit, dass Code mit undefiniertem Verhalten
akzeptiert wird? Dann siehe oben: -D__PROG_TYPES_COMPAT__ als
Compiler-Option ist dein schlechter Freund.
Wilhelm K. schrieb:> Uuuups! Das verblüfft mich nun total. Wie kann man dann noch> unterscheiden, ob eine Variable im SRAM oder im Flash liegt?
PROGMEM aka. __attribute__((progmem)) funktioniert ähnlich wie das
section-Attribut: Es bestimmt die Ablage, d.h. die Section, des damit
markierten Objekts.
Im folgenden Beispiel liegen alle p1...p4 im Flash (Section
.progmem.data, denn PROGMEM wirkt auf das jeweils definierte Objekt,
nämlich p1...p4:
1
#include<stdlib.h>
2
#include<avr/pgmspace.h>
3
4
// p1 liegt im Flash (.progmem.data) und wird mit
5
// NULL initialisiert.
6
char*constp1PROGMEM=NULL;
7
8
// p2 liegt im Flash und wird mit der Adresse eines
9
// String-Literals initialisier, das "P2" enthält.
10
// Das Literal liegt im RAM (.rodata).
11
char*constp2PROGMEM="P2";
12
13
// p3 liegt im Flash und wird mit "P3" initialisiert.
14
charconstp3[]PROGMEM="P3";
15
16
// p4 liegt im Flash und wird mit der Adresse eines
17
// String-Literals initialisier, das "P4" enthält.
18
// Das Literal liegt im RAM (.rodata).
19
constcharPROGMEM*constp4="P4";
Am Beispiel p4 sieht man, daß prog_char nicht einfach durch char PROGMEM
ersetzt werden darf.
Ich rate davon ab, __PROG_TYPES_COMPAT__ zu verwenden, denn das progmem
in Typedefs hatte nie ein definiertes/dokumentiertes Verhalten. Die
GCC-Dokumentation definiert diese Attribut ausschließlich für
Deklarationen und nicht für Typen.
Man kann nun auf avr-gcc schimpfen und fragen, warum er progmem in
typedef je akzeptiert hat. Das war ein Designfehler, der nicht
korrigiert wurde, weil niemand ihn als so wichtig erachtete, es in
avr-gcc einzupflegen.
Die AVR-Libc wiederum hat das Feature fleissig verwendet nach dem Motto
"alles was keine Warnung bringt ist in Ordnung", obwohl progmem für
Typen nie dokumentiert war. Es ist einzig und allen für Deklarationen
dokumentiert und im Compiler unterstützt.
Ich für meinen Teil verwende die Zeit, die ich auf avr-gcc verwende,
lieber auf Dinge, die den Compiler weiter bringen, anstatt Aufwand in
Features zu stecken, die nie dokumentiert waren und auch keine neue
Funktionalität bringen.
Jeder, der seine Prioritäten bei der avr-gcc Entwicklung anders gesetzt
hat, kann natürlich die entsprechende Erweiterung zum Compiler
beitragen.
Und die Anwender von avr-gcc sind gut damit beraten, die Dokumentation
zu lesen...
Johann L. schrieb:> Die AVR-Libc wiederum hat das Feature fleissig verwendet nach dem Motto> "alles was keine Warnung bringt ist in Ordnung", obwohl progmem für> Typen nie dokumentiert war.
Sagen wir mal so: es scheint erstmal naheliegend zu sein, ein typedef
dafür zu verwenden, und es hat einfach niemand hinterfragt, ob das
überhaupt technisch in Ordnung ist.
Jörg Wunsch schrieb:> Johann L. schrieb:>> Die AVR-Libc wiederum hat das Feature fleissig verwendet nach dem Motto>> "alles was keine Warnung bringt ist in Ordnung", obwohl progmem für>> Typen nie dokumentiert war.>> Sagen wir mal so: es scheint erstmal naheliegend zu sein, ein typedef> dafür zu verwenden, und es hat einfach niemand hinterfragt, ob das> überhaupt technisch in Ordnung ist.
Zugegeben; die Dokumentation im GCC-Manual war sicherlich nicht
erschöpfend. Inzwischen sollte sich die Situation aber deutlich
verbessert haben.
Eine ganz ähnliche Tretmine war die gleichzeitige Verwendung von signal
und interrupt in ISR... aua
Natürlich kann man sich beschweren, wenn der Compiler da nicht gleich
gemeckert hat. Und auch darüber, wenn AVR-Maintainer
nicht-dokumentierte Erweiterungen akzeptieren, Beispiel OS_task und
OS_main (Ok, Anatoly ist ja selbst Maintainer...)
Aber Undokumentiertes zu verwenden und nach Sichtprüfung zu verwenden
ist eigentlich immer ein Vabanque-Spiel.
Eine eigene Frage?
Dieser Thread ist über 14 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.