Forum: Compiler & IDEs const String-Arrays im Flash ablegen mit avr-gcc


von Stefan (Gast)


Lesenswert?

Hallo!

Gibt es inzwischen eine gute Möglichkeit, die Strings eines Arrays, in
den Flash-Speicher zu verlegen oder muß ich immer noch die
fehlerträchtigen und konfusen "_P", PROGMEM, PGM_P Statements
hinzufügen, damit ich ein String ins Flash-Mem verlegen kann?

Wird es dafür irgendwann mal eine Lösung geben, denn der Code ist alles
andere als portierbar und unschön anzusehen? Gibt es Compiler, die das
besser können?

Das alles kommt ja wohl daher, daß der AVR den LPM Befehl benutzen muß,
um an den Code-Speicher zu kommen. Warum kann der gcc das nicht alleine
merken? Ist jemand in der Lage, mir das zu erklären (evtl. Jörg
Wunsch)?

Für Hinweise jeglicher Art bin ich sehr dankbar!! Leider ist das ein
weiterer Punkt, der mich an den AVRs echt stört...

Dankeschön!!

Stefan

von mthomas (Gast)


Lesenswert?

>es Compiler, die das besser können?
auf das "besser" und die restliche Aussagen/Fragen werden sicher noch
einige Reaktionen kommen. Vorab: die kommerziellen Compiler haben
meines Wissens alle ein Flash-Attribut (FLASH, _flash etc.) und die
Zugriffe auf Variablen, die mit diesem Attribut versehen werden
erfolgen "transparent". Je nach Geldbeutel und Vorlieben: IAR Emb.
Workbench, CodevisionAVR, ImageCraft ICCAVR.

von Jörg Wunsch (Gast)


Lesenswert?

Nun, sagen wir, die Zugriffe sind dort teilweise transparent...
Irgendwelche Sonderfunktionen braucht man trotzdem noch, statt
strcmp_P() heißt es bei IAR wohl strcmp_f(), wenn ich mich nicht irre,
aber das Prinzip bleibt.  Außerdem Martin, Du erinnerst Dich an die
Diskussion um die Verrenkungen im Butterfly-Code, teilweise scheint
mir die Transparenz selbst bei den kommerziellen Compilern an ihre
Grenzen zu stoßen.

Ansonsten ist das schon zur Unendlichkeit durchgekaut worden: GCC hat
keine Vorkehrungen, um mit Harvard-Architekturen wirklich gut
umzugehen.  Solange er die nicht hat, wird sich folglich auch im
AVR-GCC kaum was ändern können.

In einer Diskussion in avrfreaks.net war nach allen Argumenten jemand
zu dem Schluß gekommen, daß C als Sprache eigentlich eher schlecht mit
Harvard zurechtkommt, dem konnte ich mich dann nur anschließen.

Wirklich portierbar ist Controller-Code meiner Meinung nach ohnehin
nur, wenn man einen HAL dazwischenschiebt (hardware abstraction
layer), aber das geht dann gut auf die Performance.  Wahrscheinlich
werden auch nur die wenigsten Leute beim Thema Controller wirklich auf
Portabilität so großen Wert legen, sprich Dinge wie Geschwindigkeit,
Stromaufnahme, Codegröße, effektive Nutzung der Peripherie (statt
Einschränkung auf einen kleinsten gemeinsamen Hardware-Nenner) werden
stärker im Vordergrund stehen.

von Stefan (Gast)


Lesenswert?

Ob ich nun strcpy_f oder strcpy_p schreibe, ist gehuckt wie gesprungen.
Schön wäre es, wenn der Compiler es selber merken würde, aber ist nun
mal nicht, schade. Zumindest weiß ich jetzt, daß man von
Mikrocontrollern mit Harvard-Technologie Abstand nehmen sollte.

Ich hatte vor einem Jahr ein Projekt mit einem 16-Bit Controller von
National Semiconductor und dieser wurde auch mit einem gcc-Compiler
Derivat programmiert. Dort konnten Strings ganz normal mit "const"
abgelegt werden und jetzt dachte ich, daß das mit dem avr-gcc doch auch
gehen müsste, aber geht nicht, weil der 16-Bitter eine "von Neumann"
Architektur hatte. Dank Euren Hinweisen bin ich jetzt wieder etwas
schlauer...danke!!!

Das Portieren von Code ist für mich nur deshalb wichtig, weil ich so
wenig wie möglich Zeit auf einem Mikrocontroller entwickeln möchte. Der
Grund ist klar: Das ewige Flashen und schlechte debuggen stört mich,
einen ICE50 möchte ich mir deswegen nicht zulegen und der ICE200 ist
leider zu klein für dieses Projekt (auch zu langsam, nicht optimal für
den avr-gcc).

Um das zu umgehen, habe ich mir ein kleines include-File geschrieben,
mit dem ich AVR-Code auf den PC portieren, dort die logischen,
hardware-unabhängigen Fehler herausholen und dann den Rest auf dem
Controller entwickeln kann. Man spart durch gdb, Insight und Konsorten
eine ganze Menge Zeit. Arbeitet man viel mit Buffern (klar, kostet mehr
RAM), so kann man die Zeichen der seriellen Schnittstelle und sogar die
Ausgabe auf LCDs wunderbar debuggen.

Ist der Code auf dem PC getestet, so entferne ich nur einen
Define-Schalter und schon kompiliert sich der Code auf dem avr-gcc.

Einziger Nachteil ist nun nur noch das dumme Einfügen eines Strings
in ein Array:

const char foo[] PROGMEM = "Foo";
const char bar[] PROGMEM = "Bar";
PGM_P array[2] PROGMEM = { foo, bar };

Ist das auch der letzte Stand der Technik oder kann man das noch
irgendwie schöner darstellen?

Danke nochmals!!!

von Stefan (Gast)


Lesenswert?

Sorry, habe nochmal ein paar Fragen:

Ich habe folgende Menü-Struktur Typdefinition:

typedef struct SMenuTab
{
  const char                  *menuentry;
  const char                  **p_str;
        void                  *val;
  const uint8_t               dtype;
  const int                   min_val;
  const int                   max_val;
  const struct SMenuTab       *child_tab;
  const struct SMenuFunc      *menu_func;
} TMenuTab;

Davon sollen MEHRERE "Instanzen" im Flash abgelegt werden (ich weiß,
nach unterem Bsp. befinden sich die Strings noch im RAM, der Rest ist
laut Mapfile im ROM):

__attribute__((progmem))
const TMenuTab SM_MenuTab1[] PROGMEM =
{

{"Menüpunkt1",0,NULL,0,0,8,SM_LHeSetup_MenuTab,&SM_MAIN_GenFuncTab},
  {"Menüpunkt2",0,NULL,0,0,0,SM_LHeSetup_MenuTab,NULL},
};
__attribute__((progmem))
const TMenuTab SM_MenuTab2[]  ...
__attribute__((progmem))
const TMenuTab SM_MenuTab3[]  ...
 etc.

Wie man sieht, verbirgen sich dort eine Menge Pointer, Pointer auf
Pointer und auch Funktionspointer (hinter der Struktur SMenuFunc).
Nun möchte ich auf die Elemente der SM_MenuTab1 oder SM_MenuTab2 etc.
zugreifen. Sehe ich das richtig, daß ich dafür die komplette Struktur
erstmal über den memcpy_P Befehl (bzw. mittels PRG_RDB) ins RAM
kopieren muß (also in dafür bereits reservierten Speicher)?? Oder kann
man das auch noch anders lösen? Zumindest hätte ich dadurch den
Vorteil, daß ich die ganz normalen Funktionen (ohne _P) benutzen
kann?!

Wofür muß ich eigentlich vor jedem "=" ein "PROGMEM" schreiben? Am
Mapfile ändert sich nichts! Ist das ein Hinweis für den Compiler oder
kann man es auch weglassen??

Danke Euch!

von Peter D. (peda)


Lesenswert?

"Zumindest weiß ich jetzt, daß man von
Mikrocontrollern mit Harvard-Technologie Abstand nehmen sollte."


Das stimmt nicht !

Der Keil 8051 Compiler macht das über generic pointer, d.h. eine
Adresse besteht immer aus 3 Byte, wobei das eine Byte den Typ
kennzeichnet.

Somit kann man Programme genauso schreiben, als hätte man eine von
Neumann Architektur.

Allerdings geht das manchmal auf Kosten der Ausführungsgeschwindigkeit,
da ja sämtliche Stringfunktionen erstmal abtesten müssen, welche
Speicherzugriffe sie verwenden müssen.
Deshalb kann man da, wo es kritisch ist, trotzdem memory specific
pointer benutzten.

Das mit den generic pointern geht sogar soweit, daß man auch externe
Speicherbausteine, die über I2C oder 1-wire angesprochen werden, direkt
verwenden und dort Variablen ablegen kann. Man muß dann nur die
low-level Zugriffsfunktionen (Lese, Schreibe Byte) definieren und
einbinden.


Peter

von Jörg Wunsch (Gast)


Lesenswert?

Die generic pointer sind auch die einzige Variante, wie man das
C-Standard-konform ohne Weiteres auf die Reihe bekommen kann.
Insofern finde ich sie gut.  Aber sie bringen den Nachteil sämtlicher
OO-Programmierung (``late binding'') mit sich: großer Code,
geringere
Ausführungsgeschwindigkeit.  Damit sind wir eigentlich wieder bei dem,
was besagter Poster in avrfreaks.net festgestellt hat: so richtig
wirklich für Harvard-Architekturen scheint C einfach nicht geschaffen.

Ja Stefan, man muß sich das Zeug einzeln aus dem ROM popeln.

von Christian (Gast)


Lesenswert?

mmh komich. ein atmel vertreter hat uns gesagt das gerade die atmel
serie auf hochsprachen optimiert ist.

von Jörg Wunsch (Gast)


Lesenswert?

Ja, und?  Was hilft's, wenn die Sprache C trotzdem auf Kriegsfuß mit
Harvard steht, sich Atmel aber für Harvard bereits entschieden hatte?

Was der Verdreher gemeint hat ist, daß der Befehlssatz in
Zusammenarbeit mit IAR ein wenig überarbeitet worden ist.  Das Ganze
ist in irgendeinem PDF dokumentiert worden, das Du bei Atmel finden
kannst.  Das verbessert übrigens in der Tat die Zusammenarbeit mit
einem C-Compiler, aber es beseitigt eben nicht die aus der
Harvard-Architektur resultierenden Grundprobleme.

von Peter D. (peda)


Lesenswert?

"ein atmel vertreter hat uns gesagt das gerade die atmel
serie auf hochsprachen optimiert ist."

Das ist nur unwissend nachgeplapperter Werbequatsch.

Wenn man will, kann man als optimiert bezeichenen, daß kein Banking und
Paging von RAM und Flash und dafür aber mehrere Datenpointer vorhanden
sind. Damit läßt sich z.B. im Gegensatz zum PIC verschiebbarer und
kleinerer Code erzeugen.
Beim PIC muß man den einzigen Pointer immer umständlich umladen und
dann an den Bankgrenzen testen und die Bank umschalten.


Aber im Prinzip kann ein guter Compilerbauer auch ne Menge machen bei
Architekturen, die auf den allerersten Blick nicht ganz so optimal für
C aussehen.
Ein gutes Beispiel dafür ist der Keil C51 Compiler für die 8051
Familie, der in der Regel kleineren Code erzeugt, als auf einem AVR
benötigt wird.

Auch da haben sich die Atmel-Werbefuzzies voll ins Knie gefickt, indem
sie auch in Bytes rechen. Hätten sie dem AT89C52 mit 8k-Bytes einen
AT90S8515 mit 8k-Worten gegenübergestellt, hätten bestimmt viel mehr
zum AVR wechseln können.


Peter

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.