Linker Optionen beim Mega2560 setzen, zwecks ext. SRAM

Hallo,

ich habe 64k externen SRAM an meinen Arduino Mega2560 angeschlossen und kann auch per Pointer darauf zugreifen - also z.B. den kompletten Speicher mit Werten füllen und diese wieder auslesen. Speicher sollte also funktionieren.

Damit der Linker jetzt aber auch Variablen usw. in den ext. Speicher packt, müsste ich folgende Optionen übergeben:
EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff

Leider finde ich weder das Makefile, mit dem meine Sketches gebaut werden, noch eine Stelle, wo ich dem Linker irgendwelche Optionen übergeben könnte. Hat da vielleicht jemand einen guten Rat für mich? Ich wäre echt dankbar...

Gruß,
Ralf

So, dank der Tipps von jurs (siehe dieser Thread: [OT] Welchen Atmelprozessor für "Von Neumann Architektur" ? - #20 by system - Deutsch - Arduino Forum) bin ich einen großen Schritt weiter gekommen.

Folgender Sketch läuft jetzt mit dem SRAM und alloziert insgesamt 48k Speicher. Wenn die auskommentierten Zeilen mit kompiliert werden, kann man auch sehen, dass der Speicher korrekt beschrieben und gelesen wird (kompiliert mit Code::Blocks Arduino Edition 12.11).

#include <Arduino.h>

// Linker-Optionen:
// -Wl,--section-start,.data=0x802200,--defsym=__heap_end=0x80ffff


void initExtSRAM(void) __attribute__((naked, section(".init3")));

void initExtSRAM(void)
{
    MCUCR=0x80;
    XMCRA=0x80;
    XMCRB &=~7 ;
}

extern int __bss_end;
extern void *__brkval;


int get_free_memory()
{
  int free_memory;

  if((int)__brkval == 0)
    free_memory = ((int)&free_memory) - ((int)&__bss_end);
  else
    free_memory = ((int)&free_memory) - ((int)__brkval);

  return free_memory;
}


void setup() {
  Serial.begin(9600);
}


void loop() {
    char *data;     // Character-Array soll dynamisch angelegt werden
    int ndata=4096; // Größe des Arrays 4kB
    int i, u;
    uint8_t *mem;

    Serial.print("Freier Speicher: ");
    Serial.print((unsigned int) get_free_memory());
    Serial.println(" Bytes");

    for(i=0; i<12; i++) {
        if((data=(char *) malloc(ndata*sizeof(char)))==NULL ) {
            Serial.println("Nicht alloziert");
            while(1);
        }
        else {
            Serial.print("An Adresse ");
            Serial.print((unsigned int) data);
            Serial.println(" 4096 Bytes alloziert");
        }

        Serial.print("Freier Speicher: ");
        Serial.print((unsigned int) get_free_memory());
        Serial.println(" Bytes\n");

/*        for(u=0; u<4096; u++) {
            data[u] = 0x55;
            Serial.print(data[u]);
        }
        Serial.println();

        for(u=0; u<4096; u++) {
            data[u] = 0x33;
            Serial.print(data[u]);
        }
        Serial.println();   */
    }
    while(1);
}

Man kann also (so wie ich gesagt hatte) den externen Speicher mit dem XMCRA-Register an- und ausschalten, wie man will, aber (so wie jurs angeregt hat) man kann nicht erwarten, dass der Controller den Speicher dann von Anfang an benutzt. Dazu muss (so wie jurs das richtig gesagt hat) man den Speicher anschalten ehe etwas anderes im Programm passiert. Dazu bietet sich die init3-Section an, wo ich dann im obigen Sketch die Speicherinitialisierung hin kompiliert habe. Jetzt stehen rund 64k für die Verwendung mit malloc() zur Verfügung.

Auf dem Heap (also global) lässt sich z.B. auch ein Char-Array wie

char meinArray[30000];

anlegen, lesen und auch beschreiben.

Also, nochmals besten Dank an jurs - seine Tipps haben mir wirklich sehr weiter geholfen!

Gruß,
Ralf

PS: Ich kanns mir nicht verkneifen: Mein Mega2560 hat jetzt 64k freies RAM :grin:

... aber 16 Pins weniger :frowning:

Glückwunsch, gebookmarkt !

Schachmann:
PS: Ich kanns mir nicht verkneifen: Mein Mega2560 hat jetzt 64k freies RAM :grin:

Auch von mir eine Gratulation dazu, dass es mit der Aktivierung/Einbindung als "echtes" RAM nun doch noch geklappt hat!

michael_x:
... aber 16 Pins weniger :frowning:

Glückwunsch, gebookmarkt !

Sagen wir 19 Pin weniger.
Aber was sind schon 19 Pins gegenüber 64 KByte RAM? Mit 19 Pins kannst Du wenig Variablen speichern :wink: :wink: :wink:
Grüße Uwe

Ist halt immer die Frage was brauch' ich dringender: Pins oder RAM.

Mir ging's erstmal nur um das Experiment - ob ich es zum Laufen bekomme oder nicht.

Gruß,
Ralf

@Schachmann: Deine Recherche ist sehr interessant, und wohl in der Praxis leicht Einsetzbar.

Würde bei meinem Webserver Projekt weiterhelfen, wo mir langsam aber sicher trotz Nutzung des F-Macros das S-Ram ausgeht.
Zudem macht das F Macro den Refresh der Website um den Faktor 10 langsamer (für das es keine Erklärung zu geben scheint) , ist aber ein anderes Thema.

Welche Ram-Ext Hardware nutzt du, ist wohl in den Thread's untergegangen.

Sowas: ?
http://ruggedcircuits.com/html/megaram.html

Danke.

Mfg Rudi

in wieweit lässt sich das Ram auf diese Art erweitern und anschließend verwenden? Könnte man sich z.B. auch 128k SRAM dranbasteln? Und in wieweit affektiert es das Programm? mein Problem momentan ist, dass ich mit dem WS2811 herumspiele und da einiges an RAM draufgeht, so dass ich schon auf der Suche nach einer anderen Plattform war... Ich hätte dann allerdings eh etwas gesucht, das ich in eine eigene Schaltung integrieren könnte. Wenn man allerdings den Mega 2560 mit extra Ram bestücken kann, kann man theoretisch auch gleich ein Board mit dem 2560 in TQFP basteln...

rudirabbit:
Welche Ram-Ext Hardware nutzt du, ist wohl in den Thread's untergegangen.

Ich nutze nichts Fertiges, sondern habe mir das selbst gebastelt. Beschreibung, Bauplan, Schaltplan und Erklärungen gibt es hier: Beschreibung RAM-Erweiterung.

Es dürfte wohl (nicht geprüft - aber ich denke es ist so) mit jeder Speichererweiterung funktionieren, da die hardwaremäßige Ansteuerung ja vom Controller vorgegeben ist, aber...

Sofern der Speicher größer oder gleich 64kB ist müsste die Ansteuerung so funktionieren. Bei größerem Speichervolumen als 64kB wird es notwendig Speicherbänke umzuschalten. Und das kann dann von Modul zu Modul unterschiedlich sein, dazu kann ich nichts sagen, da ich ja solch ein Modul nicht verwende. Bei dem Modul aus Deinem Link sind es wohl 2 Bänke je 64kB und die Umschaltung geht über PD7. Wenn der Speicher kleiner ist als 64kB müssen die Linker-Optionen entsprechend angepasst werden.

Gruß,
Ralf

Wenn die Bank-Umschaltung (s. vorige Antwort) gewährleistet ist, sind 128k möglich, dann dürften auch 512k kein Problem sein. Aber der Controller kann immer nur max. 64kB am Stück adressieren, deshalb die Bank-Umschaltung. Und zu beachten ist, dass der interne RAM rd. 8kB des externen RAMs überlagert. Auch hier muss (wenn der volle Zugriff bestehen soll) softwaremäßig zwischem den ersten rd. 8kB internem und externem Speicher umgeschaltet werden.

Gruß,
Ralf

Wie müsste man eine derartige umschaltung umsetzen?
EDIT: Und könnte man die init-Befehle irgentwie in den Bootloader reinkriegen, damit man sich das allokieren im Sketch sparen kann?

Weiß ich nicht genau, ich gehe aber davon aus. Ich weiß aber nicht, was Du damit gewinnen willst, Du sparst lediglich die Zeilen

void initExtSRAM(void) __attribute__((naked, section(".init3")));

void initExtSRAM(void)
{
    MCUCR=0x80;
    XMCRA=0x80;
    XMCRB &=~7 ;
}

in Deinem Programm ein. Speicher musst Du da allozieren, wo Du ihn brauchst, Du musst ja eine Adresse auf den Speicherblock haben. Und eine statische Variable im Boot-Loader bringt Dir in Deinem Programm auch nichts (naja, Du könntest irgendwie die Adresse aus dem Bootloader in Dein Programm übergeben). Aber der Aufwand zur Änderung des Bootloaders usw. ist sicherlich wesentlich höher, als die paar Zeilen Code in Dein Programm einzufügen.

Gruß,
Ralf