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
>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.
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.
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!!!
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!
"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
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.
mmh komich. ein atmel vertreter hat uns gesagt das gerade die atmel serie auf hochsprachen optimiert ist.
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.
"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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.