Structure und PROGMEM

Gast #544586
Lesenswert?
• ▲
▼
Hallo,

ich versuche das speicherintensive Menü vom SRAM in den Flash zu 
bekommen. Jedoch scheitere ich an den vorhandenen structures, die sich 
scheinbar nicht in den Flash verschieben lassen wollen. Zumindest 
menu_entry_t, dass nach der Initialisierung konstant bleibt, könnte man 
ja in den Flash verschieben.

Hat jemand Tips wie ich das bewerkstelligen kann?
1
typedef struct menu_entry_s {
2
  uint8_t flags;                            
3
  void (*select)(uint8_t *value, char *name);  
4
  char name[MENU_ENTRY_NAMELEN];            
5
  void *value;                              
6
} PROGMEM menu_entry_t;
7

8
typedef struct menu_s {
9
  uint8_t top_entry;        
10
  uint8_t current_entry;    
11
  uint8_t num_entries;      
12
  struct menu_s *previous; 
13
  menu_entry_t entry[];
14
} menu_t;
15

16
menu_t Zeit = {
17
   .top_entry = 0,
18
   .current_entry = 0,
19
   .entry =  {
20
      {.flags = 0,
21
       .select = vEditTime,
22
       .name = "Uhrzeit",
23
       .value = 0,
24
      },
25
      {.flags = 0,
26
       .select = vEditDate,
27
       .name = "Datum",
28
       .value = 0,
29
      },
30
   },
31
   .num_entries = 2,
32
   .previous = NULL,
33
};
Persönliche Seite #549655
Lesenswert?
• ▲
▼
Gemäß Tutorial würde ich es so versuchen (habe derzeit keinen AVR-GCC 
zum selbst testen):
1
typedef struct menu_entry_s {
2
  uint8_t flags;                            
3
  void (*select)(uint8_t *value, char *name);  
4
  char name[MENU_ENTRY_NAMELEN];            
5
  void *value;                              
6
} /* PROGMEM */ menu_entry_t;       // <==
7

8
typedef struct menu_s {
9
  uint8_t top_entry;        
10
  uint8_t current_entry;    
11
  uint8_t num_entries;      
12
  struct menu_s *previous; 
13
  menu_entry_t entry[];
14
} menu_t;
15

16
menu_t Zeit = {
17
   .top_entry = 0,
18
   .current_entry = 0,
19
   .entry = PROGMEM {               // <==
20
      {.flags = 0,
21
       .select = vEditTime,
22
       .name = "Uhrzeit",
23
       .value = 0,
24
      },
25
      {.flags = 0,
26
       .select = vEditDate,
27
       .name = "Datum",
28
       .value = 0,
29
      },
30
   },
31
   .num_entries = 2,
32
   .previous = NULL,
33
};

(1) "GCC and the PROGMEM Attribute" von abcminiuser
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=38003
Gast #549672
Lesenswert?
• ▲
▼
Danke für den Vorschlag, hab diese Variante auch schon ausprobiert, 
jedoch kommen dabei einige Fehlermeldungen:

menu.c:92: error: syntax error before "__attribute__"
menu.c:94: error: field name not in record or union initializer
menu.c:94: error: (near initialization for `Zeit')
menu.c:94: warning: missing braces around initializer
menu.c:94: warning: (near initialization for `Zeit.entry')
menu.c:94: warning: initialization makes integer from pointer without a 
cast
menu.c:94: error: initializer element is not computable at load time
menu.c:94: error: (near initialization for `Zeit.entry[0].flags')
menu.c:95: warning: excess elements in struct initializer
menu.c:95: warning: (near initialization for `Zeit')
menu.c:95: error: unknown field `name' specified in initializer
menu.c:95: warning: excess elements in struct initializer
menu.c:95: warning: (near initialization for `Zeit')
menu.c:96: error: unknown field `value' specified in initializer
menu.c:96: warning: excess elements in struct initializer
menu.c:96: warning: (near initialization for `Zeit')
menu.c:98: error: syntax error before '{' token
Persönliche Seite #549731
Lesenswert?
• ▲
▼
Ich komme nur durch Aufteilung der verschachtelten Struktur um das 
Problem herum:
1
#include <avr/io.h>
2
#include <avr/pgmspace.h>
3

4
typedef unsigned char uint8_t;
5

6
#define MENU_ENTRY_NAMELEN 42
7
#define NULL ((void *)0)
8
#define vEditTime ((void *)1234)
9
#define vEditDate ((void *)5678)
10

11
typedef struct menu_entry_s {
12
  uint8_t flags;
13
  void (*select)(uint8_t *value, char *name);
14
  char name[MENU_ENTRY_NAMELEN];
15
  void *value;
16
} PROGMEM menu_entry_t;
17

18
typedef struct menu_s {
19
  uint8_t top_entry;
20
  uint8_t current_entry;
21
  uint8_t num_entries;
22
  struct menu_s *previous;
23
  menu_entry_t *entry;             // <===
24
} menu_t;
25

26
menu_entry_t progmem_entry[] = {   // <===
27
      {.flags = 0,
28
       .select = vEditTime,
29
       .name = "Uhrzeit",
30
       .value = 0,
31
      },
32
      {.flags = 0,
33
       .select = vEditDate,
34
       .name = "Datum",
35
       .value = 0,
36
      },
37
   };
38

39
menu_t Zeit = {
40
   .top_entry = 0,
41
   .current_entry = 0,
42
   .entry = progmem_entry,         // <===
43
   .num_entries = 2,
44
   .previous = NULL,
45
};
46

47
int main(void)
48
{
49
  return 0;
50
}

Ich erkläre mir das so, dass im Ausgangsfall die im SRAM abgelegte 
Struktur gleichzeitig einen Teil haben soll, der im FLASH liegt - das 
ist ein Widerspruch in sich.

Was geht und hier gemacht wurde: die Struktur 1 liegt im FLASH und der 
Zeiger auf diese Struktur wird in die Struktur 2 im Flash eingebunden. 
Man "opfert" einen Zeiger (2 Bytes) pro Struktur 2
Gast #549745
Lesenswert?
• ▲
▼
menu_entry_t bekommst du so ins Flash:
1
typedef struct
2
{
3
  uint8_t flags;                            
4
  void (*select)(uint8_t *value, char *name);  
5
  char name[10];            
6
  void *value;                              
7
} menu_entry_s;
8

9
menu_entry_s PROGMEM menu_entry_t;

Allerdings kommt dann noch die berechtigte Warnung:
../Main.c:12: warning: only initialized variables can be placed into 
program memory area


Also noch initialisieren:
1
#include <avr/io.h>
2
#include <avr/pgmspace.h>
3

4
void selectfunc(uint8_t *value, char *name);
5

6
typedef struct
7
{
8
  uint8_t flags;                            
9
  void (*select)(uint8_t *value, char *name);  
10
  char name[10];            
11
  void *value;                              
12
} menu_entry_s;
13

14
menu_entry_s PROGMEM menu_entry_t = {0xff, selectfunc, "hallo", 0};
15

16
void selectfunc(uint8_t *value, char *name)
17
{
18
}

Oliver
Gast #549819
Lesenswert?
• ▲
▼
Danke für die Hilfe. Ich hab nun die obige Variante von Stefan mit der 
Trennung der beiden structs vorgenommen. Irgendwas mach ich aber noch 
immer beim Auslesen falsch, da ich weder 3 noch 4 angezeigt bekomme.
1
#include <avr/io.h>
2
#include <avr/pgmspace.h>
3

4
typedef unsigned char uint8_t;
5

6
#define MENU_ENTRY_NAMELEN 42
7
#define NULL ((void *)0)
8
#define vEditTime ((void *)1234)
9
#define vEditDate ((void *)5678)
10

11
typedef struct menu_entry_s {
12
  uint8_t flags;
13
  void (*select)(uint8_t *value, char *name);
14
  char name[MENU_ENTRY_NAMELEN];
15
  void *value;
16
} PROGMEM menu_entry_t;
17

18
typedef struct menu_s {
19
  uint8_t top_entry;
20
  uint8_t current_entry;
21
  uint8_t num_entries;
22
  struct menu_s *previous;
23
  menu_entry_t *entry;             
24
} menu_t;
25

26

27
menu_entry_t zeitsub[]= {
28
  {.flags = 3,                       //<== Dieser Wert soll ausgelesen werden
29
   .select = vEditTime,
30
   .name = "Uhrzeit",
31
   .value = 0,
32
  },
33
  {.flags = 4,
34
   .select = vEditDate,
35
   .name = "Datum",
36
   .value = 0,
37
  },
38
};
39

40
menu_t Zeit = {
41
   .top_entry = 0,
42
   .current_entry = 0,
43
   .entry = (menu_entry_t*)&zeitsub,
44
   .num_entries = 2,
45
   .previous = NULL,
46
};
47

48
typedef struct {
49
    menu_t *menu; 
50
} menu_context_t;
51

52
menu_context_t context = {
53
   .menu = NULL
54
};
55

56

57
int main(void)
58
{
59
     uint8_t flag=0;
60
  
61
     context.menu = &Zeit;
62

63
     flag = pgm_read_byte(&((menu_entry_t*)pgm_read_word(&context.menu->entry))[0].flags);
64

65
  return 0;
66
}
Gast #549823
Lesenswert?
• ▲
▼
>Irgendwas mach ich aber noch
>immer beim Auslesen falsch, da ich weder 3 noch 4 angezeigt bekomme.

Das PROGMEM gehört in die Variablendeklaration, nicht in die 
Typdefinition.

Also:
1
typedef struct menu_entry_s {
2
  uint8_t flags;
3
  void (*select)(uint8_t *value, char *name);
4
  char name[MENU_ENTRY_NAMELEN];
5
  void *value;
6
} menu_entry_t;
7

8
menu_entry_t PROGMEM zeitsub[]= {
9
  {.flags = 3,                
10
   .select = vEditTime,
11
   .name = "Uhrzeit",
12
   .value = 0,
13
  },
14
  {.flags = 4,
15
   .select = vEditDate,
16
   .name = "Datum",
17
   .value = 0,
18
  },
19
};

Oliver

Antwort schreiben

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.