www.mikrocontroller.net

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


Autor: daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
typedef struct {
  PGM_P           pcCmd;
  const PF_GSM_IF pfCmd;
} PACKED ST_STR_RESLV;
wird fuer pcCmd statt 0x65(Byte-Adresse) wird 0x2465(invalid) angezeigt
.progmem.data  0x00000054       0x1e gsm_com.o
...
               0x00000054                g_stCmdSmpl
               0x00000065                g_strCSQ
               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
 .text          0x000000b0      0x16a main.o
                0x000000d0                SetNiveuVal
                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:
#include <stdint.h>
#include <avr/pgmspace.h>
//commands
enum EN_AT_CMD{
  EN_AT_INVALID,
  EN_AT_SEP_EXT,
  EN_AT_CSQ,
  EN_AT_END_CMD,
};

#define PCHAR(c) ((const char PROGMEM)(c))
// GSM protocol processing
typedef uint8_t (*PF_GSM_IF) (uint8_t*);

//PGM_P - #define PGM_P const prog_char *

// string resolving tab
typedef struct {
  PGM_P           pcCmd;
  const PF_GSM_IF pfCmd;
} PACKED ST_STR_RESLV;

// char resolving tab
typedef struct {
  const uint8_t    cCmd;
  const PF_GSM_IF  pfCmd;
} PACKED ST_BYTE_RESLV;

extern uint8_t SetNiveuVal(uint8_t* pubData);

const prog_char g_strAT[] = "AT";
const prog_char g_strEND[] = "/r";

// simple commands 
const char g_stCmdSmpl[] PROGMEM =
{0};

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

const prog_char g_strCSQ[] = "CSQ";

// strings in flash
const ST_STR_RESLV g_stCmdExt0[] PROGMEM  =
{
  {(PGM_P)(g_strCSQ),SetNiveuVal}
};

void put0text_P(PGM_P str)
{
  uint8_t c;
  while(c = pgm_read_byte(str++)) put0byte(c);               
}

uint8_t GSM_Cmd_TxProc(uint8_t ubCmd)
{
  const char* ptext;

  put0text_P(g_strAT);
  if (ubCmd < EN_AT_SEP_EXT) 
  {
    // simple command
    put0byte(pgm_read_byte(&g_stCmdSmpl[ubCmd]));
  } else {
    // extended command
    put0byte(pgm_read_byte(&g_stCmdBase[((sizeof(g_stCmdBase)/sizeof(ST_BYTE_RESLV))-1)].cCmd)); // '+'
    // now we crash the system ?! why?
    ptext = (const char*)pgm_read_word(&(g_stCmdExt0[ubCmd-EN_AT_SEP_EXT+1].pcCmd));
    put0text_P((PGM_P)ptext);
  }
  if(ubCmd > EN_AT_SEP_WR)
  {
    ptext = (const char*)pgm_read_word(&(g_stCmdWr[ubCmd-EN_AT_SEP_WR].pcCmd));
    put0text_P((PGM_P)ptext);
  }
  put0text_P(g_strEND);
  return GSM_RET_OK; 
}

void main()
{

  GSM_Cmd_TxProc(EN_AT_CSQ); //fails after "AT+"
}

Vielen Dank!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.
# 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.

    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
const ST_BYTE_RESLV g_stCmdBase[] PROGMEM =
{
  { PSTR( "+" ), GSM_CmdExt0 },
lauten. Also einen String, statt einem einzelnen Character.

Autor: Schnappi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Edit:

In
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ähm
  GSM_Cmd_TxProc(EN_AT_CSQ); //fails after "AT+"
....
enum EN_AT_CMD{
  EN_AT_INVALID,    // 0
  EN_AT_SEP_EXT,    // 1
  EN_AT_CSQ,        // 2
  EN_AT_END_CMD,    // 3
};
.....
const ST_STR_RESLV g_stCmdExt0[] PROGMEM  =
{
  {(PGM_P)(g_strCSQ),SetNiveuVal}
};
.....
    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
 ....   g_stCmdExt0[ ubCmd - EN_AT_SEP_EXT + 1 ]  ....
auf ein Element zu, welches laut
const ST_STR_RESLV g_stCmdExt0[] PROGMEM  =
{
  {(PGM_P)(g_strCSQ),SetNiveuVal}
};
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
   ptext = (const char*)pgm_read_word( &(g_stCmdExt0[ ubCmd - EN_AT_SEP_EXT - 1 ].pcCmd) );
heißen sollen. Würde auch Sinn ergeben.

Autor: daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank fuer die vielen Hinweise,

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.
 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.
 da muss schon etwas mehr Aufwand getrieben werden, um etwas inline ins
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

Autor: daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:

// protocol processing
typedef uint8_t (*PF_GSM_IF) (uint8_t*);

// string resolving tab
typedef struct {
  PGM_P           pcCmd;   // constant pointer to string in flash
  const PF_GSM_IF pfCmd;   // constant pointer to function in flash
} PACKED ST_STR_RESLV;

// char resolving tab
typedef struct {
  const prog_char  cCmd;   // constant character in flash
  const PF_GSM_IF  pfCmd;  // constant character in flash
} PACKED ST_BYTE_RESLV;

// simple tx command lookup - EN_AT<x>
const char g_stCmdSmpl[] PROGMEM =
{
 0
// here to add more simple command char <x>
};

//rx command lookup table
const ST_BYTE_RESLV g_stCmdBase[] PROGMEM =
{
  {'+',NULL}, 
};

const prog_char g_strCSQ[] = GSM_CMD_CSQ;

// extented tx,rx command lookup - EN_AT_<x>
const ST_STR_RESLV g_stCmdExt0[] PROGMEM  =
{
  {g_strCSQ,SetNiveuVal}
// here to add extended command strings <x>
};

const prog_char g_strAT[] = "AT";
const prog_char g_strEND[] = "\r";

//commands for TxProc
enum EN_AT_CMD{
  EN_AT_INVALID,
  // ... here add more simple commands AT<x>
  EN_AT_SEP_EXT,
  EN_AT_CSQ,
  // ... here add more extended commands AT+<x>
  EN_AT_END_CMD,
};

uint8_t GSM_Cmd_TxProc(uint8_t ubCmd)
{
  PGM_P ptext;
    
  put0text_P(g_strAT);
  if (ubCmd < EN_AT_SEP_EXT) 
  {
    // simple command
    put0byte(pgm_read_byte(&g_stCmdSmpl[ubCmd]));
  } else {
    // extended command
    put0byte(pgm_read_byte(&g_stCmdBase[((sizeof(g_stCmdBase)/sizeof(ST_BYTE_RESLV))-1)].cCmd)); // '+'
    ptext = (PGM_P)pgm_read_word(&(g_stCmdExt0[ubCmd-EN_AT_SEP_EXT-1].pcCmd));
    put0text_P(ptext);
  }
  put0text_P(g_strEND);
  return GSM_RET_OK; 
}

extern void put0byte(char);

void put0text_P(PGM_P str)
{
  uint8_t c;
  //! sending until no delimiter
  while(c = pgm_read_byte(str++)) put0byte(c);               
}

void main()
{
GSM_Cmd_TxProc(EN_AT_CSQ); //fails after "AT+"
}


Vielen Dank!

daniel

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
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.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.