Reputation: 3095
I need to make it possible to load data from the USB connector onto the HSPI bus of an ESP32S2. I've built the following code, which works well but is very slow:
#ifndef ARDUINO_USB_MODE
#error This ESP32 SoC has no Native USB interface
#elif ARDUINO_USB_MODE == 1
#warning This sketch should be used when USB is in OTG mode
void setup() {}
void loop() {}
#else
#include "FS.h"
#include "SD.h"
#include "SPI.h"
#include "USB.h"
#include "USBMSC.h"
USBMSC MSC;
static const uint16_t DISK_SECTOR_SIZE = 512;
int sck = 14;
int miso = 12;
int mosi = 13;
int cs = 15;
static int32_t onWrite(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize)
{ return SD.writeRAW( (uint8_t*) buffer, lba) ? DISK_SECTOR_SIZE : -1 ; }
static int32_t onRead(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
{ return SD.readRAW( (uint8_t*) buffer, lba) ? DISK_SECTOR_SIZE : -1 ; }
static bool onStartStop(uint8_t power_condition, bool start, bool load_eject) {
// Serial.printf("Start/Stop power: %u\tstart: %d\teject: %d", power_condition, start, load_eject);
return true;
}
void setup() {
static SPIClass* spi = NULL;
spi = new SPIClass(HSPI);
spi->begin(sck, miso, mosi, cs);
if (!SD.begin(cs, *spi, 20000000) {
return;
}
uint8_t cardType = SD.cardType();
if (cardType == CARD_NONE) {
return;
}
MSC.vendorID("ESP32");
MSC.productID("USB_MSC");
MSC.productRevision("1.0");
MSC.onRead(onRead);
MSC.onWrite(onWrite);
MSC.onStartStop(onStartStop);
MSC.mediaPresent(true);
MSC.isWritable(true);
MSC.begin(SD.numSectors(), DISK_SECTOR_SIZE);
USB.begin();
}
void loop() {}
#endif /* ARDUINO_USB_MODE */
I'm not used to USB/SPI programming and I don't know where my mistake is. The data is copied at around 200KB/s, which is enough for my needs, but the MS Windows progress bar pauses for 2-3 seconds every 7% (of a 7MB file). So in the end, the transfer takes a very long time.
I've had a look deeper in SD.h
and the write command finishes in ff_sd_write()
with the count
parameter always set to `1``. So it seems that the writing operations are only called sector by sector, maybe that could be a clue ?
if (count > 1) {
res = sdWriteSectors(pdrv, (const char *)buffer, sector, count) ? RES_OK : RES_ERROR;
} else {
res = sdWriteSector(pdrv, (const char *)buffer, sector) ? RES_OK : RES_ERROR;
}
Anyway, if anyone could help me to avoid these outages (and maybe improve data transfer rate), I'd be very grateful, as I can't see myself asking users to use the box like this...
Thanks
Julien
Upvotes: 0
Views: 35