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 ↨text2 ↑↓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
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.
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.
Hups, zu lahm ;-) ...und auch noch daneben gelegen...
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
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.
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...
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.
> 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.
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.
> 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).
"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.
@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
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
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
> 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.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.