ESP32-S3 USB MSC with SD-Card
Posted: Tue Apr 04, 2023 12:33 pm
Hi
i've got trouble to run a simple code for an USB-MSC SD-Card with the Native USB of the ESP32-S3. (ESP32-S3-Wroom-1 N16R8)
I use the Arduino Framework wiht the USBMSC Example from arduino-esp32 labrary.
what i got so far is posted below.
What works:
Plugging in a WIN11 computer shows the Files on the SD-Card. read/write and edit small Files works. but if i try to copy bigger files (>10MB) the hole thing gets unstable and disconnects from WIN11...
I could only debug very little things due to Arduino-Framework...
What i see is that the size of the buffer witch is written during the onWrite Callbacks is not 512 Bytes but up to 4096 bytes ... i addressed that in my code.
the secound thing i see is, that an onWrite can occure even if SD-Card is busy ... so i checkt this and wait until SD-Card is not busy anymore bevor i write. and still i get some unstable transfers...
has anyone done this in a stable way?
what am i missing?
help would be apreaciated ...
i've got trouble to run a simple code for an USB-MSC SD-Card with the Native USB of the ESP32-S3. (ESP32-S3-Wroom-1 N16R8)
I use the Arduino Framework wiht the USBMSC Example from arduino-esp32 labrary.
what i got so far is posted below.
What works:
Plugging in a WIN11 computer shows the Files on the SD-Card. read/write and edit small Files works. but if i try to copy bigger files (>10MB) the hole thing gets unstable and disconnects from WIN11...
I could only debug very little things due to Arduino-Framework...
What i see is that the size of the buffer witch is written during the onWrite Callbacks is not 512 Bytes but up to 4096 bytes ... i addressed that in my code.
the secound thing i see is, that an onWrite can occure even if SD-Card is busy ... so i checkt this and wait until SD-Card is not busy anymore bevor i write. and still i get some unstable transfers...
Code: Select all
static int32_t onWrite(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize){
//HWSerial.printf("MSC WRITE: lba: %u, offset: %u, bufsize: %u\n", lba, offset, bufsize);
if(sd.card()->isBusy())
busyCounter++;
//wait Method
while(sd.card()->isBusy());
if(bufsize > DISK_SECTOR_SIZE)
{
writeCounter += bufsize/DISK_SECTOR_SIZE;
return sd.card()->writeSectors( lba, (uint8_t*)buffer, bufsize/DISK_SECTOR_SIZE)? bufsize: -1;
}
else
{
writeCounter++;
return sd.card()->writeSector( lba, (uint8_t*)buffer) ? bufsize : -1;
}
//return bufsize;
}
what am i missing?
help would be apreaciated ...
Code: Select all
#if ARDUINO_USB_MODE
#warning This sketch should be used when USB is in OTG mode
void setup(){}
void loop(){}
#else
#include "USB.h"
#include "USBMSC.h"
#include "SD.h"
#include "SPI.h"
#include "SdFat.h"
#include "Timer.h"
#define SPI_CS 21
#define SPI_MOSI 12
#define SPI_MISO 13
#define SPI_SCK 14
SdFat sd;
Timer timer;
#if ARDUINO_USB_CDC_ON_BOOT
#define HWSerial Serial0
#define USBSerial Serial
#else
#define HWSerial Serial
USBCDC USBSerial;
#endif
USBMSC MSC;
static const uint16_t DISK_SECTOR_SIZE = 512; // Should be 512
static uint32_t sectors = 0;
static uint32_t readCounter, writeCounter, busyCounter = 0;
static int32_t onWrite(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize){
//HWSerial.printf("MSC WRITE: lba: %u, offset: %u, bufsize: %u\n", lba, offset, bufsize);
if(sd.card()->isBusy())
busyCounter++;
//wait Method
while(sd.card()->isBusy());
if(bufsize > DISK_SECTOR_SIZE)
{
writeCounter += bufsize/DISK_SECTOR_SIZE;
return sd.card()->writeSectors( lba, (uint8_t*)buffer, bufsize/DISK_SECTOR_SIZE)? bufsize: -1;
}
else
{
writeCounter++;
return sd.card()->writeSector( lba, (uint8_t*)buffer) ? bufsize : -1;
}
//return bufsize;
}
static int32_t onRead(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize){
//HWSerial.printf("MSC READ: lba: %u, offset: %u, bufsize: %u\n", lba, offset, bufsize);
if(sd.card()->isBusy())
busyCounter++;
while(sd.card()->isBusy());
if(bufsize > DISK_SECTOR_SIZE)
{
readCounter += bufsize/DISK_SECTOR_SIZE;
return sd.card()->readSectors( lba, (uint8_t*)buffer, bufsize/DISK_SECTOR_SIZE)? bufsize: -1;
}
else
{
readCounter++;
return sd.card()->readSector( lba, (uint8_t*)buffer)? bufsize : -1;
}
//return bufsize;
}
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
// used to flush any pending cache.
void sdcard_flush_cb (void)
{
if(sd.card()->isBusy())
busyCounter++;
while(sd.card()->isBusy());
sd.card()->syncDevice();
HWSerial.printf("sdcard_flush_cb");
}
static bool onStartStop(uint8_t power_condition, bool start, bool load_eject){
HWSerial.printf("MSC START/STOP: power: %u, start: %u, eject: %u\n", power_condition, start, load_eject);
return true;
}
static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){
if(event_base == ARDUINO_USB_EVENTS){
arduino_usb_event_data_t * data = (arduino_usb_event_data_t*)event_data;
switch (event_id){
case ARDUINO_USB_STARTED_EVENT:
HWSerial.println("USB PLUGGED");
break;
case ARDUINO_USB_STOPPED_EVENT:
HWSerial.println("USB UNPLUGGED");
break;
case ARDUINO_USB_SUSPEND_EVENT:
HWSerial.printf("USB SUSPENDED: remote_wakeup_en: %u\n", data->suspend.remote_wakeup_en);
break;
case ARDUINO_USB_RESUME_EVENT:
HWSerial.println("USB RESUMED");
break;
default:
break;
}
}
}
void setup() {
HWSerial.begin(115200);
HWSerial.setDebugOutput(true);
//sd
HWSerial.print("SD init ... ");
pinMode(SPI_CS, OUTPUT); digitalWrite(SPI_CS, HIGH);
SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
if(!sd.begin(SPI_CS)) ///, SPI_FULL_SPEED
HWSerial.println("sd.begin() failed ...");
HWSerial.println("done");
sectors = sd.card()->sectorCount();
HWSerial.print("Sectors: ");
HWSerial.println(sectors);
USB.onEvent(usbEventCallback);
MSC.vendorID("USBMSC");//max 8 chars
MSC.productID("USBMSC");//max 16 chars
MSC.productRevision("1.0");//max 4 chars
MSC.onStartStop(onStartStop);
MSC.onRead(onRead);
MSC.onWrite(onWrite);
MSC.mediaPresent(true);
MSC.begin(sectors, DISK_SECTOR_SIZE);
USBSerial.begin();
USB.begin();
timer.every(1000, printReadWriteCounter);
}
void printReadWriteCounter( void )
{
HWSerial.printf("ReadCounter: %d WriteCounter: %d, BusyCounter: %d\r\n", readCounter, writeCounter, busyCounter);
}
void loop() {
// put your main code here, to run repeatedly:
timer.update();
}
#endif /* ARDUINO_USB_MODE */