Speicherplatz Frage C & EEMEM

Gast #5399346
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;
#5399367
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.
#5400124
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.
Gast #5400137
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.
#5400149
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...
Gast #5400539
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.
Gast #5400542
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.
#5400577
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.
Gast #5400609
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..
Gast #5400624
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
Gast #5400629
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?
Gast #5400644
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.
#5400658
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
}

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