Forum: Mikrocontroller und Digitale Elektronik linked lists im program space (flash)


von DrKarlTheodor (Gast)


Lesenswert?

Hallo, Folgendes Problem:
Ich habe eine Verkettete liste angelegt mit daten gefüllt und diese is 
Flash gelegt.

typedef const struct PROGMEM  MENU_STR
{
  const struct PROGMEM  MENU_STR *sub_menu;
  CALL_FUNC     MenuFuncPtr;
  const unsigned char       text_u8 [15];
}MENU_STRUKTUR;


MENU_STRUKTUR sub_test1 [MENU_MAX]
={
  {NULL , move_midas_logo,"Demo1_t"},
  {NULL , foo            ,"sub menu"},
  {NULL , sw_stand       ,"SW_St_t"},
  {NULL , sm_reset       ,"RESET_t"},
  {NULL , sm_sleep       ,"Sleep_t"}
 };

MENU_STRUKTUR Main_Menu_Table_MenStr [MENU_MAX]
={
  {sub_test1  , move_midas_logo , "Demo1"},
  {sub_test1  , change_menu     , "sub_menu"},
  {NULL       , sw_stand        , "SW_St"},
  {NULL       , sm_reset        , "RESET"},
  {NULL       , sm_sleep        , "Sleep"}
 };

Soweit so gut !

wenn ich jetzt ein Array von Pointern erstelle und diese Auf mein 
Strktur array zeigen lasse:

MENU_STRUKTUR *CurrentMenu_MenStr_ptr[MENU_MAX];

  for (i_u8= 0; i_u8 < MENU_MAX; i_u8++)
  {
    CurrentMenu_MenStr_ptr[i_u8]= &Main_Menu_Table_MenStr[i_u8];
  }

Will ich jetzt auf den Text zugreifen:

pgm_read_byte(CurrentMenu_MenStr_ptr[1]->text_u8);  //kalppt !

will ich aber auf den text meies sub_menus zugreifen klappt das nicht
pgm_read_byte(CurrentMenu_MenStr_ptr[1]->sub_menu[1].text_u8); //klappt 
nicht

Warum geht das so nicht?
Wenn ich das ganze im Ram mache geht es.


Danke!!

von DrKarlTheodor (Gast)


Lesenswert?

sorry,
Das ganze Auf einem AVR XMEGA

von Tom M. (tomm) Benutzerseite


Lesenswert?

DrKarlTheodor schrieb:
> pgm_read_byte(CurrentMenu_MenStr_ptr[1]->text_u8);  //kalppt !

Hier dereferenzierst du einmal. Zur Compile-Time sind alle relevanten 
Grössen bekannt, deshalb musst du nur einmal via pgm_read_byte 
eingreifen, um aus dem Flash zu lesen.

> will ich aber auf den text meies sub_menus zugreifen klappt das nicht
> pgm_read_byte(CurrentMenu_MenStr_ptr[1]->sub_menu[1].text_u8); //klappt
> nicht

Hier liegt der Fall etwas anders, da du Pointer auf Pointer hast. Du 
musst "zu Fuss" dereferenzieren bzw. die Pointer aus dem Flash lesen 
(pgm_read_word). Jetzt dereferenzierst du "übers RAM" und landest 
irgendwo im Flash!

von DrKarlTheodor (Gast)


Lesenswert?

kannst du dass ev. an einem Beispiel erleutern?

von DrKarlTheodor (Gast)


Lesenswert?

Ich verstehe das so, dass ich erst den die Pointer mit pgm_read_word 
lesen muss.
z.B. so:
MENU_STRUKTUR *test [5]
test [1] = pgm_read_word( &CurrentMenu_MenStr_ptr[1]->sub_menu[1]);

und dann mit pgm_read_byte das zeichen aus dem String

pgm_read_byte(test[1]->text[1]);


das funktioniert so aber nicht.

von Karl H. (kbuchegg)


Lesenswert?

DrKarlTheodor schrieb:
> Ich verstehe das so, dass ich erst den die Pointer mit pgm_read_word
> lesen muss.
> z.B. so:
> MENU_STRUKTUR *test [5]
> test [1] = pgm_read_word( &CurrentMenu_MenStr_ptr[1]->sub_menu[1]);

Du kannst hier keinen -> benutzen!

Mal dir die Situation auf
1
  Current...                   F Main_Menu_Table_MenStr
2
  +-----------+                 +-----------------+
3
  |   o------------------------>|    o---------------------+
4
  +-----------+                 | move_midas_logo |        |
5
  |   o------------------+      | "Demo1"         |        |
6
  +-----------+          |      +-----------------+        |   F sub1
7
  |   o---------------+  +----->|    o-----------------+   |    +--------------------+
8
  +-----------+       |         | change_menu     |    |   +--->|  * NULL            |
9
  |   o-------------+ |         | "sub_menu"      |    +------->|  * move_midas_logo |
10
  +-----------+     | |         +-----------------+             |  * "Demo1_t"       |
11
  |   o----------+  | +-------->|   NULL          |             +--------------------+
12
  +-----------+  |  |           | sw_stand        |             |  * NULL            |
13
                 |  |           | "SW_St"         |             |  * foo             |
14
                 |  |           +-----------------+             |  * "sub menu"      |
15
                 |  +---------->|   NULL          |             +--------------------+
16
                 |              | sm_reset        |             |  * NULL            |
17
                 |              | "RESET"         |             |  * sw_stand        |
18
                 |              +-----------------+             |  * "SW_St_t"       |
19
                 +------------->|   NULL          |             +--------------------+
20
                                | sm_sleep        |             |  * NULL            |
21
                                | "SLEEP"         |             |  * sm_reset        |
22
                                +-----------------+             |  * "RESET_t"       |
23
                                                                +--------------------+
24
                                                                |  * NULL            |
25
                                                                |  * sm_sleep        |
26
                                                                |  * Sleep_t"        |
27
                                                                +--------------------+

Das ist die Datenstruktur, die du da zusammengebaut hast.
Mal abgesehen davon, dass sie nicht seh sinnvoll ist (das Array 
Current... braucht in Wirklichkeit kein Mensch) sieht man eines: Immer 
dann, wenn du, um an die Daten zu kommen einem Pfeil folgen musst, an 
dessen Ende ein Kasten steht, der links oben mit einem "F" (wie Flash) 
markiert ist, dann kannst du nicht -> oder * benutzen, sondern musst die 
Adresse an pgm_read.... übergeben und diese Funktion besorgt dir dann 
die Daten.

    CurrentMenu_MenStr_ptr[1]->sub_menu[1]);

CurrentMenu_MenStr_ptr

    das ist ok. Der zugehörige Kasten hat kein F, daher ist

CurrentMenu_MenStr_ptr[1]

    in Ordnung.
    Von dort geht ein Pfeil weg. Sowohl in der Zeichnung als auch
    in deinem Programm:

CurrentMenu_MenStr_ptr[1]->

    Mööp. Ein BLick in die Zeichnung verrät: Der Pfeil endet in einem
    Block, der 'F' markiert ist, die Daten liegen also im Flash.
    Daher kannst du hier nicht -> benutzen, sondern musst mittels
    pgm_read_.... den dich interessierenden Teil holen.
    Was willst do holen?
    Einen Pointer, also 2 Bytes, also ist pgm_read_word dein Freund.
1
    tmp = pgm_read_word( CurrentMenu_MenStr_ptr[1] + offsetof( sub_menu ) );
Damit hast du jetzt in tmp den Pointer aus dem Flash geholt, der auf das 
sub1 zeigt (in diesem Fall). sub1 ist selber wieder im Flash (ist 'F' 
markiert). Um also an Werte in diesem Block ran zu kommen auf den du 
einen Zeiger hast, muss wieder eine pgm_read.... Funktion bemüht werden.

Wenn du bei verzeigerten Datenstrukturen den Überblick verlierst, wie 
sie aussehen, DANN MAL DIR DIE SITUATION AUF PAPIER AUF!
Wenn du dann noch markierst, welche Teile im SRAM liegen und welche im 
Flash, dann kannst du ganz leicht entscheiden, wie der Zugriff aussehen 
muss. Die Zeichnung leitet dich.

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.