Sketch stürzt ab 88.378 B Größe ab - Fehler einkreisen? [64 K-Grenze, solved]

Guten Abend Forum,

es ist mal wieder so weit - ich laufe vor eine Wand und kann nicht einmal genau sagen was für eine :o)

Ich lade in die 258.048 Bytes Flash-Speicher meines Arduino mega 2560 einen Sketch mit mehreren sehr großen Arrays (jeweils 8192 Werte). Ist der Sketch kleiner als 88.202 Bytes groß funktioniert alles astrein.

Ist der Sketch jedoch 88.378 Bytes groß oder größer, dann reagiert mein Arduino leider gar nicht mehr! Kein Serial-output, keine sonstige Reaktion mehr und vor allem keine Fehlermeldung, die ich irgendwie interpretieren könnte. Der Upload wird trotzdem mit der Erfolgsmeldung beendet:

# | 100% 12.13s

avrdude: verifying ...
avrdude: 88378 bytes of flash verified
...

avrdude done.  Thank you.

Wenn ich einen anderen (kleineren!) Sketch kompiliere und uploade funktioniert alles wieder wie gehabt.

Die verwendeten Variablentypen wurden groß genug dimensioniert.

Der Sketch wird übrigens ausschließlich wegen der Arrays immer größer, am Code wurde nichts verändert

Ratlos,

viele Grüße, kuahmelcher!

Am Quellcode vieleicht nicht, am Compilat aber schon. Der Punkt ist: sobald Du die 64k Grenze überschreitest passen Adressen für die Daten im Flash nicht mehr in 16bit Pointer. Ich würde mal vermuten, daß Du dann Probleme mit dem Compiler bekommst. Die spannende Frage warum nicht sofort beim Überschreiten der 64k Grenze --> weil Du wohl Glück gehabt hast.

Davon abgesehen: bist Du sicher, daß Deine Arrays ins SRAM passen? Wie wurden die Arrays deklariert?

[quote author=Udo Klein link=topic=174084.msg1292569#msg1292569 date=1372193111]
Am Quellcode vieleicht nicht, am Compilat aber schon. Der Punkt ist: sobald Du die 64k Grenze überschreitest passen Adressen für die Daten im Flash nicht mehr in 16bit Pointer. Ich würde mal vermuten, daß Du dann Probleme mit dem Compiler bekommst. Die spannende Frage warum nicht sofort beim Überschreiten der 64k Grenze --> weil Du wohl Glück gehabt hast.[/quote]

OK, 16-bit-pointer. Hast du eine Idee, wie ich systematisch die restlichen (258.048 - 88.378=) 169.670 Bytes nutzen oder zumindest einkreisen kann, ob's an der 64k-Grenze liegt - damit ich weiß wo ich einen Hebel ansetzen kann? Momentan fische ich im Trüben. Irgendwie muss doch der restliche Speicher nutzbar sein! Wenn ich wenigstens eine vernünftige Fehlermeldung hätte, aber der Sack tut ja so als wäre alles in Ordnung! ;o) … ist dieses "Verhalten" vielleicht typisch für die 64K-Grenze?

Diese Klippe habe ich dank der Hilfe in diesem Forum und dem praktischen Befehl "progmem" umschifft. Die Arrays werden direkt in den Flash geladen und auch direkt daraus genutzt. Klappt auch prima. Ich würde halt nur gerne noch mehr Flash nutzen, ich habe doch noch so viel davon! :o)

Danke und Gruß, kuahmelcher!

Die verwendeten Variablentypen wurden groß genug dimensioniert.

Der Sketch wird übrigens ausschließlich wegen der Arrays immer größer, am Code wurde nichts verändert

Initialisierte Arrays liegen sowohl im Flash wie im RAM.

Vermutlich ist die Größe des Flash-Speichers nicht das Problem, sondern der RAM ...
Ein Mega2560 hat zwar 4 mal so viel RAM wie ein UNO mit dem 328P Controller, aber wirklich viel ist das auch nicht.


Aber wie PROGMEM bei Adressen > 64k funktioniert, ist eine gute Frage ...

kuahmelcher:
Diese Klippe habe ich dank der Hilfe in diesem Forum und dem praktischen Befehl "progmem" umschifft. Die Arrays werden direkt in den Flash geladen und auch direkt daraus genutzt. Klappt auch prima. Ich würde halt nur gerne noch mehr Flash nutzen, ich habe doch noch so viel davon! :o)

Also ich weiß definitiv, dass sich mit 16-bit Pointern nicht mehr als 64 KB Speicherbereich adressieren lassen.

Wenn Dein Programm jetzt erst mit 88.378 Bytes nicht mehr läuft, dann liegt es wahrscheinlich daran, dass Compiler und Linker das Programm bereits im Hintergrund in "Sektionen" aufgeteilt haben, von denen jede nicht mehr als 64 KB groß ist. Sagen wir mal in

  • Sektion RAM-Speicherbereich
  • Sektion Programmcode-Anweisungen
  • Sektion PROGMEM Daten
    Sorry falls ich hier falsche Fachbegriffe verwende oder irgendwas falsch erkläre, ich habe nur grundlegende Kenntnisse über die Interna und eher grobe Vorstellungen davon als detailreiche Kenntnisse.

Ich würde in Deinem Fall als erstes versuchen, Daten in andere Sektionen als PROGMEM zu packen. Wenn ich mich nicht täusche, geht das bei der Variablendeklaration über einen "attribute" Zusatz mit Angabe der gewünschten Sektion.

Codebeispiel für Variablen in PROGMEM und in Sektion .fini3:

#include <avr/pgmspace.h>
const char text1[] PROGMEM ="Das ist Text in PROGMEM";
const char text2[] __attribute__ ((section (".fini3"))) ="Das ist Text in Sektion .fini3";
 
char textbuf[80]; 
void setup() {
  Serial.begin(9600);
  
  // Text aus PROGMEM ausgeben
  memcpy_P(textbuf,text1, strlen_P(text1));
  Serial.println(textbuf);
  // Text aus section (".fini3") ausgeben
  memcpy_P(textbuf,text2, strlen_P(text2));
  Serial.println(textbuf);
}

void loop() {
}

Die Sektionen ".fini1" bis ".fini5" sind als "User definable" angegeben.

Ich weiß nicht ob es hilft (habe in diese Richtung noch absolut gar nichts programmiert), aber ich würde erstmal versuchen, neue Daten über entsprechende Attribute in die Sektionen ".fini1" bis ".fini5" statt PROGMEM zu deklarieren und dann die Daten dort wieder herauszuziehen.

Und immer drauf achten: Nur immer max. 64 KB Daten in jede Sektion packen, nicht mehr.

Keine Ahnung, ob das so funktioniert.
Vielleicht meldest Du mal zurück, wenn ja.

Edit/Nachtrag: Habe mal ein bisschen mit diesem Ansatz getestet, aber auch damit komme ich nicht über die 64 KB Grenze für Daten im Flash-Speicher. Scheint eine Sackgasse zu sein.

michael_x:
Initialisierte Arrays liegen sowohl im Flash wie im RAM.

Vermutlich ist die Größe des Flash-Speichers nicht das Problem, sondern der RAM ...

Hallo michael_x,

also ich bin da kein wirklicher Routinier, glaube aber, dass DIESES Problem tatsächlich nicht vorliegt. Ich fülle vor der Setup-Funktion die Arrays folgendermaßen mit Bytes und lese sie später wieder aus:

// RGB-Werte in Arrays füllen:
prog_uchar rgb1[] PROGMEM = {125,242,53, usw.usf 8000 * 3 Werte} 
...
// Arrays wieder auslesen und LEDs zum leuchten bringen:
leds[led].r = pgm_read_byte (&rgb1[counter]);

Dafür spricht IMHO auch, dass der SRAM bereits mit dem ersten Array überfordert wäre, weil 3 x 8.000 = 24.000 Bytes da nicht 'reinpassen. Von den unhandlichen Arrays habe ich aber momentan bis zu fünf Stück im Einsatz und das dürfte die 8KB deutlich überfordern.

Sollte da noch irgendwo ein Denkfehler drin sein, wäre ich dankbar für einen kurzen Hinweis!

Danke und Gruß, kuahmelcher

Hallo jurs,

Wenn Dein Programm jetzt erst mit 88.378 Bytes nicht mehr läuft, dann liegt es wahrscheinlich daran, dass Compiler und Linker das Programm bereits im Hintergrund in "Sektionen" aufgeteilt haben, von denen jede nicht mehr als 64 KB groß ist. Sagen wir mal in

  • Sektion RAM-Speicherbereich
  • Sektion Programmcode-Anweisungen
  • Sektion PROGMEM Daten

Meinem amateurhaften Verständnis nach könnte ja der Compiler selbst auf die Idee kommen, jedes dicke Array in eine Sektion zu packen, damit der riesige Flash-Platz von 256 KB auch genutzt werden kann - scheint aber nicht so zu sein! ;o) Ich muss zugeben, so ganz verstanden hab ich's noch nicht. Irgendwann muss ich mich mal mit dem Speicherkonzept von C beschäftigen.

Keine Ahnung, ob das so funktioniert.
Vielleicht meldest Du mal zurück, wenn ja.

Edit/Nachtrag: Habe mal ein bisschen mit diesem Ansatz getestet, aber auch damit komme ich nicht über die 64 KB Grenze für Daten im Flash-Speicher. Scheint eine Sackgasse zu sein.

Das ist wirklich sehr schade, weil dein Vorschlag bisher der einzige Ansatz war und sich auch vielversprechend angehört hat. Vermutlich haben erst wenige überhaupt so große Arrays in den Sketch eingebettet sodass das Problem nicht häufig aufgetaucht ist.

Aber mir stellt sich mehr und mehr die Frage: Wie kann ich ÜBERHAUPT auf den großen Flashspeicher des MEGA zugreifen? Der nutzt mir ja dann eigentlich gar nix?! Irgendwo muss es noch etwas geben, was ich nicht beachtet habe.

Danke und Gruß, kuahmelcher!

hi,

http://forum.arduino.cc/index.php?topic=146211.0
schau hier. ich hab's nicht wirklich komplett durchgelesen, aber es scheint eine lösung zu geben.
das thema ist schon öfter hochgekommen, gib bei der suche hier im forum "mega2560 64k" ein.

gruß stefan

Sollte da noch irgendwo ein Denkfehler drin sein, wäre ich dankbar für einen kurzen Hinweis!

Nein, Entschuldigung kuahmelcher, dass ich dich offensichtlich für so unbedarft gehalten habe.

Eigentlich bin ich kein Freund von " bitte poste deinen ganzen Code" (= ignorieren oder viel Müll lesen )
aber dass es sich tatsächlich nur um serielles Lesen aus PPROGMEM handelt, konnte ich vorher nicht sehen.

Oft sind die Probleme auch einfacher, als der Frager denkt.

Aber mangels eines eigenen 2560 (werd mich demnächst mal mit einem atmega1284 beschäftigen) kenn ich mich mit deiner Problematik nicht aus.
(
Das Faszinierende an Arduino ist, dass durch die Kleinheit manche Probleme gar nicht erst entstehen, andere aber um so kniffliger werden
64k Grenzen bei 16-Bit Pointern hatte ich bisher der ersten Kategorie zugerechnet :wink:
)

Nachdem jetzt bezüglich der Art der Wand Klarheit herscht stellt sich die Frage was nun. Mir fallen zwei Lösungen ein:

  1. Compiler wechseln --> kostet allerdings wohl eher mehr als Du ausgeben willst.
  2. Platform wechseln --> wenn Du eh schon über 64k bist, warum dann nicht gleich ein billiges Linuxsystem ("Raspi") nehmen?

Mit Lösung (2) hast Du dann jede Menge Luft nach oben und brauchst Dir keine Gedanken mehr um den Speicher zu machen. Ggf. kannst Du ja Deine Arduino basierte Lösung auch so erweitern, daß sie von der größeren Kiste Steuerbefehle entgegen nimmt und Du somit Teile Deiner Hardware weiterverwenden kannst.

jurs:

  • Sektion PROGMEM Daten

Lieber jurs, ich habe über deinen Beitrag nochmal nachgedacht (hilft mir manchmal ;o)

Ich nutze die folgende Seite um JPG-Dateien in ihre RGB-Werte zu zerlegen, um sie über eine LED-Zeile mit 59 LEDs darzustellen (http://raspberrypi.fmhmamehlauorxfo.myfritz.net/rgb/eeprom3.php).

Die Dateien, die ich gerade eben noch hochladen kann haben die Größe 59 x 370 Pixel. Wenn ich jetzt meinen Taschenrechner anschmeiße, dann rechne ich: 593703(Byte)/1024=63,9 KiB. ... und das kam mir bekannt vor!

Wähle ich eine einzige Spalte mehr, dann kommt 64,1 KiB raus (593713/1024) und DAS kann ich dann auch nicht mehr in meinen Sketch verpacken und hochladen. Da wäre ich allein NIE drauf gekommen!!

Das bedeutet, dass ich jetzt tatsächlich genau sagen kann, aus welchem Material die "Wand" ist, aber noch nicht so recht weiß wie ich sie überwinden kann! Aber das bekomme ich auch noch hin!

Danke auf jeden Fall schon mal dafür. Ich habe mit diesem Problem schon die eine oder andere Stunde zugebracht und war mittlerweile echt frustriert.

Gruß, kuahmelcher.

Hei Udo,

tja, ich bin sogar stolzer Besitzer eines Raspberrys. Allerdings habe ich meinen RGB-Drucker als Shield extra für den Arduino mega gelötet traue mir auch ehrlich gesagt nicht mal so eben zu von Arduino zu Raspbi zu migrieren. Klar geht das bestimmt, aber der Teufel steckt da ja sicher (wie immer) im Detail und ich habe eigentlich schon viel zu viel Zeit für ein Spaß-Projekt investiert. Und last but not least: Der mega HAT DOCH 256 KiB, die will ich auch nutzen - das MUSS doch irgendwie gehen. Ich suche heute abend mal wieder ein bisschen, ich weiß ja jetzt wonach!
Vielleicht gibt's irgendwann eine Version 2.0 und die baue ich dann mit dem Raspbi :o)

Gruß, kuahmelcher

kuahmelcher:
Das ist wirklich sehr schade, weil dein Vorschlag bisher der einzige Ansatz war und sich auch vielversprechend angehört hat.

OK, dann rudere ich wieder etwas zurück, nachdem ich noch mehr gegoogelt habe:

Mit der Datenablage in verschiedenen Sektionen ist es doch keine Sackgasse. Es ist möglich, auf hohe Speicheradressen zuzugreifen und wenn Du Daten in hohen Speicheradressen abgelegt hast, kommst Du da auch irgendwie wieder dran.

Zufrieden?

kuahmelcher:
Ich nutze die folgende Seite um JPG-Dateien in ihre RGB-Werte zu zerlegen, um sie über eine LED-Zeile mit 59 LEDs darzustellen (http://raspberrypi.fmhmamehlauorxfo.myfritz.net/rgb/eeprom3.php).

Die Dateien, die ich gerade eben noch hochladen kann haben die Größe 59 x 370 Pixel. Wenn ich jetzt meinen Taschenrechner anschmeiße, dann rechne ich: 593703(Byte)/1024=63,9 KiB. ... und das kam mir bekannt vor!

Wie sehen denn Deine Datenstrukturen aus?

Eine Definition wie
const byte picture[65490] PROGMEM= {1,2,3,4};
kann es nicht sein, das gibt bei mir einen Compilerfehler "Overflow in array dimensions".

Mein Compiler 1.0.3 frißt nur Arrays bis max 32 KB Größe.

Ich kann mich ja nochmal um Zugriffe kümmern.
Vielleicht kannst Du mal posten, wie die Datenstrukturen aussehen, die Du brauchst und wie Du sie aufteilen kannst. Und wie Du darauf zugreifen möchtest.

Immer Array für Array in real existierenden RAM Speicher umkopieren?
Oder eher linear byteweise darauf zugreifen?
Oder immer nur Stücken eines Array in einen RAM-Puffer kopieren?

Erklär bitte mal genauer Aufbau und Zugriff auf die Daten!
Ich glaube, da geht was.

Zumindest wenn Du diese Vorgaben nicht sprengst:

  • Maximale Größe einer einzelnen Datenstruktur (Array) nicht über 32 KB.
  • Maximale Größe aller Datenstrukturen (Arrays) in einer Sektion nicht über 64 KB.
  • Maximale Anzahl an Sektionen: Nicht mehr als man an den Fingern abzählen kann

jurs:
Wie sehen denn Deine Datenstrukturen aus?

Also ich habe jetzt mal versucht, meine gefühlten 12 Millionen Zeilen Code in ein Minimalbeispiel einzudampfen. Es verdeutlicht den Umgang mit den Arrays und Variablen, läuft allerdings trotzdem nicht, weil ich der Übersichtlichkeit halber den ganzen FastSPI-Kram weggelassen habe. Die Zeile 6 (Array-Deklaration) enthält bei mir im Einsatz nicht 16 Werte, sondern bis zu 24576 Werte. Danach wird einfach ein zweites druntergeschrieben usw. Erst beim dritten Array komme ich an die magische 64KiB-Grenze.

#include <FastSPI_LED.h>
#include <avr/pgmspace.h> 

#define PIN 7 // DAtenpin für die LEDs

long zeile, spalte, led, poti_wert_alt;
long counter = 0;

prog_uchar rgb1[] PROGMEM = {35,0,45,35,0,45,70,0,90,70,0,89,67,0,9,71,13,9,10,67,0,9,68,0}

byte hoehe = 2;
unsigned int breite = 4, pixelanzahl = breite * hoehe;
      

void setup() {
  
  // Beginn der seriellen Kommunikation
  Serial.begin(115200);

}



void leuchten(){

	for (int spalte=0; spalte < breite; spalte++)
    {
	//Serial.print("********************** Spalte: "); Serial.println(spalte);
    
    	for (byte led=0; led < hoehe; led++)
          {            
            if (int counter < pixelanzahl*3){
            	// Hier werden die RGB-Werte wieder aus dem Array rgb1 aus 
            	// dem Flash ausgelesen: 
              	leds[led].r = pgm_read_byte (&rgb1[counter-tmp]); counter++;
              	leds[led].g = pgm_read_byte (&rgb1[counter-tmp]); counter++;
              	leds[led].b = pgm_read_byte (&rgb1[counter-tmp]); counter++;
            } 
          
          FastSPI_LED.show(); // bringt die LEDs zum leuchten

          delay(poti_wert);   // mit Poti eingestellte Verzögerung
      }
}



void loop() {
	leuchten();
}

Oder eher linear byteweise darauf zugreifen?

Äh ... ich glaube so! Es wird immer genau ein Byte aus dem PROGMEM-Bereich ausgelesen und sofort dem Array leds[led].r/g/b zugewiesen. Davon gibt's zwar eine ganze Spalte, aber es werden trotzdem nicht mehr als 59*3=177 Werte, weil die ja anschließend mit der nächsten Spalte überschrieben werden.

Ist vielleicht jetzt etwas umständlich erklärt, aber ich mache da sowas mit:
Dropbox - Error - Simplify your life,
Dropbox - Error - Simplify your life,
Dropbox - Error - Simplify your life

Momentan sind halt nur kurze Spruchbänder/Bilder/Muster möglich.

  • Maximale Größe einer einzelnen Datenstruktur (Array) nicht über 32 KB.

Passt!

  • Maximale Größe aller Datenstrukturen (Arrays) in einer Sektion nicht über 64 KB.

OK, das ist noch "Baustelle"

  • Maximale Anzahl an Sektionen: Nicht mehr als man an den Fingern abzählen kann

Passt, mehr hat der mega ja eh nicht an Flash und mehr brauch ich auch nicht.

Danke und Gruß, kuahmelcher

kuahmelcher:

Oder eher linear byteweise darauf zugreifen?

Äh ... ich glaube so! Es wird immer genau ein Byte aus dem PROGMEM-Bereich ausgelesen

Wunderbar, alles bestens!

Um zu verstehen, weshalb das alles nicht so einfach funktioniert, werfe ich den Blick auf die AVR libc und was im Modul "avr/pgmspace.h: Program Space Utilities" drin sein soll und was tatsächlich in der Arduino-Software drin ist:
http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html

Drin sein sollten: Eine Haufen Funktionen, die mit großen Pointern ("Far Pointer") über 64 KB Speicher hinaus zugreifen können sollen. Solche Funktionen wie memcpy_PF, strcpy_PF, strlen_PF, strstr_PF und diverse andere.

Tatsächlich enthalten sind diese Funktionen nur in einer "P" Version: memcpy_P, strcpy_P, strlen_P, strstr_P und diverse andere. Diese Funktionen können alle nur mit bis zu maximal 64 KB Variablen im Programm-Flash umgehen, den PROGMEM Variablen. Alle diese Funktionen kann man daher für Zugriffe über 64 KB Variablenspeicher komplett vergessen.

Jetzt gibt es in pgmspace.h aber auch Funktionen, die am Ende den Namen "far" haben, und hier wird es interessant: pgm_read_byte_far, pgm_read_word_far, pgm_read_float_far gibt es nämlich tatsächlich in der Arduino-Software, man kann sie verwenden und diese funktionieren tatsächlich: Man übergibt ihnen eine long-Zahl, und die Funktion liefert den Inhalt aus dem gewünschten Speicherbereich zurück.

Es gibt nur ein Problem: Woher bekommt man eine long-Zahl mit der Speicheradresse der Variablen, die man im Programmspeicher abgelegt hat? Alle Pointer in der Arduino-Software haben ha nur 16 Bit? Und hier kommt nun irgendein genialer Open Source Programmierer ins Spiel, der dafür eine Funktion gemacht hat: Es hat jemand ein Makro gemacht, mit dem man aus einer Far-Pointer-Flash-Variablen die Adresse herausbekommt:
#define GET_FAR_ADDRESS(var)
Ist mit Inline-Assembler Code drin, aber alles so verpackt, dass die Arduino-Software es frißt.

Und nun ist es einfach:

  1. Die Flash-Variablen auf Flash-Speichersektionen von max. 64KB Größe aufteilen
  2. Startadresse des Speichers als long-Variable mittels GET_FAR_ADDRESS ermitteln
  3. Linear auf diese und nachfolgende Speicheradressen zugreifen mittels pgm_read_byte_far und anderen "_far" Funtkonen

Wenn man weiß, wie es funktioniert, ist es eigentlich ganz einfach.

Im Beispielcode erzeuge ich vier Variablen mit je 32000 Bytes Größe als Char-Arrays und verteile diese auf zwei Sektionen.
Im Setup lasse ich einmal die Vier long-Startadressen des Speichers ausgeben.
In der loop lasse ich dann die ersten 32 Bytes jeder Variable ausgeben, einmal als Text und einmal als Bytes in Dezimaldarstellung. Alles rein zur Demonstration.

#include <avr/pgmspace.h>

/* GET_FAR_ADDRESS() macro

   This macro facilitates the obtention of a 32 bit "far" pointer (only 24 bits
   used) to data even passed the 64KB limit for the 16 bit ordinary pointer. It
   is similar to the '&' operator, with some limitations.

   Comments:

   - The overhead is minimal and it's mainly due to the 32 bit size operation.

   - 24 bit sizes guarantees the code compatibility for use in future devices.

   - hh8() is an undocumented feature but seems to give the third significant byte
     of a 32 bit data and accepts symbols, complementing the functionality of hi8()
     and lo8(). There is not an equivalent assembler function to get the high
     significant byte.

   - 'var' has to be resolved at linking time as an existing symbol, i.e, a simple
     type variable name, an array name (not an indexed element of the array, if the
     index is a constant the compiler does not complain but fails to get the address
     if optimization is enabled), a struct name or a struct field name, a function
     identifier, a linker defined identifier,...

   - The natural place for this macro should be the header avr/pgmspace.h and the
     name... pgm_get_far_address?

   - The returned value is the identifier's VMA (virtual memory address) determined
     by the linker and falls in the corresponding memory region. The AVR Harvard
     architecture requires non overlapping VMA areas for the multiple address spaces
     in the processor: Flash ROM, RAM, and EEPROM. Typical offset for this are
     0x00000000, 0x00800xx0, and 0x00810000 respectively, derived from the linker
	 script used and linker options. The value returned can be seen then as a
     universal pointer.

*/

#define GET_FAR_ADDRESS(var)                          \
({                                                    \
	uint_farptr_t tmp;                                \
                                                      \
	__asm__ __volatile__(                             \
                                                      \
			"ldi	%A0, lo8(%1)"           "\n\t"    \
			"ldi	%B0, hi8(%1)"           "\n\t"    \
			"ldi	%C0, hh8(%1)"           "\n\t"    \
			"clr	%D0"                    "\n\t"    \
		:                                             \
			"=d" (tmp)                                \
		:                                             \
			"p"  (&(var))                             \
	);                                                \
	tmp;                                              \
})


// max array size not above 32 KB
#define ARRAYSIZE 32000

// Mal eben 4 arrays a 32000 Bytes = 128000 Bytes deklarieren
// In jede Sektion nur max. 64 KB Daten hineinpacken!

const char text01[ARRAYSIZE] __attribute__ ((section (".fini1"))) ={"Das ist Text1 in Sektion .fini1"};
const char text02[ARRAYSIZE] __attribute__ ((section (".fini1"))) ={"Das ist Text2 in Sektion .fini1"};
const char text03[ARRAYSIZE] __attribute__ ((section (".fini2"))) ={"Das ist Text3 in Sektion .fini2"};
const char text04[ARRAYSIZE] __attribute__ ((section (".fini2"))) ={"Das ist Text4 in Sektion .fini2"};

void setup() {
  long longAddress;
  Serial.begin(9600);
  pinMode(13,OUTPUT);
  Serial.println("Die folgenden Variablen liegen an diesen long-Adressen:");
  Serial.print("text01: ");
  Serial.println(GET_FAR_ADDRESS(text01));
  Serial.print("text02: ");
  Serial.println(GET_FAR_ADDRESS(text02));
  Serial.print("text03: ");
  Serial.println(GET_FAR_ADDRESS(text03));
  Serial.print("text04: ");
  Serial.println(GET_FAR_ADDRESS(text04));
}

void loop() {
  // Ein bischen LEDs blinken lassen
  digitalWrite(13,HIGH);
  delay(1000);
  digitalWrite(13,LOW);
  delay(1000);
  // Und die Inhalte aus den Flash-Variablen ziehen:
  long longAddress;
  for (int num=1; num<=4; num++)
  {
    if (num==1) longAddress=GET_FAR_ADDRESS(text01);
    if (num==2) longAddress=GET_FAR_ADDRESS(text02);
    if (num==3) longAddress=GET_FAR_ADDRESS(text03);
    if (num==4) longAddress=GET_FAR_ADDRESS(text04);
    for(int i=0;i<32;i++) 
      Serial.write(pgm_read_byte_far(longAddress+i));
    Serial.println();
    for(int i=0;i<32;i++)
    {
      Serial.print(pgm_read_byte_far(longAddress+i),DEC);
      Serial.print(" ");
    }
    Serial.println();
  }
  Serial.println();
}

Den etwas längeren Kommentar zum GET_FAR_ADDRESS-Makro habe ich mal rein informationshalber mit in den Code kopiert, der kann da natürlich rausgelöscht werden.

Zur Aufteilung in 64kb Sektionen: Ich glaube, man kann sogar komplett alle Variablen in nur eine einzige Sektion packen, z.B. ".fini1". Ich habe das mal mit meinem Programm gemacht und es funktioniert mit 128000 Bytes nur in der ".fini1" Sektion.

Die Variablen über 64 KB müssen aber zwingend in eine andere Sektion als PROGMEM definiert werden, d.h. PROGMEM darf definitiv NICHT für so große Datenstrukturen verwendet werden, sonst läuft das Programm hinterher nicht. Aber das weißt Du natürlich schon, weil das ja der Grund für Dich war, diesen Thread zu starten.

Viel Spaß damit!
War ein lustiges Googeln und Herumprobieren, bis ich alle Puzzleteilchen zur Lösung beisammenhatte.

jurs:
Viel Spaß damit!
War ein lustiges Googeln und Herumprobieren, bis ich alle Puzzleteilchen zur Lösung beisammenhatte.

jurs! Es klappt!!! Wie du dir sicher vorstellen kannst war ich nicht untätig, sondern habe fleißig versucht mit deinen Erläuterungen durch die Materie zu steigen. Bisher konnte ich - wie gesagt - 59 x 370 Pixel beschreiben, jetzt sind es üppige 59 x 1248 Pixel!!! Gut dreimal so viel - Respekt!

Der Sketch enthält nun acht Arrays zu 32000 Bytes und eine Gesamtgröße von 246.000 von möglichen 258.000 Bytes. Wahrscheinlich könnte ich also noch ein paar Spalten mehr einfügen, aber jetzt habe ich den Speicher ja fast komplett ausgereizt.

Ein kleineres Problem taucht nun auf, aber das scheint unkritisch zu sein, weil eigentlich alles funktioniert:

: verifying ...
avrdude: verification error, first mismatch at byte 0x3c000
         0x13 != 0x10
avrdude: verification error; content mismatch

Jedenfalls ein großes Dankeschön, Respekt und Anerkennung für diese Lösung, die ich niemals ohne Hilfe hinbekommen hätte!!

Gruß, kuahmelcher!

kuahmelcher:
Ein kleineres Problem taucht nun auf, aber das scheint unkritisch zu sein, weil eigentlich alles funktioniert:

: verifying ...

avrdude: verification error, first mismatch at byte 0x3c000
         0x13 != 0x10
avrdude: verification error; content mismatch

Sieht aus, als wenn der Avrdude da eine defekte Speicherstelle mit zwei defekten Bits entdeckt hat.
Bei Byte 0x3c000 = 245760

Wenn sich derselbe Fehler an derselben Speicherstelle reproduzieren läßt, ist es wohl der Speicher, der da eine kleine Macke hat.

Aber irgendwie scheint der Avrdude mit dem Upload sehr großer Sketche auch Probleme zu haben. Ich wollte mich heute mal durch Definition von noch mehr Daten an die maximale Sketchgröße herantasten, der Sketch war dann am Ende nur 2 KB kleiner als die angezeigte maximale Sketchgröße für den MEGA2560, dann ist der Avrdude beim Upload hängengeblieben und war selbst nach 10 Minuten noch nicht fertig. Und nach USB-Zwangstrennung war dann der Bootloader meines MEGA2560 zerschossen. Nichts ging mehr, ich konnte keine neuen Sketche mehr hochladen.

Da ich keinen Programmer habe, konnte ich mir erstmal ansehen, wie man einen UNO als ISP-Programmer für einen MEGA verwendet und habe darüber dann einen neuen Bootloader hochgeladen. Das ging am Ende zwar immer mit einem Verify-Fehler ab, den ich nicht rausbekommen konnte, aber wenigstens funktioniert der Bootloader jetzt wieder und ich bekomme wieder Sketche auf den MEGA geladen.

Also Vorsicht: Beim Uploaden von Sketchen dicht unterhalb der Maximalgröße kann Avrdude sich auch mal verhauen und dann den Bootloader schrotten, so dass keine neuen Sketche mehr uploadbar sind, bevor man den Bootloader nicht neu installiert hat.

Aber wenn Du das letzte Kilobyte an Speicher nutzbar machen möchtest, brauchst Du ja sowieso einen ISP-Programmer: Um den Bootloader plattzumachen und auch noch den Speicherplatz für Daten zu nutzen, den sonst der Bootloader bereits belegt.