Hallo,
ich habe Probleme auf eine komplexere Datenstruktur im Programmspeicher
des Atmega328P mittels Arduino C zuzugreifen.
Es geht um den Zugriff mit:
strcpy_P(s, (char*)pgm_read_byte(&(SubArray[i].submenu[j])));
Wenn i eine Konstante ist gehts, wenn i eine Variable ist gehts nicht.
Was geht da schief und wie mach ichs richtig?
Danke, Tom
Hier der Arduino Sketch mit meiner Datenstruktur und meinen
Leseversuchen:
Tom schrieb:> Serial.write(0x0D);> Serial.write(0x0A);
1
Serial.println();
Tom schrieb:> ich habe Probleme auf eine komplexere Datenstruktur im Programmspeicher> des Atmega328P mittels Arduino C zuzugreifen.
Ich sehe keine komplexe Datenstruktur.
Das ist C++, kein C
Mein Vorschlag!
Verwende Codetags.
Reduziere das Programm auf ein Minimum.
Sage, was du erreichen willst, dem Code sehe ich das nicht an.
Warum Machst du das nicht so, wie in der Doku beschrieben?
Tom schrieb:> Hier der Arduino Sketch mit meiner Datenstruktur und meinen> Leseversuchen (sorry, habe nicht herausfinden können, wie man hier Code> vernünftig formatiert):
"Wichtige Regeln - erst lesen, dann posten!"
Formatierung unter: "C-Code"
Sorry, ich dachte, wenns im Editor zum Formatieren keinen Knopf gibt,
dann kann man auch nicht formatieren. Habe ich jetzt repariert.
Das obige Beispiel ist bereits das lauffähige Minimalbeispiel.
Was ich erreichen will:
Ich habe diese Menü-Datenstruktur im Flash:
Tom schrieb:> Wie gehts richtig?
Wenn du ein Array mit Zeigern hast, dann solltest du auch Zeiger aus dem
Array lesen.
Tom schrieb:> Die Strings will ich indiziert in ein Array im RAM kopieren,
Warum?
Eine Ausgabe ist auch ohne Kopie möglich.
Vorschlag:
Wenn die Zeichenketten immer gleich lang sind, dann kannst du auch mit
einem 2 Dimensionalen Array arbeiten.
Den doofen Count mitzuführen ist dann nicht notwendig. (vielleicht)
count als char ist doof, weil man mit char nicht rechnen kann/soll
Tom schrieb:> Wenn i eine Konstante ist gehts, wenn i eine Variable ist gehts nicht.> Was geht da schief und wie mach ichs richtig?
Das ist die interessante Frage....
Warum?
1
#include<Streaming.h> // die Lib findest du selber ;-)
Es ist die Optimierung die dir einen Streich spielt.
Der Compiler weiß nix über PROGMEM und EEMEM.
Kennt er nicht, darum benötigen wir auch besondere Zugriffsfunktionen um
in die Speicher zu greifen.
Die Verwendung von Konstanten kann der Optimizer super gut optimieren.
Den Zugriff über Variablen weniger.
Wenn man die Optimierung deaktiviert, dann brichts auch mit Konstanten
ins Essen.
Hier schalte ich partiell die Optimierung per volatile ab.
a funktioniert trotz falschem Zugriff, dank Optimierung richtig
b funktioniert, zeigt wie es muss
c hat zwei Gesichter ein richtiges, da mit Zugriffsmethode und ein
falsches, da Optimierung für c abgeschaltet
Das ist genau die Falle in die du getappt bist
Dein Menü:
1
#include<Streaming.h> // die Lib findest du selber ;-)
Arduino F. schrieb:> Hier schalte ich partiell die Optimierung per volatile ab.> a funktioniert trotz falschem Zugriff, dank Optimierung richtig> b funktioniert, zeigt wie es muss>> c hat zwei Gesichter ein richtiges, da mit Zugriffsmethode und ein> falsches, da Optimierung für c abgeschaltet
Sei mir nicht böse, aber das ist Wort für Wort von vorne bis hinten
völliger Unsinn.
Die richtige Antwort ist schlicht RTFM.
Ob es die von der avrlibc ist, oder die vom Arduino, ist egal. Oder
gleich hier:
https://www.mikrocontroller.net/articles/AVR-Tutorial:_Speicher
Da ist beschrieben und dokumentiert, wie man auf Daten im Flash
zugreift. Das hat mit irgendwelchen Gesichtern von C (die es nicht gibt)
oder abschalten der Optimierung durch volatile (was völliger Unsinn ist)
nichts zu tun.
Oliver
Oliver S. schrieb:> ...
Du hast das Problem des TO nicht verstanden!
Natürlich liegt es an der Optimierung, dass er "versehentlich" richtige
Daten bekommt, wenn ihm Konstanten verwendet.
Oliver S. schrieb:> RTFM
Da hast du allerdings wahr.
Oliver S. schrieb:> Ob es die von der avrlibc ist, oder die vom Arduino, ist egal.
Das ist nicht egal, sondern exakt das selbe.
Oliver S. schrieb:> Ob es die von der avrlibc ist, oder die vom Arduino, ist egal. Oder> gleich hier:> https://www.mikrocontroller.net/articles/AVR-Tutorial:_Speicher>> Da ist beschrieben und dokumentiert, wie man auf Daten im Flash> zugreift.
Was soll die dämliche Nebelkerze?
Wir sind hier in C++ und nicht in ASM.
Arduino F. schrieb:> Vorschlag:> Wenn die Zeichenketten immer gleich lang sind, dann kannst du auch mit> einem 2 Dimensionalen Array arbeiten.
So mache ich das auch. Ansonsten ist das ein riesen Wust an
Schreibarbeit und somit gerne eine Fehlerquelle.
Im Flash muß man ja nicht mit jedem Byte geizen, da legt man einfach die
maximale Länge für alle Strings im Array fest.
Wie schon gesagt wurde, einen Pointer im Flash muß man dann mit
pgm_read_word() zugreifen, die Pointerschreibweise x[i] funktioniert
also nicht mehr.
Arduino F. schrieb:> Du hast das Problem des TO nicht verstanden!> Natürlich liegt es an der Optimierung, dass er "versehentlich" richtige> Daten bekommt, wenn ihm Konstanten verwendet.
Wenn ein Programm mit/ohne Optimierung funktioniert, und ohen/mit nicht,
liegt es niemals an der Optimierung, sondern immer am Programm (seltene
Compilerfehler mal ausgenommen). Und den Begriif volatile mit
Optimierung in einem Satz zu nennen ist ebenso immer garantiert
unsinnig.
Das Problem, daß folgendes nicht das tut, was der TO erwartet
> strcpy_P(s, (char*)pgm_read_byte(&(SubArray[i].submenu[j])));
hat nichts mit Optimierungen zu tun, sondern damit, daß SubArray in
Flash liegt, und submenu auch. pgm_read_byte macht das, was es lt. Doku
macht, und liest ein byte von der übergeben Adresse aus dem Flash.
SubArray[i] wird in dem Fall aber einer Adressen im SRam gelesen, obwohl
das eigentlich im Flash stehen. Das liefert in solchen Fällen sogar
häufig trotzdem das richtige Ergebnis, weil der gleiche Fehler auch beim
Schreiben gemacht wird, und die Daten daher tatsächlich im SRAM stehen,
und gar nicht bzw. nicht nur, wie eigentlich gewollt, im Flash.
Falsch ist das trotzdem.
Man kann per PROGMEM ins Flash gelegte Daten, auf die ein ebenfalls im
Flash liegender Pointer zeigt, nicht in einem Schritt mit pgm_read über
den Flashpointer auslesen. Das braucht immer zwei pgm_read-Aufrufe,
einer für den Pointer, den zweiten dann für die Daten.
Arduino F. schrieb:> Was soll die dämliche Nebelkerze?> Wir sind hier in C++ und nicht in ASM.
Das war tatsächlich der falsche link. Hier der richtige:
https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Flash_mit_PROGMEM_und_pgm_read
Oliver
Oliver S. schrieb:> liegt es niemals an der Optimierung,
Merke: Ich habe nicht gesagt, dass die Optimierung kaputt ist.
Mit keinem Wort!
Noch nicht einmal angedeutet.
Ja, der TO verwendet die Zugriffsfunktionen nicht, bzw. unzureichend.
Und die Optimierung bügelt seinen Fehler teilweise/manchmal wieder aus.
Das habe ich gesagt/gemeint und sogar mit einem Programm belegt.
Reproduzierbar.
Auch für dich.
Oliver S. schrieb:> hat nichts mit Optimierungen zu tun,
Offensichtlich doch!
Siehe Beispiel mit a b c
Oliver S. schrieb:> Das war tatsächlich der falsche link.
Nicht nur ein falscher Link, sondern auch extrem blöde Anmache, obwohl
das Verständnisproblem alleine auf deiner Seite liegt.
Oliver S. schrieb:> Und den Begriif volatile mit> Optimierung in einem Satz zu nennen ist ebenso immer garantiert> unsinnig.
Deine Kompetenz leuchtet heute recht schwach!
Eigentlich erwarte ich viel mehr von dir.....