Stringmaster Flash schrieb:
> Ich beschäftige mich derzeit mit AVRs und und dem avr-gcc. Soweit
> funktioniert auch alles, ich frage mich jedoch wann es Sinn macht
> Strings im Flash abzulegen (so wie im Tutorial beschrieben).
Dazu wurde ja schon einiges geschrieben. Der Grund dafür, read-only
Daten (.rodata) im RAM abzulegen und nicht im Flash, ist, dass man bei
1 | char readc (const char *c)
|
2 | {
|
3 | return c;
|
4 | }
|
Nicht weiß, ob ausm RAM per LD oder ausm Flash per LPM gelesen werden
muss. readc kann nämlich auch für veränderliche Daten aufgerufen
werden. Das const char* sagt ja nur, dass diese Funktion *c nicht
ändert.
Manche neuere AVR-Derivate wie ATtiny40 (Reduced Tiny -mmcu=avrtiny) und
ATtiny1616 etc. (-mmcu=avrxmega3) haben einen linearen Adressraum, wo
das Flash im RAM-Adressbereich sichbar ist. Auf diesen Devices kann man
auf __flash und PROGMEM / PSTR etc. ohne Overhead verzichten.
1 | const int i = 2;
|
2 |
|
3 | __attribute((noinline,noclone))
|
4 | int readi (const int *pi)
|
5 | {
|
6 | return *pi;
|
7 | }
|
8 |
|
9 | int main (void)
|
10 | {
|
11 | return readi (&i);
|
12 | }
|
Zunächst für ein "normales" Device mit .rodata im RAM:
1 | $ avr-gcc foo.c -o foo.elf -mmcu=attiny25 -Os -save-temps -Wl,-Map,foo.map
|
2 | $ avr-objdump -d foo.elf
|
1 | Disassembly of section .text:
|
2 | ...
|
3 |
|
4 | 00000042 <readi>:
|
5 | 42: fc 01 movw r30, r24
|
6 | 44: 80 81 ld r24, Z
|
7 | 46: 91 81 ldd r25, Z+1
|
8 | 48: 08 95 ret
|
9 |
|
10 | 0000004a <main>:
|
11 | 4a: 80 e6 ldi r24, 0x60
|
12 | 4c: 90 e0 ldi r25, 0x00
|
13 | 4e: f9 cf rjmp .-14 ; 0x42 <readi>
|
i liegt also an Adresse 0x60, das ist die erste RAM-Adresse des
ATtiny25. Im Flash liegt i an Adresse 0x54 (direkt nach dem Code), und
der Startup-Code kopiert es an RAM-Adresse 0x60.
1 | .data 0x00800060 0x2 load address 0x00000054
|
2 | ...
|
3 | .rodata 0x00800060 0x2 foo.o
|
4 | 0x00800060 i
|
5 | ...
|
6 | 0x00000054 __data_load_start = LOADADDR (.data)
|
7 | 0x00000056 __data_load_end = (__data_load_start + SIZEOF (.data))
|
Das gleiche Programm compilert für einen ATtiny40:
1 | $ avr-gcc foo.c -o foo.elf -mmcu=attiny40 -Os -save-temps -Wl,-Map,foo.map
|
2 | $ avr-objdump -d foo.elf
|
1 | Disassembly of section .text:
|
2 | ...
|
3 |
|
4 | 00000040 <main>:
|
5 | 40: 8a e4 ldi r24, 0x4A
|
6 | 42: 90 e4 ldi r25, 0x40
|
7 | 44: f8 cf rjmp .-16 ; 0x36 <readi>
|
1 | .rodata 0x0000404a 0x2 load address 0x0000004a
|
2 | .rodata 0x0000404a 0x2 foo.o
|
3 | 0x0000404a i
|
4 | ...
|
5 | .data 0x00800040 0x0 load address 0x0000004c
|
6 | ...
|
7 | 0x0000004c __data_load_start = LOADADDR (.data)
|
8 | 0x0000004c __data_load_end = (__data_load_start + SIZEOF (.data))
|
Hier liegt i an Flash-Adresse 0x4a, was per RAM-Adresse 0x404a
zugegriffen wird. Das RAM beginnt bei 0x40, enthält hier aber keine
Daten. Wenn es welche hätte, würde es vom Startup-Code mit Flash-Daten
ab 0x4c initialisiert werden.