Forum: Compiler & IDEs Leseprobleme von char[] in einer struct im Flash


von Frank (Gast)


Lesenswert?

Hallo,

obwohl ich sämtliche Suchen und Dokumentationen benutzt/durchsucht
habe, kann ich keine Lösung für mein spezielles Problem finden. Deshalb
möchte ich Euch bitten mir zu helfen.
Ziel ist, ein Array von struct's im Flash abzulegen und dann über den
Index auf die Daten zuzugreifen. Anschließend sollen die Werte auf dem
LCD (16x2) ausgegeben werden. Folgendes (verkürztes) Beispiel
funktioniert:


database.c:
-----------

#include <avr/pgmspace.h>

struct database_object
{
    char name[6];
    int  i1;
    int  i2;
};

unsigned char MAX_OBJECT_INDEX=109;

struct database_object PROGMEM objects[110]=
{
    {"text1\0",    1234,  12345},
    {"text2\0",   12345,    123},
    ....
    {"textn\0",   12345,    123}
}


Zugriffsmethode:
----------------

char    object_name[16];

...
strcpy_P(object_name, objects[act_object].name);

// Ausgabe von object_name auf LCD


Ausgabe:
--------

text1
text2
...
textn



Das Problem liegt jetzt im Zugriff auf die Strings. mit den int-Werten
habe ich kein Problem. Erhöhe ich die Anzahl der char's in der
struct-Definition auf 7 bekomme ich irgendwelchen Mist ausgegeben. Ziel
ist, diese Länge auf maximal 16 zu erhöhen. Das dabei Speicherplatz
verschwendet wird, würde ich erstmal in Kauf nehmen. Erhöhe ich die
Länge weiter, wird der Mist noch größer.

hier noch ein Beispiel:
-----------------------

struct database_object
{
    char name[7];
    int  i1;
    int  i2;
};


und die zugehörige Ausgabe:
---------------------------

text1
&#8616;text2
&#8593;&#8595;text3
...


Erhöhe ich die Länge weiter, zerlegt sich die Anzeige meist schon von
Anfang an.

Könnte mir bitte jemand sagen, wo mein Fehler liegt!

Als Controller verwende ich einen Atmega16. Die Definition der Werte
würde ich, wegen der Übersicht, strukturell so gern beibehalten.


Danke
   Frank

von Jörg Wunsch (Gast)


Lesenswert?

Ist schon x-mal durchgekaut worden.  Du hast zwar die eher kleine
Tabelle im ROM, die Strings selbst sind aber im RAM.  Wahrscheinlich
willst du es eher umgekehrt oder beides im ROM.

von OldBug (Gast)


Angehängte Dateien:

Lesenswert?

Ich bin mir nicht sicher, ob das so stimmt, aber kann es sein, daß

 "text1\0"

nicht in 6 chars reinpasst!? "Gänsefüße" veranlassen den Compiler,
eine Nullterminierung durchzuführen, d.h. Du müsstest bei Deinem
erzeugten Binary zwei Nullen hinter den Strings haben.

Ich weis nicht, ob das Dein Problem löst. Das ganze ohne "Progmem
geraffel" auf dem x86-gcc (mit ein paar kleinen Änderungen) läuft
jedenfalls einwandfrei, siehe Anhang.

von OldBug (Gast)


Lesenswert?

Hups, zu lahm ;-)

...und auch noch daneben gelegen...

von Frank (Gast)


Lesenswert?

Danke für die schnellen Antworten.

@OldBug: Daß das Ganze im RAM läuft wußte ich schon. Selbst auf dem
Atmega (natürlich mit weniger Daten). Daß ich die '\0' weglassen
kann hatte ich mir schon gedacht, war mir aber nicht sicher.

@Jörg: Meckern kann ich selber: "Ist schon x-mal durchgekaut
worden.". Deshalb erklär's mir bitte! Leider sorgt hier keiner dafür,
daß man die Hintergründe auch versteht (Das, was ich zumindest gefunden
habe). Ich nehme jetzt mal an, daß die "Pointer"/"Referenzen" auf
die einzelnen Objekte des Array's im FLASH liegen, aber die Daten
weiterhin im RAM. Nur verstehe ich nicht, warum mir
"pgm_read_word(&objects[index].i1);" dann die Werte korrekt liefert
und ich auch die Strings, solange sie kleiner als 6 sind, korrekt
zurück bekomme. Würden die Daten im RAM liegen, dann müßte ich generell
nur Schrott bekommen. Außerdem würde ich mit meiner Menge an Daten das
RAM generell überladen und mir würde die komplette Anwendung um die
Ohren fliegen.
Also ist meine Vermutung, daß schon jedes (struct-)Objekt mit seinen
Daten im FLASH abgelegt wird, nur beim Zugriff auf die Strings
irgendwas schief geht. Mach mir doch bitte mal nen Vorschlag, wie ich
dieses spezielle Problem lösen könnte und erklär mir meinen Fehler. Auf
jeden Fall muß die Überichtlichkeit (Wartbarkeit) der Daten
gewährleistet bleiben.


Danke
   Frank

von Jörg Wunsch (Gast)


Lesenswert?

Nein, ich habe keine Zeit, das zum (x+1). Mal durchzukauen.

Am besten schaust du dir mal die GCC-Version der Butterfly-Applikation
an.  Die macht sowas in laufenden Metern.

von Frank (Gast)


Lesenswert?

Dann frage ich mich, was Du hier machst!!! Den dicken Löffel raushängen,
dazu gehört nicht viel! So ziemlich alle Beiträge, die ich von Dir hier
gefunden habe drehen sich nur darum, daß Du keine Lust hast alles X-Mal
zu wiederholen. Nur fachlich hast Du keine wirklichen Antworten. Zum
Rumsülzen scheinst Du ja mehr als ausreichend Zeit zu haben! Ich frage
mich wirklich, was so lange dauert mal kurz nen Stück Code zu
korrigieren, bzw. ein paar ordentliche Antworten zu geben. Wenn Du
soviel Ahnung hättest, wie du tust, wäre das in 2min erledigt. Für mich
stellt es sich eher so dar, als ob Du versuchst den Eindruck zu
erwecken, daß Du der absolute Oberguru wärst, aber in Wirklichkeit
keinen blassen Schimmer hast.

Sorry, aber das mußte jetzt raus. Sowas regt mich auf!


Könnte mir mal bitte einer sagen, was ne Butterfly-Applikation ist und
wo ich die finde?

Ich geh mich jetzt erstmal abkühlen...

von OldBug (Gast)


Lesenswert?

Hoho!

Mach mal halblang!
Die avr-libc-FAQ beschreibt das Problem ganz gut.
Ausserdem befindet sich EINIGES an Sourcen in mindestens zwei der Foren
hier.

von Jörg Wunsch (Gast)


Lesenswert?

> Könnte mir mal bitte einer sagen, was ne Butterfly-Applikation ist

Eine Art Minimal-Demo von Atmel für den AVR.  Guck mal bei denen auf
dem Webserver nach.

> und wo ich die finde?

Für den IAR-Compiler bei Atmel selbst.

Für den GCC tippst du bitte "avr butterfly gcc" in Google ein und
folgst dem ersten Link.

von Frank (Gast)


Lesenswert?

Hallo OldBug,

In der avr-libc-faq habe ich dazu nichts gefunden. (Wahrscheinlich zu
blind) Im Tutorial steht zu dem Thema nur: "TODO: Beispiele fuer
structs und pointer aus flash auf struct im flash (menues,
state-machines etc.)"

In den Sourcen finde ich nur die Geschichte, daß z.B. in meiner struct
jedes char-array außerhalb extra deklariert wird. Komischerweise die
int's aber nicht. gerade das wollte ich mir aber ersparen, dadurch die
Übersichtlichkeit flöten geht. Außerdem kann ich mir nicht erklären,
warum ein String extra mit PROGMEM gekennzeichnet werden muß und ein
int nicht.

von Chris (Gast)


Lesenswert?

> In der avr-libc-faq habe ich dazu nichts gefunden.

Schau nochmal nach, ungefähr in der Mitte (nein, die genaue Nummer sag
ich jetzt nicht).

von Frank (Gast)


Lesenswert?

"Am besten schaust du dir mal die GCC-Version der
Butterfly-Applikation
an.  Die macht sowas in laufenden Metern."

...genau das macht sie eben nicht. Das was sie macht, sind Arrays von
primitiven Datentypen in den FLASH zu schreiben. Ich habe aber nicht
eine struct gefunden, die die in den FLASH schreiben, geschweige denn
ein Array von struct.

von Frank (Gast)


Lesenswert?

@Chris: Gut, das kannte ich. Nur ist das für mich die schlechteste
Lösung und die Hintergründe sind (zumindest für den
Assamblerunkundigen) nicht erläutert. Wenn ich die Strings erst
außerhalb der Arraydeklaration anlegen muß, dann brauche ich auch keine
Struct mehr. Dann kann ich mir gleich ein windiges #define-Kunstrukt
schaffen und darüber auf meine Daten zugreifen.
Außerdem wird auch dort nur ein Array von Array's erzeugt aber kein
Array von struct's

von mthomas (Gast)


Lesenswert?

An http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_rom_array
geht noch kein Weg vorbei. Hintergund ist m.W. die noch unvollkommene
Anpassung des gcc an die AVR-Architektur, die es nicht ermoeglicht z.B.
Character-Arrays als Elemente von Structs im Progmem zu initialisieren.
Im gcc-Port der Butterfly-Application wird sehr wohl ein Array von
Structs im Progmem abgelegt und auch das "Umschiffen" des Problems
mit den Character-Arrays als Elemente von Structs und deren
Initialisierung fuer Objekte des Arrays im Progmem demonstriert. Das
Struct enthaelt zur Verwaltung von Zeichenketten Pointer, diese werden
mit der Adresse der "progmem-Zeichenkette" initialisiert, die
ausserhalb definiert ist. Vgl. gcc-Port Quellcodedateien menu.h (struct
MENU_STATE, Array of MENU_STATE menu_state[]) fuer Initialisierung und
main.c (pgm_read...) fuer Zugriff. Das ist zwar etwas umstaendlich,
weniger bei der Initialisierung als beim Zugriff, aber m.W. mit
avr-gcc/avr-libc nicht anders zu machen. Warum dadurch die Verwendung
von structs in diesem Anwendungsfall ueberfluessig sein sollte und wie
dies mit "windigen" #defines zu machen sein soll, wuerde mich
allerdings interessieren.

Martin

von Frank (Gast)


Lesenswert?

Hallo mthomas!

vielen, vielen Dank für Deine ausführliche Beschreibung. Diese Stelle
hatte ich dann doch übersehen. Damit sollte es generell machbar sein.
Das große Problem ist, daß ich mit relativ großen Datenmengen (mind.
150 Objekte) operieren will. Wenn jetzt jeder Objektname erst außerhalb
der Strukturinitialisierung deklariert werden muß ist die Wartbarkeit
für'n Bobs, da Objektname und Objektdaten im direkten Zusammenhang
stehen. Außerdem sind das Einpflegen neuer Daten und anderer
Operationen darauf von Hand extrem mühsam. Zwar nimmt einem ein guter
Texteditor mit einer sehr guten "Ersetzen"-Funktion viel Arbeit ab
aber die Fehlerquote wird an dieser Stelle extrem steigen.
Mein Problem ist an dieser Stelle wahrscheinlich, daß ich die
prozedurale Programmierung lange hinter mir gelassen habe und von den
Möglichkeiten der Objektorientierung mittlerweile zu sehr verwöhnt
bin.

Frank

von Jörg Wunsch (Gast)


Lesenswert?

> Das große Problem ist, daß ich mit relativ großen Datenmengen (mind.
> 150 Objekte) operieren will. Wenn jetzt jeder Objektname erst
> außerhalb der Strukturinitialisierung deklariert werden muß ist die
> Wartbarkeit für'n Bobs, da Objektname und Objektdaten im direkten
> Zusammenhang stehen. Außerdem sind das Einpflegen neuer Daten und
> anderer Operationen darauf von Hand extrem mühsam.

Wie Martin schon schrieb, GCC hatte vor dem AVR nie ernsthaft was mit
Harvard-Architekturen am Hut.  Im Grunde genommen hat C selbst nie
ernsthaft etwas mit Harvard am Hut gehabt... (Erstaunlich übrigens, da
es selbst von der PDP-11 eine Art Harvard-Modifikation gab, die die
Jungs damals sehnsüchtig erwartet haben, weil sie den Adressraum von
64 KB auf 2 * 64 KB erweitert hat.)  Es gibt einen Vorschlag zur
Erweiterung des C-Standards um die Möglichkeit, mehrere Speicherräume
angeben zu können, und hoffentlich wird sich dann auch jemand
finden, der den für den GCC umsetzt (was natürlich massive Eingriffe
in den Compiler verursacht).  Wenn das mal passiert ist, wird das
hoffentlich alles ein Stück einfacher.

Kannst du deine Strukturen und Datenelemente denn nicht eventuell mit
einem Script anlegen?  Auch Makros könnten eine Hilfe sein, weil man
die Makro-Parameter ja sowohl in einen Namen als auch einen String
expandieren kann, also sowas:

#define FOO(x) const char data_##x[] = #x
FOO(hi);
FOO(lo);

expandiert zu:

const char data_hi[] = "hi";
const char data_lo[] = "lo";

Das nur als Idee -- ich würde das vermutlich eher über einen Script
(Shell, Perl, Python) tun, insbesondere dann, wenn das auch
gelegentlichen Änderungen unterworfen ist.

von mthomas (Gast)


Lesenswert?

Jörgs Vorschlag, die Verwaltung mit einem "externem Praeprozessor"
(Skript od. C-Programm) zu machen (Textdatei mit "Metainformationen"
als Eingabe - Ausgabe: avr-gcc/avr-libc Code), scheint mit fuer die
beschriebene Anwendung auch die beste Loesung. Dies duerfte die
Wartung/Erweiterung deutlich erleichtern. Sicher wuerde ein solches
Skript/Programm auch viele Interessenten finden.

von Frank (Gast)


Lesenswert?

Hmm, na mal sehen. Jetzt muß ich das Ganze erstmal zum Laufen bringen
(wenn ich mal wieder Zeit finde) und dann kann ich mir immer noch nen
kleines PC-Progrämmchen zur Verwaltung schreiben. Wär nicht das erste
Mal. Ist warscheinlich die beste Lösung, da ich es auch mit
unterschiedlichen Datenquellen zu tun haben werde.

Danke für die Vorschläge.

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.