Problem reading from SD card directly into PSRAM

Status
Not open for further replies.

jcj83429

Member
Hi,

I'm having trouble reading directly from the SD card into PSRAM. I'm using a Teensy 4.1 with one 8MB PSRAM chip. When I pass a pointer in PSRAM to the FsFile read function, the read would often fail. The same read succeeds reliably when I pass a pointer in the internal RAM. The T4.1 is not connected to anything so it seems that the PSRAM access is interfering with the SD card access. Has anyone seen similar problems? I created a test program to reproduce it.

Code:
#include "SdFat.h"

#define BUFSIZE (256*1024)
#define FILENAME "TESTFILE.BIN"

SdFs sd;
FsFile file;
char itcmBuf[BUFSIZE];
EXTMEM char psramBuf[BUFSIZE];

bool runTest(int variant){
  Serial.print("running variant ");
  Serial.println(variant);
  file.open(FILENAME);
  if(!file){
    Serial.println("file open failed");
    return false;
  }
  int total_bytes_read = 0;
  while(file.available()){
    int bytes_read;
    if(variant == 1){
      bytes_read = file.read(psramBuf, BUFSIZE);
    }else{
      bytes_read = file.read(itcmBuf, BUFSIZE);
    }

    if(bytes_read < 0){
      Serial.print("read failed after ");
      Serial.print(total_bytes_read);
      Serial.println(" bytes");
      file.close();
      return false;
    }else{
      //Serial.println("read ok");
      total_bytes_read += bytes_read;
    }

    if(variant == 3 || variant == 4){
      memcpy(psramBuf, itcmBuf, BUFSIZE);
      if(variant == 4){
        arm_dcache_flush_delete(psramBuf, BUFSIZE);
      }
    }
  }
  Serial.println("reads succeeded");
  file.close();
  return true;
}

void setup() {
  Serial.begin(115200);
  while(!Serial);
  while (!sd.begin(SdioConfig(FIFO_SDIO))) {
    Serial.println("SdFs begin() failed");
  }
  sd.chvol();

  // stress test
  // while(runTest(4));
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println("Select test variant");
  Serial.println("1: SD -> PSRAM");
  Serial.println("2: SD -> ITCM");
  Serial.println("3: SD -> ITCM, ITCM -> PSRAM");
  Serial.println("4: SD -> ITCM, ITCM -> PSRAM with cache flush");
  int variant = 0;
  while(variant == 0){
    while(!Serial.available());
    char c = Serial.read();
    if(c >= '1' && c <= '4'){
      variant = c - '0';  
    }
  }
  runTest(variant);
}

The test has 4 variants:
1: Read from SD to PSRAM. This fails most of the time
2: Read from SD to ITCM. This passes reliably.
3: Read from SD to ITCM then copy to PSRAM. This fails occasionally.
4: Read from SD to ITCM then copy to PSRAM and flush the PSRAM cache. This passes reliably.

Place a large file named TESTFILE.BIN in the root of the SD card and enter the variant in the serial console when prompted.

I'm using Arduino 1.8.13, Teensyduino 1.53 and Bill Greiman's latest SdFat-beta. I tried 2 SD cards (SDXC with EXFAT and SDHC with FAT32) and the result is the same. I don't think it's a problem with the soldering because I tried Paul's PSRAM test and it passed. And I don't think it's a problem with the SD card or the SdFat library either because the reads into ITCM works reliably.
 
Have not seen this noted as done or tried or done it here.

The TeensyDuino 1.54 Beta 5 has integrated a release version ( not Beta ) of the Greiman SdFat to replace the standard SD library.

Not sure that will offer a FIX for the issue - but will lead to repro case for resolution in current code with all code and elements under PJRC control during beta into release of TD 1.54.
 
Also note - there have been posts like "tried Paul's PSRAM test and it passed" - but then other usage fails until solder joints are reflowed or cleaned.

Noted as: "large file named TESTFILE.BIN" - but not how large? 1MB or something closer to 8MB?
 
I can confirm this.
Have you informed Bill Greimann?
He should know, at least, why read returns an error here. Seems to be totally random?
 
I tried reflowing the solder and adding more solder to make sure the connection is good but it didn't fix the problem. I will try the 1.54 beta. Thanks.

I used a file around 100MB.
 
I'm using the beta. Does not help.
Looking the schematic, there are again no pullups on the SD lines..
 
@Frank B: I haven't informed Bill Greimann. I didn't think it's the SdFat library's fault. I will try with the 1.54 beta see if the same thing happens there.
 
Edited the code to work with TD 1.54 b5:
Code:
#include <SD.h>
#include <SPI.h>

// https://forum.pjrc.com/threads/65851-Problem-reading-from-SD-card-directly-into-PSRAM?p=266951&viewfull=1#post266951

#define BUFSIZE (256*1024)
#define FILENAME "TESTFILE.BIN"

// SdFs sd;
[B]File file;[/B]
char itcmBuf[BUFSIZE];
EXTMEM char psramBuf[BUFSIZE];

bool runTest(int variant){
  Serial.print("running variant ");
  Serial.println(variant);
  [B]file = SD.open(FILENAME);[/B]
  if(!file){
    Serial.println("file open failed");
    return false;
  }
  int total_bytes_read = 0;
  while(file.available()){
    int bytes_read;
    if(variant == 1){
      bytes_read = file.read(psramBuf, BUFSIZE);
    }else{
      bytes_read = file.read(itcmBuf, BUFSIZE);
    }

    if(bytes_read < 0){
      Serial.print("read failed after ");
      Serial.print(total_bytes_read);
      Serial.println(" bytes");
      file.close();
      return false;
    }else{
      //Serial.println("read ok");
      total_bytes_read += bytes_read;
    }

    if(variant == 3 || variant == 4){
      memcpy(psramBuf, itcmBuf, BUFSIZE);
      if(variant == 4){
        arm_dcache_flush_delete(psramBuf, BUFSIZE);
      }
    }
  }
  Serial.println("reads succeeded");
  file.close();
  return true;
}

void setup() {
  Serial.begin(115200);
  while(!Serial);
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);

    if (!SD.begin(BUILTIN_SDCARD)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");

  // stress test
  // while(runTest(4));
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println("Select test variant");
  Serial.println("1: SD -> PSRAM");
  Serial.println("2: SD -> ITCM");
  Serial.println("3: SD -> ITCM, ITCM -> PSRAM");
  Serial.println("4: SD -> ITCM, ITCM -> PSRAM with cache flush");
  int variant = 0;
  while(variant == 0){
    while(!Serial.available());
    char c = Serial.read();
    if(c >= '1' && c <= '4'){
      variant = c - '0';  
    }
  }
  runTest(variant);
}

Here shows file size ( I renamed a 2MB ZIP for testfile ). It can work with 'variant 1' - 'variant 4' does not seem to fail.
Code:
Initializing SD card...initialization done.
System Volume Information/
  IndexerVolumeGuid                               76
TESTFILE.BIN                                      2299501
done!

T:\tCode\RAM\SDtoPSRAM\SDtoPSRAM.ino Jan 17 2021 14:00:46
card initialized.
Select test variant
1: SD -> PSRAM
2: SD -> ITCM
3: SD -> ITCM, ITCM -> PSRAM
4: SD -> ITCM, ITCM -> PSRAM with cache flush
running variant 1
read failed after 0 bytes
Select test variant
1: SD -> PSRAM
2: SD -> ITCM
3: SD -> ITCM, ITCM -> PSRAM
4: SD -> ITCM, ITCM -> PSRAM with cache flush
running variant 1
read failed after 524288 bytes
Select test variant
1: SD -> PSRAM
2: SD -> ITCM
3: SD -> ITCM, ITCM -> PSRAM
4: SD -> ITCM, ITCM -> PSRAM with cache flush
[B]running variant 1
reads succeeded
Select test variant
1: SD -> PSRAM
2: SD -> ITCM
3: SD -> ITCM, ITCM -> PSRAM
4: SD -> ITCM, ITCM -> PSRAM with cache flush[/B]
 
The reason for this is patch is a bit complicated.. If the connections have no pullup, they can toggle when the interface pauses. Maybe beacuse lines in the near toggle.
The chance that this happens may increase when the PS-RAM gets accessed..

Of course this is just a shot in the blue.
But it WAS a problem on earlier Teensys and other! MCUs

Bill copied this patch for his library, too. But I'm not that sure that it is still there.. for the new MCUs...
 
Don't know...

And I can't find the old thread :-(
I remember the SD Spec says, the pullups are required. I guess the controller thinks they are there...
The patch was a workaround. And it took me a long time to identify the problem..
 
Closest is the below in : ...\hardware\teensy\avr\libraries\SdFat\src\SdCard\SdioTeensy.cpp
Code:
#elif defined(__IMXRT1062__)
//------------------------------------------------------------------------------
static void gpioMux(uint8_t mode) {
...
 
With IOMUXC_SW_PAD_CTL_PAD_PUS(3), it takes longer to fail but still fails.

edit: This may not be true. I may have just gotten lucky.
 
I think this is the equivalent for T4.1 https://github.com/greiman/SdFat-beta/blob/master/src/SdCard/SdioTeensy.cpp#L308-L309 . IOMUXC_SW_PAD_CTL_PAD_PUS(1) means 47K ohm pullup. I can try IOMUXC_SW_PAD_CTL_PAD_PUS(3) for 22K ohm pullup.

That is in the spot of code noted in p#14.

Those "#if defined(ARDUINO_TEENSY41) " in "static void enableGPIO(bool enable) {" would preclude that from working on Teensy 4.0 with SDIO soldered on - but should use the same code?
 
Sorry too late here - almost midnight - have to work tomorrow.
Again - this is a shot into the blue. I don't know if it is the problem - but for me, it seems not too unlikely.
I can be totally wrong, of course.

Good night.
 
I found the fix. Change
Code:
#if defined(ARDUINO_TEENSY41)
                              IOMUXC_SW_PAD_CTL_PAD_DSE(1) |
to
Code:
#if defined(ARDUINO_TEENSY41)
                              IOMUXC_SW_PAD_CTL_PAD_DSE(6) |
The SD -> PSRAM test case is passing reliably now. I will submit a pull request. Thanks for your suggestion to look in this area.

PR is here: https://github.com/greiman/SdFat-beta/pull/66
 
Last edited:
Indeed that change makes this work in setup():
Code:
	while(runTest(1));

So this need changed and also the :: "#if defined(ARDUINO_TEENSY41) "

Should also include :: #if defined(ARDUINO_TEENSY40)

It won't have PSRAM - but it will need to work when the SDIO pins are wired.
 
Added #ifdef note to the PR on the Greiman repository ... tested compile on T_4.1 - but not to run on T_4.0
 
Tested to work - Using a T_4.0 with loglow/TallDog T_4.0 board PCB to present SDIO pins to an SD socket.

That does not have PSRAM - but with reduced BUFFER it will use processor memory instead when EXTRAM is requested!

With this change to post #9 code above it does work on ALL 4 Variants presented to read from SD - just showing the BUILTIN_SDCARD on T_4.0 is usable!

Code:
#if defined(ARDUINO_TEENSY41)
#define BUFSIZE (256*1024)
#elif defined(ARDUINO_TEENSY40) 
#define BUFSIZE (200*1024)
#endif
 
Status
Not open for further replies.
Back
Top