Forum: Compiler & IDEs AVR-GCC Linker Symbol als Initializer verwenden


von Jay K. (deeplyembedded)


Lesenswert?

Hallo zusammen,

ich möchte im Flash meines ATMEGA88 Start- und Endadresse eines 
Bereiches ablegen, über den eine CRC berechnet werden soll.
Die Adressinformation erzeuge ich über das Linkerskript mit
__CHECKSUM_START = .;
und
__CHKSUM_END = .;

Nun deklariere ich diese Symbole entsprechend mit
extern const uint32 __CHECKSUM_START;
extern const uint32 __CHKSUM_END;

Definieren möchte ich dann eine Variable mit

const uint32 PROGMEM ChksumStartAddr = &__CHECKSUM_START;

Aber der Compiler macht mir einen Strich durch die Rechnung:
error: initializer element is not computable at load time

Kann mir jemand sagen, was ich verkehrt mache?

Danke und viele Grüße

von Oliver S. (oliverso)


Lesenswert?

Mal ohne & probiert?

Oliver

von Jay K. (deeplyembedded)


Lesenswert?

Jap, da steigt der GCC dann aber gleich aus mit:
error: initializer element is not constant

von Dr. Sommer (Gast)


Lesenswert?

Jay K. schrieb:
> const uint32 PROGMEM ChksumStartAddr = &__CHECKSUM_START

Welchen Sinn hat das überhaupt? Kannst du nicht einfach __CHECKSUM_START 
statt ChksumStartAddr nutzen? Ist ja eh konstant. Kann übrigens sein 
dass das in C++ geht. Probier es mal aus...

von Jay K. (deeplyembedded)


Lesenswert?

Dr. Sommer schrieb:
> Welchen Sinn hat das überhaupt?

Der Sinn ist, dass diese Werte während des Builds vom Hauptprogramm eben 
im Flash abgelegt werden und dann zur Laufzeit von einer anderen Instanz 
(z.B. dem Bootloader) ausgelesen und zur CRC Berechnung genutzt werden 
können

von Tassilo H. (tassilo_h)


Lesenswert?

Eigentlich müsste es gehen. Zum Vergleich, in meinem Code (ist zwar 
ARM-GCC, aber dafür spielt das ja keine Rolle) sieht das so aus:
1
// first address that follows the rom space used by the linker
2
extern uint32_t _usedromend;  
3
// first address that is used for the .text section by the linker 
4
extern uint32_t _usedromstart; 
5
6
uint32_t sysComputeFlashCRC()
7
{
8
  uint32_t *dp;
9
10
  dp = &_usedromstart;
11
  sysCRCReset();
12
  while (dp != &_usedromend) sysCRCAdd(*dp++);
13
  return sysCRCGet();
14
}

und im Linkerscript:
1
SECTIONS
2
{
3
  .text :
4
  {
5
  _usedromstart = .;
6
    KEEP(*(.isr_vector))
7
    *(.text*)
8
    *(.rodata*)
9
  } > rom 
10
  
11
  .ARM.exidx : 
12
  {
13
    __exidx_start = .;
14
    *(.ARM.exidx* .gnu.linkonce.armexidx.*)
15
    __exidx_end = .;
16
  } > rom
17
  
18
  __etext = .;
19
  /* _sidata is used in startup code */
20
  _sidata = __etext;
21
  .data : AT (__etext)
22
  {
23
    __data_start__ = .;
24
    /* _sdata is used in startup code */
25
    _sdata = __data_start__;
26
    
27
    *(vtable)
28
    *(.data*)
29
    . = ALIGN(4);
30
    /* All data end */
31
    __data_end__ = .;
32
    /* _edata is used in startup code */
33
    _edata = __data_end__;
34
  } > ram 
35
  /* _siccmdata is used in startup code to init vars in ccm */
36
  _siccmdata = __etext + SIZEOF (.data);
37
  .ccmdata : AT ( _siccmdata )
38
  {
39
    __ccmdata_start__ = .;
40
    _sccmdata = __ccmdata_start__;
41
    *(.ccmdata*)
42
    . = ALIGN(4);
43
    /* All data end */
44
     __ccmdata_end__ = .;
45
    _eccmdata = __ccmdata_end__;
46
  } > ccm
47
  _usedromend = _siccmdata + SIZEOF (.ccmdata);
48
  .bss :
49
  {
50
...

Vielleicht hilft das ja...

PS: Gerade ausprobiert:
1
const uint32_t *rompointer = &_usedromstart;
im Code compiliert einwandfrei. Also sollte dein Beispiel eigentlich 
auch gehen... Muss wohl eine AVR-Spezialität sein. Kannst du denn eine 
nicht-PROGMEM-Variable damit initialisieren?

: Bearbeitet durch User
von deeplyembedded (Gast)


Lesenswert?

Hallo Tassilo,

danke für das Beispiel. So wie ich das sehe ist es nicht ganz das 
Gleiche. Du arbeitest hier mit dem Linkersymbol nach der Definition der 
(lokalen) Variablen.
Zudem ist der ARM keine Harvard-Architektur...vielleicht ist da auch ein 
Problem?

von Tassilo H. (tassilo_h)


Lesenswert?

Habe gerade nochmal probiert:

Eine globale variable:
1
const uint32_t romstartadr = (uint32_t)&_usedromstart;
2
3
// uses the built in CRC engine to compute
4
// the CRC of the FLash
5
uint32_t sysComputeFlashCRC()
6
{
7
  uint32_t *dp;
8
9
  //dp = &_usedromstart;
10
  dp = (void*)romstartadr;
11
  sysCRCReset();
12
  while (dp != &_usedromend) sysCRCAdd(*dp++);
13
  return sysCRCGet();
14
}

funktioniert auch. Die liegt auch im Flash und nicht im RAM, da const. 
Wenn der GCC das beim ARM zur Linkzeit eintragen kann, müsste das doch 
beim AVR auch gehen?!

von Jay K. (deeplyembedded)


Lesenswert?

Also mit einer "nicht-progmem" Variablen geht es auch nicht.
Ich habe nun folgendes probiert:

const uint32_t startaddr = __CHKSUM_START;

Funktioniert auch nicht. Fehlermeldung ist wieder
error: initializer element is not computable at load time

Ich denke wirklich, es ist hier eine AVR-GCC Spezialität

Edit:
Brauch ich noch ein spezielles Compiler-Flag oder einen zusätzlichen 
Link-Run oder so etwas?

: Bearbeitet durch User
von Daniel A. (daniel-a)


Lesenswert?

Jay K. schrieb:
> Ich denke wirklich, es ist hier eine AVR-GCC Spezialität

Das ist keine Limitation des Compilers, sondern des Linkers. Ich glaube 
ich hatte mit const auch schon ähnliche Probleme.

Interessanter weise scheint das hier bei mir zu gehen:
1
#include <stdio.h>
2
3
int x __attribute__((section("testsec")));
4
int y __attribute__((section("testsec")));
5
6
extern char __start_testsec[];
7
extern char __stop_testsec[];
8
9
struct my_structure {
10
  void* start;
11
  void* end;
12
};
13
14
const struct my_structure testsec_info = {
15
  .start = __start_testsec,
16
  .end = __stop_testsec
17
};
18
19
int main(){
20
  printf("%p %p\n",testsec_info.start, testsec_info.end);
21
}

: Bearbeitet durch User
von Jay K. (deeplyembedded)


Lesenswert?

Hallo Daniel,

vielen Dank, damit läuft es jetzt bei mir auch durch!
Geholfen hat der void* als Typ und bei der extern Deklaration das uint8 
/ char Array.

extern uint8_t __CHECKSUM_START[];
const void* ptrStartAddr = __CHECKSUM_START;

von Dr. Sommer (Gast)


Lesenswert?

Daniel A. schrieb:
> Interessanter weise scheint das hier bei mir zu gehen:

Na sowas...

Eine andere Möglichkeit wäre, es folgendermaßen komplett übers 
Linkerscript zu machen:
1
.text : {
2
  LONG(__CHECKSUM_START)
3
  LONG(__CHECKSUM_END)
4
  . = ALIGN(4);
5
  __CHECKSUM_START = .;
6
  ...
7
  . = ALIGN(4);
8
  __CHKSUM_END = .;
9
}
Im C-Code braucht man gar nichts mehr zu schreiben. Wenn man die 
Adressen auslesen will kann man wie gehabt extern benutzen:
1
extern const uint32_t __CHECKSUM_START;
2
extern const uint32_t __CHKSUM_END;

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.