Forum: Mikrocontroller und Digitale Elektronik Speicherplatz Frage C & EEMEM


von Uwe K. (Gast)


Lesenswert?

Moin,

sehe ich das richtig, dass ich mit EEMEM, Speicher für den EEPROM 
alloziere und gleichzeitig diese Variablen auch als "normale" nutzen 
kann=
1
typedef struct
2
{
3
  enum 
4
  {
5
    IS_INIT,
6
    MES_MESZ,
7
    ALERT,
8
    ALERT_CYCLES,
9
    BRIGHT,
10
    SOUND_ENABLE,
11
    MOTOR_ENABLE,
12
    SYNC_HOUR,
13
    SYNC_MINUTE,
14
    AUTO_CHANGE_MINUTE,
15
    AUTO_CHANGE_SECOUND,
16
    
17
    DIMM_HOUR_ON,
18
    DIMM_HOUR_OFF,
19
    DIMM_MINUTE_ON,
20
    DIMM_MINUTE_OFF,
21
    
22
    ALERT_HOUR_I,
23
    ALERT_HOUR_II,
24
    ALERT_HOUR_III,
25
    ALERT_HOUR_IIII,
26
    ALERT_HOUR_IIIII,
27
    ALERT_HOUR_IIIIII,
28
    ALERT_HOUR_IIIIIII,
29
    ALERT_HOUR_IIIIIIII,
30
    
31
    ALERT_MINUTE_I,
32
    ALERT_MINUTE_II,
33
    ALERT_MINUTE_III,
34
    ALERT_MINUTE_IIII,
35
    ALERT_MINUTE_IIIII,
36
    ALERT_MINUTE_IIIIII,
37
    ALERT_MINUTE_IIIIIII,
38
    ALERT_MINUTE_IIIIIIII,
39
    
40
    DCF77_NUM_OF_RECORDS,
41
      
42
    SYSTEM_CONFIG,
43
      
44
    MAX_8_BYTE_ENTRYS,
45
  }byte8_entrys;
46
  
47
  uint8_t byte8[ MAX_8_BYTE_ENTRYS - 1 ];
48
  
49
}var_t; var_t eep EEMEM;

von Falk B. (falk)


Lesenswert?

@Uwe K. (Gast)

>sehe ich das richtig, dass ich mit EEMEM, Speicher für den EEPROM
>alloziere

Ja.

> und gleichzeitig diese Variablen auch als "normale" nutzen
>kann=

Nö. Auf die EEPROM-Variablen, hier eep,  kann man nur mittels der 
eeprom_read/write Funktionen zugreifen. Das einzige, was man natürlich 
mehrfach wiederverwenden kann, ist deine Typdefinition var_t.

von Peter D. (peda)


Lesenswert?

Uwe K. schrieb:
> ALERT_MINUTE_IIIIIII,
>     ALERT_MINUTE_IIIIIIII,

Wer kommt denn auf sowas verrücktes. Den Code möchte ich nicht pflegen 
müssen.

von M. K. (sylaina)


Lesenswert?

Peter D. schrieb:
> Wer kommt denn auf sowas verrücktes. Den Code möchte ich nicht pflegen
> müssen

Das hab ich mich auch grad gefragt, zumindest lateinische Nummerierung 
hätte ich hier in Verwendung, wahrscheinlicher aber arabische 
Nummerierung.

von Einer K. (Gast)


Lesenswert?

Peter D. schrieb:
> Wer kommt denn auf sowas verrücktes.

Ach da muss nur der "Sinn und Zweck" von Arrays nochmal verinnerlicht 
werden.

Es gibt noch viel zu lernen!
z.B. dass das durchnummerieren von Variablen, oder sonstigen 
Bezeichnern, böse ist.

von M. K. (sylaina)


Lesenswert?

Arduino F. schrieb:
> Ach da muss nur der "Sinn und Zweck" von Arrays nochmal verinnerlicht
> werden.

Jetzt hör aber auf, das wird ja noch einfacher :D

von Heiko L. (zer0)


Lesenswert?

Gibt es diese Speicherklassen eigentlich in generalisierter Form oder 
nur, wenn ein entsprechendes EEPROM verbaut ist?
Oder anders: Kann man virtuelle Addressräume frei definieren?

von Einer K. (Gast)


Lesenswert?

Suchtipp: "avr gcc sections"

von Heiko L. (zer0)


Lesenswert?

Ja, Sections wären schon einmal nicht schlecht. Aber was, wenn z.B. das 
System eigentlich nur 16-bit Addressen unterstützt, man aber virtuell 
32-bit braucht?
Einfaches Beispiel: Man klemmt ein externes EEPROM mit 4Mbit an einen 
Attiny oder sowas. Die Addressen im EEPROM könnte man bequem den 
Compiler berechnen lassen, wenn man an 32-bit Addressen heran käme.

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Soweit mir bekannt, wird das nicht gelingen.

Das einzige mir bekannte Mittel um was zu bauen ist sizeof() in 
Verbindung mit offsetof(). Aber einen größeren Wertebereich als size_t 
hat das auch nicht.

von Heiko L. (zer0)


Lesenswert?

Sowas befürchte ich auch. Einige AVR-Header für größere Chips besorgen 
sich aber in der Tat die längeren Addressen via &-Operator. Meine 
Vermutung war nun, dass das entweder gelingt, weil die Addressen erst 
beim Speichern in eine Variable geclamp'd oder gewrapped werden, oder es 
an einer speziellen Speicherklasse der Variablen liegt (siehe 
morepgmspace.h).
Mir ist an der Stelle das Konzept vom GCC nicht klar. Bei VC war so 
etwas eine Eigenschaft des Zeigertyps. "pointer to progmem_far" oder 
sowas kann logischerweise nur gelingen, wenn progmem_far definiert ist.
Ich muss das wohl bei Gelegenheit mal selbst austesten...

: Bearbeitet durch User
von Uwe K. (Gast)


Lesenswert?

Peter D. schrieb:
> Uwe K. schrieb:
>> ALERT_MINUTE_IIIIIII,
>>     ALERT_MINUTE_IIIIIIII,
>
> Wer kommt denn auf sowas verrücktes. Den Code möchte ich nicht pflegen
> müssen.

Klär mich bitte auf. Wie würdest du das lösen?

von NurEinGast (Gast)


Lesenswert?

Für das menschliche Auge leichter zu unterscheiden wäre
ALERT_MINUTE_1
ALERT_MINUTE_2
ALERT_MINUTE_3
...
ALERT_MINUTE_7
ALERT_MINUTE_8

Wenn Du irgendwo mitten im Code ALERT_MINUTE_IIIIIII findest, muss man 
abzählen. Der Unterschied ALERT_MINUTE_IIIIIIII zu ALERT_MINUTE_IIIIIII 
ist nicht auf den ersten Blick zu erkenenn. Das ist Fehleranfällig.

von HildeK (Gast)


Lesenswert?

Uwe K. schrieb:
> Klär mich bitte auf. Wie würdest du das lösen?

Na wenigsten so: ALERT_MINUTE_7 bzw. ALERT_MINUTE_8. Das ist schon mal 
um Faktor 1000 besser lesbar.

von x^2 (Gast)


Lesenswert?

Es ist übrigens eine sehr mäßige Idee einen enum Typ zu nutzen, um eine 
solche Variable zu definieren. Der Grund ist, dass C dir die Größe einer 
enum Variable nicht garantiert. Es garantiert dir lediglich, dass alle 
Werte darin gespeichert werden können. Konkret könnte zum Beispiel 
uint8, uint16 oder uint32 verwendet werden. Dies kann sich sogar mit der 
Optimierungsstufe des Compilers ändern. Der GCC hat Flags womit du 
explizit die Größe von enum Variablen packen kannst.

Verändert sich irgendwas (Compiler, Optimierungsstufe, ...) kann so dein 
EEPROM Inhalt nicht mehr zur Variable passen, ohne dass das 
offensichtlich wäre.

Es ist auch keine gute Idee eine struct zu verwenden, da ein naives 
Lesen/Speichern a la

var_t x;
read_ee(0x1000, &x, sizeof(x));
write_ee(0x1000, &x, sizeof(x));

Annahmen über das Padding und Alignment in dieser Struktur macht.

von HildeK (Gast)


Lesenswert?

NurEinGast schrieb:
> Wenn Du irgendwo mitten im Code ALERT_MINUTE_IIIIIII findest, muss man
> abzählen.

Ja. Und wenn du mit dem Editor nach ALERT_MINUTE_II suchst, dann findet 
er auch ALERT_MINUTE_III, ALERT_MINUTE_IIII usw.

von M. K. (sylaina)


Lesenswert?

Uwe K. schrieb:
> Klär mich bitte auf. Wie würdest du das lösen?

Besser wäre:
1
...
2
uint8_t ALERT_MINUTE_I;
3
uint8_t ALERT_MINUTE_II;
4
uint8_t ALERT_MINUTE_III;
5
uint8_t ALERT_MINUTE_IV;
6
...
Ist aber immer noch recht komplex lesbar (das ist lateinische/römische 
Nummerierung), daher wäre es noch besser arabische Zahlen zu benutzten:
1
...
2
uint8_t ALERT_MINUTE_1;
3
uint8_t ALERT_MINUTE_2;
4
...
Das ist noch besser lesbar, jedoch immer noch recht komplex 
automatisierbar (Programmierer sind ein recht schreibfaules Volk ;)) 
weshalb der ein und andere von uns wohl auf die Idee käme, es so zu 
definieren:
1
...
2
uint8_t ALERT_MINUTE[8];
3
...
Da könnte man z.B. mit ner for-Schleife ruck-zuck alle Werte durchgehen, 
auslesen, verändern, etc.pp.

: Bearbeitet durch User
von Uwe K. (Gast)


Lesenswert?

x^2 schrieb:
> Annahmen über das Padding und Alignment in dieser Struktur macht.

Das heißt?

von M. K. (sylaina)


Lesenswert?

Uwe K. schrieb:
> Das heißt?

Dass man schon beim Coden davon ausgeht, wie der Compiler den ganzen 
Kladeradatsch im Speicher anlegen werden wird. Das kann Probleme machen 
wenn man sich verschätzt hat, eine andere Optimierungsfunktion des 
Compilers wählt, den Datensatz erweitern will usw.

von Uwe K. (Gast)


Lesenswert?

M. K. schrieb:
> Uwe K. schrieb:
>> Das heißt?
>
> Dass man schon beim Coden davon ausgeht, wie der Compiler den ganzen
> Kladeradatsch im Speicher anlegen werden wird. Das kann Probleme machen
> wenn man sich verschätzt hat, eine andere Optimierungsfunktion des
> Compilers wählt, den Datensatz erweitern will usw.
1
typedef enum
2
{
3
  SYNC_ERROR_CNT,
4
  SYNC_SUCCESS_CNT,
5
  
6
  MAX_BYTE16_ENTRYS,  
7
}bit16_enum;
8
9
uint16_t arr[MAX_BYTE16_ENTRYS-1];

Was kann der Kompilert dort anders machen mit einer anderen 
Kompilierungsstufe?

Wenn ich mich auf die Byte Reihenfolge nicht verlassen kann..

von x^2 (Gast)


Lesenswert?

Uwe K. schrieb:
> typedef enum
> {
>   SYNC_ERROR_CNT,
>   SYNC_SUCCESS_CNT,
>
>   MAX_BYTE16_ENTRYS,
> }bit16_enum;
>
> uint16_t arr[MAX_BYTE16_ENTRYS-1];
>
> Was kann der Kompilert dort anders machen mit einer anderen
> Kompilierungsstufe?
>
> Wenn ich mich auf die Byte Reihenfolge nicht verlassen kann..

In deinem ursprünglichen Beitrag hattest du ein Struktur-Member mit 
einem enum Typ. Jetzt steht hier nur noch ein typedef (in einem 
struct??). Sagen wir du hättest das hier:
1
struct
2
{
3
   bit16_enum type;
4
   uint8_t byte[MAX_8_BYTE_ENTRYS - 1];
5
}

Dein Compiler könnte z.B. folgendes machen:
1
[type_0][byte:0][byte:1][...]
2
[type_0][type_1][byte:0][byte:1][...]
3
[type_0][type_1][type_2][type_3][byte:0][byte:1][...]

Mit O0 könnte er (auf einer 32-bit architektur) 32-bit enums machen 
(letztere Variante) und für Os das enum packen und erstere Variante 
nehmen. In deinem EEPROM steht dann letzere Variante. Und dein Os Code 
lädst dann type_1 in byte:0

von x^2 (Gast)


Lesenswert?

Schau dir z.B. beim GCC mal "-fshort-enums" an:

https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html

Damit kannst du explizit enums packen lassen.

von Uwe K. (Gast)


Lesenswert?

1
enum bit16_enum
2
{
3
  SYNC_ERROR_CNT,
4
  SYNC_SUCCESS_CNT,
5
  
6
  MAX_BYTE16_ENTRYS,  
7
};
8
9
/*
10
*  Fall 1.: Hier wird in der Struktur "enum" verwendet..
11
*/
12
typedef struct  
13
{  
14
  enum bit16_enum  bit16Desc;
15
  uint16_t byte16[ MAX_BYTE16_ENTRYS - 1 ];
16
}error_t; error_t err; error_t erreep EEMEM;
17
18
19
20
typedef enum
21
{
22
  SYNC_ERROR_CNT,
23
  SYNC_SUCCESS_CNT,
24
  
25
  MAX_BYTE16_ENTRYS,  
26
}bit16_t;
27
28
/*
29
*  Fall 2.: Hier wird in der Struktur mit einem Datentyp gearbeitet..
30
*/
31
typedef struct  
32
{  
33
  bit16_t  bit16Desc;
34
  uint16_t byte16[ MAX_BYTE16_ENTRYS - 1 ];
35
}error_t; error_t err; error_t erreep EEMEM;
36
37
Wo ist der Unterschied? Gibt es einen?

von Uwe K. (Gast)


Lesenswert?

Sollte man "enums" lieber nicht als Member einer Struktur mitgeben?

von Ichkriegmich Nichtmehr (Gast)


Lesenswert?

Faszinierend.

Eine Variable mit <byte16> zu benennen grenzt schon
wahrlich an Genialität.

von x^2 (Gast)


Lesenswert?

Uwe K. schrieb:
> Sollte man "enums" lieber nicht als Member einer Struktur
> mitgeben?

Ja. Zumindest dann nicht, wenn die Größe aus irgend einem Grund eine 
Rolle spielt. Ich tendiere dazu immer Typen fester Breite zu nehmen und 
mit enums nur dazu passende Konstanten.

von Uwe K. (Gast)


Lesenswert?

Ichkriegmich Nichtmehr schrieb:
> Faszinierend.
>
> Eine Variable mit <byte16> zu benennen grenzt schon
> wahrlich an Genialität.

Stimmt schon. Da muss ich noch dran feilen.

von Uwe K. (Gast)


Lesenswert?

x^2 schrieb:
> Uwe K. schrieb:
>> Sollte man "enums" lieber nicht als Member einer Struktur
>> mitgeben?
>
> Ja. Zumindest dann nicht, wenn die Größe aus irgend einem Grund eine
> Rolle spielt. Ich tendiere dazu immer Typen fester Breite zu nehmen und
> mit enums nur dazu passende Konstanten.

In meinem Fall, sollten die "enums" einfach nur den Index der aktuell 
benötigen Variable "ersichtlicher" machen.

Die enums sind ja in diesem Fall auch konstant.

von M. K. (sylaina)


Lesenswert?

Uwe K. schrieb:
> Die enums sind ja in diesem Fall auch konstant.

Wann sind sie das denn nicht?

von Peter D. (peda)


Lesenswert?

Enums sind immer vom Typ int, d.h. je nach Architektur signed 16 oder 32 
Bit. Daher ist enum als Typangabe zwar zulässig, aber ungebräuchlich.

Unter c sind Enums einfach nur eine anderer Schreibweise für 
fortlaufende Defines, d.h. sie schränken nicht den Wertebereich von 
Variablen ein.
Z.B.:
1
enum Wochentag{SO, MO, DI, MI, DO, FR, SA}
2
heute, gestern;
3
4
int i;
5
6
void test(void)
7
{
8
  heute = SA;
9
  gestern = -1000;
10
  i = MI;
11
}

: Bearbeitet durch User
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.