chegewara / EspTinyUSB

ESP32S2 native USB library. Implemented few common classes, like MIDI, CDC, HID or DFU (update).
MIT License
473 stars 70 forks source link

sd_msc is too slow (200KB/s write, 400KB/s read) #124

Open tueddy opened 1 year ago

tueddy commented 1 year ago

First, thank's for this great library! I've managed to compile & run the sd_msc.ino example on PlatformIO / Lolin-S3 in a few minutes!

I wonder about the transfer speed, can only reach 200KB/s for write and 400KB/s for read, tested on Win11 & MacOS Ventura.

Can this improved? What is the limiting factor? If it is SD-card, can SD_MMC be used?

Thank's Dirk

chegewara commented 1 year ago

Hi, honestly im not sure, but most likely it is SPI and sd card and yes, i think using SD_MMC can improve it.

Currently i am working on new version of library. I am completely refactoring it, to make it compatible with arduino/platformio and esp-idf. Also i want to use more advanced c++ api, not just to make a wrapper around tinyusb.

New library will be easier to implement own usb classes, to use composite devices etc.

I hope it will be better library and more users will find it useful.

tueddy commented 1 year ago

Hi @chegewara,

thank's for your fast response! I've tried to convert to SD_MMC but failed with converting functions SD.readRAW() and SD.writeRAW(). I'm using Arduino ESP32 on PIO.

I've tried MSC RAMDisk also, but could not measure speed due to limited cardsize. The benchmark program needs at least 1MB file..

Looking forward Best Dirk

chegewara commented 1 year ago

I could benchmark ramdisk on ubuntu and you can find results here: https://esp32.com/viewtopic.php?t=15908

tueddy commented 1 year ago

As far as i can see from the benchmarks you reach 6MB/s for RAM-disk and nearly the same values for SD-card access, arround 200KB/s for write, 400-500KB/s for read? So limiting factor must be SD-card access? According to https://www.instructables.com/Select-SD-Interface-for-ESP32/ i use 1-Bit SD-MMC for good performance and minimal hardware: grafik

Is there a simple way to convert to SD_MMC?

chegewara commented 1 year ago

Sorry, but i didnt play with SD_MMC, yet.

JimDrewGH commented 1 year ago

There is a dramatic difference in speed between SPI and SD_MMC modes! It stinks that the ESP32S2 doesn't have a SD_MMC mode, and I didn't realize (until this thread) that the S3 does have the MMC module built in. I am going to have to switch to it. Now, if Espressif would increase their USB interface from Fullspeed (12mbps) to Highspeed (480mbps), that would be huge.

I am getting ~10MB/s reads from a SD card with a standard ESP32 using the SD_MMC module. The bottle neck with the S3 is going to be the USB speed, once you start using the SD_MMC module.

RPdenBoer commented 1 year ago

Following, I'm also wanting to get SD_MMC working

chegewara commented 1 year ago

Nice to see that some of you make use of this library. This gives me motivation to make 2nd, better i hope, version. It is not ready and is in private repo yet, but it will be published with this documentation: https://tinyusb.esp32.eu.org/

Im not sure how to do it, as new library or as replacement of this one, but should be released before end of this year i hope. I can promise it will be very easy to add sd_mmc to list of supported protocols if someone knows how to work with sd_mmc (i dont know yet).

chegewara commented 1 year ago

Well, i have some working code which can run on S3 sd_mmc, but its still just a PoC, and i have to say its not impressive:

image

I think i have to learn about using DMA with sd_mmc.

chegewara commented 1 year ago

Here is benchmark with sd_mmc 1-bit mode

image

For some reason card is working in memory card mode:

Name: SN64G
Type: SDHC/SDXC
Speed: 40 MHz
Size: 60906MB
tueddy commented 1 year ago

Thank's for your benchmark! SD_MMC seems no rocket here, bottleneck seems to be elsewehre?

How have you implemented the replacement for SD.readRAW() and SD.writeRAW()? With sdmmc_read_sectors ?

chegewara commented 1 year ago

Since arduino is backward compatible with esp-idf i am completely replacing arduino-ish code with esp-idf.

            sdmmc_card_t card;
            auto sector_count = bufsize /card.csd.sector_size;
            auto err = sdmmc_write_sectors(&card, buffer, lba, sector_count);
            return bufsize;

Im not sure what is the botleneck, because ramdisk with spiram is speedy, so its not tinyusb nor my code i think. In that case it may be only esp-idf, which is hard to believe.

chegewara commented 1 year ago

One more thing worth to mention. Not only esp32 performance is important here to get better throughput. I have fe USB port on my PC which are hosteb by different chips. When i am using second set of ports (480mbps) i am getting very bad results:

image

I am suspecting it may have something to do with usb driver on my linux, which may not use full potential of BULK endpoints. That could also explain low throughput on write, but here i may be wrong.

chegewara commented 1 year ago

And here is result with sd_mmc on another set of ports:

image

chegewara commented 1 year ago

Even SD_SPI with "better" port is not that bad:

image

RPdenBoer commented 1 year ago

Thanks for looking into this, interesting results. I've previously run simple tests (just regular reads and writes, non-USB) across multiple cards and I'm consistently seeing significantly better performance with SD_MMC. Approx 4x better than SPI with 1-bit SD_MMC and approx 5x better than SPI with 4-bit SD_MMC, which is also consistent with what others seem to be getting. If I remember correctly this was with a buffer size of about 2048 bytes - larger than that makes minimal difference but smaller can be a fair bit slower. You almost certainly already know all this; just confirming for clarity. Not sure what's contributing to disappointing results you're seeing in this scenario unfortunately. I'm happy to test your code on my machine/chip/ports if that's helpful?

tueddy commented 1 year ago

For SD-card speed i can confirm the results of this article:

Best choice for minimal wiring/no pullups is 1-Bit mode. 4 Bit mode has issues in S3 currently, will be fixed very late in Arduino 3.0. So i recommend moving forward with SD_MMC 1 bit..

I'm contributing to a Kids MP3.Player project, here we have a highly optimized Web upload to SD card reaching 300-400 KB/s. Maybe splitting USB/SD part into 2 separate tasks using a ringbuffer brings the speed rocket? Relevant code is here. Maybe this can speedup USB/MSC also?

Looking forward for testing your new code..

chegewara commented 1 year ago

Im not using arduino SD_MMC library, so im not sure my results are affected by it. For SD_MMC speed, it is USB speed limit, thats why its just a bit faster than SPI mode, and its about 800-1000kB/s.

I have some small read/write cache using PSRAM, but i didnt test it too much so far, and it requires a bit more work, and i am still learning "good" programming style.

In general my conclusion is that we can achieve read speed 800+kB/s and write speed 600+kB/s over USB, just sometimes the problem is on host device (different ports on PC giving different results with the same firmware).

Im glad you are interested in this new code and i will publish it soon, but its still a bit messy, because i am playing with different options to get better results.

tueddy commented 1 year ago

I've tested your new library and get same speed measurements for SD_MMC in 1 Bit mode. Reading spead about 800KB/s, writing 600 KB/s, thank's for improvement!

I have tested on Win7/11 and MacOS. SD card recognition is very slow in Exlorer/Finder. In Win 11 i get a deactivated device now in device manager. Writing on SD card feels slow as before. Do you have any idea how to improve (USB speed?) or has it to be done by Espressif in IDF?

Anywhere, thank's for your effort! Dirk

chegewara commented 1 year ago

Just make sure you are using USB 3 port on PC. I dont know why, but on USB 2 high speed port the writing speed is about 200kB/s. Its probably how drivers handle bulk timing.