Forum: Compiler & IDEs Feste Speicheradressen mit WinAVR und AVRStudio


von Stefan Kleinwort (Gast)


Lesenswert?

Hallo,

oft ergibt sich die Notwendigkeit, bestimmte Variablen an feste
Speicheradressen zu schreiben (z.B. um Parameter getrennt vom Programm
laden zu können).

Das funktioniert mit gcc, wenn man die entsprechenden Variablen mit
const my_varyp my_var _attribute_ ((section (".my_section"))) =
{...};
definiert.
Dem Linker muss man dann die Section my_section mit
  --change-section-address=.my_section=0x2000
bekannt machen (hier: feste Adresse 200hex).

Leider funktioniert dieses Vorgehen nicht mit AVRStudio (getestet mit
den Versionen 4.09 und 4.10 sowohl mit extcoff als auch mit dwarf-2).
Die neu angelegte Section wird von AVRStudio schlicht ignoriert.
Erzeugt man ein Hex-File, tauchen die Variablen dagegen auf. Allerdings
entfällt dann die Debug-Möglichkeit.

Als Lösung benutze ich mittlerweile folgende Möglichkeit:
Die neue Section wird nicht als eigenständige Section, sondern als
Untersection von text deklariert. Dazu muss im Linker-Scriptfile
geändert werden (welches Script-File von der aktuellen Konfiguration
verwendet wird, lässt sich einfach und brutal herausfinden: das
Verzeichnis \WinAVR\avr\lib\ldscripts umbenennen und neu linken,
die Linker-Fehlermeldung zeigt dann den Namen des verwendeten
Linker-Scripts). Das Linker-Script ins Projektverzeichnis kopieren,
sinnvoll umbenennen und folgende Änderungen einfügen:

    *(.fini3)
    *(.fini2)
    *(.fini1)
    *(.fini0)
    . = ABSOLUTE(0x2F00);   /* neue Zeile: feste Adresse vorgeben */
    *(.my_section)          /* neue Zeile: Section bekannt machen */
     _etext = . ;
  }  > text
  .data    :  AT (0x3780)    /* optional: Anfang des S.Data vorgeben */

  {

Im Makefile mus dem Linker die Verwendung des modifizierten
Linker-Scripts bekannt gegeben werden (ich benutze ansonsten das
Standard-Makefile aus WINAVR 20040720):
LDFLAGS = Wl,-Map=$(TARGET).map,--cref,--script=my_linkerscript_avr5.x

Wer eine elegantere Lösung gefunden hat, kann sich natürlich gerne
melden!

Viele Grüße, Stefan

von Jörg Wunsch (Gast)


Lesenswert?

Mach' doch mal'n feature request bei Atmel, dass AVR Studio alle
loadable sections unterstützen möge.

von thkais (Gast)


Lesenswert?

Moin,
ich bin in C nicht so richtig bewandert - aber kann man Variablen nicht
auch mit #PRAGMA an eine vorgegebene Speicherstelle definieren?
Oder habe ich irgendetwas mißverstanden?

von Jörg Wunsch (Gast)


Lesenswert?

Kann man zumindest bei GCC nicht.  Geht insbesondere schon deshalb
nicht, weil es der Linker ist, nicht der Compiler, der etwas an eine
Adresse bindet.

#pragma ist compilerabhängig, genau dafür ist es gemacht worden.

von Stefan Kleinwort (Gast)


Lesenswert?

@Jörg,
werde ich machen, ich wollte nur erstmal die Meinung der Experten
hören, ob das wirklich ein Problem des AVRStudio ist oder nur meine
Fehlinterpretation.

Viele Grüße, Stefan

von Stefan Kleinwort (Gast)


Lesenswert?

Hallo,

ich habe in der oben geposteten Verfahrensweise noch einen Bug
entdeckt. Vorinitialisierte Variablen werden mit obiger Methode aus dem
falschen Speicherbereich initialisiert. Mit folgender zusätzlich
eingefügter Zeile funktionieren auch die initialisierten (globalen)
Variablen:

    *(.fini1)
    *(.fini0)
    . = ABSOLUTE(0x2F00);
    *(.my_section)          /* Platz für Daten mit fester Adresse */
    . = ABSOLUTE(0x3780);   /* diese Zeile zusätzlich einfügen    */
    _etext = . ;
  }  > text
  .data    :  AT (0x3780)
  {

Viele Grüße, Stefan

von mthomas (Gast)


Lesenswert?

Es gibt im avrfreaks gcc-Forum grade zwei aktuelle Threads mit
aehnlichem Thema.

von Stefan Seegel (Gast)


Lesenswert?

Tach!

Frage dazu: Wie kann ich im Code die Startadresse einer Section
rausfingern ?

Ich hab z.B. die Versionkennung bei Adresse 0x37FE geschrieben:

Makefile:
LDFLAGS  += -Wl,--section-start=.version=0x37FE

Code:
const unsigned char ver[2] _attribute_ ((section (".version"))) =
{VERSION_MAJOR, VERSION_MINOR};


Ich möchte nun im Code mit pgm_readbyte die Version auslesen, die
Adresse dafür möchte ich aber automatisch dem makefile entnehmen lassen
falls das mal verschoben werden sollte. Geht das ?

Stefan

von OldBug (Gast)


Lesenswert?

Ich bin mir jetzt nicht sicher, ob ich die Frage richtig verstanden
habe.

>Makefile:
>LDFLAGS  += -Wl,--section-start=.version=0x37FE
>
>Code:
>const unsigned char ver[2] _attribute_ ((section (".version"))) =
>{VERSION_MAJOR, VERSION_MINOR};

- Die Adresse, auf die .version zeigt, wird im Linkerfile festgelegt
- Im Makefile wird an diese Adresse das Versionsword zugewiesen
- Im Code zeigt das array ver auf die beiden Bytes des Words

Ändert man jetzt die Position von .version im Linkerfile, muss man das
Programm neu Kompilieren und schon kennt das Programm wieder die
richtige Adresse (ver = .version) mit dem korrekten Inhalt
(ver[0] = 0x??; ver[1] = 0x??).

Möchtest Du die Adresse, auf die .version zeigt, im Makefile zuweisen?

von Stefan Seegel (Gast)


Lesenswert?

Hmmm,

ich glaub ich hab grad gemerkt dass ich da ne total bescheuerte Frage
gestellt habe... Ja, ich möchte im Makefile die Adresse zuweisen, und
im Code die Variable auslesen mit pgm_read_byte, aber im Code nicht
noch mal die Adresse hinschreiben müssen. Sonst müsste man das zweimal
ändern falls die Adresse geändert werden soll. Aber ein einfaches
pgm_read_byte(ver) sollte ja da genügen...
Naja, um diese Zeit klappts besser mit dem Hirn ;-)

Stefan

von OldBug (Gast)


Lesenswert?

Sorry, ich habe mich da ein wenig "verhauen" ;)

Die Adresse, auf die .version zeigt, wird in Deinem Falle natürlich
im Makefile zugewiesen (0x37FE).

Da hab ich wohl ein wenig Verwirrung gestiftet.

von Stefan Kleinwort (Gast)


Lesenswert?

>pgm_read_byte(ver) sollte ja da genügen...

fast richtig, aber bitte die Adresse übergeben:
pgm_read_byte(&ver)

Der kleine Haken an pgm_read_byte und Konsorten ist, dass es ein Makro
ist und damit keine Typkontrolle besitzt - Du kannst so ziemlich alles
übergeben, ohne Fehlermeldungen zu bekommen.

Viele Grüße, Stefan

von OldBug (Gast)


Lesenswert?

>fast richtig, aber bitte die Adresse übergeben:
>pgm_read_byte(&ver)

Ebenso "fast richtig" g

pgm_read_byte(ver[x]);

...wobei x 0 oder 1 sein kann, und entweder die major oder minor
Version enthält ;)

von Stefan Seegel (Gast)


Lesenswert?

Hmm, bin mir da nicht so sicher, pgm_read_byte will ja einen Pointer
übergeben haben, also müsste eigentlich

pgm_read_byte(ver)
oder
pgm_read_byte(&ver[0])

richtig sein, (ver (ohne []) ist ja ein Pointer)

werd das mal eben testen...

stefan

von Stefan Kleinwort (Gast)


Lesenswert?

grummel  .... stimmt ;-)

Viele Grüße, Stefan

von OldBug (Gast)


Lesenswert?

;)

RTFKNR:
unsigned char ver[2];

 - ver ist ein Pointer (auf den Anfang des Arrays)
 - ver[x] ist ein Pointer (auf den Eintrag x des Arrays)
 - ver + 1 ist ein Pointer auf den Anfang von ver + 1 Element

von Jörg Wunsch (Gast)


Lesenswert?

Nö, ver[x] ist vom Elementtyp von `ver', also `char'.  Für einen
Pointer muss man schon wirklich &ver[x] oder ver + x schreiben (beide
Ausdrücke sind in dem Zusammenhang äquivalent).

von Stefan Seegel (Gast)


Lesenswert?

Ja, gerade getestet (und gelesen ;-)

Nochmal zum mitmeiseln:

mychar=pgm_read_byte(ver + x);
oder
mychar=pgm_read_byte(&ver[x]);

Jörg hats auf den Punkt gebracht...

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.