ESP32S-S3-DevkitC-1... Hard work

Hi

I have been playing with a ESP32S-S3-DevkitC-1, and I am finding it ridiculously hard work.
Been trying to add external SPI SPIFFS memory (w25q128fv)

The Espressiff data sheet is a minefield of baffling terminology.. why can't they just stick to Miso, Miso etc
What does Flash/PSRAM SPIQ8 mean?

Finally got it to recognise the external chip, but I have found that many (most) of the serial libraries don't compile or have errors in them.

I have coded at hobby level for 20 years.... so I don't think I am stupid.

I am currently using the Flashdiagnostics example in the <SPIMemory.h> library.
That reads the external chip details, but fails nearly all of the write tests.

So I thought I would get it to read the onboard SPIFFs for a test..... but what pin is CS for the onboard SPIFFs IC? Nowhere to be found.

I just WISH they would think of us non-genius level folk when laying out this stuff.

Eventually, I want to move data from an SD card to the external SPIFFs.... but I am 3 days in and that isn't looking likely

Libraries I have tried:
SparkFun_SPI_SerialFlash - This reads the memory fine, but there are no other examples to try apart from read memory.

Effortless_SPIFFS - No configuration information/options and no examples I can use

Serialflash library - doesn't compile

Adafruit_SPIFlash - Tying this next

Any idea what the CS pin is for the onboard SPIFFS?

SPIMemory - TESTING NOW

Which chips do you use? Eventually you need 4 in parallel for the QSPI variant?

I'm still before using simple SPI, have no special experience with ESP32 yet.

This has been such a pain to work with...

All the libraries I have tried have some kind of issue, or don't have enough information for me to work out how to adapt them to read my external IC.

I am using the default PSI pins for the external SPI chip and this works fine (Mosi 35, Miso 37 and SCK 36). I have CS set up as pin 38.

Pin 34 is the internal CS pin for the SPIFFS onboard... pretty sure of that.

I can read this chip fine using the SparkFun_SPI_SerialFlash library, but there is only a read example.

Effortless_SPIFFS - No configuration options and no examples. Can't get this to work.
Serialflash library - doesn't compile at all
Adafruit_SPIFlash - Doesn't compile
ESPflash - works, but no useful examples and cannot access external SPI
SPIMemory - Not working

I think the best library is likely to be Serialflash, but it throws up the following error, and I am not good enough to work out how to fix it.

C:\Users\steve\AppData\Local\Temp\arduino_modified_sketch_384014\ListFiles.ino: In function 'void setup()':
ListFiles:35:57: error: cannot bind non-const lvalue reference of type 'uint32_t&' {aka 'unsigned int&'} to an rvalue of type 'uint32_t' {aka 'unsigned int'}
     if (SerialFlash.readdir(filename, sizeof(filename), filesize)) {
                                                         ^~~~~~~~
In file included from C:\Users\steve\AppData\Local\Temp\arduino_modified_sketch_384014\ListFiles.ino:1:
C:\Users\steve\Documents\Arduino\libraries\SerialFlash/SerialFlash.h:61:14: note:   initializing argument 3 of 'static bool SerialFlashChip::readdir(char*, uint32_t, uint32_t&)'
  static bool readdir(char *filename, uint32_t strsize, uint32_t &filesize);
              ^~~~~~~
exit status 1
cannot bind non-const lvalue reference of type 'uint32_t&' {aka 'unsigned int&'} to an rvalue of type 'uint32_t' {aka 'unsigned int'}

I don't actually think there is a real onboard 'SPIFFS" , but rather a section of FLASH that is being used for it (with it's lifetime limitations) Hence the different partitioning settings under Tools. SPIFFS goes at the expense of Flash program memory, and you can simply use SPIFFS.h & FS.h
There are examples for that.

Now i know that SPI on a normal ESP32 can be a bit tricky, with pin assignments and all, but it can't be that hard that you wont manage. External SPIFFS (actually one of those "F"s stands for Flash, ) It should be an issue, just keep in mind that you can define any of the pins also to be the SPI port, as long as that doesn't interfere with other assignments (like flash or Serial)

Yes. I don't really know enough to address this.
My coding usually derives from finding an example, and editing that to achieve what I need.

I know my access to the external SPIFFs is working, I can communicate with that IC.

But, I was hoping to use Paul's Serialflash library as it actually has an example of CopyfromSD.

My final goal is to press a button, and upload all data (MP3) from an SD card (which is working fine) to the external SPIFFS memory.

The internal SPIFFS is far too small for meaningful MP3 files.

Then, play them back from the External SPIFFS, rather than the internal one which one of the the Audio.h examples does.

I am finding the ESP32 S3 particularly difficult to work with.

It is a fairly complex machine, but also really powerful. I don't actually have that particular type available to me, just a standard 38-pin esp32 devkit, and i have heard that there are some significant differences, but i don't know exactly which. Is there any reason to use an external SPIFFS over an SD-card, it would be rather easier to get one of them to work first anyway.

What i found here shows that there is 1 SPI port available for general purpose. SPI2. There is no SPI3 on an esp32-S3.
So Try with those pins first to get the SD-card working using the SD examples. If for some reason the unit crashes, it is possible that we need to try other pins. The ESP32 has the possibility of routing peripherals to specific pins. Most Libraries though tend to call SPI.begin() themselves which will revert those assignment to their default. I know that the SD library allows the passing of an SPI object as an argument on initialization.
The code i use for it is this

#define LED_YELLOW 2
#define HSPI_SCK 17
#define HSPI_MISO 16
#define HSPI_MOSI 4
#define SD_CS 15
#define SPI_FRQ 32000000
#define TEST_BLOCKS 4

#include "FS.h"
#include "SD.h"
#include "SPI.h"

SPIClass * hspi = NULL;  // the name of the pointer doesn't actually matter

void setup() {
  Serial.begin(115200);
  pinMode(LED_YELLOW, OUTPUT);
  digitalWrite(LED_YELLOW, LOW);  // active LOW
  hspi = new SPIClass(HSPI); // now on an S3 this should probably be FSPI

  hspi->begin(HSPI_SCK, HSPI_MISO, HSPI_MOSI, SD_CS);
  hspi->setFrequency(SPI_FRQ);
  //hspi->begin();


  if (!SD.begin(SD_CS, *hspi, SPI_FRQ)) {
    Serial.println("Card Mount Failed");
    return;
  }
  uint8_t cardType = SD.cardType();

  if (cardType == CARD_NONE) {
    Serial.println("No SD card attached");
    return;
  }

  Serial.print("SD Card Type: ");
  if (cardType == CARD_MMC) {
    Serial.println("MMC");
  } else if (cardType == CARD_SD) {
    Serial.println("SDSC");
  } else if (cardType == CARD_SDHC) {
    Serial.println("SDHC");
  } else {
    Serial.println("UNKNOWN");
  }

  uint64_t cardSize = SD.cardSize() / (1024 * 1024);
  Serial.printf("SD Card Size: %lluMB\n", cardSize);

  listDir(SD, "/", 0);
  createDir(SD, "/mydir");
  listDir(SD, "/", 0);
  removeDir(SD, "/mydir");
  listDir(SD, "/", 2);
  writeFile(SD, "/hello.txt", "Hello ");
  appendFile(SD, "/hello.txt", "World!\n");
  readFile(SD, "/hello.txt");
  deleteFile(SD, "/foo.txt");
  renameFile(SD, "/hello.txt", "/foo.txt");
  readFile(SD, "/foo.txt");
  testFileIO(SD, "/test.txt");
  Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
  Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
  digitalWrite(LED_YELLOW, HIGH);  // active LOW

}

void loop() {

}

void listDir(fs::FS &fs, const char * dirname, uint8_t levels) {
  Serial.printf("Listing directory: %s\n", dirname);

  File root = fs.open(dirname);
  if (!root) {
    Serial.println("Failed to open directory");
    return;
  }
  if (!root.isDirectory()) {
    Serial.println("Not a directory");
    return;
  }

  File file = root.openNextFile();
  while (file) {
    if (file.isDirectory()) {
      Serial.print("  DIR : ");
      Serial.println(file.name());
      if (levels) {
        listDir(fs, file.name(), levels - 1);
      }
    } else {
      Serial.print("  FILE: ");
      Serial.print(file.name());
      Serial.print("  SIZE: ");
      Serial.println(file.size());
    }
    file = root.openNextFile();
  }
}

void createDir(fs::FS &fs, const char * path) {
  Serial.printf("Creating Dir: %s\n", path);
  if (fs.mkdir(path)) {
    Serial.println("Dir created");
  } else {
    Serial.println("mkdir failed");
  }
}

void removeDir(fs::FS &fs, const char * path) {
  Serial.printf("Removing Dir: %s\n", path);
  if (fs.rmdir(path)) {
    Serial.println("Dir removed");
  } else {
    Serial.println("rmdir failed");
  }
}

void readFile(fs::FS &fs, const char * path) {
  Serial.printf("Reading file: %s\n", path);

  File file = fs.open(path);
  if (!file) {
    Serial.println("Failed to open file for reading");
    return;
  }

  Serial.print("Read from file: ");
  while (file.available()) {
    Serial.write(file.read());
  }
  file.close();
}

void writeFile(fs::FS &fs, const char * path, const char * message) {
  Serial.printf("Writing file: %s\n", path);

  File file = fs.open(path, FILE_WRITE);
  if (!file) {
    Serial.println("Failed to open file for writing");
    return;
  }
  if (file.print(message)) {
    Serial.println("File written");
  } else {
    Serial.println("Write failed");
  }
  file.close();
}

void appendFile(fs::FS &fs, const char * path, const char * message) {
  Serial.printf("Appending to file: %s\n", path);

  File file = fs.open(path, FILE_APPEND);
  if (!file) {
    Serial.println("Failed to open file for appending");
    return;
  }
  if (file.print(message)) {
    Serial.println("Message appended");
  } else {
    Serial.println("Append failed");
  }
  file.close();
}

void renameFile(fs::FS &fs, const char * path1, const char * path2) {
  Serial.printf("Renaming file %s to %s\n", path1, path2);
  if (fs.rename(path1, path2)) {
    Serial.println("File renamed");
  } else {
    Serial.println("Rename failed");
  }
}

void deleteFile(fs::FS &fs, const char * path) {
  Serial.printf("Deleting file: %s\n", path);
  if (fs.remove(path)) {
    Serial.println("File deleted");
  } else {
    Serial.println("Delete failed");
  }
}

void testFileIO(fs::FS &fs, const char * path) {
  File file = fs.open(path);
  static uint8_t buf[512];
  size_t len = 0;
  uint32_t start = millis();
  uint32_t end = start;
  uint32_t ustart = micros();
  uint32_t uend = start;
  if (file) {
    len = file.size();
    size_t flen = len;
    start = millis();
    ustart = micros();
    while (len) {
      size_t toRead = len;
      if (toRead > 512) {
        toRead = 512;
      }
      file.read(buf, toRead);
      len -= toRead;
    }
    uend = micros() - ustart;
    end = millis() - start;
    if (end > 100) Serial.printf("%u bytes read for %u ms\n", flen, end);
    else Serial.printf("%u bytes read for %u us\n", flen, uend);
    file.close();
  } else {
    Serial.println("Failed to open file for reading");
  }


  file = fs.open(path, FILE_WRITE);
  if (!file) {
    Serial.println("Failed to open file for writing");
    return;
  }

  size_t i;
  start = millis();
  ustart = micros();
  for (i = 0; i < TEST_BLOCKS; i++) {
    file.write(buf, 512);
  }
  uend = micros() - ustart;
  end = millis() - start;
  
  if (end > 100) Serial.printf("%u bytes written for %u ms\n", TEST_BLOCKS * 512, end);
  else Serial.printf("%u bytes written for %u us\n", TEST_BLOCKS * 512, uend);

  file.close();
}

You can connect up to 3 devices to the same port so i think it should work in the end, but for the other libraries you may also need to investigate the workings of the function of the class that is being used in the .h & .cpp files (or .hpp etc) to find out what they do and how they do what they do. Most of the libraries do not switch the CS pin for you (actually i haven't found one that does) but hey let's start with one SPI device first.
internal SPIFFS works, but because of it's nature it is also rather slow.

Hi

I have the SD card working fine. Uses the default SPI pins, and it's own CS pin I allocated.
This plays WAVs and MP3's perfect.

The onboard ESP32 SPIFFs plays Wavs and MP3's fine (using example code) as well (but it is very small storage).

So... my end game is to be able to mix Wavs while they play (I have found some examples of this).
Therefore I think this will need to read from a memory chip for speed, as I don't think I can read multiple music files from an SD card.

Plus, I intended to add significant memory for a lot of tracks.

My external SPIFFs memory IC is on the same SPI bus as the SD card.... maybe that is a problem, but I am trying to save as many pins on the ESP32 for other uses as I can.

I have to put the CS pin of the SD card high before I can 'find it' on the SPI bus. The 10K resistor I have pulling the SD card CS pin to 3.3v obviously isn't enough.

I just find the data sheet baffling. WHY they can't use the same terminology for SPI pins as the rest of the world I don't know.

I will keep tinkering, but without a working example to connect to the external SPIFFs chip, I am a bit stumped.
Maybe I will move it over to it's own SPI bus and try that.... but it doesn't fix the SP[ libraries not compiling.

Only other thing it could/probably might be, I am using version 1.8.5 IDE. I HATE the new one and it breaks far too many things. This IDE version is the most useable for my projects.


So... little update.

SPI0 and SPI1 are internal. I knew that and I assume untouchable
SPI2 is apparently SCK = 12, MOSI =11, MISO = 13 and CS = 10.
SPI3 can be assigned to any pins.

NOWHERE in the Goddam PDF.... I had to Google for an hour to find that out.
The pinout has weird names on those pins which I assume is their own design.

There is reference to HSPI and VSPI.... but no idea what they mean. I though HSPI would be Hardware SPI, but it isn't.

But, if I run:

//Find the default SPI pins for your board
//Make sure you have the right board selected in Tools > Boards

#include <SPI.h>

void setup() {
// put your setup code here, to run once:
Serial.begin(115200);

delay(1000);

Serial.println(" ");
Serial.print("MOSI: ");
Serial.println(MOSI);
Serial.print("MISO: ");
Serial.println(MISO);
Serial.print("SCK: ");
Serial.println(SCK);
Serial.print("SS: ");
Serial.println(SS);


Serial.println("Finished");
}

void loop() {
}

It returns SCK = 36, Mosi = 35, Miso = 37 and CS = 34. WTF?
I am using these pins at the moment. Are they SPI2's default pins? Who knows.... How do you identify what SPI you are using?

My brain is fried

More Googling....

SD card pin|ESP32-WROOM pin|ESP32-S3|
D0|GPIO19 (VSPI MISO)|GPIO2|
D3|GPIO5 (CS)|GPIO13|
CLK|GPIO18 (VSPI CLK)|GPIO14|
CMD|GPIO23 (VSPI MOSI)|GPIO17|

GPIO9: FSPIHD (not sure what it stands for)
GPIO10: FSPICS0 (chip select)
GPIO11: FSPID (dual SPI)
GPIO12: FSPICLK (clock)
GPIO13: FSPIQ (quad SPI)
GPIO14: FSPIWP ("write protect")

FSPID is MOSI
FSPIQ is MISO
FSPICS0 is chip select
FSPICLK is the clock.

ESP32 has 4 SPI controllers. They are SPI0、SPI1、SPI2、SPI3.
SPI0 can be used to access to the external storage unit as a fast cache.
SPI1 can be used as the Master host.
SPI2, SPI3 can be used as both Master and Slave.
SPI0 and SPI1 share one BUS prefixed with "SPI", they consist of signals "D, Q, CS0 ~ CS2, CLK, WP, HD",
while SPI2 and SPI3 use BUS prefixed "HSPI" and "VSPI" respectively.

Madness..... PDF is 1500 pages.
https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf

I am still none the wiser on how to use this goddam chip.
I believe my patience has almost expired.

The chip includes more ports than can be brought to pins. It's a matter of the GPIOMUX and other settings which signals are connected to which pin. So it's a matter of the libraries to configure the pins and what functionality they make available. And I fear that some libraries hinder each other, like known from the multiple timer use on the AVR controllers.

Be happy with what the libraries do for you, or try to program yourself all the low level settings and handling of the built-in hardware modules.

I'm about trying various libraries and find out with my scope on which pins (and possibly signal names) the signals appear.

I have now tried all the SPI libaries I can find. Most don't work (for me at least).

Trouble is, I don't understand enough about configuring the SPI pins (apart from the basic SPI.begin pin, pin pin pin) method).

So if the SPI library doesn't have enough information in the examples, I don't know how to change stuff about.

The other issue I am finding is a lot of people are having the same issue with the SPI pins on the S3, and therefore a lot of people are stating incorrect pins/allocations. I have found multiple threads with conflicting info.

This is where I am so far with pin identification. Still not really sure what FSPI, SUBSPI, VSPI etc mean or which SPI ports they relate to.

I’m not sure if I understand what you are trying to do but if it’s to communicate with an external flash like the Winbond series used for program storage you are looking to use QSPI and those are Pins 30,31,34,35 on the ESP32 module. Read the Espressif data on the subject.

QSPI? Oh goody, another new name!
Thank Emily. I have drawn a line under this ESP32 S3. It's just a headache

I also believe HSPI (whatever pins they are on/whatever SPI bus that is), control the WiFi and should be avoided.

I have spent FAR too much time on this in a bid to understand it, and for hobby level chumps like me... I am clearly never going to get it. If it's too hard for these people to stick to some kind of labelling format, then I just will have to find something else to use.

I can probably get it to work, but I don't understand it or the pinouts... and I wanted to understand it.

Shame... nice bit of kit.

PS...
This Wiki is wrong I think for the SPI2 pins...
http://wiki.fluidnc.com/en/hardware/ESP32-S3_Pin_Reference

As i stated before on that ESP32 you have only 1 available

no i guess not, if you have the pin in output mode for sure not, anyway the library should switch the CS pin HIGH on init() setting the pinmode as well, then you have to switch it LOW thereafter before you can use the SPI bus for another device. Best practice is actually set the pinMode for any of the CS pins and set them LOW and start initializations from there.

SPI 3 doesn't exist on an S3.

Yes, also not sure what the H & V stand for but on an S3 there is FSPI which is the VSPI (V = F hmmm)

Also SPI2 can be assigned to any pin

That is unfortunate,
Anyway i shared a link before

So i don't know what you googled, but it does provide the information correctly. The thing about ESP32's is that there are variants that do not all have the same capability.
The thing about double & quad SPI are just using 2 or 4 data pins to transfer more information within the same time, but with the speed supported i can not imagine myself ever using those modes (also you'd need devices that support that)
Anyway i hope you may give it another go.
Use the SPI bus you have (SPI2 or FSPI it is called not sure what the macro is called) If you have the SD-card working all you need to do is control the individual CS pins (which are always free assignable of course as long as the GPIO can be used as output pin.

No SPI3? The datasheet says different...

That link you posted says this...

controller SPI3 can be used for peripherals

Thus, SPI2 (FSPI) and SPI3 can be used as general purpose SPI in RIOT as SPI_DEV(0) and SPI_DEV(1) by defining the symbols SPI0_# and SPI1_#

If I run the standard SPI pin allocation test routine, it reports back those pins I listed above (can't remember what they were). They must be the default SPI pins then, as I never set them

The CS line on the SD card breakout is 10k, and clearly not quite enough. Needs dropping in size.
But, all CS lines get set as outputs and I set them high as a matter of course at the beginning of setup. Why not and it it makes things work.

But... once the SD has been accessed, it's entirely probably the 10k won't pull it back high enough for me to continue to use that SPI bus. BUT... for now, I am not using the SD card anyway (because it works fine). I will change that resistor at some point.

I said 'My external SPIFFs memory IC is on the same SPI bus as the SD card.'
You replied 'As i stated before on that ESP32 you have only 1 available'

What do you mean? I have SPI2 and SPI3 according the to datasheet. SPI0 and SPI1 are internal for Flash and PSRAM.

Or.... am I not understanding something about all these stated SPI3 statements and that is actually doesn't exist?

This is what I mean..... conflicting information all over the place
Thanks for the advice

This can't be right (although you probably know more than me)
Do you mean ESP32 pins 30,31,34,35 or GPIO pins 30,31,34,35?

GPIO35 is broken out, but the rest are not available. So how can that be used to connect to an 'external' flash? Do you mean the factory onboard flash? I am not a using that.

Bedtime...

I got those PIN numbers off the small table on the right of post #10. I assumed those tables were somehow related to your module.

Ok i missed something there, i must have gotten 2 threads mixed up or read something wrong somewhere
I got my code for using 2 different SPI ports with custom pin assignments from here you will need to scroll down a bit.
Main thing is on the board i have with the board definition the Macros HSPI & VSPI are defined, i am just not sure whether that is true for the C3 as well (worth a go though, if it compiles it should work) If not, you may have to search through the core or try things like FSPI.

Ah see this is the issue.... all these chips are different and this one is I believe different to all other ESP32's so far.

I also understand that either HSPI or VSPI was possibly renamed at some point in the PDF.
It mentions FSPI quite a lot, but I can't find reference to what SPI port that is. I think it is SPI2.

SPI0, SPI1, SPI2, SPI3, SPICLK, SPICS0, SPICS1, SPID, SPIQ, SPIWP, SPIHD, FSPI, HSPI, VSPI, FSPIHD,FSPICS0, FSPICLK, FSPID, FSPIQ, FSPIWP, SUBSPICS1, SUBSPIHD, SUBSPICS0, SUBSPICLK, SUBSPIQ, SUBSPIWP, FSPII04, FSPII05, FSPII06, FSPII07, FSPIDQS....

I miss Mosi, Miso, SKC and CS.

This is where I am.... right or not? Yet to be confirmed.

But. I think I need to stop there anyway. Too much time, not enough return from this.

Thanks all

Darn hard to read. I think we can confirm that the pins you are using for the SD card work :wink:

On my board i had issues connecting things to GPIO 12, 13 & 14, hence i opted to re-map.

I see default CS macros & CLK for different ports, but as said, as long as you can find the SPI port, you can map any pin anyway.