Forum: Compiler & IDEs bin zu blöd für progmem


von john (Gast)


Lesenswert?

hi alle,

ich bin zu blöd um strings im rom abzlegen glauube ich. ich habe
mehrere beiträge gelesen, aber irgendwie klappt das nicht. vielleicht
habe ich nur was übersehen. hier der code

const char pms01[] PROGMEM = "starting ...\0";
const char pms02[] PROGMEM = "starting VS1001\0";
const char pms03[] PROGMEM = "VS1001 OK\0";
const char pms04[] PROGMEM = "starting MMC\0";
const char pms05[] PROGMEM = "MMC OK\0";
const char pms06[] PROGMEM = "starting FAT\0";
const char pms07[] PROGMEM = "FAT OK\0";

PGM_P pgm_strings[2] PROGMEM = {
    pms01,
  pms02
};


// if c == 0x01 then a new line is added
void USART_sendpgmstring (u08 id, u08 c) {
   char buf[16];
  char *str = &buf[0];
  u08 i =0;
  strcpy_P(buf, pgm_strings[id]);
  // parse and send string until end is found
  while ((*str != (char)0) && (*str != (char)10)&& (i<16)){
     USART_send ((u08)*str++);
    i++;
   };
  if(c ==0x01) USART_newline();
}

aber über usart kommen nur hyroglyphen raus.

john

von Stefan Seegel (Gast)


Lesenswert?

Hi John!

Gleiches Problem hatte ich die Tage auch, nur mit nem LCD.
Schau mal ein paar Threads früher, da wurde genau das Problem erklärt:
http://www.mikrocontroller.net/forum/read-2-94515.html

Knackpunkt ist dass das array pgm_strings Zeiger auf Strings im Flash
sind, aber die Zeiger selber auch im Flash stehen. Du musst also
erstmal die Zeiger aus dem Flash ziehen. Wenn du dein pgm_strings[id]
zum testen mal durch pgm_strings[0] oder pgm_strings[1] ersetzt müsste
es gehen, weil dann der Compiler dann die Adresse gleich einsetzt...

von Jörg Wunsch (Gast)


Lesenswert?

IMHO ist es übrigens bald sinnvoller, in solchen Konstellationen die
Zeigertabelle selbst (die ja nicht sehr groß ist) als normale Variable
zu deklarieren, statt sie in den progmem zu nageln.  Das spart die
LPMs dafür.

von john (Gast)


Lesenswert?

hi,

erstmal danke, ich sehe jetzt was.
ich habe jetzt -->

const u08 pms01[] PROGMEM = "starting ...\0  ";
const u08 pms02[] PROGMEM = "starting VS1001";
const u08 pms03[] PROGMEM = "VS1001 OK\0     ";
const u08 pms04[] PROGMEM = "starting MMC\0  ";
.
.
.

PGM_P pgm_strings[34] PROGMEM = {
    pms01,
    pms02,
    .
    .
    .

void USART_sendpgmstring (u08 id, u08 c) {
  u08 buf[16];
  u08 *str = &buf[0];
  u08 i =0;
  strcpy_P(buf, pgm_strings[0]+(16*id));
  while ((*str != (char)0) && (*str != (char)10)&& (i<16)){
     USART_send ((u08)*str++);
    i++;
   };
  if(c ==0x01) USART_newline();
}


aber das ist ja noch nicht richtig. ich verschwende ja jetzt immer ein
paar byte, da die breite ja bei 16 byte festgelegt ist.

john

von Jörg Wunsch (Gast)


Lesenswert?

Wo kommt denn die `16 * id' her?  Sieht mir so aus, als hättest Du das
Konzept von Zeigern in C nicht verstanden.


void USART_sendpgmstring (u08 id, u08 c) {
  char *buf;
  char c;

  buf = (char **)pgm_read_word(pgm_strings + id);
  while ((c = pgm_read_byte(buf)) != '\0' && c != '\n') {
     USART_send (c);
     buf++;
  };
  ...

von Stefan Seegel (Gast)


Lesenswert?

Genau, so müssts wohl gehen, weil man erst den Pointer aus dem PROGMEM
ließt und dann die Chars aus dem Progmem.
Was ich aber immer noch nicht kapiert habe: Wieso ließt man Pointer als
"Word" ? Wer/was/wo steht definiert dass ein Pointer 2 Bytes lang ist
? Ist das halt einfach so bei AVRs ?

Stefan

von john (Gast)


Lesenswert?

@Jörg : Danke hat geklappt. hatte das zweite * bei (char **) vergessen,
als ich es so probiert hatte ;) danke nochmal

von Jörg Wunsch (Gast)


Lesenswert?

> Wieso ließt man Pointer als "Word"? Wer/was/wo steht definiert dass
> ein Pointer 2 Bytes lang ist? Ist das halt einfach so bei AVRs?

Zumindest bei den derzeitigen AVRs sind Zeiger 16 bits breit.  Das
wird bei künftigen AVRs (ATmega256) nicht mehr notwendig der Fall
sein.  (Für den Zugriff auf den RAM sehr kleiner AVRs würden auch 8
bit breite Zeiger genügen, aber das ist erstens hier nicht das Thema
und zweitens vom AVR-GCC nicht berücksichtigt.)

Streng genommen sind die Zeiger in den ROM beim ATmega128 auch jetzt
schon 17 bits breit, wenn man sie auf Daten zeigen läßt (also für den
ELPM oder ESPM Befehl), aber nur 16 bits breit, wenn man sie auf Code
zeigen läßt (Adressen von Funktionen), da der Programmcode in 16 bit
breiten Worten zählt.  AVR-GCC kann diese Situation aber nicht
wirklich handhaben (mit Ausnahme der Makros für den Bootloader) und
behilft sich derzeit, indem maximal 64 KB konstante Daten unterstützt
werden und diese durch den Linkerscript garantiert vor dem
ausführbaren Code plaziert werden.

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.