Forum: Compiler & IDEs AVR Flash jenseits der 64kB


von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

Hallo Allerseits,

es geht hier darum, Daten in einem AVR jenseits der 64kB Grenze im Flash 
zu platzieren und darauf zuzugreifen.

https://www.mikrocontroller.net/articles/Kategorie:AVR-GCC-Tutorial#Variablenzugriff_.3E64kB

Das geht so nicht. Mein Testprogramm (siehe Anhang) hat nur 704Bytes, 
nicht ~128kB. Die Parameter für die .far_section stehen unter custom 
options / Linker.

Wie geht's richtig? Wie kann man dem Compiler und Linker verclickern, 
daß die Daten so wie bei PROGMEM in der .far_section landen. Die 
Zugriffe über die _far Funktionen von pgmspace.h gibt es ja schon.

Mein Ziel ist es, das erstmal im old school AVR Studio und später im 
Atmel Studio zum laufen zu bringen, dann vielleicht sogar in der Arduino 
IDE. Ich fürchte aber, daß ich das allein nicht gebacken kriege, u.a. 
weil ich definitiv NICHT in die Untiefen der Linkerscripts absteigen 
kann und will. Das ist mir ne Nummer zu kryptisch.

Wer kann helfen? Wie geht es im Atmelstudio?

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

Hmm, hier mein Test mit Atmel Studio 6.2 (jaja, schon ein wenig 
angestaubt)

Wie es scheint, werden die Daten in der far_section zwar eingebunden, 
aber bei der Berechnung der Flash-Nutzung vergessen. Nicht schön, aber 
schonmal ein Fortschritt. Könnte es sein, daß das auch beim AVR-Studio 
passiert und die Daten doch im Hexfile landen? Gleich mal testen.

von Falk B. (falk)


Lesenswert?

Tatsächlich, auch im AVR-Studio landen die Daten der far_section im 
Flash, werden aber nicht bei der Berechnung der Flash-Ausnutzung 
einbezogen. Wie kann man das ändern?

Hier das Ausschnitt aus dem .map File
1
.far_section    0x00010000    0x1fd00
2
 .far_section   0x00010000    0x1fd00 test_256kB.o
3
                0x00027fff                dummy6
4
                0x00010000                dummy1
5
                0x0002fcff                dummy7
6
                0x00018001                dummy4
7
                0x00010001                dummy2
8
                0x00020000                dummy5
9
                0x00018000                dummy3

von Oliver S. (oliverso)


Lesenswert?

avr-size kurz etwas umschreiben sollte reichen. Die Sourcen sind 
auffindbar.

Oliver

von Falk B. (falk)


Lesenswert?

Oliver S. schrieb:
> avr-size kurz etwas umschreiben sollte reichen. Die Sourcen sind
> auffindbar.

Sehr witzig!

von Falk B. (falk)


Lesenswert?

Oliver S. schrieb:
> avr-size kurz etwas umschreiben sollte reichen. Die Sourcen sind
> auffindbar.

Außerdem, avr-size macht es anscheinend richtig, nur die nachfolgende 
Auswertung durch Atmel Studio geht schief.
1
"C:\Programme\Atmel\Atmel Toolchain\AVR8 GCC\Native\3.4.1061\avr8-gnu-toolchain\bin\avr-size.exe" "test_256k_AS6.elf"
2
       text     data      bss      dec      hex  filename
3
     130690        0        0   130690    1fe82  test_256k_AS6.elf
4
  Done executing task "RunCompilerTask".
5
  Task "RunOutputFileVerifyTask"
6
        Program Memory Usage   :  65156 bytes   24,9 % Full
7
        Data Memory Usage     :  0 bytes   0,0 % Full
8
  Done executing task "RunOutputFileVerifyTask".

Sieht nach einem internen Problem vom Atmel Studio aus. Da kommt man 
wahrscheinlich nicht ran. Naja, ist halt so.

: Bearbeitet durch User
von pittiplatsch (Gast)


Lesenswert?

> Das ist mir ne Nummer zu kryptisch.

MIPS Linkerscripte sind noch viel uebler!

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

Hmmm, wie es scheint, ist das in der Arduino-IDE leichter als gedacht! 
Es funktioniert!

Man muss nur 2 Zeilen in

C:\Programme\Arduino\hardware\arduino\avr\plattform.txt

anpassen. Die Arduino-IDE darf dabei NICHT laufen! Erst schließen, dann 
ändern und neu starten!
1
## Combine gc-sections, archives, and objects
2
 * recipe.c.combine.pattern= .... viele Parameter..... -Wl,--section-start=.far_section=0x10000

also ans Ende der Zeile
1
 -Wl,--section-start=.far_section=0x10000

anfügen. Damit wird dem Linker die Section mitgeteilt.
1
## Compute size
2
recipe.size.regex=^(?:\.text|\.data|\.bootloader|\.far_section)\s+([0-9]+).*


Hiermit wird die far_section in die Berechnung der Flash-Größe 
einbezogen! Und damit kann man den Flash nicht überladen! Ebenso kommt 
eine Fehlermeldung, wenn man >64kB PROGMEM + Programmcode compilieren 
will, weil der sich dann mit der far_section überlagert. Super! Genau so 
soll es sein!
Das kann man leicht selber prüfen, indem man die Arrays dummy6 sowie 
dummy_PGM_B mal ein bisschen größer macht. Mehr als 32767 Bytes sind 
beim avr gcc so oder so nicht möglich, das ist die Maximalgröße für ein 
Array (wegen der Indexberechung mit 16 Bit Integer).
Das Testprogramm macht nix sinnvolles außer die Konstanten im Flash 
anlegen und durch eine Zuweisung auf PORTA das Wegoptimieren verhindern.
Es wird auch gezeigt, wie man eine 32 Bit Variable als Adresse verwenden 
kann, um die Arrays zu lesen. Ein Zugriff über den Index ist hier NICHT 
möglich! Adressberechnungen müssen die Größe des Datentyps 
berücksichtigem, der 32 Bit Pointer ist immer ein Byte-Pointer!


Viel Spaß beim Ausschöpfen der 256kB des ArduinoMEGA!

P S Ja, der Zugriff auf die Daten >64kB ist natürlich sowohl was den 
Schreibaufwand im C-Code als auch real auf Assemblerebene angeht etwas 
mühsam und deutlich langsamer als unterhalb von 64kB. Ein Byte-Zugriff 
dauert mal fix 9 Takte, 4 zum Laden der 32 Bit Adresse (FAR_ADR() 
Makro), 5 zum Zugriff via ELPM (pgm_read_byte_far() Makro). Naja, aber 
besser als nix, denn ohne diese Funktionen kann man mit dem Flash >64kB 
für Daten nix anfangen!

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Weitere Möglichkeit sind die Address-Spaces __flash1 etc, die man 
genauso verwendne kann wie __flash.  Es sind 16-Bit Adressen, und für 
den Zugriff wird RAMPZ mit 1 geladen bzw. mit N für __flashN.

Das einzige, was zu beachne ist, ist dass das default Linker-Skript die 
entsprechenden Sections nicht lokatiert; das muss der Anwender machen je 
nachdem wie er es braucht.  Für __flash1 könnte das zum Beispiel so 
aussehen:
1
SECTIONS
2
{
3
  .flash1 :
4
  {
5
    . = MAX (ABSOLUTE(0x10000), .);
6
    PROVIDE (__flash1_start = .);
7
    . = ALIGN(2);
8
    *(.text.flash1.*)
9
    *(.progmem1.data*)
10
    PROVIDE (__flash1_end = .);
11
    ASSERT (__flash1_end <= 0x20000,
12
      "__flash1 data in .progmem1.data exceeds 0x20000");
13
  }
14
}
15
16
INSERT AFTER .text

Als Textdatei speichern und beim Linken mit -T <datei> als Ergänzung zum 
Linker-Skript angeben.

So wird dann auch die Verwaltung etwas einfacher, weil mit einem 
einzigen Makro Ablage und Zugriff auf einen anderen Address-Space 
umgestellt werden kann:
1
#ifdef __FLASH1
2
#define SPACE_A __flash1
3
#else
4
#define SPACE_A __flash

Wenn man nicht für jeden Space eigene Funktionen vorhalten will, dann 
kann man die Zugriffsfunktionen für __memx schreiben.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Johann L. schrieb:
> ASSERT (__flash1_end <= 0x20000,
>       "__flash1 data in .progmem1.data exceeds 0x20000");

Hmm, sind das 16 Bit Word oder Byte Adressen? Für 256kB müßte dort 
eigentlich 0x40000 stehen.

von Falk B. (falk)


Lesenswert?

Johann L. schrieb:
> Wenn man nicht für jeden Space eigene Funktionen vorhalten will,

Das würde ich nicht wollen, denn damit wird das Kuddelmuddel noch 
größer. Außerdem erlauben die Makros pgm_read_xxx_far() den Zugriff auf 
den vollen Adressraum, wenn gleich natürlich mit aufwändigerer 
Schreibweise.

> dann
> kann man die Zugriffsfunktionen für __memx schreiben.

Dazu braucht man aber wieder Inline-Assembler Makros. Richtig?
Gibt es da Ansätze, Beispiele?

von c-hater (Gast)


Lesenswert?

Falk B. schrieb:

> Dazu braucht man aber wieder Inline-Assembler Makros. Richtig?
> Gibt es da Ansätze, Beispiele?

In nacktem Assembler ist das aber absolut trivial. Ich stelle das 
Prinzip einfach mal im Vergleich zum Zugriff auf die ersten 64k dar.

;16Bit-Adresse, wahlfrei
ldi ZH,Byte2(Flashaddress)
ldi ZL,Byte1(Flashaddress)
lpm reg,Z

;16Bit-Adresse, sequenziell
ldi ZH,Byte2(Flashaddress)
ldi ZL,Byte1(Flashaddress)
lpm reg,Z+
lpm reg,Z+
lpm reg,Z+
...

;22Bit-Adresse, wahlfrei
ldi ZH,Byte3(Flashaddress)
out RAMPZ,ZH
ldi ZH,Byte2(Flashaddress)
ldi ZL,Byte1(Flashaddress)
elpm reg,Z

;22Bit-Adresse, sequenziell
ldi ZH,Byte3(Flashaddress)
out RAMPZ,ZH
ldi ZH,Byte2(Flashaddress)
ldi ZL,Byte1(Flashaddress)
elpm reg,Z+
elpm reg,Z+
elpm reg,Z+
...

Man kann das Zeug natürlich auch in Makros verpacken. Habe ich in 
Assembler auch getan. Meine Macros sehen so aus:

;->@0: address somewhere in flashspace
;<-[RAMPZ:]ZH:ZL: set to given address
.MACRO LEAPM
.IFDEF RAMPZ
 ldi ZH,Byte3(@0)
 out RAMPZ,ZH
.ENDIF
 ldi ZH,Byte2(@0)
 ldi ZL,Byte1(@0)
.ENDMACRO

;->@0: target register
;  @1: source (Z or Z+)
;<-target register set to flash content
.MACRO ULPM
.IFDEF RAMPZ
 elpm @0,@1
.ELSE
 lpm @0,@1
.ENDIF

Damit ist das Thema schon vollständig abgehandelt.

Der einzige Nachteil ist, wenn man nicht nachdenkt und auf Devices mit 
>64k für eine Adresse unterhalb von 64k das LEAPM-Macro benutzt, dann 
hat man zwei (meist) unnötige Extra-Ticks an der Backe. Das aber zum 
Glück nur beim Setup einer Adresse, danach sind dann beliebig viele 
sequentielle Zugriffe via ULPM ohne Verlust möglich, da elpm genau so 
viele Takte wie lpm benötigt.

Der Vorteil ist: die 64k-Grenze verschwindet als solche. Ein Array kann 
problemlos diese Grenze überschreiten, zumindest solange es halt bloß 
sequentiell gelesen wird.

von c-hater (Gast)


Lesenswert?

c-hater schrieb:

> Damit ist das Thema schon vollständig abgehandelt.

Nicht ganz, da fehlte noch ein .ENDMACRO. Hab' ich wohl beim Kopieren 
nicht mit erwischt.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Falk B. schrieb:
> Johann L. schrieb:
>> ASSERT (__flash1_end <= 0x20000,
>>       "__flash1 data in .progmem1.data exceeds 0x20000");
>
> Hmm, sind das 16 Bit Word oder Byte Adressen? Für 256kB müßte dort
> eigentlich 0x40000 stehen.

Byte-Adressen.  __flash1 reicht von 0x10000 bis 0x1ffff.

Du kannst also __flash1 bis __flash3 verwenden für 0x10000 bis 0x3ffff 
mit entsprechenden Lokatierungen im Linker-Skript.  Das braucht man aber 
eigentlich nur, wenn man händlisch auf die einzelnen Bänke verteilen 
will.

Falk B. schrieb:
> Johann L. schrieb:
>> dann kann man die Zugriffsfunktionen für __memx schreiben.
>
> Dazu braucht man aber wieder Inline-Assembler Makros. Richtig?

Nö, eigentlich nicht.  Außer du brauchst Äquivalente zu PSTR bzw. FSTR.

Die __flashN und __memx Adressen können alle via __memx zugegriffen 
werden, und __memx verdaut auch RAM-Adressen, ist allerdings aufwändiger 
mit seinen 3-Byte Adressen.  Eine Linkerskipt-Erweiterung braucht man 
mit __memx nicht; .progmemx.data ist in den Binutils abgehandelt.

Mit __memx kann man auch Objekte über Segmentgrenzen hinweg lesen.
1
#include <stdio.h>
2
3
void out (const __memx char *str)
4
{
5
    char c;
6
    while ((c = *str++))
7
        putchar (c);
8
}
9
10
const __flash char flash[] = "Flash 0";
11
const __flash1 char flash1[] = "Flash 1";
12
const __memx char memx[] = "MemX";
13
14
int main (void)
15
{
16
    out (memx);
17
    out (flash);
18
    out (flash1);
19
    out ("\n");
20
}

Bei gleichzeitiger Verwendung von __memx und __flashN muss man sich 
natürlich entscheiden, wie man .progmem1.data relativ zu .progmemx.data 
lokatiert; beim obigen Beispiel mit der Linkerskript-Ergänzung liegt 
.progmem1.data nach .text, also auch nach .progmemx.data.  Nicht so 
sinnvoll, und der Grund, warum .progmemN nicht im default Linkerskript 
behandelt wird und der Anwender das machen muss.

Wenn aber ohnehin alles über __memx zugegriffen wird, kann man auch 
gleich alles nach __memx lokatieren.  Die Zugriffe per __memx sind aber 
langsamer als bei bekanntem Address-Space, weil

1. es sich um 24-Bit Zeiger handelt

2. die Zugriffsfunktionen in der libgcc sind und

3. __memx auch RAM-Adressen verwurstet wie das "\n" oben.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Johann L. schrieb:
>> Dazu braucht man aber wieder Inline-Assembler Makros. Richtig?
>
> Nö, eigentlich nicht.  Außer du brauchst Äquivalente zu PSTR bzw. FSTR.

Falsch gedenkt: Auch für Äquivalente zu PSTR / FSTR braucht man 
natürlich kein Inline-Asm.

von Falk B. (falk)


Lesenswert?

Johann L. schrieb:
> Wenn aber ohnehin alles über __memx zugegriffen wird, kann man auch
> gleich alles nach __memx lokatieren.

Danke für die Hinweise, vor allem mit dem Linkerscript. Aber ich werde 
eher nicht __memx umsetzen. Ersten gibt es noch gar keine Anwendung 
dafür und 2. ist es eher Overkill. Der Lesezugriff per pgm_read_xx_far() 
reicht mir.

Es gibt aber noch ein paar Problemchen.

1.) Die Berechnung des belegten Flash-Speichers ist zwar richtig, aber 
nur netto! Sprich, meine far_section ab 0x10000 kann max. 192kB 
aufnehmen. Außerdem muss man noch ~10kB für den Bootloader abziehen, der 
am Ende vom Flash liegt. Wenn ich nun 200kB in far_section an Daten 
platziere, meldet die Berechnung vom Arduino weniger als 256kB Daten im 
Flash, was netto auch stimmt. Aber die Lücke zwischen .text section ab 
0x0000 und far_section ab 0x10000 muss man je beim Brutto einrechnen. 
Spätestes beim Programmiervorgang meckert avrdude, daß Daten oberhalb 
von 0x40000 geschrieben werden sollen. Wenn es nur knapp darunter ist, 
zerschießt man sich den Bootloader 8-0

Frage: Wie kriegt man die richtige Bruttorechnung in die Arduino-IDE? 
Ich würde meinen, man muss die far_section wie von Johann gezeigt 
platzieren und die Obergrenze auf 256-10kB festlegen.

2.) Problem ist, daß AVR-Dude anscheinend ein Problem mit HEX-Files mit 
>64kB hat. Denn das Programmieren des Hex-Files mit nahezu vollem Flash 
geht schief, oberhalb 64kB ist im AVR alles leer! Im Hexfile stehen aber 
die richtigen Daten! Wenn man mittels Atmelstudio und Atmel-ICE 
programmiert landen die auch im AVR. Was klemmt da? Falsche 
Konfigurationsdaten für avr-dude? Hat avr-dude ein Problem mit der 
Segmentadresse im Intel-HEX?

von Falk B. (falk)


Lesenswert?

Oder liegt das am Arduino-Bootloader?

https://www.nongnu.org/avrdude/user-manual/avrdude_4.html

(**) Flash addressing above 128 KB is not supported by all programming 
hardware. Known to work are jtag2, stk500v2, and bit-bang programmers.

Aber ich meine, der Arduino-Bootloader basiert doch auf STK500V2, denn 
die Datei dafür heißt ja stk500boot_v2_mega2560.hex

von Falk B. (falk)


Lesenswert?

Hmm, gerade mal probiert, mit -cstk500V2 oder -cstk500v1 geht nix, nur 
mit -cwiring

Liegt dort vielleicht das Problem?

von Joachim B. (jar)


Lesenswert?

am Atmel Studio 4.18 habe ich mit dem 2560 mal Bilder abgelegt
https://display3000.com/shop/mikrocontrollerloesungen/uc-mit-15-tft/d062x-mikrocontroller-atmega-tft-farbdisplay-15.html

war irgendwie Krampf, habe dort Bilder abgelegt für eine Auto Diashow, 
habe das dann nicht mehr untersucht weil mir der ATmega1284p dann doch 
besser gefällt mit doppelt SRAM, ich brauchte nie über 128K flash, mehr 
SRAM hilft mehr!
8K m2560
16K m1284p

von Falk B. (falk)


Lesenswert?

Hmm, ich hab mal den Bootloader angeschaut,, da findet man sowas hier.
1
        case CMD_LOAD_ADDRESS:
2
  #if defined(RAMPZ)
3
          address = ( ((address_t)(msgBuffer[1])<<24)|((address_t)(msgBuffer[2])<<16)|((address_t)(msgBuffer[3])<<8)|(msgBuffer[4]) )<<1;
4
  #else
5
          address = ( ((msgBuffer[3])<<8)|(msgBuffer[4]) )<<1;    //convert word to byte address
6
  #endif

Das heißt wohl, daß >64kB unterstützt werden, dazu gibt es auch an 
mehreren Stellen Kommentare. Außerdem ist der Support für den Mega2560 
seit 2010 drin 8-0

Wo klemmt es dann?

von Peter D. (peda)


Lesenswert?

c-hater schrieb:
> In nacktem Assembler ist das aber absolut trivial.

Was nützen mir die dollsten Assemblermacros, wenn ich die Daten nicht 
bequem und lesbar mit Structs aus Strings, Funktionspointern, 64bit, 
float usw. vorbelegen kann.

von Joachim B. (jar)


Lesenswert?

Falk B. schrieb:
> Wo klemmt es dann?

wenn du mich meinst, ich habs vergessen weil es ewig her ist wo ich 
Bilder im m2560 flash ablegte, irgendwie ging es, oder doch nur in den 
ersten 64k, wie gesagt vergessen, ist aber auch Schnee von gestern, 
witzig dabei meine ersten Erfahrungen mit einer WS2812B LIB die auf dem 
m1284p im Timing um 10% langsamer war als mit dem m328p, das sollte auch 
auf dem erweiterten Adressbit/byte zurückzuführen sein, so ganz klären 
konnte ich das nie, habe aber auch nicht mehr spätere Versionen probiert 
weil mein eigener Patch für mich funktioniert.

von Falk B. (falk)


Lesenswert?

Joachim B. schrieb:
> Falk B. schrieb:
>> Wo klemmt es dann?
>
> wenn du mich meinst,

Nö, ich fragte allgemein wo der Download >64kB beim ATmega 2560 über 
avrdude und wiring Protokoll klemmt.

von c-hater (Gast)


Lesenswert?

Peter D. schrieb:

> Was nützen mir die dollsten Assemblermacros, wenn ich die Daten nicht
> bequem und lesbar mit Structs aus Strings, Funktionspointern, 64bit,
> float usw. vorbelegen kann.

Kann man doch. Auch in Assembler. Wenn man es kann. Und wenn man es 
kann, kann man es auch problemlos lesen.

Ist halt so, wie in jeder anderen Sprache auch...

von Veit D. (devil-elec)


Lesenswert?

Hallo,

vielleicht hilft das hier weiter. Antworten von jurs und Serenifly 
beachten.
https://forum.arduino.cc/index.php?topic=264039.0
https://forum.arduino.cc/index.php?topic=174084.msg1294539#msg1294539

von Falk B. (falk)


Lesenswert?

Veit D. schrieb:
> vielleicht hilft das hier weiter.

Nein, tut es leider nicht. Die Beiträge sind recht alt. Das Grundproblem 
ist schon gelöst, der Compiler erzeugt korrekten Code. Es bleibt noch 
das Problem, daß avrdude das KORREKTE HEX-File nicht korrekt per 
Bootloader auf den ArduinoMEGA schreibt. Per ATMEL-ICE und ISP geht es.

von Oliver S. (oliverso)


Lesenswert?

Falk B. schrieb:
> ist schon gelöst, der Compiler erzeugt korrekten Code. Es bleibt noch
> das Problem, daß avrdude das KORREKTE HEX-File nicht korrekt per
> Bootloader auf den ArduinoMEGA schreibt.

Da ich meinen Arduino Mega eh gerade am Rechner hängen hatte, ein kurzer 
Versuch im Atmel Studio:
1
start:
2
  ldi  R30, 00
3
  ldi  R31, 0xB8
4
  ldi  R26, 0x1
5
  out EIND, R26
6
  EIJMP
7
8
.ORG 0x1B800-1
9
loop:
10
  rjmp loop
11
12
led:
13
  ldi r16, (1<<PB7)
14
  out PORTB, r16
15
  out DDRB, r16
16
end:
17
  rjmp end

avrdude -pm2560 -cwiring -Pcom8 -F -D ...

Die LED leuchtet.

Oliver

von jo mei (Gast)


Lesenswert?

Oliver S. schrieb:
> Die LED leuchtet.

Die leuchtet auch wenn gar kein Code drin ist. Die LED wird
von einem OP gespeist der an PB7 hängt. Wenn PB7 floatet
hängt der OP irgenwo zwischen 0 und 5V. Das reicht damit
die LED leuchtet.

RTFS (Read the fucking schematic)

LED blinken lassen wäre mindestens angesagt.

von Oliver S. (oliverso)



Lesenswert?

jo mei schrieb:
> Die leuchtet auch wenn gar kein Code drin ist. Die LED wird
> von einem OP gespeist der an PB7 hängt.

Dann hast du einen anderen Mega als der Rest der Welt. Beim Original 
(und auch bei meiner Kopie) hängt die LED direkt an Port7, über 
Widerstand gegen Masse. Da leuchtet ohne Ansteuerung des Ports gar nix.

> RTFS (Read the fucking schematic)

So isses.

Oliver

von jo mei (Gast)


Angehängte Dateien:

Lesenswert?

Oliver S. schrieb:
> Dann hast du einen anderen Mega als der Rest der Welt.

Ich denke viele Leute haben einen anderen als du.

Wird schon seinen Grund haben dass man die LED gepuffert hat.
Leider keine Version im Schematic verfügbar.

YMMV

von Oliver S. (oliverso)


Lesenswert?

Ich hab jetzt mal meine Lupe rausgekramt, und meine Mega-Kopie ist doch 
tatsächlich auch ein R3.

UNd ja, die LED leuchtet da tatsächlich auch ohne Prgramm.
Und nein, avrdude lädt das oben gezeigte Programm tatsächlich nicht 
richtig. Den Verification-Error hatte ich schlicht übersehen.

Da ich aber ganz sicher war, daß ich den Mega mit avrdude mit einem 
ähnlichen Programm schonmal laufen hatte, hab ich in meinen alten 
Projekten gekramt. Ergebnis: Das hatte ich mit der gcc-toolchain gebaut 
(gelinkt mit -nostartfiles  -nodefaultlibs  -nostdlib). Die erzeugt ein 
hex-file, welches die ganzen 256kB des Speicher enthält, und das lädt 
avrdude fehlerfrei hoch. (dauert halt etwas länger).

Das hex-file aus dem Studio dagegen ist nur ein paar Bytes groß, und 
enthält nur die tasächlich Code enthaltenen Adressen.

Das wäre mal einen avrdude bug-report wert.

Oliver

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Oliver S. schrieb:
> Das hex-file aus dem Studio dagegen ist nur ein paar Bytes groß, und
> enthält nur die tasächlich Code enthaltenen Adressen.

Hmm, beim Upload sieht man an dem Fortschrittsbalken, wie der bei 1/3 
mal kurz springt. Das wäre bei MEINEM HEX-File OK, denn das hat ca. 20kB 
Lücke unterhalb 64kB.

Ok, ich werde heute abend mal das rückgelesene HEX-File mit avrdude 
brennen, das ist vollständig.

von Falk B. (falk)


Lesenswert?

Oliver S. schrieb:
> Das hex-file aus dem Studio dagegen ist nur ein paar Bytes groß, und
> enthält nur die tasächlich Code enthaltenen Adressen.

So, ich hab es jetzt mal getestet. Es ist so, wie du es beschrieben 
hast.
Das originale Hex-File aus dem avr gcc enthält die korrekten Daten, aber 
eben auch nur die, da ist eine Lücke. Per Atmel-ICE kann man das brennen 
und es funktioniert auch so, wie es soll. das gleiche Hex-File per 
avrdude funktioniert nicht, Oberhalb 64kB fehlen die Daten. Wenn man 
aber ein korrekt programmiertes File aus dem Flash zurück liest, kann 
man das per avrdude korrekt brennen. Hmmm.
>
> Das wäre mal einen avrdude bug-report wert.

Wo kann man das tun? Wird das noch bearbeitet? Gibt es da jemanden, der 
die Software pflegt?

von Veit D. (devil-elec)


Lesenswert?

Oliver S. schrieb:
> Dann hast du einen anderen Mega als der Rest der Welt. Beim Original
> (und auch bei meiner Kopie) hängt die LED direkt an Port7, über
> Widerstand gegen Masse.
> Oliver

Hallo,

da muss ich Einspruch erheben. Beim Original ist immer ein OPV 
dazwischen. Dein Schaltplan wird nicht vom Originalen sein. Hole dir 
nochmal einen frischen Schaltplan.

von Veit D. (devil-elec)


Lesenswert?

@ Falk,

welchen Programmer verwendest du wenn du mit avrdude flashst?
Mit welchen Tool flashst du wenn du mit Atmel ICE flashst?

Kann mich dunkel an einen älteren Thread erinnern mit ähnlichen Problem, 
da lag es Programmer, war aber kein Atmel Ice sondern ein mkII Nachbau. 
Da musste die Firmware aktualisiert werden.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Veit D. schrieb:
> Dein Schaltplan wird nicht vom Originalen sein. Hole dir
> nochmal einen frischen Schaltplan.

Offizieller als das hier gehts eigentlich nicht:

https://www.arduino.cc/en/uploads/Main/arduino-mega2560-schematic.pdf

Ist halt die Urversion, inzwischen ist R3 aktuell.

Oliver

von Falk B. (falk)


Lesenswert?

Veit D. schrieb:
> @ Falk,
>
> welchen Programmer verwendest du wenn du mit avrdude flashst?

mit dem Arduino bootloader per virtuellem COM-Port.

> Mit welchen Tool flashst du wenn du mit Atmel ICE flashst?

Atmelstudio 6.2

> Kann mich dunkel an einen älteren Thread erinnern mit ähnlichen Problem,
> da lag es Programmer, war aber kein Atmel Ice sondern ein mkII Nachbau.
> Da musste die Firmware aktualisiert werden.

Nein.
Das Atmel-ICE macht alles richtig. Das Problem liegt bei avrdude. Ist 
das so unverständlich in den Beiträgen beschrieben?

von Veit D. (devil-elec)


Lesenswert?

@ Oliver:
Will ja nichts sagen, aber der R3 ist schon seit Jahren aktuell, da kann 
man nicht mit einem uralten Schaltplan um die Ecke kommen. Da kann der 
noch so original sein.   :-)  :-)  :-)   Deswegen solltest du dir ja 
einen frischen Schaltplan runterladen.

@ Falk:
avrdude habe ich verstanden. Konnte mir nur keinen Zusammenhang bilden 
mit deinen Testmethoden. Jetzt ist alles klar.

avrdude wird doch von Jörg W. betreut?

Edit:
Doofe Frage. Nimmt Atmel Studio nicht auch avrdude zum flashen?

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Veit D. schrieb:
> Will ja nichts sagen, aber der R3 ist schon seit Jahren aktuell, da kann
> man nicht mit einem uralten Schaltplan um die Ecke kommen. Da kann der
> noch so original sein. Ä

Sag das mal google...

Veit D. schrieb:
> Doofe Frage. Nimmt Atmel Studio nicht auch avrdude zum flashen?

Freiwillig nicht ;)

Oliver

von jo mei (Gast)


Lesenswert?

Oliver S. schrieb:
> Offizieller als das hier gehts eigentlich nicht:
>
> https://www.arduino.cc/en/uploads/Main/arduino-mega2560-schematic.pdf

Besonders zuverlässig scheint das nicht gepflegt zu werden.

Im Arduino Shop gibt es einen Link auf einen neuen Schaltplan.

https://content.arduino.cc/assets/MEGA2560_Rev3e_sch.pdf

von Falk B. (falk)


Lesenswert?

jo mei schrieb:
>> https://www.arduino.cc/en/uploads/Main/arduino-mega2560-schematic.pdf
>
> Besonders zuverlässig scheint das nicht gepflegt zu werden.

Naja, wenn man sich den Schaltplan und auch die Eagle-Files (Layout) mal 
so anschaut, da wundert es mich eher, daß der Kram in den Stückzahlen 
überhaupt halbwegs läuft . . . .

von Veit D. (devil-elec)


Lesenswert?

Hallo,

ich sehe das anders. Arduino stellt zu jedem Board alle Dokus zur 
Verfügung. Auch zu denen die nicht mehr im Handel sind. Deswegen findet 
man auch Schaltpläne zu älteren Boardversionen. Ich gehe immer auf die 
aktuelle Produktseite, da gibts im Falle vom Mega2560 nur den R3, dann 
dort zur Doku und man hat aktuelle Dateien zu dem Teil.
Seht es mal so. Sucht nach "VW Golf" und ihr werdet auch nicht direkt 
zum aktuellen Modell verwiesen.  :-)

Das es funktioniert beweist aber auch, dass man nicht alles so 
haarspalterisch betrachten muss wie es hier im Forum manchmal ausartet - 
für die reine Funktion. Es sind schließlich keine! Industrieboards. Du 
verwendest sie ja auch. Also können sie nicht so schlecht sein ...  ;-) 
:-)

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Johann L. schrieb:
> Für __flash1 könnte das zum Beispiel so
> aussehen:

Moin,

ich versuche gerade, die Section mittels dieser extra Datei zu 
definieren. Es klemmt aber noch. Hier meine Version, angepaßt auf die 
far_section. Diese soll bis zu 256kB aufnehmen und nach allen anderen 
sektionen liegen.
1
SECTIONS
2
3
{
4
5
  .far_section :
6
7
  {
8
9
    . = MAX (ABSOLUTE(0x10000), .);
10
11
    PROVIDE (__far_section_start = .);
12
13
    . = ALIGN(2);
14
15
    *(.text.far_section.*)
16
17
    *(.progmem1.data*)
18
19
    PROVIDE (__far_section_end = .);
20
21
    ASSERT (__far_section_end <= 0x30000,
22
23
      "__far_section data in .progmem1.data exceeds 0x30000");
24
25
  }
26
27
}
28
29
INSERT AFTER .text

Was bedeutet

= MAX (ABSOLUTE(0x10000), .);

Ist das eine feste Startadresse oder maximal Länge? Ich glaube erstes.
Wie kann man erreichen, daß diese section unmittelbar nach allen anderen 
sections platziert wird? Ich dachte, INSERT AFTER .text macht das. Ist 
da so?

von Falk B. (falk)


Lesenswert?

Warum fängt meine far_section exakt bei 0x10000 an? Ich hab das doch gar 
nicht angegeben. Ich teste jettz mit der extra Section im Linkerscript, 
nicht mit der festen Adresse 0x10000.

Auzug aus dem .map File

00010000 l    d  .far_section  00000000 .far_section
000277c6 l     O .far_section  00007d42 fire_1
0001fa84 l     O .far_section  00007d42 fire_2
00017d42 l     O .far_section  00007d42 fire_3
00010000 l     O .far_section  00007d42 fire_4

Gibt es in den Linkerscripts eine Einstellung, welche den Platz bis 
0xFFFF reserviert?

von Falk B. (falk)


Lesenswert?

Hmm, irgendwie hat sich der Compiler jetzt die Definition der 
far_section bei 0x10000 gemerkt. Denn wenn ich den Zusatz beim Linker 
wieder entferne, läuft die Compilierung auch vollständig durch, obwohl 
die großen Datenobjekte in der far_section landen sollen, die der 
Compiler aber gar nicht kennt!
Also, wo hat sich diese Info eingenistet?

von jo mei (Gast)


Lesenswert?

Falk B. schrieb:
> Also, wo hat sich diese Info eingenistet?

Ich weiss es auch nicht, aber ich freue mich wie du dich abmühst,
nicht weil ich Schadenfreude übe sondern hoffe dass du uns irgend-
wann eine Lösung präsentierst die wir auch nutzen dürfen/können.

Mich würde dann später auch experimentell interessieren ab
welcher (alter) Compilerversion das Ganze funktioniert ....

Danke (ausdrücklich) für's Kopf zerbrechen.

von Falk B. (falk)


Lesenswert?

OK, mein Fehler, da hatte ich wohl die section noch in eine andere Zeile 
mit Linker-Flags kopiert. Oder war es die Arduino-IDE? Egal.
Jedenfalls, es geht jetzt! Und zwar deutlich einfacher als gedacht! Man 
muss dem Linker gar keine Anweisung geben, wo die far_section hin soll. 
Er fügt die automatisch ans Ende der bestehenden sections an! Genau das 
wollte ich ja, damit gibt es keine Lücke im Flash und auch der Upload 
per avrdude geht jetzt! Es kann so einfach sein!

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

So, ich denke jetzt hab ich es wirklich. Hier nochmal alles 
zusammengefaßt.
Wenn man Daten im Flash >64kB ablegen und nutzen will, geht das so. 
Siehe Anhang. Außerdem muss man nur 1 Zeile in

C:\Programme\Arduino\hardware\arduino\avr\plattform.txt

anpassen. Die Arduino-IDE darf dabei NICHT laufen! Erst schließen, dann
ändern und neu starten!

## Compute size
recipe.size.regex=^(?:\.text|\.data|\.bootloader|\.far_section)\s+([0-9] 
+).*

Hiermit wird die far_section in die Berechnung der Flash-Größe
einbezogen und man kann den Flash nicht überladen! Das kann man leicht 
selber prüfen, indem man die Arrays dummy6 sowie dummy_PGM_B mal ein 
bisschen größer macht. Mehr als 32767 Bytes sind beim avr gcc so oder so 
nicht möglich, das ist die Maximalgröße für ein Array (wegen der 
Indexberechung mit 16 Bit Integer). Das Testprogramm macht nix 
sinnvolles außer die Konstanten im Flash anlegen und durch eine 
Zuweisung auf PORTA das Wegoptimieren verhindern. Es wird auch gezeigt, 
wie man eine 32 Bit Variable als Adresse verwenden kann, um die Arrays 
zu lesen. Ein Zugriff über den Index ist hier NICHT möglich! 
Adressberechnungen müssen die Größe des Datentyps berücksichtigem, der 
32 Bit Pointer ist immer ein Byte-Pointer!

Viel Spaß beim Ausschöpfen der 256kB des ArduinoMEGA!

P S Ja, der Zugriff auf die Daten >64kB ist natürlich sowohl was den
Schreibaufwand im C-Code als auch real auf Assemblerebene angeht etwas
mühsam und deutlich langsamer als unterhalb von 64kB. Ein Byte-Zugriff
dauert mal fix 9 Takte, 4 zum Laden der 32 Bit Adresse (FAR_ADR()
Makro), 5 zum Zugriff via ELPM (pgm_read_byte_far() Makro). Naja, aber
besser als nix, denn ohne diese Funktionen kann man mit dem Flash >64kB
für Daten nix anfangen!

P S Die far_section muss man dem Compiler bzw. Linker nicht mitteilen, 
der packt die automatisch ans Ende aller Sections. genau dort hin, wo 
sie hingehört, ohne die bestehende Ordnung zu stören.

von jo mei (Gast)


Lesenswert?

Danke sehr, werde ich bei Gelegenheit ausprobieren.

Falk B. schrieb:
> Die Arduino-IDE darf dabei NICHT laufen! Erst schließen, dann
> ändern und neu starten!

Wie gut dass ich so gut wie nie diese Krücke verwende, für
solche Spezialitäten dann sowieso nicht. Möchte ja irgendwas
Sinnvolles tun bei der sich die Krücke mir nicht in den Weg
stellt.

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

So sieht mein Test der 256kB aus. 7 Bilder a 160x100 in 16 Bit 
Farbtiefe, direkt aus dem Flash auf das LCD, dauert aber immer noch 
150ms/Bild 8-0

von Falk B. (falk)


Lesenswert?

Hier für die libc 1.6.7, da sind die _far() Zugriffe schon drin, aber 
das Macro fehlt. Vermutlich auch schon in älteren Versionen.
1
#define pgm_get_far_address(var)                      \
2
({                                                    \
3
    uint_farptr_t tmp;                                \
4
                                                      \
5
    __asm__ __volatile__(                             \
6
                                                      \
7
            "ldi    %A0, lo8(%1)"           "\n\t"    \
8
            "ldi    %B0, hi8(%1)"           "\n\t"    \
9
            "ldi    %C0, hh8(%1)"           "\n\t"    \
10
            "clr    %D0"                    "\n\t"    \
11
        :                                             \
12
            "=d" (tmp)                                \
13
        :                                             \
14
            "p"  (&(var))                             \
15
    );                                                \
16
    tmp;                                              \
17
})

von Veit D. (devil-elec)


Lesenswert?

Hallo Falk,

Glückwunsch auch von mir. Wo darf ich den Fleißbienchenstempel 
reindrücken?  :-)

Noch ein Tipp am Rande. Lege dir dort wo die platform.txt liegt noch 
eine platform.local.txt an. Dort rein schreibste deine Spezialzeile. In 
der platform.txt nimmste Zeile wieder raus. Änderungen in der 
platform.local.txt werden ohne schließen/öffnen der IDE übernommen.

: Bearbeitet durch User
von Thomas B. (ewi)


Lesenswert?

Zufälligerweise stand ich gerade auch vor dem Problem, bei einem 
AT90CAN128 Daten in den Bereich im Flash > 64kB abzulegen. Da ich 
bereits für die unteren 64kB den __flash Qualifier bei der Definition 
von Konstanten verwende, damit beim Zugriff keine pgm-Makros benötigt 
werden, stand die Lösung mit pgm_far-Makros nicht zur Debatte.

Mit der Definition von
1
const uint8_t flash1tab[32767] __attribute__((__section__(".flash1tab"))) = { ... };
hab ich das für avr-gcc größtmögliche Datenarray angelegt. Die 
Startadresse gibt man dem Compiler z.B. über
1
LDFLAGS += -Wl,--section-start=.flash1tab=0x18000
mit, der das dann an den Linker weiterreicht. Hier im Beispiel liegt das 
Array dann ab 96kB im Flash. Es kommt auch eine Fehlermeldung, wenn es 
mit anderen Sections überlappt.

Am besten platziert man das ganz ans Ende oder, falls es einen 
Bootloader gibt, vor den Bootloader. Dann können die .text und .data 
Sections weiter wachsen, ohne dass es sofort zu Überlappungen kommt. Man 
muss nur beachten, dass bei der Definition des Arrays kein __flash1 
Qualifier verwendet wird. Erst beim Zugriff auf die Daten kann ein 16bit 
__flash1 Pointer verwendet werden. Die im Vergleich dazu langsameren und 
etwas mehr Flash belegenden pgm_far-Makros funktionieren auch. __memx 
Pointer funktionieren bei dieser Variante nicht.

Das mit dem weiter oben im Thread von Johann angegebene zusätzliche 
Linker Script hat mich aber interessiert, so dass ich das ebenfalls 
ausprobiert habe. Um es vorweg zunehmen, wer sich da nicht extrem gut 
auskennt, sollte die Finger davon lassen, wenn man nicht die letzten 
Haare verlieren will ;-P

Aufgabenstellung:
Füge eine Section .flash1 hinter .text und vor .data ein.
Zusätzliche Bedingungen:
Startadresse von .flash1 muss >= 0x10000 sein.
Endadresse von .flash1 muss < 0x20000 sein.

Nach vielen Versuchen habe ich zwei Linker Script Varianten gefunden, 
die zumindest für meine Fälle und dem AT90CAN128 funktionieren. Hier 
zuerst die in einer Datei flash1section.ld abgespeicherte Variante auf 
Basis von Johanns Script, die man dem Compiler über
1
LDFLAGS += -Wl,-Tflash1section.ld
mitgibt, der die -T Option dann an den Linker weiterreicht.
1
SECTIONS
2
{
3
  .flash1 :
4
  {
5
    . = MAX (0x10000, ABSOLUTE(.));
6
7
    PROVIDE (__flash1_start = .);
8
9
    . = ALIGN(2);
10
11
    *(.flash1.text*)
12
    *(.progmem1.data*)
13
14
    PROVIDE (__flash1_end = .);
15
16
    ASSERT (ABSOLUTE(__flash1_start) >= 0x10000,
17
      "__flash1 data in .progmem1.data starts below 0x10000");
18
19
    ASSERT (ABSOLUTE(__flash1_end) < 0x20000,
20
      "__flash1 data in .progmem1.data exceeds 0x20000");
21
  }
22
}
23
INSERT AFTER .text;
Dieses Script setzt den .flash1 Section relativen Location Counter "." 
auf die Adresse 0x10000, falls der absolute Location Counter nach der 
.text Section < 0x10000 ist. Sonst wird der Location Counter beibehalten 
und die .flash1 Section fängt dann eben erst entsprechend mehr oder 
weniger weit hinter 0x10000 an. Als Ergebnis erhält man eine .flash 
Section, die nahtlos an .text anschließt. Falls der absolute Location 
Counter nach der .text Section allerdings < 0x10000 ist, gibt es am 
Anfang der .flash1 Section eine Lücke, die mit 0x00 gefüllt wird, bevor 
ab 0x10000 tatsächliche Daten folgen. Das sieht man auch schön im 
generierten Hexfile, das diese 0x00 bis 0x10000 enthält. Wer mit anderen 
Werten füllen will z.B. 0xFF oder auch längeren Mustern, kann dazu am 
Anfang der Section .flash1 den FILL(0xFF); Befehl einfügen.

Der erste Fallstrick war hier der Location Counter ".". Innerhalb einer 
Section ist der Location Counter Section relativ, fängt also immer bei 0 
an. Deshalb wurde die ursprüngliche Zeile ". = MAX (0x10000, .);" immer 
zu ". = MAX (0x10000, 0);" und das zu ". = 0x10000", was Falk ja weiter 
oben schon festgestellt hat.

Ein weiterer Fallstrick sind die ASSERTs im zusätzlichen LD Script. Auf 
Variablen, die in der Output Section definiert wurden, kann im ASSERT 
nicht zugegriffen werden, außer die Variablen enthalten nur den Location 
Counter ".". Und selbst wenn die Variable nur den Location Counter 
enthält, ist das dann der Section relative Location Counter. Deshalb 
muss da noch ein ABSOLUTE(variable) um den jeweiligen Variablennamen, 
damit da das tatsächlich Gewünschte geprüft wird.

Meine zweite Variante des zusätzlichen LD Scripts sieht so aus:
1
SECTIONS
2
{
3
  . = MAX (0x10000, .);
4
5
  .flash1 . :
6
  {
7
    PROVIDE (__flash1_start = .);
8
9
    . = ALIGN(2);
10
11
    *(.flash1.text*)
12
    *(.progmem1.data*)
13
14
    PROVIDE (__flash1_end = .);
15
16
    ASSERT (ABSOLUTE(__flash1_start) >= 0x10000,
17
      "__flash1 data in .progmem1.data starts below 0x10000");
18
19
    ASSERT (ABSOLUTE(__flash1_end) < 0x20000,
20
      "__flash1 data in .progmem1.data exceeds 0x20000");
21
  } > text
22
}
23
INSERT AFTER .text;
Hier wird der Location Counter außerhalb der Section gesetzt. Dort ist 
der Location Counter absolut. Das hat aber Nebenwirkungen, die 
zusätzliche Script Änderungen nötig machen. Das Setzen des Location 
Counters außerhalb der Section hat laut Mapfile keine Auswirkungen auf 
die tatsächliche Startadresse von .flash1. Die Section wird immer noch 
direkt hinter .text platziert, auch wenn das Ende von .text < 0x10000 
ist. Abhilfe schafft die explizite Angabe der VMA (Virtual Memory 
Address, das ist die virtuelle Adresse zur Laufzeit des Programms) in 
Abhängigkeit vom Location Counter vor dem ":" in der Zeile ".flash1 . 
:". Wenn man hinter dem ":" keine LMA (Load Memory Address, das ist die 
physikalische Adresse) angibt, wird LMA automatisch auf VMA gesetzt. Man 
könnte das auch explizit angeben ".flash1 . : AT (ADDR (.flash1) )".
Wenn jetzt das Ende von .text < 0x10000 ist, fängt .flash1 wie gewünscht 
bei 0x10000 an. Aber es gibt dazwischen eine Lücke, in die der Linker 
.data platziert. Wenn die Lücke kleiner ist als die Größe der .data 
Section, dann überlappt das mit der .flash1 Section und beim Linken 
kommt eine entsprechende Fehlermeldung: "section .data overlaps section 
.flash1".
Der Grund liegt im default LD Script vergraben. Das kann man sich, ohne 
es im Filesystem zu suchen, vom Linker anzeigen lassen, wenn man die 
"LDFLAGS += -Wl,--verbose" erweitert. Da gibt es am Ende der Deklaration 
der .data Output Section die Zeile "} data AT> text". Das bedeutet, 
weise die .data Section der im default LD Script deklarierten Memory 
Region "data" zu und setze die LMA von .data auf die nächste freie 
Adresse nach der Memory Region "text". Und wenn dann eine Lücke zwischen 
.text und .flash1 ist, startet .data am Ende von .text und leider nicht 
erst am Ende von .flash1.
Das kann man mit der Angabe von "} > text" am Ende der Deklaration der 
Ouput Section .flash1 verhindern. Damit wird .flash1 der Memory Region 
text zugewiesen und das Ende von text liegt dann immer hinter .flash1. 
Leider führt das wieder zu neuen Komplikationen. Beim Linken kommen zwei 
Warnungen:
1. Beim Lesen des zusätzlichen LD Scripts kommt: warning: memory region 
'text' not declared.
2. Beim Lesen des default LD Scripts kommt: warning: redeclaration of 
memory region 'text'.

Der Grund ist, dass das zusätzliche LD Script zuerst gelesen und 
bearbeitet wird. Aber zu dem Zeitpunkt sind die Memory Regions noch 
nicht deklariert worden. Das geschieht erst am Anfang vom default LD 
Script. Die erste Warnung kann man umgehen, wenn man die Memory Region 
"text" im zusätzlichen LD Script definiert. Dann kommt aber immer noch 
die zweite.
Trotz der ein oder zwei Warnungen kommt zumindest bei mir das Gewünschte 
heraus. Die .data Output Section liegt immer hinter .flash1, auch wenn 
es eine Lücke zwischen .text und .flash1 gibt, wenn die unteren 64kB 
Flash noch nicht ausgereizt sind. Wer also diese Variante lieber mag, 
sollte besser das default LD Script kopieren und die Änderung in der 
Kopie eintragen. Die Zeile "INSERT AFTER .text" muss man dann natürlich 
weglassen, damit das zusätzliche LD Script, das default LD Script 
komplett ersetzt.

Der Unterschied zwischen den oben angegebenen Scripten ist die Lücke im 
Hexfile, wenn das Ende von .text < 0x10000 ist. Das erste Script führt 
im Hexfile dazu, dass die Lücke mit 0x00 gefüllt enthalten ist. Das 
zweite Script führt zu einem kleineren Hexfile. Die Lücke taucht im 
Hexfile nicht auf und wird beim Flashen nicht beschrieben. In der ersten 
Variante kann die .flash1 Section vor 64kB anfangen, enthält dann aber 
0x00 bis 0x10000. In der zweiten Variante fängt die .flash1 Section 
immer erst bei 0x10000 oder weiter hinten an.

Beide LD Scripts führen dazu, dass Konstanten, die mit
1
const __flash1 <Datentyp> name = ...;
definiert sind, im Flash im Bereich 64-128kB abgelegt werden. Auf diese 
Konstanten kann entweder direkt oder über einen 16bit __flash1 Pointer 
zugegriffen werden, so dass man die sperrigen und langsameren 
pgm_far-Makros aus avr/pgmspace.h nicht benötigt. Im Gegensatz zu meiner 
Lösung von ganz oben funktioniert auch der Zugriff über __memx Pointer. 
Da __flash1 nur beim avr-gcc existiert, muss man die Zugriffe und Daten 
in C-Files auslagern, wenn man das mit avr-g++, z.B. in der Arduino 
Welt, benutzen will.
1
// array tab located in .flash1
2
static const __flash1 uint8_t tab[] =
3
   { 0xDE, 0xAD, 0x00, 0xBE, 0xEF };
4
5
// access function for array tab located in .flash1
6
uint8_t getTab(const uint16_t idx)
7
{
8
   return (idx < sizeof(tab)) ?  tab[idx] : 0;
9
}

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.