www.mikrocontroller.net

Forum: Compiler & IDEs PROGMEM Adresse in uint8_t-Array speichern


Autor: Mirko Kaffka (mka)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe mehrere uint8_t-Arrays im PROGMEM, die eine Art Bytecode für 
eine Ablaufsteuerung enthalten. Nun möchte innerhalb eines solchen 
Arrays den Pointer auf ein anderes Array ablegen. Wegen des uint8_t muss 
ich den noch in High- und Low-Byte zerlegen:

#include <inttypes.h>
#include <avr/pgmspace.h>

uint8_t PROGMEM prog_thread1[] = { 1, 2, 3 };

uint8_t PROGMEM prog_main[] = {
  42, // ... beliebig viele weitere Bytes
  (uint8_t)(((uint16_t)prog_thread1) &  0xff),
  (uint8_t)(((uint16_t)prog_thread1) >> 8),
};

avr-gcc -c -mmcu=atmega16   foo.c
foo.c:7: error: initializer element is not constant
foo.c:7: error: (near initialization for 'prog_main[0]')
foo.c:8: error: initializer element is not constant
foo.c:8: error: (near initialization for 'prog_main[1]')

Was ist denn an dem prog_thread1 Pointer nicht konstant? Hat jemand eine 
Idee für einen Workaround mit dem avr-gcc (Version 4.2.2) oder weiß wie 
man das richtig macht?

Autor: Mirko Kaffka (mka)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich glaube ich komme langsam dahinter was hier passiert. Vielleicht kann 
mir jemand meine Vermutung bestätigen:
Für den Compiler ist die Adresse von prog_thread1 zwar konstant, aber 
nur innerhalb des Object-Files bekannt. Die Adresse schreibt er in die 
Symboltabelle. Die wirkliche Adresse setzt aber am Ende der Linker ein 
und der muss sie u.a. aus dem Eintrag der Symboltabelle berechnen.
Die logischen Verknüpfungen zur Trennung in Hi und Lo Byte (& und >>) 
müssen auf die vom Linker berechnete Adresse angewendet werden. Der 
Compiler kann das noch nicht machen. Der Linker ist für sowas 
(verständlicherweise) nicht ausgelegt.

Wenn ich das Array, in das ich die Adresse einfügen will, zu einem 
uint16_t mache, entfallen die & und >> Operationen und es funktioniert 
(danke Jörg):

uint8_t  prog_thread1[] = { 1, 2, 3 };
uint16_t  prog_main[] = {
  42,
  (uint16_t)prog_thread1
};

Das möchte ich allerdings vermeiden, da ich so meinen Kommandosatz auf 
16 Bit umstellen muss und wegen einer Reihe von 3 Byte Befehlen 
reichlich Verschnitt hätte.
Hat jemand eine Idee, wie man das mit 8 Bit Arrays hinbekommen kann?

Mirko

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Notfalls halt nicht als Initialisierung, sondern gleich nach
Programmstart mit einer normalen Zuweisung?

Autor: Mirko Kaffka (mka)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Arrays sind im Flash. Das PROGMEM hatte ich im ersten Beitrag noch 
drin, im zweiten dann aber vergessen.

Autor: Grrrr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielleicht wäre es auch ein Weg, in prog_main nicht Adressen sondern 
Indizes zu speichern?

Autor: Mirko Kaffka (mka)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, die Idee hatte ich auch schon. So in der Art:

#include <inttypes.h>
#include <avr/pgmspace.h>

uint8_t  prog_thread1[] = { 1, 2, 3 };

prog_uint8_t *thread_addresses[] = {
  prog_thread1
  /* , weitere Adressen */
};

uint8_t  prog_main[] = {
  42,
  0 /* Index ins thread_addresses[] Array */
};

Mein Programm muss dann über thread_addresses[i] die Adresse holen. Es 
ist zwar nicht so schön, das thread_addresses-Array noch extra pflegen 
zu
müssen, erscheint mir aber noch praktikabel. Ich glaube so werde ich es 
machen.

Danke, wieder was gelernt :-)

Mirko

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mirko Kaffka schrieb:

> Die logischen Verknüpfungen zur Trennung in Hi und Lo Byte (& und >>)
> müssen auf die vom Linker berechnete Adresse angewendet werden. Der
> Compiler kann das noch nicht machen. Der Linker ist für sowas
> (verständlicherweise) nicht ausgelegt.

Ja, ich denke auch, dass das das Problem ist.

Der Linker von RSX-11 (dort "taskbuilder" genannt) auf der PDP-11
konnte sowas. ;-)  Die haben im Objektcode einen RPN-Faden mit
Berechnungen ablegen können, die auf das Symbol anzuwenden sind bei
der Relokation.  Ich hatte dafür mal einen Disassembler geschrieben
und hatte die Ehre, aus dem RPN-Faden eine algebraische Darstellung
zu erfinden. :)

Der Unix-Linker kann das nicht.  Alles, was der machen soll, muss als
"relocation record type" zwischen Assembler und Linker vereinbart
worden sein.  In diesem Falle hier bedürfte es offenbar sogar noch
einer Vereinbarung zwischen Compiler und Assembler, wie man sowas
auf Assembler-Niveau ausdrücken soll.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.