diff --git a/libraries/SD_MMC/examples/SD2USBMSC/SD2USBMSC.ino b/libraries/SD_MMC/examples/SD2USBMSC/SD2USBMSC.ino new file mode 100644 index 00000000000..d379e409960 --- /dev/null +++ b/libraries/SD_MMC/examples/SD2USBMSC/SD2USBMSC.ino @@ -0,0 +1,102 @@ +#if !SOC_USB_OTG_SUPPORTED || ARDUINO_USB_MODE +#error Device does not support USB_OTG or native USB CDC/JTAG is selected +#endif + +#include +#include +#include + +// USB Mass Storage Class (MSC) object +USBMSC msc; + +int clk = 36; +int cmd = 35; +int d0 = 37; +int d1 = 38; +int d2 = 33; +int d3 = 34; +bool onebit = true; // set to false for 4-bit. 1-bit will ignore the d1-d3 pins (but d3 must be pulled high) + +static int32_t onWrite(uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) { + uint32_t secSize = SD_MMC.sectorSize(); + if (!secSize) { + return false; // disk error + } + log_v("Write lba: %ld\toffset: %ld\tbufsize: %ld", lba, offset, bufsize); + for (int x = 0; x < bufsize / secSize; x++) { + uint8_t blkbuffer[secSize]; + memcpy(blkbuffer, (uint8_t *)buffer + secSize * x, secSize); + if (!SD_MMC.writeRAW(blkbuffer, lba + x)) { + return false; + } + } + return bufsize; +} + +static int32_t onRead(uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) { + uint32_t secSize = SD_MMC.sectorSize(); + if (!secSize) { + return false; // disk error + } + log_v("Read lba: %ld\toffset: %ld\tbufsize: %ld\tsector: %lu", lba, offset, bufsize, secSize); + for (int x = 0; x < bufsize / secSize; x++) { + if (!SD_MMC.readRAW((uint8_t *)buffer + (x * secSize), lba + x)) { + return false; // outside of volume boundary + } + } + return bufsize; +} + +static bool onStartStop(uint8_t power_condition, bool start, bool load_eject) { + log_i("Start/Stop power: %u\tstart: %d\teject: %d", 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: Serial.println("USB PLUGGED"); break; + case ARDUINO_USB_STOPPED_EVENT: Serial.println("USB UNPLUGGED"); break; + case ARDUINO_USB_SUSPEND_EVENT: Serial.printf("USB SUSPENDED: remote_wakeup_en: %u\n", data->suspend.remote_wakeup_en); break; + case ARDUINO_USB_RESUME_EVENT: Serial.println("USB RESUMED"); break; + + default: break; + } + } +} + +void setup() { + Serial.begin(115200); + Serial.println("Starting Serial"); + + Serial.println("Mounting SDcard"); + SD_MMC.setPins(clk, cmd, d0, d1, d2, d3); + if (!SD_MMC.begin("/sdcard", onebit)) { + Serial.println("Mount Failed"); + return; + } + + Serial.println("Initializing MSC"); + // Initialize USB metadata and callbacks for MSC (Mass Storage Class) + msc.vendorID("ESP32"); + msc.productID("USB_MSC"); + msc.productRevision("1.0"); + msc.onRead(onRead); + msc.onWrite(onWrite); + msc.onStartStop(onStartStop); + msc.mediaPresent(true); + msc.begin(SD_MMC.numSectors(), SD_MMC.sectorSize()); + + Serial.println("Initializing USB"); + + USB.begin(); + USB.onEvent(usbEventCallback); + + Serial.printf("Card Size: %lluMB\n", SD_MMC.totalBytes() / 1024 / 1024); + Serial.printf("Sector: %d\tCount: %d\n", SD_MMC.sectorSize(), SD_MMC.numSectors()); +} + +void loop() { + delay(-1); +} diff --git a/libraries/SD_MMC/examples/SD2USBMSC/ci.json b/libraries/SD_MMC/examples/SD2USBMSC/ci.json new file mode 100644 index 00000000000..2a5ca52e079 --- /dev/null +++ b/libraries/SD_MMC/examples/SD2USBMSC/ci.json @@ -0,0 +1,9 @@ +{ + "targets": { + "esp32": false, + "esp32s2": false, + "esp32c3": false, + "esp32c6": false, + "esp32h2": false + } +} diff --git a/libraries/SD_MMC/src/SD_MMC.cpp b/libraries/SD_MMC/src/SD_MMC.cpp index 18aa9169f59..13e5fcf27fc 100644 --- a/libraries/SD_MMC/src/SD_MMC.cpp +++ b/libraries/SD_MMC/src/SD_MMC.cpp @@ -26,6 +26,8 @@ #include "driver/sdmmc_host.h" #include "driver/sdmmc_defs.h" #include "sdmmc_cmd.h" +#include "diskio_sdmmc.h" +#include "diskio.h" #include "soc/sdmmc_pins.h" #include "ff.h" #include "esp32-hal-periman.h" @@ -191,6 +193,7 @@ bool SDMMCFS::begin(const char *mountpoint, bool mode1bit, bool format_if_mount_ return false; } _impl->mountpoint(mountpoint); + _pdrv = ff_diskio_get_pdrv_card(_card); if (!perimanSetPinBus(_pin_cmd, ESP32_BUS_TYPE_SDMMC_CMD, (void *)(this), -1, -1)) { goto err; @@ -280,5 +283,27 @@ uint64_t SDMMCFS::usedBytes() { return size; } +int SDMMCFS::sectorSize() { + if (!_card) { + return 0; + } + return _card->csd.sector_size; +} + +int SDMMCFS::numSectors() { + if (!_card) { + return 0; + } + return (totalBytes() / _card->csd.sector_size); +} + +bool SDMMCFS::readRAW(uint8_t *buffer, uint32_t sector) { + return (disk_read(_pdrv, buffer, sector, 1) == 0); +} + +bool SDMMCFS::writeRAW(uint8_t *buffer, uint32_t sector) { + return (disk_write(_pdrv, buffer, sector, 1) == 0); +} + SDMMCFS SD_MMC = SDMMCFS(FSImplPtr(new VFSImpl())); #endif /* SOC_SDMMC_HOST_SUPPORTED */ diff --git a/libraries/SD_MMC/src/SD_MMC.h b/libraries/SD_MMC/src/SD_MMC.h index 3a69850470c..a2bc12aed64 100644 --- a/libraries/SD_MMC/src/SD_MMC.h +++ b/libraries/SD_MMC/src/SD_MMC.h @@ -16,7 +16,11 @@ #include "sdkconfig.h" #include "soc/soc_caps.h" -#ifdef SOC_SDMMC_HOST_SUPPORTED +#ifndef SOC_SDMMC_HOST_SUPPORTED +#ifdef ARDUINO +#warning The SDMMC library requires a device with an SDIO Host +#endif +#else #include "FS.h" #include "driver/sdmmc_types.h" @@ -40,6 +44,7 @@ class SDMMCFS : public FS { int8_t _pin_d1 = -1; int8_t _pin_d2 = -1; int8_t _pin_d3 = -1; + uint8_t _pdrv = 0xFF; bool _mode1bit = false; public: @@ -55,6 +60,10 @@ class SDMMCFS : public FS { uint64_t cardSize(); uint64_t totalBytes(); uint64_t usedBytes(); + int sectorSize(); + int numSectors(); + bool readRAW(uint8_t *buffer, uint32_t sector); + bool writeRAW(uint8_t *buffer, uint32_t sector); private: static bool sdmmcDetachBus(void *bus_pointer);