Forum: Mikrocontroller und Digitale Elektronik ESP32 Wrover 4MB SPI-RAM mit Arduino nutzen


von ESP-User (Gast)


Lesenswert?

Hallo, ich versuche bei einem ESP32 Wrover Modul die externen 4MByte 
SPI-RAM zu nutzen. Dies gelingt mir leider nicht.

Gemäß Espressif Doku kann das RAM grundsätzlich in unterschiedlichen 
Betriebsarten genutzt werden, wenn man die Espressif Toolchain nutzt. 
Ich nutze aber die Arduino IDE. Da kann ich wohl nichts einstellen.

Die Programmzeile
1
Serial.printf("\n%d Bytes free.\n\n", ESP.getFreeHeap());
gibt folgendes aus:
1
291352 Bytes free.

Das ist nur das interne RAM. Ich nehme an, dass ich das SPI-RAM nur über 
direkten Adresszugriff ab Adresse 0x3F80000 nutzen kann.

Hier ein kleines Testprogramm:
1
#define SPIRAM ((byte*)0x3F800000)
2
3
void setup() {
4
  Serial.begin(115200);
5
  // Free Memory
6
  Serial.printf("\n%d Bytes free.\n\n", ESP.getFreeHeap());
7
  // test SPI RAM
8
  Serial.print("Test 128B:"); testram(128);
9
  Serial.print("Test 256B:"); testram(256);
10
  Serial.print("Test  1KB:"); testram(1024);
11
  Serial.print("Test 16KB:"); testram(16*1024);
12
  Serial.print("Test 64KB:"); testram(64*1024);
13
  Serial.print("Test  1MB:"); testram(1*1024*1024);
14
  Serial.print("Test  4MB:"); testram(4*1024*1024);
15
}
16
17
void loop() {
18
}
19
20
void testram(int ramSize) {
21
  // Test SPI-RAM: write
22
  for(int i=0; i<(ramSize); i++) {
23
    SPIRAM[i] = (0xA5-i) & 0xFF;
24
  }
25
  // Test SPI-RAM: verify
26
  int e = 0;
27
  for(int i=0; i<(ramSize); i++) {
28
    if(SPIRAM[i] != (0xA5-i) & 0xFF) e++;
29
  }
30
  Serial.printf(" %7d Bytes: %7d OK, %7d Errors.\n",ramSize,ramSize-e,e);
31
}


Wenn ich mehr als 128 Bytes nutze, geht es in die Hose.
1
//  291352 Bytes free.
2
//  
3
//  Test 128B:     128 Bytes:     128 OK,       0 Errors.
4
//  Test 256B:     256 Bytes:     166 OK,      90 Errors.
5
//  Test  1KB:    1024 Bytes:     166 OK,     858 Errors.
6
//  Test 16KB:   16384 Bytes:     166 OK,   16218 Errors.
7
//  Test 64KB:   65536 Bytes:       1 OK,   65535 Errors.
8
//  Test  1MB: 1048576 Bytes:       1 OK, 1048575 Errors.
9
//  Test  4MB: 4194304 Bytes:       1 OK, 4194303 Errors.

Frage:

Ist es jemand schon gelungen, den SPI-RAM mit der Arduino IDE zu nutzen?
Wo liegt mein Fehler?

Ich nutze einen Odroid Go, in dem das Wrover Modul sitzt.

Vielen Dank für Tipps.

von K. S. (the_yrr)


Lesenswert?

ESP-User schrieb:
> Das ist nur das interne RAM. Ich nehme an, dass ich das SPI-RAM nur über
> direkten Adresszugriff ab Adresse 0x3F80000 nutzen kann.
wieso sollte das so drekt gehen, muss da nichts initialisiert werden?

ESP-User schrieb:
> Gemäß Espressif Doku kann das RAM grundsätzlich in unterschiedlichen
> Betriebsarten genutzt werden, wenn man die Espressif Toolchain nutzt.
hast du mal Beispielcode dafür? ich denke da fehlt noch was damit das 
funktioniert, der Controller wüsste vllt. gerne dass du versuchst RAM zu 
mappen und nicht Flash oder vllt. irgendeinen Sensor.

in deinem Beispielcode schreibst du einfach an die Adresse
> #define SPIRAM ((byte*)0x3F800000)
ohne den SPI zu initialisieren? ich denke das solltest du tun. eventuell 
schreibst du zur Zeit nur in den Cache für den externen Ram, ohne dass 
dieser verwendet wird.

poste mal Beispielcode für Espressif.

von K. S. (the_yrr)


Lesenswert?

lies mal hier
https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/external-ram.html
https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/kconfig.html#config-spiram-use

Du machst grade "ich hab nen Arduino auf nen Wecker geklebt, warum weiß 
der nicht wie spät es ist"

da muss alles konfiguriert werden und der RAM dann auch gemappt werden, 
dass musst du alles selber machen.

Datenblatt:
Accesses to the external flash and external SPI RAM are done through a 
cache and are also handled by an MMU. This Cache MMU can apply different 
mappings, depending on the PID of the process as well as the CPU the 
process is running on.
die MMU für den externen Speicher solltest du auch konfigurieren, 
entweder gibts da was fertiges oder es heißt Datenblatt lesen (nur die 
paar duzend interessanten Seiten, nicht alle <700) und alle register 
selber schreiben.

von Weihnachtsmann (Gast)


Lesenswert?

ESP-User schrieb:
> Hallo, ich versuche bei einem ESP32 Wrover Modul die externen 4MByte
> SPI-RAM zu nutzen. Dies gelingt mir leider nicht.
>
> Gemäß Espressif Doku kann das RAM grundsätzlich in unterschiedlichen
> Betriebsarten genutzt werden, wenn man die Espressif Toolchain nutzt.
> Ich nutze aber die Arduino IDE. Da kann ich wohl nichts einstellen.
>
> Die Programmzeile
>
1
Serial.printf("\n%d Bytes free.\n\n", ESP.getFreeHeap());
> gibt folgendes aus:
>
1
291352 Bytes free.


Lass Dich vom Unsinn, den K.S. geschrieben hat, nicht verwirren. Ist 
vermutlich die zu hohe Dosis Weihnachtspunsch.

Du solltest die Arduino-Version prüfen. In den korrekten Versionen wird 
der PSRAM automatisch eingebunden, wenn er beim Booten erkannt wird.
ESP.getFreeHeap() sollte den gesamten RAM dann auch anzeigen.

Probier mal eine andere Arduino-Version aus.

von Weihnachtsmann (Gast)


Lesenswert?

Reservier zum Testen einfach mal 1MB RAM mit ps_malloc.

von Weihnachtsmann (Gast)


Lesenswert?

Sorry, da hat sich in der Zwischenzeit was geändert. Das PSRAM wird 
nicht mehr zum Heap dazugenommen. Der Zugriff geht nur noch über 
ps_malloc:
https://github.com/espressif/arduino-esp32/issues/2226

von ESP-User (Gast)


Lesenswert?

Vielen Dank schonmal an alle Helfer.

ps_malloc funktioniert leider nicht, oder vielleicht nutze ich es 
falsch.
1
const int N = 128*1024;
2
byte* buff;
3
  if (buff = (byte*)ps_malloc(sizeof(byte)*N)) 
4
    Serial.println("ps_malloc succeeded");
5
  else
6
    Serial.println("ps_malloc failed");
Ergibt
1
-> ps_malloc failed

Hier nochmal mein geändertes Testprogramm:
1
//  291352 Bytes free.
2
//  
3
//  Test 128B:     128 Bytes:     128 OK,       0 Errors.
4
//  Test 256B:     256 Bytes:     166 OK,      90 Errors.
5
//  Test  1KB:    1024 Bytes:     166 OK,     858 Errors.
6
//  Test 16KB:   16384 Bytes:     166 OK,   16218 Errors.
7
//  Test 64KB:   65536 Bytes:       1 OK,   65535 Errors.
8
//  Test  1MB: 1048576 Bytes:       1 OK, 1048575 Errors.
9
//  Test  4MB: 4194304 Bytes:       1 OK, 4194303 Errors.
10
11
#define SPIRAM ((byte*)0x3F800000)
12
13
const int N = 128*1024;
14
byte* buff;
15
16
void setup() {
17
  Serial.begin(115200);
18
  // Free Memory
19
  Serial.printf("\n%d Bytes free.\n\n", ESP.getFreeHeap());
20
  // ps_malloc
21
  if (buff = (byte*)ps_malloc(sizeof(byte)*N)) 
22
    Serial.println("ps_malloc succeeded");
23
  else
24
    Serial.println("ps_malloc failed");
25
  // heap_caps_malloc
26
  if (buff = (byte*)heap_caps_malloc(sizeof(byte)*N, MALLOC_CAP_8BIT))
27
    Serial.println("heap_caps_malloc succeeded");
28
  else
29
    Serial.println("heap_caps_malloc failed");
30
  // heap_info
31
  Serial.println("\nheap_info");
32
  heap_caps_print_heap_info(MALLOC_CAP_8BIT);
33
  Serial.println();
34
    
35
 
36
  // test SPI RAM
37
  Serial.print("Test 128B:"); testram(128);
38
//  Serial.print("Test 256B:"); testram(256);
39
//  Serial.print("Test  1KB:"); testram(1024);
40
//  Serial.print("Test 16KB:"); testram(16*1024);
41
//  Serial.print("Test 64KB:"); testram(64*1024);
42
  Serial.print("Test  1MB:"); testram(1*1024*1024);
43
  Serial.print("Test  4MB:"); testram(4*1024*1024);
44
}
45
46
void loop() {
47
}
48
49
void testram(int ramSize) {
50
  // Test SPI-RAM: write
51
  for(int i=0; i<(ramSize); i++) {
52
    SPIRAM[i] = (0xA5-i) & 0xFF;
53
  }
54
  // Test SPI-RAM: verify
55
  int e = 0;
56
  for(int i=0; i<(ramSize); i++) {
57
    if(SPIRAM[i] != (0xA5-i) & 0xFF) e++;
58
  }
59
  Serial.printf(" %7d Bytes: %7d OK, %7d Errors.\n",ramSize,ramSize-e,e);
60
}

Und hier die Ausgabe:
1
291344 Bytes free.
2
3
ps_malloc failed
4
heap_caps_malloc failed
5
6
heap_info
7
Heap summary for capabilities 0x00000004:
8
  At 0x3ffb0000 len 65536 free 56072 allocated 9272 min_free 56072
9
    largest_free_block 56072 alloc_blocks 9 free_blocks 1 total_blocks 10
10
  At 0x3ffae6e0 len 6192 free 6092 allocated 36 min_free 6092
11
    largest_free_block 6092 alloc_blocks 1 free_blocks 1 total_blocks 2
12
  At 0x3ffaff10 len 240 free 0 allocated 180 min_free 0
13
    largest_free_block 0 alloc_blocks 1 free_blocks 1 total_blocks 2
14
  At 0x3ffc3650 len 117168 free 99804 allocated 16312 min_free 93984
15
    largest_free_block 93932 alloc_blocks 62 free_blocks 4 total_blocks 66
16
  At 0x3ffe0440 len 15296 free 15248 allocated 0 min_free 15248
17
    largest_free_block 15248 alloc_blocks 0 free_blocks 1 total_blocks 1
18
  At 0x3ffe4350 len 113840 free 113792 allocated 0 min_free 113792
19
    largest_free_block 113792 alloc_blocks 0 free_blocks 1 total_blocks 1
20
  Totals:
21
    free 291008 allocated 25800 min_free 285188 largest_free_block 113792
22
23
Test 128B:     128 Bytes:     128 OK,       0 Errors.
24
Test  1MB: 1048576 Bytes:       1 OK, 1048575 Errors.
25
Test  4MB: 4194304 Bytes:       1 OK, 4194303 Errors.

von ESP-User (Gast)


Lesenswert?

Weihnachtsmann schrieb:
> Du solltest die Arduino-Version prüfen.

Ich nutze derzeit Version 1.8.5. Werde mal nach einem Update suchen und 
dann nochmal probieren.

von Michael U. (amiga)


Lesenswert?

Hallo,

beim Odroid Go nicht den Odroid als Board einstellen sondern entweder 
ESP32 Wrover oder ESP32 Devkit und dort PSRAM enable.
Warum die boards.txt beim OdriodGo bzw. auch beim M5Stack da falsch ist, 
wissen nur die Götter. Ich nutze auf dem Odroid Go den PSRAM als Buffer 
für MP3-Streamplay.
Initalisiert werden muß dann nichts, ps_malloc() geht dann problemlos.
Für die heap-Einbindung muß vermutlich noch was in der 
ArduinoIDE/boards.txt/Partitiontable beim ESP32 angepasst werden, habe 
ich aber bisher nicht weiter verfolgt.

IDE hier 1.8.7 / 1.8.8 und ESP32 Boardmanagerversion 1.0.0.

Gruß aus Berlin
Michael

von ESP-User (Gast)


Lesenswert?

Michael U. schrieb:
> Hallo,
>
> beim Odroid Go nicht den Odroid als Board einstellen sondern entweder

Vielen Dank, Problem ist gelöst.
Update der IDE auf die neue 1.8.8 brachte keine Veränderung.
Nach Umstellung des Boards lief es.


Ursprünglich hatte ich ODROID ESP32 eingestellt, da ich den ODROID GO 
verwende.
1
Board: ODROID ESP32
2
291344 Bytes free.
3
ps_malloc failed
4
heap_caps_malloc failed


ESP32 Wrover Module geht.
1
Board: ESP32 Wrover Module
2
4480504 Bytes free.
3
ps_malloc succeeded
4
heap_caps_malloc succeeded


ESP32 Dev Module geht auch
1
Board: ESP32 Dev Module
2
PSRAM enabled
3
4480504 Bytes free.
4
ps_malloc succeeded
5
heap_caps_malloc succeeded

von ESP-User (Gast)


Angehängte Dateien:

Lesenswert?

Nachtrag:

Ich verwende jetzt die Board-Einstellung "ESP32 Dev Module" mit PSRAM 
enabled (siehe Screenshot). Das läuft soweit.

Jedoch funktionierte der Zugriff auf die SD-Karte nicht mehr und ich 
konnte keine Grafiken mehr auf das Display laden.


Konnte das Porblem lösen indem ich im Sourcecode
1
  SD.begin()

durch
1
  SD.begin(22)

ersetzte.

von ESP-User (Gast)


Lesenswert?

Noch ein Nachtrag:

Die Konstante LED_BUILTIN ist beim Board ESP32 Dev Module nicht 
definiert.

Folgenden Zeilen beheben dies:
1
// ODROID GO LED_BUILTIN
2
#ifndef LED_BUILTIN
3
#define LED_BUILTIN 2
4
#endif

von Michael U. (amiga)


Lesenswert?

Hallo,

SD.begin(22) ist richtig, CS_00 vom SPI liegt auf dem 
Erweiterungsstecker, CS_01 wird für die SD-Card benutzt.
Da ich das OdroidGo-Arduino-Paket ohnhin nur für wenihe Tests genutzt 
habe, mußte ich es ohnehin immer angeben. Die LIbs in dem Paket sind 
großtenteils Anleihen bzw. Anpassungen existierenden Libs, wo nur 
sozusagen ein Wrapper und ein paar Definitionen rübergelegt wurde. Sie 
sind auch nahezu identisch zum M5Stack-Paket.
Ich nutze, wie sonst auch, TFT_eSPI für das Display, ausgeliehen habe 
ich mir nur die Button-Lib, weil ich zu faul war, die Analogabfrage des 
Steuerkreuzes selber irgendwo einzubauen.
Der eingebaute Lautsprecher ist auch so eine Sache: der Verstärker hängt 
an Pin 25 und 26. Das sind auch die internen DAC des ESP32. Leider ist 
Pin 25 aber mit Shutdown des Verstärkers verbunden, will also Low um den 
Verstärker einzuschalten. Direkt Ausgabe an den DAC auf Pin 26 geht zwar 
und wird von Odroid Go genutzt, die Einbindung der ESP8266 Lib mit 
I2S-Ausgabe an den internen DAC ist mir aber noch nicht gelungen.

Ist nicht wirklich wichtig, ist ja sowieso keine HiFi-Box. ;-)

Pin 2 von der LED habe ich zusätzlich noch mit dem freien Pin 9 der 
Erweiterungsleiste verbunden, weil ich für Spielerein noch einen 
zusätzlichen IO haben wollte.

Gruß aus Berlin
Michael

: Bearbeitet durch User
von Stefan L. (Gast)


Lesenswert?

Hallo,

entschuldigt bitte das ich den älteren Thread wieder hervorkrame.
Ich habe einen M5Stack Fire mit PSRAM.
Den ZusatzRAM kann ich leider nicht ansprechen.

Die Ausgabe mit dem keinen Programm schaut für mich auch seltsam aus:
1
369696 Bytes free.
2
3
ps_malloc succeeded
4
heap_caps_malloc succeeded
5
6
heap_info
7
Heap summary for capabilities 0x00000004:
8
  At 0x3ffbdb28 len 52 free 4 allocated 0 min_free 4
9
    largest_free_block 4 alloc_blocks 0 free_blocks 1 total_blocks 1
10
  At 0x3ffb8000 len 6688 free 5256 allocated 1208 min_free 5256
11
    largest_free_block 5256 alloc_blocks 11 free_blocks 1 total_blocks 12
12
  At 0x3ffb0000 len 25480 free 17172 allocated 8228 min_free 17172
13
    largest_free_block 17172 alloc_blocks 2 free_blocks 1 total_blocks 3
14
  At 0x3ffae6e0 len 6192 free 6092 allocated 36 min_free 6092
15
    largest_free_block 6092 alloc_blocks 1 free_blocks 1 total_blocks 2
16
  At 0x3f800000 len 4194303 free 3932076 allocated 262144 min_free 3932076
17
    largest_free_block 3932076 alloc_blocks 2 free_blocks 1 total_blocks 3
18
  At 0x3ffaff10 len 240 free 0 allocated 120 min_free 0
19
    largest_free_block 0 alloc_blocks 5 free_blocks 1 total_blocks 6
20
  At 0x3ffb6388 len 7288 free 0 allocated 6800 min_free 0
21
    largest_free_block 0 alloc_blocks 28 free_blocks 1 total_blocks 29
22
  At 0x3ffb9a20 len 16648 free 6188 allocated 9876 min_free 40
23
    largest_free_block 6136 alloc_blocks 33 free_blocks 3 total_blocks 36
24
  At 0x3ffc0e50 len 127408 free 127360 allocated 0 min_free 127008
25
    largest_free_block 127360 alloc_blocks 0 free_blocks 1 total_blocks 1
26
  At 0x3ffe0440 len 15072 free 15024 allocated 0 min_free 15024
27
    largest_free_block 15024 alloc_blocks 0 free_blocks 1 total_blocks 1
28
  At 0x3ffe4350 len 113840 free 113792 allocated 0 min_free 113792
29
    largest_free_block 113792 alloc_blocks 0 free_blocks 1 total_blocks 1
30
  Totals:
31
    free 4222964 allocated 288412 min_free 4216464 largest_free_block 3932076
32
33
Test 128B:     128 Bytes:     128 OK,       0 Errors.
34
Test 256B:     256 Bytes:     166 OK,      90 Errors.
35
Test  1KB:    1024 Bytes:     166 OK,     858 Errors.
36
Test 16KB:   16384 Bytes:     166 OK,   16218 Errors.
37
Test 64KB:   65536 Bytes:     166 OK,   65370 Errors.
38
Test  1MB: 1048576 Bytes:     166 OK, 1048410 Errors.
39
Test  4MB: 4194304 Bytes:     166 OK, 4194138 Errors.

Kann sich das einer erklären, das sowohl ps_malloc als auch 
heap_caps_malloc initialisiert werden kann, aber dann nicht 
angesprochen?

Arduino IDE habe ich auf 1.8.8 Aktualisiert.
ESP32 Board Version ist die 1.0.1
Als Board habe ich ESP32 Dev Module mit PSRAM Enabled ausgewählt.

Vielen Dank für eure Unterstützung

Stefan

von holger (Gast)


Lesenswert?

Hi,

Ich habe das auch mal getestet … (jetzt geht es) manchmal liegt der 
Fehler
auch ganz wo anders..
mir ist aufgefallen 166 Bytes ok  getestet mit "(0xA5-i) & 0xFF" ..
0xA5 = 165 dezimal  das war mir zu merkwürdig als nur Zufall zu sein.

habe das mal geändert auf

byte fill;
  for (uint i = 0; i<(ramSize); i++) {

    fill = (i ^ maske);
    data[i] = fill;
  }

zu prüfen dann...

byte compare;
  for (uint i = 0; i<(ramSize); i++) {

    compare = (i ^ maske);
    if (data[i] != compare) e++;
  }


und alles rennt..

von holger (Gast)


Lesenswert?

das sieht dann so aus

void ramtest(int ramSize,byte maske) {

  GO.lcd.setTextColor(WHITE, BLACK);
  GO.lcd.setCursor(0, 0);
  GO.lcd.fillScreen(BLACK);
  GO.lcd.setTextSize(1);

  GO.lcd.printf(" %7d Bytes: fuellen \r\n", ramSize);
  Serial.printf(" %7d Bytes: fuellen \r\n", ramSize);

  byte fill;
  for (uint i = 0; i<(ramSize); i++) {

    fill = (i ^ maske);
    data[i] = fill;
  }

  GO.lcd.printf(" %7d Bytes: starte Pruefen \r\n", ramSize);
  Serial.printf(" %7d Bytes: starte Pruefen \r\n", ramSize);

  uint e = 0;
  byte compare;
  for (uint i = 0; i<(ramSize); i++) {

    compare = (i ^ maske);
    if (data[i] != compare) e++;
  }

  GO.lcd.printf(" %7d Bytes: %7d OK, %7d bad.\r\n", ramSize, ramSize - 
e, e);
  Serial.printf(" %7d Bytes: %7d OK, %7d bad.\r\n", ramSize, ramSize - 
e, e);

}

void loop() {


  ramtest(4000000, 0xDE);
  delay(5000);
  ramtest(4000000, 0xAA);
  delay(5000);
  ramtest(4000000, 0x00);
  delay(5000);

}

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.