Hallo,
folgendes Problem habe ich bisher nur unzufriedenstellend gelöst:
Ich habe ein Projekt, bei dem es die Möglichkeit gibt einen Paramtersatz, gespeichert in einer Struktur, nach der Programmierung mittels Bootloaders zu erstellen oder zu ändern.
Im Hauptprogramm gibt es einen Pointer auf diese Stelle (die Struktur wird hier nicht angelegt sondern nur gelesen) und soweit funktioniert es auch.
Nun möchte ich manchmal die Struktur doch anlegen lassen und habe dafür eine Sektion an der entsprechenden Adresse erstellt. Dies funktioniert auch, aber ich habe jetzt an mehreren Stellen die Adresse stehen. Im Linker und bei der Initialisierung des Pointers.
Ich könnte natürlich den Pointer auf die Strukur initialisieren, aber falls ich die Struktur nicht anlegen möchte habe ich ein Problem.
deklariere ich die Struktur ohne sie zu initialisieren wird der Flash an der Stelle mit Nullen gefüllt und das Hex-File entsprechend aufgebläht.
Ich hoffe ich habe mich verständlich ausgedrückt und frage ob ihr vielleicht eine bessere Idee habt.
und dann ganz normal drauf zugreifen. So wird es dann eben nicht mehr initialisiert, die Werte 1 und 2 verschwinden beim Linken (d.h. beim ersten Programmstart wirst du Nonsense lesen), dafür brauchst du dann die üblichen Flash-Zugriffs-Routinen.
Wenn du das struct dann doch mal befüllen möchtest (z.B. beim Flashen in der Produktion) lasse das (NOLOAD) weg und die gewünschten Werte (1, 2) werden geflasht.
Da sich die Daten ändern können, sind sie streng genommen nicht const, sondern volatile const. Damit die Daten bei jedem Zugriff gelesen werden und nicht etwa vom Compiler in Immediate Operanden von Instruktionen eingebaut werden.
Das wäre aber ziemlich ineffizient, weil sie dann wirklich jedes Mal neu geladen werden... Wäre es da nicht sinnvoller das "static" wegzulassen und nach dem Schreiben ins-Flash ein memory-Barrier hinzuzufügen (asm volatile ("" : : : "memory") )?
Das funktioniert vermutlich nur in C, nicht in C++. In C++ könnte man "static" und "const" weglassen, aber die Variablen privat machen und nur getter hinzufügen...
Man muss halt dafür sorgen, dass jeder Zugriff im Programm zu einem Zugriff im Assembly führt, und der Compiler nix rausoptimiert weil Initialwerte des Arrays als unveränderlich angenommen werden, was sie nicht sind.
Da sich die Daten ändern können, sind sie streng genommen nicht const,
sondern volatile const. Damit die Daten bei jedem Zugriff gelesen werden
und nicht etwa vom Compiler in Immediate Operanden von Instruktionen
eingebaut werden.
Die Problematik verstehe ich scheinbar noch nicht ganz.
Für mich ist der Pointer konstant und die Struktur auf die dieser zeigt, sind für dieses Programm ebenfalls konstant, da sie sich innerhalb des Programms nicht ändern.
Entweder werden sie bei der Initialisierung einmalig geschrieben, oder über den Bootloader.
Die Problematik verstehe ich scheinbar noch nicht ganz
Wenn der Compiler sieht, dass die Daten sich nicht ändern (In C: Weil "static const" dran steht, in C++: Weil "const" oder "constexpr" dran steht), kann es sein, dass der Compiler den Lesezugriff komplett wegoptimiert. D.h. die Initializer-Werte (bzw 0 wenn nicht angegeben) werden in den Maschinencode hart kodiert und es erfolgt überhaupt kein Lesezugriff auf die gewünschte Stelle.
Weiß nicht, das erscheint mir eine recht hinterhältige Methode, im
Linkerscript vermutet man so etwas eher...
Da ich das Microchip Studio benutze boot sich das an, in der Projekt-Konfiguration kann man die Sektionen einfach anlegen und sie werden dann entsprechend als Paramter eingefügt.
Aber ich kann natürlich, und ich werde es wahrscheinlich auch machen, die Sektion im Linkersript entsprechend anlegen.
Wenn der Compiler sieht, dass die Daten sich nicht ändern (In C: Weil
"static const" dran steht, in C++: Weil "const" oder "constexpr" dran
steht), kann es sein, dass der Compiler den Lesezugriff komplett
wegoptimiert. D.h. die Initializer-Werte (bzw 0 wenn nicht angegeben)
werden in den Maschinencode hart kodiert und es erfolgt überhaupt kein
Lesezugriff auf die gewünschte Stelle.
Das leuchtet ein, wahrscheinlich gab es noch keine Probleme, da ich bisher immer über den Pointer auf die Struktur zugegriffen habe.
Wäre es da nicht sinnvoller das "static" wegzulassen
und nach dem Schreiben ins-Flash ein memory-Barrier hinzuzufügen
(asm volatile ("" : : : "memory") )?
machen. Das weist den Compiler an, zuvor in CPU-Registern zwischengespeicherte Werte neu aus dem Speicher zu laden. Allerdings nur bei Variablen die nicht "static const" (C) bzw. "const"/"constexpr" (C++) sind.
oder in Ausnahmefällen durch die Initialisierung der Struktur im
Programm.
Diese Initialisierung greift aber nicht wenn NOLOAD im Spiel ist. Hier brauchst du die Memory Barrier dann auch nicht aber du musst dennoch mit dem "const" aufpassen weil sonst ggf. gar keine Lesezugriffe gemacht werden.
Diese Initialisierung greift aber nicht wenn NOLOAD im Spiel ist. Hier
brauchst du die Memory Barrier dann auch nicht aber du musst dennoch mit
dem "const" aufpassen weil sonst ggf. gar keine Lesezugriffe gemacht
werden.
Dann werde ich zwei Linkerscripte vorhalten, eins für den Standardfall in welchem NOLOAD steht und bei dem keine Initialisierung gewünscht wird, und ein zweites ohne NOLOAD.