Forum: Mikrocontroller und Digitale Elektronik flash struct mit flash string pointern auslesen


von daniel (Gast)


Lesenswert?

Hi,

mal wieder so ein PROGMEM Problem. Habe schon einige Beitraege und 
Tutorials durchgelesen. Im Prinzip ja immer das selbe: Pointer aus Flash 
lesen(pgm_read_word ), an x_P function uebergeben, die wiederum mit 
pgm_read_byte liest.

Beim debugger wird mir aber gar nichts klar. Schau ich mir die Struktur
1
typedef struct {
2
  PGM_P           pcCmd;
3
  const PF_GSM_IF pfCmd;
4
} PACKED ST_STR_RESLV;
wird fuer pcCmd statt 0x65(Byte-Adresse) wird 0x2465(invalid) angezeigt
1
.progmem.data  0x00000054       0x1e gsm_com.o
2
...
3
               0x00000054                g_stCmdSmpl
4
               0x00000065                g_strCSQ
5
               0x0000005c                g_stCmdBase
fuer pfCmd statt 0x0068 wird 0x2468(invalid) angezeigt.
0x65 / 2 = Wordadresse im Flash(jedoch 0x32)
0x68 * 2(warum?) = Adresse in Map fuer Function 0xD0
1
 .text          0x000000b0      0x16a main.o
2
                0x000000d0                SetNiveuVal
3
                0x000001a8                Init

Es werden Strings aus dem Flash ueber put0text_P() normal geprintet. 
Ebenso werden zeichen aus dem Flash gelesen und geprintet mittels 
put0byte().Jedoch Strings welche erst referenziert werden muessen 
crashen das system.

Vielleicht kann mir bitte jemand einen Hinweis geben.

Hier der Code:
1
#include <stdint.h>
2
#include <avr/pgmspace.h>
3
//commands
4
enum EN_AT_CMD{
5
  EN_AT_INVALID,
6
  EN_AT_SEP_EXT,
7
  EN_AT_CSQ,
8
  EN_AT_END_CMD,
9
};
10
11
#define PCHAR(c) ((const char PROGMEM)(c))
12
// GSM protocol processing
13
typedef uint8_t (*PF_GSM_IF) (uint8_t*);
14
15
//PGM_P - #define PGM_P const prog_char *
16
17
// string resolving tab
18
typedef struct {
19
  PGM_P           pcCmd;
20
  const PF_GSM_IF pfCmd;
21
} PACKED ST_STR_RESLV;
22
23
// char resolving tab
24
typedef struct {
25
  const uint8_t    cCmd;
26
  const PF_GSM_IF  pfCmd;
27
} PACKED ST_BYTE_RESLV;
28
29
extern uint8_t SetNiveuVal(uint8_t* pubData);
30
31
const prog_char g_strAT[] = "AT";
32
const prog_char g_strEND[] = "/r";
33
34
// simple commands 
35
const char g_stCmdSmpl[] PROGMEM =
36
{0};
37
38
// only char
39
const ST_BYTE_RESLV g_stCmdBase[] PROGMEM =
40
{
41
  // ...
42
  {PCHAR('+'),GSM_CmdExt0}, 
43
};
44
45
const prog_char g_strCSQ[] = "CSQ";
46
47
// strings in flash
48
const ST_STR_RESLV g_stCmdExt0[] PROGMEM  =
49
{
50
  {(PGM_P)(g_strCSQ),SetNiveuVal}
51
};
52
53
void put0text_P(PGM_P str)
54
{
55
  uint8_t c;
56
  while(c = pgm_read_byte(str++)) put0byte(c);               
57
}
58
59
uint8_t GSM_Cmd_TxProc(uint8_t ubCmd)
60
{
61
  const char* ptext;
62
63
  put0text_P(g_strAT);
64
  if (ubCmd < EN_AT_SEP_EXT) 
65
  {
66
    // simple command
67
    put0byte(pgm_read_byte(&g_stCmdSmpl[ubCmd]));
68
  } else {
69
    // extended command
70
    put0byte(pgm_read_byte(&g_stCmdBase[((sizeof(g_stCmdBase)/sizeof(ST_BYTE_RESLV))-1)].cCmd)); // '+'
71
    // now we crash the system ?! why?
72
    ptext = (const char*)pgm_read_word(&(g_stCmdExt0[ubCmd-EN_AT_SEP_EXT+1].pcCmd));
73
    put0text_P((PGM_P)ptext);
74
  }
75
  if(ubCmd > EN_AT_SEP_WR)
76
  {
77
    ptext = (const char*)pgm_read_word(&(g_stCmdWr[ubCmd-EN_AT_SEP_WR].pcCmd));
78
    put0text_P((PGM_P)ptext);
79
  }
80
  put0text_P(g_strEND);
81
  return GSM_RET_OK; 
82
}
83
84
void main()
85
{
86
87
  GSM_Cmd_TxProc(EN_AT_CSQ); //fails after "AT+"
88
}

Vielen Dank!

von Karl H. (kbuchegg)


Lesenswert?

daniel schrieb:

> Vielleicht kann mir bitte jemand einen Hinweis geben.

Nicht 100% sicher


> #define PCHAR(c) ((const char PROGMEM)(c))

...


> const ST_BYTE_RESLV g_stCmdBase[] PROGMEM =
> {
>   // ...
>   {PCHAR('+'),GSM_CmdExt0},

Ich denke nicht, dass das das macht, was du erwartest.

Das hier
> #define PCHAR(c) ((const char PROGMEM)(c))
ist letztendlich einfach nur ein simpler cast. Er veranlasst aber nicht, 
dass

a) c   ins Flash geschoben wird
b) Der ganze Ausdruck als die Adresse von "c-im_Flash" evaluiert.

Sieh dir an, wie zb PSTR in pgmspace.h definiert ist.
1
# define PSTR(s) (__extension__({static char __c[] PROGMEM = (s); &__c[0];}))
da muss schon etwas mehr Aufwand getrieben werden, um etwas inline ins 
Flash zu legen.

1
    ptext = (const char*)pgm_read_word(&(g_stCmdExt0[ubCmd-EN_AT_SEP_EXT+1].pcCmd));

Nach const char* ?
Du hast doch gar keinen String angelegt!

Das müsste doch dann
1
const ST_BYTE_RESLV g_stCmdBase[] PROGMEM =
2
{
3
  { PSTR( "+" ), GSM_CmdExt0 },
lauten. Also einen String, statt einem einzelnen Character.

von Schnappi (Gast)


Lesenswert?

Jaja. Wieder mal ganz sorgfältig überlegt und dann flach durch die kalte 
Küche in die Ecke geschossen. ;-)

P.S.
Ist nicht böse gemeint, haben wir alle schon mal gemacht.

von Karl H. (kbuchegg)


Lesenswert?

Edit:

In
1
ptext = (const char*)pgm_read_word(&(g_stCmdExt0[ubCmd-EN_AT_SEP_EXT+1].pcCmd));
geht es ja um g_stCmdExt0 und nicht um g_stCmdBase.

Mann, dein ewiges Rumgecaste nervt.
Merk dir eines: Wenn du alles und jedes ständig rum casten musst, dann 
ist etwas oberfaul. In einem korrekten Programm braucht man wenige 
Casts.
Merk dir auch: Ein Cast ist eine Waffe, die du niemals leichtfertig 
einsetzen willst. Mit einem Cast hebelst du das Typsystem in C (das 
sowieso nicht das beste ist) komplett aus. Ein Cast ist das Äquivalent 
zu einem bewaffneten Raubüberfall: Du tust jetzt was ich dir anschaffe, 
oder ...


Kannst du das nicht mal ein wenig abspecken, da verliert man komplett 
den Überblick, wer nun wo und worauf zugreift.

von Karl H. (kbuchegg)


Lesenswert?

Ähm
1
  GSM_Cmd_TxProc(EN_AT_CSQ); //fails after "AT+"
....
1
enum EN_AT_CMD{
2
  EN_AT_INVALID,    // 0
3
  EN_AT_SEP_EXT,    // 1
4
  EN_AT_CSQ,        // 2
5
  EN_AT_END_CMD,    // 3
6
};
.....
1
const ST_STR_RESLV g_stCmdExt0[] PROGMEM  =
2
{
3
  {(PGM_P)(g_strCSQ),SetNiveuVal}
4
};
.....
1
    ptext = (const char*)pgm_read_word(&(g_stCmdExt0[ubCmd-EN_AT_SEP_EXT+1].pcCmd));

logo, crasht das.
EN_AT_CSQ ist 2, damit greifst du hier
1
 ....   g_stCmdExt0[ ubCmd - EN_AT_SEP_EXT + 1 ]  ....
auf ein Element zu, welches laut
1
const ST_STR_RESLV g_stCmdExt0[] PROGMEM  =
2
{
3
  {(PGM_P)(g_strCSQ),SetNiveuVal}
4
};
nicht existiert.

ubCmd - EN_AT_SEP_EXT + 1  ergibt   2 - 1 + 1 -> 2

g_stCmdExt0 hat aber nur 1 Element, daher ist 0 der einzig zulässige 
Index.
Ich vermute mal, das hätte eigentlich
1
   ptext = (const char*)pgm_read_word( &(g_stCmdExt0[ ubCmd - EN_AT_SEP_EXT - 1 ].pcCmd) );
heißen sollen. Würde auch Sinn ergeben.

von daniel (Gast)


Lesenswert?

Vielen Dank fuer die vielen Hinweise,

1.
1
Mann, dein ewiges Rumgecaste nervt.
Die casts sind erst im nachhinein gekommen, weils nicht funktionierte. 
Aber vielen Dank fuer den Hinweis, ich werde es auf ein minimum 
reduzieren und nochmal posten.

2.
1
 ubCmd - EN_AT_SEP_EXT + 1  ergibt   2 - 1 + 1 -> 2
Vielen Dank, logisch das es schief geht, da fehlen die Klammern?! (oder 
-1). Wie immer: Imaginaere Klammern nuetzen nichts!

3.
1
 da muss schon etwas mehr Aufwand getrieben werden, um etwas inline ins
2
Flash zu legen.
Vielen Dank, dass schau ich mir nochmal an. Jedes Byte zaehlt.

Nochmals vielen Dank, heute abend wirds getestet und ich werd mich 
melden.
daniel

von daniel (Gast)


Lesenswert?

Hi,

@Karl heinz Buchegger
Vielen Dank! Das was du in den zwei Stunden geloest hast, ist mir in 3 
Tagen nicht aufgefallen. Das war das Problem, deswegen ist mir das 
gesamte System abgestuerzt.

Hier noch mal der korrigierte Code:
1
// protocol processing
2
typedef uint8_t (*PF_GSM_IF) (uint8_t*);
3
4
// string resolving tab
5
typedef struct {
6
  PGM_P           pcCmd;   // constant pointer to string in flash
7
  const PF_GSM_IF pfCmd;   // constant pointer to function in flash
8
} PACKED ST_STR_RESLV;
9
10
// char resolving tab
11
typedef struct {
12
  const prog_char  cCmd;   // constant character in flash
13
  const PF_GSM_IF  pfCmd;  // constant character in flash
14
} PACKED ST_BYTE_RESLV;
15
16
// simple tx command lookup - EN_AT<x>
17
const char g_stCmdSmpl[] PROGMEM =
18
{
19
 0
20
// here to add more simple command char <x>
21
};
22
23
//rx command lookup table
24
const ST_BYTE_RESLV g_stCmdBase[] PROGMEM =
25
{
26
  {'+',NULL}, 
27
};
28
29
const prog_char g_strCSQ[] = GSM_CMD_CSQ;
30
31
// extented tx,rx command lookup - EN_AT_<x>
32
const ST_STR_RESLV g_stCmdExt0[] PROGMEM  =
33
{
34
  {g_strCSQ,SetNiveuVal}
35
// here to add extended command strings <x>
36
};
37
38
const prog_char g_strAT[] = "AT";
39
const prog_char g_strEND[] = "\r";
40
41
//commands for TxProc
42
enum EN_AT_CMD{
43
  EN_AT_INVALID,
44
  // ... here add more simple commands AT<x>
45
  EN_AT_SEP_EXT,
46
  EN_AT_CSQ,
47
  // ... here add more extended commands AT+<x>
48
  EN_AT_END_CMD,
49
};
50
51
uint8_t GSM_Cmd_TxProc(uint8_t ubCmd)
52
{
53
  PGM_P ptext;
54
    
55
  put0text_P(g_strAT);
56
  if (ubCmd < EN_AT_SEP_EXT) 
57
  {
58
    // simple command
59
    put0byte(pgm_read_byte(&g_stCmdSmpl[ubCmd]));
60
  } else {
61
    // extended command
62
    put0byte(pgm_read_byte(&g_stCmdBase[((sizeof(g_stCmdBase)/sizeof(ST_BYTE_RESLV))-1)].cCmd)); // '+'
63
    ptext = (PGM_P)pgm_read_word(&(g_stCmdExt0[ubCmd-EN_AT_SEP_EXT-1].pcCmd));
64
    put0text_P(ptext);
65
  }
66
  put0text_P(g_strEND);
67
  return GSM_RET_OK; 
68
}
69
70
extern void put0byte(char);
71
72
void put0text_P(PGM_P str)
73
{
74
  uint8_t c;
75
  //! sending until no delimiter
76
  while(c = pgm_read_byte(str++)) put0byte(c);               
77
}
78
79
void main()
80
{
81
GSM_Cmd_TxProc(EN_AT_CSQ); //fails after "AT+"
82
}

Vielen Dank!

daniel

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.