AVR-GCC Linker Symbol als Initializer verwenden

OP #5781232
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
#5781318
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?
Gast #5781328
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?
#5781338
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?!
OP #5781347
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?
#5781365
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
}
Gast #5784072
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;

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren