Forum: Compiler & IDEs GCC AVR Fehler


von hbloed (Gast)


Lesenswert?

Hallo!
Ich habe da ein dickes Problem im GCC AVR gefunden.
Ich will einen String nach einer Reihe von Schlüsselwörtern
durchsuchen. Wenn die Schlüsselwörtern im Ram stehen und
unter verwendung von strcasecmp geht das auch wunderbar.
Kommen die Schlüsselwörter aus dem Flash mit strcasecmp_P
geht das nur wenn der index in Strings[] eine konstante ist.
Kennt da jemand einen workaround?


#include <avr/pgmspace.h>
#include <stdio.h>
#include <avr/iom128.h>
#include <avr/interrupt.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>


int16_t indx;
char cliline_ram[] = "WRITE";
const char PROGMEM Str1[] = "HELP";
const char PROGMEM Str2[] = "INFO";
const char PROGMEM Str3[] = "WRITE";
const char PROGMEM Str4[] = "READ";
const char PROGMEM Str5[] = "POLL";
const char PROGMEM Str6[] = "DEFINE";
const char PROGMEM Str7[] = "SCAN";
const char PROGMEM Str8[] = "IPADDR";
const char PROGMEM Str9[] = "IPMASK";
const char PROGMEM Str10[] = "GATEWAY";
const char PROGMEM Str11[] = "PORT";
const char* PROGMEM Strings[]  = { Str1, Str2,Str3 ,Str4 ,Str5 ,Str6 
,Str7 ,Str8,Str9,Str10,Str11     };

int16_t gr;
uint8_t i;

int16_t main(void)
{
  indx =strcasecmp_P((const char*)&cliline_ram,Strings[0]); //nicht 
gefunden
  indx =strcasecmp_P((const char*)&cliline_ram,Strings[1]); //nicht 
gefunden
  indx =strcasecmp_P((const char*)&cliline_ram,Strings[2]); //gefunden 
ok
  i=2;
  indx =strcasecmp_P((const char*)&cliline_ram,Strings[i]); //geht nicht
  gr = sizeof(Strings) / 2;
  for (i=0;i<gr; i++)
  {
    indx =strcasecmp_P((const char*)&cliline_ram,Strings[i]); //geht 
nicht
    indx =strcasecmp_P((const char*)&cliline_ram,Strings[2]); //geht
  }
  return 0;
}

von Karl H. (kbuchegg)


Lesenswert?

hbloed schrieb:

>   indx =strcasecmp_P((const char*)&cliline_ram,Strings[0]); //nicht
> gefunden

Hier liegt der Fehler.
Du kannst nicht einfach Strings[0] benutzen.
Denn Strings liegt je seinerseits selbst wieder im Flash. Zugriffe 
darauf müssen daher über die pgm_read.... Funktionen geführt werden.

Ist der Index eine Konstante, dann rettet dich der Optimizer, der den 
ZUgriff auf Strings[0] durch den Inhalt, nämlich der Adresse von Str1, 
ersetzt, die er kennt. Bei Strings[i] geht das dann klarerweise nicht 
mehr.

> Ich habe da ein dickes Problem im GCC AVR gefunden.
Wider nix. War doch nur ein Programmierfehler.

(Das Umcasten von cliline_ram auf const char* kannst du dir sparen. Das 
const ist an dieser Stelle die Zusicherung der Funktion, dass sie den 
String nicht verändern wird. Wenn eine Funktion diese Zusicherung macht, 
kann man daher der Funktion sowohl konstante Texte als auch nicht 
konstante Texte übergeben. Das weiß auch der Compiler)

von hbloed (Gast)


Lesenswert?

So einfach ist es nicht,
nicht gefunden ist in dem Fall i.o. weil der String ja nicht 
übereinstimmt.
die Zeilen wo ght nicht steht sind das Problem:

  indx =strcasecmp_P((const char*)&cliline_ram,Strings[i]); //geht nicht
  indx =strcasecmp_P((const char*)&cliline_ram,Strings[2]); //geht

Wenn ich über i zugreife geht es nicht, bei zugriff über [2] ist es ok.

Das mit dem pgm_read bring nix, hab ich auch schon probiert.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

hbloed schrieb:
> Das mit dem pgm_read bring nix, hab ich auch schon probiert.

Dann probier's beim nächsten Mal richtig, dann geht's.

Ob es allerdings wirklich lohnt, die paar Byte an Zeigern für den
Stress mit dem notwendigen pgm_read_word() tatsächlich noch in den
Flash zu verlagern, musst du selbst wissen.  Wenn du dein PROGMEM
in der Deklaration von Strings[] einfach streichst, funktioniert der
ganze Krempel auf Anhieb.

von Karl H. (kbuchegg)


Lesenswert?

hbloed schrieb:
> So einfach ist es nicht,

Doch. Ist es.

> Wenn ich über i zugreife geht es nicht, bei zugriff über [2] ist es ok.

Und ich hab (zumindest versucht) dir erklärt, warum das so ist: Das 
Verhalten ist deswegen so, weil dir der Optimizer einen eigentlich 
falschen Code durch die Optimierung ungewollt so zurechtbiegt, dass er 
wieder funktioniert.

> Das mit dem pgm_read bring nix, hab ich auch schon probiert.

Dann hast du das falsch eingebaut.
Da liegt beim Code im Eröffnungsposting der Knackpunkt. Machs richtig 
und es wird in allen Fällen funktionieren.

Wenn du mittels PROGMEM etwas ins Flash verlagerst, dann geht der 
Zugriff auf den Inhalt immer über eine der pgm_read Funktionen, der man 
die Adresse im Flash übergibt, an der die gewünschten Daten liegen.

int PROGMEM i = 5;

i liegt im Flash, also führt der Zugriff zum Auslesen von i über die 
pgm_read Funktionen

const char* Strings[] PROGMEM =  { ....

Strings liegt im Flash, also führt der Zugriff zum Auslesen des Inhalts 
eines Array Elements über die pgm_read Funktionen.

Du willst hier den Inhalt des i-ten Array elements von Strings benutzen

    strcasecmp_P((const char*)&cliline_ram,Strings[i]);

also musst du pgm_read benutzen und dieser Funktion die Adresse des 
i-ten Arrayelements in Strings übergeben.
1
  strcasecmp_P( cliline_ram, (const char*)pgm_read_word( &Strings[i] ) );

So einfach ist das.

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.