diff --git a/boards.txt b/boards.txt
index 65074d3a9f..a91fa61206 100644
--- a/boards.txt
+++ b/boards.txt
@@ -2325,6 +2325,8 @@ Nucleo_144.menu.usb.CDCgen=CDC (generic 'Serial' supersede U(S)ART)
 Nucleo_144.menu.usb.CDCgen.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC
 Nucleo_144.menu.usb.CDC=CDC (no generic 'Serial')
 Nucleo_144.menu.usb.CDC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC -DDISABLE_GENERIC_SERIALUSB
+Nucleo_144.menu.usb.CDC_MSC=CDC + MSC
+Nucleo_144.menu.usb.CDC_MSC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC_MSC
 Nucleo_144.menu.usb.HID=HID (keyboard and mouse)
 Nucleo_144.menu.usb.HID.build.enable_usb={build.usb_flags} -DUSBD_USE_HID_COMPOSITE
 Nucleo_144.menu.xusb.FS=Low/Full Speed
@@ -2338,6 +2340,8 @@ Nucleo_64.menu.usb.CDCgen=CDC (generic 'Serial' supersede U(S)ART)
 Nucleo_64.menu.usb.CDCgen.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC
 Nucleo_64.menu.usb.CDC=CDC (no generic 'Serial')
 Nucleo_64.menu.usb.CDC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC -DDISABLE_GENERIC_SERIALUSB
+Nucleo_64.menu.usb.CDC_MSC=CDC + MSC
+Nucleo_64.menu.usb.CDC_MSC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC_MSC
 Nucleo_64.menu.usb.HID=HID (keyboard and mouse)
 Nucleo_64.menu.usb.HID.build.enable_usb={build.usb_flags} -DUSBD_USE_HID_COMPOSITE
 Nucleo_64.menu.xusb.FS=Low/Full Speed
@@ -2351,6 +2355,8 @@ Nucleo_32.menu.usb.CDCgen=CDC (generic 'Serial' supersede U(S)ART)
 Nucleo_32.menu.usb.CDCgen.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC
 Nucleo_32.menu.usb.CDC=CDC (no generic 'Serial')
 Nucleo_32.menu.usb.CDC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC -DDISABLE_GENERIC_SERIALUSB
+Nucleo_32.menu.usb.CDC_MSC=CDC + MSC
+Nucleo_32.menu.usb.CDC_MSC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC_MSC
 Nucleo_32.menu.usb.HID=HID (keyboard and mouse)
 Nucleo_32.menu.usb.HID.build.enable_usb={build.usb_flags} -DUSBD_USE_HID_COMPOSITE
 Nucleo_32.menu.xusb.FS=Low/Full Speed
@@ -2364,6 +2370,8 @@ Disco.menu.usb.CDCgen=CDC (generic 'Serial' supersede U(S)ART)
 Disco.menu.usb.CDCgen.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC
 Disco.menu.usb.CDC=CDC (no generic 'Serial')
 Disco.menu.usb.CDC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC -DDISABLE_GENERIC_SERIALUSB
+Disco.menu.usb.CDC_MSC=CDC + MSC
+Disco.menu.usb.CDC_MSC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC_MSC
 Disco.menu.usb.HID=HID (keyboard and mouse)
 Disco.menu.usb.HID.build.enable_usb={build.usb_flags} -DUSBD_USE_HID_COMPOSITE
 Disco.menu.xusb.FS=Low/Full Speed
@@ -2377,6 +2385,8 @@ Eval.menu.usb.CDCgen=CDC (generic 'Serial' supersede U(S)ART)
 Eval.menu.usb.CDCgen.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC
 Eval.menu.usb.CDC=CDC (no generic 'Serial')
 Eval.menu.usb.CDC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC -DDISABLE_GENERIC_SERIALUSB
+Eval.menu.usb.CDC_MSC=CDC + MSC
+Eval.menu.usb.CDC_MSC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC_MSC
 Eval.menu.usb.HID=HID (keyboard and mouse)
 Eval.menu.usb.HID.build.enable_usb={build.usb_flags} -DUSBD_USE_HID_COMPOSITE
 Eval.menu.xusb.FS=Low/Full Speed
@@ -2390,6 +2400,8 @@ GenF1.menu.usb.CDCgen=CDC (generic 'Serial' supersede U(S)ART)
 GenF1.menu.usb.CDCgen.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC
 GenF1.menu.usb.CDC=CDC (no generic 'Serial')
 GenF1.menu.usb.CDC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC -DDISABLE_GENERIC_SERIALUSB
+GenF1.menu.usb.CDC_MSC=CDC + MSC
+GenF1.menu.usb.CDC_MSC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC_MSC
 GenF1.menu.usb.HID=HID (keyboard and mouse)
 GenF1.menu.usb.HID.build.enable_usb={build.usb_flags} -DUSBD_USE_HID_COMPOSITE
 GenF1.menu.xusb.FS=Low/Full Speed
@@ -2403,6 +2415,8 @@ GenF3.menu.usb.CDCgen=CDC (generic 'Serial' supersede U(S)ART)
 GenF3.menu.usb.CDCgen.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC
 GenF3.menu.usb.CDC=CDC (no generic 'Serial')
 GenF3.menu.usb.CDC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC -DDISABLE_GENERIC_SERIALUSB
+GenF3.menu.usb.CDC_MSC=CDC + MSC
+GenF3.menu.usb.CDC_MSC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC_MSC
 GenF3.menu.usb.HID=HID (keyboard and mouse)
 GenF3.menu.usb.HID.build.enable_usb={build.usb_flags} -DUSBD_USE_HID_COMPOSITE
 GenF3.menu.xusb.FS=Low/Full Speed
@@ -2416,6 +2430,8 @@ GenF4.menu.usb.CDCgen=CDC (generic 'Serial' supersede U(S)ART)
 GenF4.menu.usb.CDCgen.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC
 GenF4.menu.usb.CDC=CDC (no generic 'Serial')
 GenF4.menu.usb.CDC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC -DDISABLE_GENERIC_SERIALUSB
+GenF4.menu.usb.CDC_MSC=CDC + MSC
+GenF4.menu.usb.CDC_MSC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC_MSC
 GenF4.menu.usb.HID=HID (keyboard and mouse)
 GenF4.menu.usb.HID.build.enable_usb={build.usb_flags} -DUSBD_USE_HID_COMPOSITE
 GenF4.menu.xusb.FS=Low/Full Speed
@@ -2429,6 +2445,8 @@ GenH7.menu.usb.CDCgen=CDC (generic 'Serial' supersede U(S)ART)
 GenH7.menu.usb.CDCgen.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC
 GenH7.menu.usb.CDC=CDC (no generic 'Serial')
 GenH7.menu.usb.CDC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC -DDISABLE_GENERIC_SERIALUSB
+GenH7.menu.usb.CDC_MSC=CDC + MSC
+GenH7.menu.usb.CDC_MSC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC_MSC
 GenH7.menu.usb.HID=HID (keyboard and mouse)
 GenH7.menu.usb.HID.build.enable_usb={build.usb_flags} -DUSBD_USE_HID_COMPOSITE
 GenH7.menu.xusb.FS=Low/Full Speed
@@ -2440,6 +2458,8 @@ GenL0.menu.usb.CDCgen=CDC (generic 'Serial' supersede U(S)ART)
 GenL0.menu.usb.CDCgen.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC
 GenL0.menu.usb.CDC=CDC (no generic 'Serial')
 GenL0.menu.usb.CDC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC -DDISABLE_GENERIC_SERIALUSB
+GenL0.menu.usb.CDC_MSC=CDC + MSC
+GenL0.menu.usb.CDC_MSC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC_MSC
 GenL0.menu.usb.HID=HID (keyboard and mouse)
 GenL0.menu.usb.HID.build.enable_usb={build.usb_flags} -DUSBD_USE_HID_COMPOSITE
 
@@ -2448,6 +2468,8 @@ GenL0.menu.usb.HID.build.enable_usb={build.usb_flags} -DUSBD_USE_HID_COMPOSITE
 3dprinter.menu.usb.CDCgen.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC
 3dprinter.menu.usb.CDC=CDC (no generic 'Serial')
 3dprinter.menu.usb.CDC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC -DDISABLE_GENERIC_SERIALUSB
+3dprinter.menu.usb.CDC_MSC=CDC + MSC
+3dprinter.menu.usb.CDC_MSC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC_MSC
 3dprinter.menu.xusb.FS=Low/Full Speed
 3dprinter.menu.xusb.HS=High Speed
 3dprinter.menu.xusb.HS.build.usb_speed=-DUSE_USB_HS
@@ -2459,6 +2481,8 @@ Genericflight.menu.usb.CDCgen=CDC (generic 'Serial' supersede U(S)ART)
 Genericflight.menu.usb.CDCgen.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC
 Genericflight.menu.usb.CDC=CDC (no generic 'Serial')
 Genericflight.menu.usb.CDC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC -DDISABLE_GENERIC_SERIALUSB
+Genericflight.menu.usb.CDC_MSC=CDC + MSC
+Genericflight.menu.usb.CDC_MSC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC_MSC
 Genericflight.menu.usb.HID=HID (keyboard and mouse)
 Genericflight.menu.usb.HID.build.enable_usb={build.usb_flags} -DUSBD_USE_HID_COMPOSITE
 Genericflight.menu.xusb.FS=Low/Full Speed
@@ -2472,6 +2496,8 @@ Garatronic.menu.usb.CDCgen=CDC (generic 'Serial' supersede U(S)ART)
 Garatronic.menu.usb.CDCgen.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC
 Garatronic.menu.usb.CDC=CDC (no generic 'Serial')
 Garatronic.menu.usb.CDC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC -DDISABLE_GENERIC_SERIALUSB
+Garatronic.menu.usb.CDC_MSC=CDC + MSC
+Garatronic.menu.usb.CDC_MSC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC_MSC
 Garatronic.menu.usb.HID=HID (keyboard and mouse)
 Garatronic.menu.usb.HID.build.enable_usb={build.usb_flags} -DUSBD_USE_HID_COMPOSITE
 
@@ -2480,6 +2506,8 @@ Midatronics.menu.usb.CDCgen=CDC (generic 'Serial' supersede U(S)ART)
 Midatronics.menu.usb.CDCgen.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC
 Midatronics.menu.usb.CDC=CDC (no generic 'Serial')
 Midatronics.menu.usb.CDC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC -DDISABLE_GENERIC_SERIALUSB
+Midatronics.menu.usb.CDC_MSC=CDC + MSC
+Midatronics.menu.usb.CDC_MSC.build.enable_usb={build.usb_flags} -DUSBD_USE_CDC_MSC
 Midatronics.menu.usb.HID=HID (keyboard and mouse)
 Midatronics.menu.usb.HID.build.enable_usb={build.usb_flags} -DUSBD_USE_HID_COMPOSITE
 Midatronics.menu.xusb.FS=Low/Full Speed
diff --git a/cores/arduino/USB.cpp b/cores/arduino/USB.cpp
new file mode 100644
index 0000000000..1b2dfaca24
--- /dev/null
+++ b/cores/arduino/USB.cpp
@@ -0,0 +1,126 @@
+/*
+  Copyright (c) 2015 Arduino LLC.  All right reserved.
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#ifdef USBCON
+
+#include "usbd_desc.h"
+#include "USB.h"
+#include "wiring.h"
+
+#ifdef USBD_USE_CDC_CLASS
+  #include "usbd_cdc.h"
+  #include "usbd_cdc_msc.h"
+  #include "usbd_cdc_if.h"
+#endif
+
+#ifdef USBD_USE_MSC_CLASS
+  #include "usbd_msc.h"
+  #include "usbd_msc_storage_if.h"
+#endif
+
+USB USBDevice;
+
+void USB::begin()
+{
+  if (!initialized) {
+    initialize();
+  }
+}
+
+#ifdef USBD_USE_MSC_CLASS
+DummyUSBMscHandler dummyHandler;
+
+void USB::registerMscHandler(USBMscHandler &handler)
+{
+  pSingleMscHandler = &handler;
+  registerMscHandlers(1, &pSingleMscHandler, USBD_MSC_fops.pInquiry);
+}
+
+void USB::registerMscHandlers(uint8_t count, USBMscHandler **ppHandlers, uint8_t *pInquiryData)
+{
+  if (count == 0) {
+    registerMscHandler(dummyHandler);
+  } else {
+    ppUsbMscHandlers = ppHandlers;
+    usbMscMaxLun = count - 1;
+    USBD_MSC_fops.pInquiry = pInquiryData;
+  }
+}
+#endif
+
+void USB::initialize()
+{
+  hUSBD_Device_CDC = &hUSBD_Device;
+
+
+  /* Init Device Library */
+  if (USBD_Init(&hUSBD_Device, &USBD_Desc, 0) != USBD_OK) {
+    return;
+  }
+
+  /* Add Supported Class and register interface */
+#ifdef USBD_USE_CDC
+  if (USBD_RegisterClass(&hUSBD_Device, &USBD_CDC) != USBD_OK) {
+    return;
+  }
+#elif USBD_USE_CDC_MSC
+  if (USBD_RegisterClass(&hUSBD_Device, &USBD_CDC_MSC) != USBD_OK) {
+    return;
+  }
+#elif USBD_USE_MSC
+  if (USBD_RegisterClass(&hUSBD_Device, &USBD_CDC_MSC) != USBD_OK) {
+    return;
+  }
+#endif
+
+#ifdef USBD_USE_CDC_CLASS
+  hUSBD_Device_CDC = &hUSBD_Device;
+  if (USBD_CDC_RegisterInterface(&hUSBD_Device, &USBD_CDC_fops) != USBD_OK) {
+    return;
+  }
+#endif
+
+#ifdef USBD_USE_MSC_CLASS
+  if (ppUsbMscHandlers == nullptr) {
+    registerMscHandler(dummyHandler);
+  }
+  if (USBD_MSC_RegisterStorage(&hUSBD_Device, &USBD_MSC_fops) != USBD_OK) {
+    return;
+  }
+#endif
+
+  /* Start Device Process */
+  USBD_Start(&hUSBD_Device);
+  initialized = true;
+}
+
+void USB::end()
+{
+  if (initialized) {
+    deinitialize();
+  }
+}
+
+void USB::deinitialize()
+{
+  USBD_Stop(&hUSBD_Device);
+  USBD_DeInit(&hUSBD_Device);
+  initialized = false;
+}
+
+#endif // USBCON
diff --git a/cores/arduino/USB.h b/cores/arduino/USB.h
new file mode 100644
index 0000000000..1c06240d27
--- /dev/null
+++ b/cores/arduino/USB.h
@@ -0,0 +1,58 @@
+/*
+  Copyright (c) 2015 Arduino LLC.  All right reserved.
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#ifndef _USB_H_
+#define _USB_H_
+
+#ifdef USBCON
+
+#include "usbd_core.h"
+#include "usbd_ep_conf.h"
+
+#ifdef USBD_USE_MSC_CLASS
+  #include "USBMscHandler.h"
+#endif
+
+class USB {
+  public:
+#ifdef USBD_USE_MSC_CLASS
+    void registerMscHandler(USBMscHandler &pHandler);
+    void registerMscHandlers(uint8_t count, USBMscHandler **pHandlers, uint8_t *pInquiryData);
+#endif
+
+    void begin(void);
+
+    void end(void);
+
+  protected:
+    void initialize();
+    void deinitialize();
+
+    bool initialized;
+
+    USBD_HandleTypeDef hUSBD_Device;
+
+#ifdef USBD_USE_MSC_CLASS
+    USBMscHandler *pSingleMscHandler;
+#endif
+};
+
+extern USB USBDevice;
+
+#endif // USBCON
+#endif // _USB_H_
\ No newline at end of file
diff --git a/cores/arduino/USBMscHandler.h b/cores/arduino/USBMscHandler.h
new file mode 100644
index 0000000000..9f8afea1e1
--- /dev/null
+++ b/cores/arduino/USBMscHandler.h
@@ -0,0 +1,89 @@
+/*
+  Copyright (c) 2015 Arduino LLC.  All right reserved.
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+
+#ifndef _USB_MSC_HANDLER_H_
+#define _USB_MSC_HANDLER_H_
+
+#if defined(USBCON) && defined(USBD_USE_MSC_CLASS)
+
+#include "usbd_core.h"
+#include "usbd_msc.h"
+
+/* Handler for mass storage devices */
+class USBMscHandler {
+  public:
+    // Example: A 128 MB SD card has 245760 blocks, at a block size of 512 bytes
+    // Returns true if successful, otherwise false.
+    virtual bool GetCapacity(uint32_t *pBlockNum, uint16_t *pBlockSize) = 0;
+
+    // Read [blk_len] blocks, starting at [blk_addr] into [buf].
+    // Returns true if successful, otherwise false.
+    virtual bool Read(uint8_t *pBuf, uint32_t blkAddr, uint16_t blkLen) = 0;
+
+    // Write [blk_len] blocks, starting at [blk_addr] into [buf].
+    // Returns true if successful, otherwise false.
+    virtual bool Write(uint8_t *pBuf, uint32_t blkAddr, uint16_t blkLen) = 0;
+
+    /** Optional functions **/
+
+    virtual bool Init()
+    {
+      return true;
+    }
+
+    // Return false if the mass storage device has not been connected or initialized yet.
+    virtual bool IsReady()
+    {
+      return true;
+    }
+
+    // If the device should be read-only then this function should return true.
+    virtual bool IsWriteProtected()
+    {
+      return false;
+    }
+};
+
+class DummyUSBMscHandler : public USBMscHandler {
+  public:
+    // Any call to one of these functions always fails.
+    bool GetCapacity(uint32_t *pBlockNum, uint16_t *pBlockSize)
+    {
+      return false;
+    }
+
+    bool Read(uint8_t *pBuf, uint32_t blockAddr, uint16_t blkLen)
+    {
+      return false;
+    }
+
+    bool Write(uint8_t *pBuf, uint32_t blockAddr, uint16_t blkLen)
+    {
+      return false;
+    }
+
+    // The dummy handler is never ready.
+    bool IsReady()
+    {
+      return false;
+    }
+};
+
+#endif
+#endif
\ No newline at end of file
diff --git a/cores/arduino/USBSerial.cpp b/cores/arduino/USBSerial.cpp
index 256b5a1df8..741f57ce9c 100644
--- a/cores/arduino/USBSerial.cpp
+++ b/cores/arduino/USBSerial.cpp
@@ -16,8 +16,11 @@
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
 
-#if defined (USBCON) && defined(USBD_USE_CDC)
+#include "usbd_ep_conf.h"
 
+#if defined (USBCON) && defined(USBD_USE_CDC_CLASS)
+
+#include "USB.h"
 #include "USBSerial.h"
 #include "usbd_cdc.h"
 #include "usbd_cdc_if.h"
@@ -31,7 +34,7 @@ void serialEventUSB() __attribute__((weak));
 
 void USBSerial::begin(void)
 {
-  CDC_init();
+  USBDevice.begin();
 }
 
 void USBSerial::begin(uint32_t /* baud_count */)
@@ -48,7 +51,7 @@ void USBSerial::begin(uint32_t /* baud_count */, uint8_t /* config */)
 
 void USBSerial::end()
 {
-  CDC_deInit();
+  USBDevice.end();
 }
 
 int USBSerial::availableForWrite()
diff --git a/cores/arduino/USBSerial.h b/cores/arduino/USBSerial.h
index 1628eef358..6ff78af907 100644
--- a/cores/arduino/USBSerial.h
+++ b/cores/arduino/USBSerial.h
@@ -19,9 +19,11 @@
 #ifndef _USBSERIAL_H_
 #define _USBSERIAL_H_
 
-#if defined (USBCON) && defined(USBD_USE_CDC)
-#include "Stream.h"
+#include "usbd_ep_conf.h"
+
+#if defined (USBCON) && defined(USBD_USE_CDC_CLASS)
 #include "usbd_core.h"
+#include "Stream.h"
 
 //================================================================================
 // Serial over CDC
diff --git a/cores/arduino/stm32/usb/cdc/cdc_queue.c b/cores/arduino/stm32/usb/cdc/cdc_queue.c
index 2d2330c195..3209341d42 100644
--- a/cores/arduino/stm32/usb/cdc/cdc_queue.c
+++ b/cores/arduino/stm32/usb/cdc/cdc_queue.c
@@ -35,8 +35,10 @@
   ******************************************************************************
   */
 
+#include "usbd_ep_conf.h"
+
 #ifdef USBCON
-#ifdef USBD_USE_CDC
+#ifdef USBD_USE_CDC_CLASS
 
 #include "cdc_queue.h"
 
diff --git a/cores/arduino/stm32/usb/cdc/usbd_cdc.c b/cores/arduino/stm32/usb/cdc/usbd_cdc.c
index 9ee0d7885a..f76e248bb4 100644
--- a/cores/arduino/stm32/usb/cdc/usbd_cdc.c
+++ b/cores/arduino/stm32/usb/cdc/usbd_cdc.c
@@ -50,8 +50,10 @@
   ******************************************************************************
   */
 
+#include "usbd_ep_conf.h"
+
 #ifdef USBCON
-#ifdef USBD_USE_CDC
+#ifdef USBD_USE_CDC_CLASS
 
 /* Includes ------------------------------------------------------------------*/
 #include "usbd_cdc.h"
@@ -108,7 +110,7 @@ static uint8_t *USBD_CDC_GetFSCfgDesc(uint16_t *length);
 static uint8_t *USBD_CDC_GetHSCfgDesc(uint16_t *length);
 static uint8_t *USBD_CDC_GetOtherSpeedCfgDesc(uint16_t *length);
 static uint8_t *USBD_CDC_GetOtherSpeedCfgDesc(uint16_t *length);
-uint8_t  *USBD_CDC_GetDeviceQualifierDescriptor(uint16_t *length);
+uint8_t *USBD_CDC_GetDeviceQualifierDescriptor(uint16_t *length);
 
 /* USB Standard Device Descriptor */
 __ALIGN_BEGIN static uint8_t USBD_CDC_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END = {
@@ -402,6 +404,15 @@ __ALIGN_BEGIN static uint8_t USBD_CDC_OtherSpeedCfgDesc[USB_CDC_CONFIG_DESC_SIZ]
   0x00                                  /* bInterval */
 };
 
+
+
+USBD_CDC_HandleTypeDef cdc_handle_dat;
+USBD_CDC_HandleTypeDef *cdc_handle = &cdc_handle_dat;
+
+USBD_CDC_ItfTypeDef *cdc_itf = NULL; /* TODO */
+
+int cdcInitialized;
+
 /**
   * @}
   */
@@ -417,19 +428,13 @@ __ALIGN_BEGIN static uint8_t USBD_CDC_OtherSpeedCfgDesc[USB_CDC_CONFIG_DESC_SIZ]
   * @param  cfgidx: Configuration index
   * @retval status
   */
-static uint8_t  USBD_CDC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
+static uint8_t USBD_CDC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
 {
   UNUSED(cfgidx);
-  USBD_CDC_HandleTypeDef   *hcdc;
 
-  hcdc = USBD_malloc(sizeof(USBD_CDC_HandleTypeDef));
+  USBD_CDC_HandleTypeDef *hcdc = cdc_handle;
 
-  if (hcdc == NULL) {
-    pdev->pClassData = NULL;
-    return (uint8_t)USBD_EMEM;
-  }
-
-  pdev->pClassData = (void *)hcdc;
+  pdev->pClassData = &cdcInitialized;
 
   if (pdev->dev_speed == USBD_SPEED_HIGH) {
     /* Open EP IN */
@@ -468,7 +473,7 @@ static uint8_t  USBD_CDC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
   pdev->ep_in[CDC_CMD_EP & 0xFU].is_used = 1U;
 
   /* Init  physical Interface components */
-  ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Init();
+  cdc_itf->Init();
 
   /* Init Xfer states */
   hcdc->TxState = 0U;
@@ -494,7 +499,7 @@ static uint8_t  USBD_CDC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
   * @param  cfgidx: Configuration index
   * @retval status
   */
-static uint8_t  USBD_CDC_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
+static uint8_t USBD_CDC_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
 {
   UNUSED(cfgidx);
   uint8_t ret = 0U;
@@ -514,8 +519,12 @@ static uint8_t  USBD_CDC_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
 
   /* DeInit  physical Interface components */
   if (pdev->pClassData != NULL) {
-    ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->DeInit();
-    (void)USBD_free(pdev->pClassData);
+    /* DeInit physical Interface components */
+    cdc_itf->DeInit();
+  }
+
+  if (pdev->pClassData == &cdcInitialized) {
+    // only mark as uninitialised if we own the initialisation
     pdev->pClassData = NULL;
   }
 
@@ -529,10 +538,10 @@ static uint8_t  USBD_CDC_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
   * @param  req: usb requests
   * @retval status
   */
-static uint8_t  USBD_CDC_Setup(USBD_HandleTypeDef *pdev,
-                               USBD_SetupReqTypedef *req)
+static uint8_t USBD_CDC_Setup(USBD_HandleTypeDef *pdev,
+                              USBD_SetupReqTypedef *req)
 {
-  USBD_CDC_HandleTypeDef   *hcdc = (USBD_CDC_HandleTypeDef *) pdev->pClassData;
+  USBD_CDC_HandleTypeDef *hcdc = cdc_handle;
   uint8_t ifalt = 0U;
   uint16_t status_info = 0U;
   USBD_StatusTypeDef ret = USBD_OK;
@@ -541,9 +550,9 @@ static uint8_t  USBD_CDC_Setup(USBD_HandleTypeDef *pdev,
     case USB_REQ_TYPE_CLASS:
       if (req->wLength != 0U) {
         if ((req->bmRequest & 0x80U) != 0U) {
-          ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Control(req->bRequest,
-                                                            (uint8_t *)hcdc->data,
-                                                            req->wLength);
+          cdc_itf->Control(req->bRequest,
+                           (uint8_t *)hcdc->data,
+                           req->wLength);
 
           (void)USBD_CtlSendData(pdev, (uint8_t *)hcdc->data, req->wLength);
         } else {
@@ -553,8 +562,8 @@ static uint8_t  USBD_CDC_Setup(USBD_HandleTypeDef *pdev,
           (void)USBD_CtlPrepareRx(pdev, (uint8_t *)hcdc->data, req->wLength);
         }
       } else {
-        ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Control(req->bRequest,
-                                                          (uint8_t *)req, 0U);
+        cdc_itf->Control(req->bRequest,
+                         (uint8_t *)req, 0U);
       }
       break;
 
@@ -611,17 +620,18 @@ static uint8_t  USBD_CDC_Setup(USBD_HandleTypeDef *pdev,
   * @param  epnum: endpoint number
   * @retval status
   */
-static uint8_t  USBD_CDC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum)
+static uint8_t USBD_CDC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum)
 {
-  USBD_CDC_HandleTypeDef *hcdc;
+  USBD_CDC_HandleTypeDef *hcdc = cdc_handle;
   PCD_HandleTypeDef *hpcd = pdev->pData;
+  USBD_CDC_ItfTypeDef *ctrl = cdc_itf;
 
   if (pdev->pClassData == NULL) {
     return (uint8_t)USBD_FAIL;
   }
-  hcdc = (USBD_CDC_HandleTypeDef *)pdev->pClassData;
 
-  if ((pdev->ep_in[epnum].total_length > 0U) && ((pdev->ep_in[epnum].total_length % hpcd->IN_ep[epnum].maxpacket) == 0U)) {
+  if ((pdev->ep_in[epnum].total_length > 0U) &&
+      ((pdev->ep_in[epnum].total_length % hpcd->IN_ep[epnum].maxpacket) == 0U)) {
     /* Update the packet total length */
     pdev->ep_in[epnum].total_length = 0U;
 
@@ -629,7 +639,7 @@ static uint8_t  USBD_CDC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum)
     (void)USBD_LL_Transmit(pdev, epnum, NULL, 0U);
   } else {
     hcdc->TxState = 0U;
-    ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->TransmitCplt(hcdc->TxBuffer, &hcdc->TxLength, epnum);
+    ctrl->TransmitCplt(hcdc->TxBuffer, &hcdc->TxLength, epnum);
   }
 
   return (uint8_t)USBD_OK;
@@ -642,10 +652,9 @@ static uint8_t  USBD_CDC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum)
   * @param  epnum: endpoint number
   * @retval status
   */
-static uint8_t  USBD_CDC_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
+static uint8_t USBD_CDC_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
 {
-  USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef *)pdev->pClassData;
-
+  USBD_CDC_HandleTypeDef *hcdc = cdc_handle;
   if (pdev->pClassData == NULL) {
     return (uint8_t)USBD_FAIL;
   }
@@ -656,7 +665,7 @@ static uint8_t  USBD_CDC_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
   /* USB data will be immediately processed, this allow next USB traffic being
   NAKed till the end of the application Xfer */
 
-  ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Receive(hcdc->RxBuffer, &hcdc->RxLength);
+  cdc_itf->Receive(hcdc->RxBuffer, &hcdc->RxLength);
 
   return (uint8_t)USBD_OK;
 }
@@ -667,14 +676,14 @@ static uint8_t  USBD_CDC_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
   * @param  pdev: device instance
   * @retval status
   */
-static uint8_t  USBD_CDC_EP0_RxReady(USBD_HandleTypeDef *pdev)
+static uint8_t USBD_CDC_EP0_RxReady(USBD_HandleTypeDef *pdev)
 {
-  USBD_CDC_HandleTypeDef   *hcdc = (USBD_CDC_HandleTypeDef *)pdev->pClassData;
+  USBD_CDC_HandleTypeDef *hcdc = cdc_handle;
 
-  if ((pdev->pUserData != NULL) && (hcdc->CmdOpCode != 0xFFU)) {
-    ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Control(hcdc->CmdOpCode,
-                                                      (uint8_t *)hcdc->data,
-                                                      (uint16_t)hcdc->CmdLength);
+  if ((hcdc->CmdOpCode != 0xFFU)) {
+    cdc_itf->Control(hcdc->CmdOpCode,
+                     (uint8_t *)hcdc->data,
+                     (uint16_t)hcdc->CmdLength);
     hcdc->CmdOpCode = 0xFFU;
 
   }
@@ -689,7 +698,7 @@ static uint8_t  USBD_CDC_EP0_RxReady(USBD_HandleTypeDef *pdev)
   * @param  length : pointer data length
   * @retval pointer to descriptor buffer
   */
-static uint8_t  *USBD_CDC_GetFSCfgDesc(uint16_t *length)
+static uint8_t *USBD_CDC_GetFSCfgDesc(uint16_t *length)
 {
   *length = (uint16_t)sizeof(USBD_CDC_CfgFSDesc);
 
@@ -703,7 +712,7 @@ static uint8_t  *USBD_CDC_GetFSCfgDesc(uint16_t *length)
   * @param  length : pointer data length
   * @retval pointer to descriptor buffer
   */
-static uint8_t  *USBD_CDC_GetHSCfgDesc(uint16_t *length)
+static uint8_t *USBD_CDC_GetHSCfgDesc(uint16_t *length)
 {
   *length = (uint16_t)sizeof(USBD_CDC_CfgHSDesc);
 
@@ -717,7 +726,7 @@ static uint8_t  *USBD_CDC_GetHSCfgDesc(uint16_t *length)
   * @param  length : pointer data length
   * @retval pointer to descriptor buffer
   */
-static uint8_t  *USBD_CDC_GetOtherSpeedCfgDesc(uint16_t *length)
+static uint8_t *USBD_CDC_GetOtherSpeedCfgDesc(uint16_t *length)
 {
   *length = (uint16_t)sizeof(USBD_CDC_OtherSpeedCfgDesc);
 
@@ -730,7 +739,7 @@ static uint8_t  *USBD_CDC_GetOtherSpeedCfgDesc(uint16_t *length)
 * @param  length : pointer data length
 * @retval pointer to descriptor buffer
 */
-uint8_t  *USBD_CDC_GetDeviceQualifierDescriptor(uint16_t *length)
+uint8_t *USBD_CDC_GetDeviceQualifierDescriptor(uint16_t *length)
 {
   *length = (uint16_t)sizeof(USBD_CDC_DeviceQualifierDesc);
 
@@ -743,14 +752,14 @@ uint8_t  *USBD_CDC_GetDeviceQualifierDescriptor(uint16_t *length)
   * @param  fops: CD  Interface callback
   * @retval status
   */
-uint8_t  USBD_CDC_RegisterInterface(USBD_HandleTypeDef   *pdev,
-                                    USBD_CDC_ItfTypeDef *fops)
+uint8_t USBD_CDC_RegisterInterface(USBD_HandleTypeDef *pdev,
+                                   USBD_CDC_ItfTypeDef *fops)
 {
   if (fops == NULL) {
     return (uint8_t)USBD_FAIL;
   }
 
-  pdev->pUserData = fops;
+  cdc_itf = fops;
 
   return (uint8_t)USBD_OK;
 }
@@ -761,10 +770,10 @@ uint8_t  USBD_CDC_RegisterInterface(USBD_HandleTypeDef   *pdev,
   * @param  pbuff: Tx Buffer
   * @retval status
   */
-uint8_t  USBD_CDC_SetTxBuffer(USBD_HandleTypeDef   *pdev,
-                              uint8_t  *pbuff, uint32_t length)
+uint8_t USBD_CDC_SetTxBuffer(USBD_HandleTypeDef *pdev,
+                             uint8_t *pbuff, uint32_t length)
 {
-  USBD_CDC_HandleTypeDef   *hcdc = (USBD_CDC_HandleTypeDef *)pdev->pClassData;
+  USBD_CDC_HandleTypeDef *hcdc = cdc_handle;
 
   hcdc->TxBuffer = pbuff;
   hcdc->TxLength = length;
@@ -779,9 +788,9 @@ uint8_t  USBD_CDC_SetTxBuffer(USBD_HandleTypeDef   *pdev,
   * @param  pbuff: Rx Buffer
   * @retval status
   */
-uint8_t  USBD_CDC_SetRxBuffer(USBD_HandleTypeDef   *pdev, uint8_t  *pbuff)
+uint8_t USBD_CDC_SetRxBuffer(USBD_HandleTypeDef *pdev, uint8_t *pbuff)
 {
-  USBD_CDC_HandleTypeDef   *hcdc = (USBD_CDC_HandleTypeDef *)pdev->pClassData;
+  USBD_CDC_HandleTypeDef *hcdc = cdc_handle;
 
   hcdc->RxBuffer = pbuff;
 
@@ -794,9 +803,9 @@ uint8_t  USBD_CDC_SetRxBuffer(USBD_HandleTypeDef   *pdev, uint8_t  *pbuff)
   * @param  pdev: device instance
   * @retval status
   */
-uint8_t  USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev)
+uint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev)
 {
-  USBD_CDC_HandleTypeDef   *hcdc = (USBD_CDC_HandleTypeDef *)pdev->pClassData;
+  USBD_CDC_HandleTypeDef *hcdc = cdc_handle;
   USBD_StatusTypeDef ret = USBD_BUSY;
 
   if (pdev->pClassData == NULL) {
@@ -826,9 +835,9 @@ uint8_t  USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev)
   * @param  pdev: device instance
   * @retval status
   */
-uint8_t  USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev)
+uint8_t USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev)
 {
-  USBD_CDC_HandleTypeDef   *hcdc = (USBD_CDC_HandleTypeDef *)pdev->pClassData;
+  USBD_CDC_HandleTypeDef *hcdc = cdc_handle;
 
   if (pdev->pClassData == NULL) {
     return (uint8_t)USBD_FAIL;
@@ -859,6 +868,6 @@ uint8_t USBD_CDC_ClearBuffer(USBD_HandleTypeDef *pdev)
   }
 }
 
-#endif /* USBD_USE_CDC */
+#endif /* USBD_USE_CDC_CLASS */
 #endif /* USBCON */
 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/cores/arduino/stm32/usb/cdc/usbd_cdc.h b/cores/arduino/stm32/usb/cdc/usbd_cdc.h
index 5395708c06..5a9bce8606 100644
--- a/cores/arduino/stm32/usb/cdc/usbd_cdc.h
+++ b/cores/arduino/stm32/usb/cdc/usbd_cdc.h
@@ -38,6 +38,7 @@ extern "C" {
   * @{
   */
 
+
 /** @defgroup usbd_cdc_Exported_Defines
   * @{
   */
@@ -126,8 +127,13 @@ typedef struct {
   * @{
   */
 
+
 extern USBD_ClassTypeDef  USBD_CDC;
-#define USBD_CDC_CLASS    &USBD_CDC
+
+extern USBD_CDC_HandleTypeDef *cdc_handle;
+
+extern USBD_CDC_ItfTypeDef *cdc_itf;
+
 /**
   * @}
   */
@@ -135,16 +141,17 @@ extern USBD_ClassTypeDef  USBD_CDC;
 /** @defgroup USB_CORE_Exported_Functions
   * @{
   */
-uint8_t  USBD_CDC_RegisterInterface(USBD_HandleTypeDef   *pdev,
-                                    USBD_CDC_ItfTypeDef *fops);
+uint8_t USBD_CDC_RegisterInterface(USBD_HandleTypeDef *pdev,
+                                   USBD_CDC_ItfTypeDef *fops);
+
+uint8_t USBD_CDC_SetTxBuffer(USBD_HandleTypeDef *pdev, uint8_t *pbuff,
+                             uint32_t length);
 
-uint8_t  USBD_CDC_SetTxBuffer(USBD_HandleTypeDef *pdev, uint8_t *pbuff,
-                              uint32_t length);
+uint8_t USBD_CDC_SetRxBuffer(USBD_HandleTypeDef *pdev, uint8_t *pbuff);
+uint8_t USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev);
+uint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev);
+uint8_t USBD_CDC_ClearBuffer(USBD_HandleTypeDef *pdev);
 
-uint8_t  USBD_CDC_SetRxBuffer(USBD_HandleTypeDef *pdev, uint8_t *pbuff);
-uint8_t  USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev);
-uint8_t  USBD_CDC_ClearBuffer(USBD_HandleTypeDef *pdev);
-uint8_t  USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev);
 /**
   * @}
   */
diff --git a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c
index c09675f95e..6b731641b4 100644
--- a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c
+++ b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.c
@@ -17,8 +17,10 @@
   ******************************************************************************
   */
 
+#include "usbd_ep_conf.h"
+
 #ifdef USBCON
-#ifdef USBD_USE_CDC
+#ifdef USBD_USE_CDC_CLASS
 
 /* Includes ------------------------------------------------------------------*/
 #include "usbd_desc.h"
@@ -44,9 +46,7 @@
 
 /* USBD_CDC Private Variables */
 /* USB Device Core CDC handle declaration */
-USBD_HandleTypeDef hUSBD_Device_CDC;
-
-static bool CDC_initialized = false;
+USBD_HandleTypeDef *hUSBD_Device_CDC;
 
 /* Received Data over USB are stored in this buffer       */
 CDC_TransmitQueue_TypeDef TransmitQueue;
@@ -98,7 +98,7 @@ static int8_t USBD_CDC_Init(void)
   CDC_TransmitQueue_Init(&TransmitQueue);
   CDC_ReceiveQueue_Init(&ReceiveQueue);
   receivePended = true;
-  USBD_CDC_SetRxBuffer(&hUSBD_Device_CDC, CDC_ReceiveQueue_ReserveBlock(&ReceiveQueue));
+  USBD_CDC_SetRxBuffer(hUSBD_Device_CDC, CDC_ReceiveQueue_ReserveBlock(&ReceiveQueue));
 
   return ((int8_t)USBD_OK);
 }
@@ -235,7 +235,7 @@ static int8_t USBD_CDC_Receive(uint8_t *Buf, uint32_t *Len)
   receivePended = false;
   /* If enough space in the queue for a full buffer then continue receive */
   if (!CDC_resume_receive()) {
-    USBD_CDC_ClearBuffer(&hUSBD_Device_CDC);
+    USBD_CDC_ClearBuffer(hUSBD_Device_CDC);
   }
   return ((int8_t)USBD_OK);
 }
@@ -264,34 +264,6 @@ static int8_t USBD_CDC_TransmitCplt(uint8_t *Buf, uint32_t *Len, uint8_t epnum)
   return ((int8_t)USBD_OK);
 }
 
-void CDC_init(void)
-{
-  if (!CDC_initialized) {
-    /* Init Device Library */
-    if (USBD_Init(&hUSBD_Device_CDC, &USBD_Desc, 0) == USBD_OK) {
-      /* Add Supported Class */
-      if (USBD_RegisterClass(&hUSBD_Device_CDC, USBD_CDC_CLASS) == USBD_OK) {
-        /* Add CDC Interface Class */
-        if (USBD_CDC_RegisterInterface(&hUSBD_Device_CDC, &USBD_CDC_fops) == USBD_OK) {
-          /* Start Device Process */
-          USBD_Start(&hUSBD_Device_CDC);
-          CDC_initialized = true;
-        }
-      }
-    }
-  }
-}
-
-void CDC_deInit(void)
-{
-  if (CDC_initialized) {
-    USBD_Stop(&hUSBD_Device_CDC);
-    USBD_CDC_DeInit();
-    USBD_DeInit(&hUSBD_Device_CDC);
-    CDC_initialized = false;
-  }
-}
-
 bool CDC_connected()
 {
   /* Save the transmitStart value in a local variable to avoid twice reading - fix #478 */
@@ -299,16 +271,16 @@ bool CDC_connected()
   if (transmitTime) {
     transmitTime = HAL_GetTick() - transmitTime;
   }
-  return ((hUSBD_Device_CDC.dev_state == USBD_STATE_CONFIGURED)
-          && (transmitTime < USB_CDC_TRANSMIT_TIMEOUT)
-          && lineState);
+  return hUSBD_Device_CDC->dev_state == USBD_STATE_CONFIGURED
+         && transmitTime < USB_CDC_TRANSMIT_TIMEOUT
+         && lineState;
 }
 
 void CDC_continue_transmit(void)
 {
   uint16_t size;
   uint8_t *buffer;
-  USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef *) hUSBD_Device_CDC.pClassData;
+  USBD_CDC_HandleTypeDef *hcdc = cdc_handle;
   /*
    * TS: This method can be called both in the main thread
    * (via USBSerial::write) and in the IRQ stream (via USBD_CDC_TransmistCplt),
@@ -321,12 +293,12 @@ void CDC_continue_transmit(void)
     buffer = CDC_TransmitQueue_ReadBlock(&TransmitQueue, &size);
     if (size > 0) {
       transmitStart = HAL_GetTick();
-      USBD_CDC_SetTxBuffer(&hUSBD_Device_CDC, buffer, size);
+      USBD_CDC_SetTxBuffer(hUSBD_Device_CDC, buffer, size);
       /*
        * size never exceed PMA buffer and USBD_CDC_TransmitPacket make full
        * copy of block in PMA, so no need to worry about buffer damage
        */
-      USBD_CDC_TransmitPacket(&hUSBD_Device_CDC);
+      USBD_CDC_TransmitPacket(hUSBD_Device_CDC);
     }
   }
 }
@@ -342,8 +314,8 @@ bool CDC_resume_receive(void)
     if (block != NULL) {
       receivePended = true;
       /* Set new buffer */
-      USBD_CDC_SetRxBuffer(&hUSBD_Device_CDC, block);
-      USBD_CDC_ReceivePacket(&hUSBD_Device_CDC);
+      USBD_CDC_SetRxBuffer(hUSBD_Device_CDC, block);
+      USBD_CDC_ReceivePacket(hUSBD_Device_CDC);
       return true;
     }
   }
diff --git a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.h b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.h
index b415ac16de..1f2e311471 100644
--- a/cores/arduino/stm32/usb/cdc/usbd_cdc_if.h
+++ b/cores/arduino/stm32/usb/cdc/usbd_cdc_if.h
@@ -22,7 +22,7 @@
 #define __USBD_CDC_IF_H
 
 #ifdef USBCON
-#ifdef USBD_USE_CDC
+#ifdef USBD_USE_CDC_CLASS
 
 #ifdef __cplusplus
 extern "C" {
@@ -39,6 +39,7 @@ extern "C" {
 /* Exported types ------------------------------------------------------------*/
 /* Exported constants --------------------------------------------------------*/
 
+extern USBD_HandleTypeDef *hUSBD_Device_CDC;
 extern USBD_CDC_ItfTypeDef  USBD_CDC_fops;
 extern CDC_TransmitQueue_TypeDef TransmitQueue;
 extern CDC_ReceiveQueue_TypeDef ReceiveQueue;
@@ -48,8 +49,6 @@ extern CDC_ReceiveQueue_TypeDef ReceiveQueue;
 /* Exported functions ------------------------------------------------------- */
 void CDC_continue_transmit(void);
 bool CDC_resume_receive(void);
-void CDC_init(void);
-void CDC_deInit(void);
 bool CDC_connected(void);
 
 #ifdef __cplusplus
diff --git a/cores/arduino/stm32/usb/cdc_msc/usbd_cdc_msc.cpp b/cores/arduino/stm32/usb/cdc_msc/usbd_cdc_msc.cpp
new file mode 100644
index 0000000000..d846a4a965
--- /dev/null
+++ b/cores/arduino/stm32/usb/cdc_msc/usbd_cdc_msc.cpp
@@ -0,0 +1,514 @@
+/**
+  ******************************************************************************
+  * @file    usbd_template.c
+  * @author  MCD Application Team
+  * @brief   This file provides the HID core functions.
+  *
+  * @verbatim
+  *
+  *          ===================================================================
+  *                                COMPOSITE Class Description
+  *          ===================================================================
+  *
+  *
+  *
+  *
+  *
+  *
+  * @note     In HS mode and when the DMA is used, all variables and data structures
+  *           dealing with the DMA during the transaction process should be 32-bit aligned.
+  *
+  *
+  *  @endverbatim
+  *
+  ******************************************************************************
+  * @attention
+  *
+  * 
© Copyright (c) 2015 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                      www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+#include "usbd_ep_conf.h"
+
+#ifdef USBCON
+#ifdef USBD_USE_CDC_MSC
+
+#include "usbd_cdc_msc.h"
+#include "usbd_ctlreq.h"
+
+static uint8_t  USBD_COMPOSITE_Init(USBD_HandleTypeDef *pdev,
+                                    uint8_t cfgidx);
+
+static uint8_t  USBD_COMPOSITE_DeInit(USBD_HandleTypeDef *pdev,
+                                      uint8_t cfgidx);
+
+static uint8_t  USBD_COMPOSITE_Setup(USBD_HandleTypeDef *pdev,
+                                     USBD_SetupReqTypedef *req);
+
+static uint8_t  *USBD_COMPOSITE_GetHSCfgDesc(uint16_t *length);
+
+static uint8_t  *USBD_COMPOSITE_GetFSCfgDesc(uint16_t *length);
+
+static uint8_t  *USBD_COMPOSITE_GetOtherSpeedCfgDesc(uint16_t *length);
+
+static uint8_t  *USBD_COMPOSITE_GetDeviceQualifierDesc(uint16_t *length);
+
+static uint8_t  USBD_COMPOSITE_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum);
+
+static uint8_t  USBD_COMPOSITE_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum);
+
+static uint8_t  USBD_COMPOSITE_EP0_RxReady(USBD_HandleTypeDef *pdev);
+
+
+USBD_ClassTypeDef  USBD_CDC_MSC = {
+  USBD_COMPOSITE_Init,
+  USBD_COMPOSITE_DeInit,
+  USBD_COMPOSITE_Setup,
+  nullptr,
+  USBD_COMPOSITE_EP0_RxReady,
+  USBD_COMPOSITE_DataIn,
+  USBD_COMPOSITE_DataOut,
+  nullptr,
+  nullptr,
+  nullptr,
+  USBD_COMPOSITE_GetHSCfgDesc,
+  USBD_COMPOSITE_GetFSCfgDesc,
+  USBD_COMPOSITE_GetOtherSpeedCfgDesc,
+  USBD_COMPOSITE_GetDeviceQualifierDesc,
+};
+
+
+#define EP_ATTR_BULK      0x02
+#define EP_ATTR_INTERRUPT 0x03
+
+#define IF_CLASS_COMM     0x02
+#define IF_CLASS_CDC      0x0A
+#define IF_CLASS_MSC      0x08
+
+#define IF_SUBCLASS_NONE              0x00
+#define IF_SUBCLASS_ACM               0x02
+#define IF_SUBCLASS_SCSI_TRANSPARENT  0x06
+
+#define ENDPOINT_DESCRIPTOR(_EP_ADDR, _ATTR, _PACKET_SIZE, _BINTERVAL) \
+  0x07,                           /* bLength: Endpoint Descriptor size */ \
+  USB_DESC_TYPE_ENDPOINT,         /* bDescriptorType: Endpoint */ \
+  _EP_ADDR,                       /* bEndpointAddress */ \
+  _ATTR,                          /* bmAttributes: Interrupt */ \
+  LOBYTE(_PACKET_SIZE),           /* wMaxPacketSize: */ \
+  HIBYTE(_PACKET_SIZE), \
+  _BINTERVAL                      /* bInterval: */
+
+
+/* ACM Interface Descriptor */
+#define INTERFACE_DESCRIPTOR(_IF_NUM, _EP_COUNT, _CLASS, _SUBCLASS, _PROT) \
+  0x09,   /* bLength: Interface Descriptor size */ \
+  USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: Interface */ \
+  /* Interface descriptor type */ \
+  _IF_NUM,   /* bInterfaceNumber: Number of Interface */ \
+  0x00,   /* bAlternateSetting: Alternate setting */ \
+  _EP_COUNT,   /* bNumEndpoints: One endpoints used */ \
+  _CLASS,   /* bInterfaceClass: Communication Interface Class */ \
+  _SUBCLASS,   /* bInterfaceSubClass: Abstract Control Model */ \
+  _PROT,   /* bInterfaceProtocol: Common AT commands */ \
+  0x05   /* iInterface: */
+
+
+
+#define USB_DESC_TYPE_INTERFACE_ASSOC_DESC        0x0B
+
+#define CONFIGURATION_DESCRIPTOR() \
+  0x09, /* bLength: Configuation Descriptor size */   \
+  USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ \
+  USB_CDC_MSC_CONFIG_DESC_SIZ, /* wTotalLength: Bytes returned */   \
+  0x00,                                               \
+  0x03, /*bNumInterfaces: 3 interface*/               \
+  0x01, /*bConfigurationValue: Configuration value*/  \
+  0x02, /*iConfiguration: Index of string descriptor describing the configuration*/ \
+  0xC0, /*bmAttributes: bus powered and Supports Remote Wakeup */ \
+  0x32  /*MaxPower 100 mA: this current is used for detecting Vbus*/
+/* 09 */
+
+/******** IAD should be positioned just before the CDC interfaces ******
+          IAD to associate the two CDC interfaces */
+#define IAD_DESCRIPTOR() \
+  0x08, /* bLength: Interface Descriptor size */  \
+  USB_DESC_TYPE_INTERFACE_ASSOC_DESC, /* bDescriptorType: Interface */  \
+  0x00, /* bFirstInterface */     \
+  0x02, /* bInterfaceCount */     \
+  0x02, /* bFunctionClass */      \
+  0x02, /* bFunctionSubClass */   \
+  0x01, /* bFunctionProtocol */   \
+  0x04    /* iFunction (Index of string descriptor describing this function) */
+/* 08 */
+
+/* ACM Interface Descriptor */
+#define ACM_INTERFACE_DESCRIPTOR() INTERFACE_DESCRIPTOR(CDC_ACM_INTERFACE, 0x01, IF_CLASS_COMM, IF_SUBCLASS_ACM, 0x01)
+
+/* Header Functional Descriptor */
+#define ACM_HEADER_FUNCTIONAL_DESCRIPTOR() \
+  0x05,   /* bLength: Endpoint Descriptor size */ \
+  0x24,   /* bDescriptorType: CS_INTERFACE */ \
+  0x00,   /* bDescriptorSubtype: Header Func Desc */ \
+  0x10,   /* bcdCDC: spec release number */ \
+  0x01
+
+/* ACM Call Management Functional Descriptor */
+#define ACM_CALL_MANAGEMENT_FUNCTIONAL_DESCRIPTOR() \
+  0x05,   /* bFunctionLength */ \
+  0x24,   /* bDescriptorType: CS_INTERFACE */ \
+  0x01,   /* bDescriptorSubtype: Call Management Func Desc */ \
+  0x00,   /* bmCapabilities: D0+D1 */ \
+  CDC_COM_INTERFACE   /* bDataInterface: 1 */ \
+
+/* ACM Functional Descriptor */
+#define ACM_FUNCTIONAL_DESCRIPTOR() \
+  0x04,   /* bFunctionLength */ \
+  0x24,   /* bDescriptorType: CS_INTERFACE */ \
+  0x02,   /* bDescriptorSubtype: Abstract Control Management desc */ \
+  0x02    /* bmCapabilities */
+
+#define ACM_UNION_FUNCTIONAL_DESCRIPTOR() \
+  0x05,   /* bFunctionLength */ \
+  0x24,   /* bDescriptorType: CS_INTERFACE */ \
+  0x06,   /* bDescriptorSubtype: Union func desc */ \
+  CDC_ACM_INTERFACE,   /* bMasterInterface: Communication class interface */ \
+  CDC_COM_INTERFACE   /* bSlaveInterface0: Data Class Interface */
+
+#define ACM_EP_DESCRIPTOR(_BINTERVAL) ENDPOINT_DESCRIPTOR(CDC_CMD_EP, EP_ATTR_INTERRUPT, CDC_CMD_PACKET_SIZE, _BINTERVAL)
+
+#define CDC_INTERFACE_DESCRIPTOR() INTERFACE_DESCRIPTOR(CDC_COM_INTERFACE, 0x02, IF_CLASS_CDC, IF_SUBCLASS_NONE, 0x00)
+#define CDC_EP_OUT_DESCRIPTOR(_PACKET_SIZE) ENDPOINT_DESCRIPTOR(CDC_OUT_EP, EP_ATTR_BULK, _PACKET_SIZE, 0x00)
+#define CDC_EP_IN_DESCRIPTOR(_PACKET_SIZE) ENDPOINT_DESCRIPTOR(CDC_IN_EP, EP_ATTR_BULK, _PACKET_SIZE, 0x00)
+
+#define MSC_INTERFACE_DESCRIPTOR() INTERFACE_DESCRIPTOR(MSC_INTERFACE, 0x02, IF_CLASS_MSC, IF_SUBCLASS_SCSI_TRANSPARENT, 0x50)
+#define MSC_EP_IN_DESCRIPTOR(_PACKET_SIZE) ENDPOINT_DESCRIPTOR(MSC_EPIN_ADDR, EP_ATTR_BULK, _PACKET_SIZE, 0x00)
+#define MSC_EP_OUT_DESCRIPTOR(_PACKET_SIZE) ENDPOINT_DESCRIPTOR(MSC_EPOUT_ADDR, EP_ATTR_BULK, _PACKET_SIZE, 0x00)
+
+
+#if defined ( __ICCARM__ ) /*!< IAR Compiler */
+  #pragma data_alignment=4
+#endif
+
+
+/* USB COMPOSITE device Configuration Descriptor */
+#if defined ( __ICCARM__ ) /*!< IAR Compiler */
+  #pragma data_alignment=4
+#endif
+static uint8_t USBD_COMPOSITE_HSCfgDesc[USB_CDC_MSC_CONFIG_DESC_SIZ] = {
+  CONFIGURATION_DESCRIPTOR(),
+  IAD_DESCRIPTOR(),
+
+  ACM_INTERFACE_DESCRIPTOR(),
+  ACM_HEADER_FUNCTIONAL_DESCRIPTOR(),
+  ACM_CALL_MANAGEMENT_FUNCTIONAL_DESCRIPTOR(),
+  ACM_FUNCTIONAL_DESCRIPTOR(),
+  ACM_UNION_FUNCTIONAL_DESCRIPTOR(),
+  ACM_EP_DESCRIPTOR(CDC_HS_BINTERVAL),
+
+  CDC_INTERFACE_DESCRIPTOR(),
+  CDC_EP_OUT_DESCRIPTOR(CDC_DATA_HS_MAX_PACKET_SIZE),
+  CDC_EP_IN_DESCRIPTOR(CDC_DATA_HS_MAX_PACKET_SIZE),
+
+  MSC_INTERFACE_DESCRIPTOR(),
+  MSC_EP_IN_DESCRIPTOR(MSC_MAX_HS_PACKET),
+  MSC_EP_OUT_DESCRIPTOR(MSC_MAX_HS_PACKET)
+};
+
+#if defined ( __ICCARM__ ) /*!< IAR Compiler */
+  #pragma data_alignment=4
+#endif
+/* USB COMPOSITE device Configuration Descriptor */
+static uint8_t USBD_COMPOSITE_FSCfgDesc[USB_CDC_MSC_CONFIG_DESC_SIZ] = {
+  CONFIGURATION_DESCRIPTOR(),
+  IAD_DESCRIPTOR(),
+
+  ACM_INTERFACE_DESCRIPTOR(),
+  ACM_HEADER_FUNCTIONAL_DESCRIPTOR(),
+  ACM_CALL_MANAGEMENT_FUNCTIONAL_DESCRIPTOR(),
+  ACM_FUNCTIONAL_DESCRIPTOR(),
+  ACM_UNION_FUNCTIONAL_DESCRIPTOR(),
+  ACM_EP_DESCRIPTOR(CDC_FS_BINTERVAL),
+
+  CDC_INTERFACE_DESCRIPTOR(),
+  CDC_EP_OUT_DESCRIPTOR(CDC_DATA_FS_MAX_PACKET_SIZE),
+  CDC_EP_IN_DESCRIPTOR(CDC_DATA_FS_MAX_PACKET_SIZE),
+
+  MSC_INTERFACE_DESCRIPTOR(),
+  MSC_EP_IN_DESCRIPTOR(MSC_MAX_FS_PACKET),
+  MSC_EP_OUT_DESCRIPTOR(MSC_MAX_FS_PACKET)
+};
+
+
+#if defined ( __ICCARM__ ) /*!< IAR Compiler */
+  #pragma data_alignment=4
+#endif
+/* USB COMPOSITE device Configuration Descriptor */
+static uint8_t USBD_COMPOSITE_OtherSpeedCfgDesc[USB_CDC_MSC_CONFIG_DESC_SIZ] = {
+  CONFIGURATION_DESCRIPTOR(),
+  IAD_DESCRIPTOR(),
+
+  ACM_INTERFACE_DESCRIPTOR(),
+  ACM_HEADER_FUNCTIONAL_DESCRIPTOR(),
+  ACM_CALL_MANAGEMENT_FUNCTIONAL_DESCRIPTOR(),
+  ACM_FUNCTIONAL_DESCRIPTOR(),
+  ACM_UNION_FUNCTIONAL_DESCRIPTOR(),
+  ACM_EP_DESCRIPTOR(CDC_FS_BINTERVAL),
+
+  CDC_INTERFACE_DESCRIPTOR(),
+  CDC_EP_OUT_DESCRIPTOR(CDC_DATA_FS_MAX_PACKET_SIZE),
+  CDC_EP_IN_DESCRIPTOR(CDC_DATA_FS_MAX_PACKET_SIZE),
+
+  MSC_INTERFACE_DESCRIPTOR(),
+  MSC_EP_IN_DESCRIPTOR(MSC_MAX_FS_PACKET),
+  MSC_EP_OUT_DESCRIPTOR(MSC_MAX_FS_PACKET)
+};
+
+
+#if defined ( __ICCARM__ ) /*!< IAR Compiler */
+  #pragma data_alignment=4
+#endif
+/* USB Standard Device Descriptor */
+static uint8_t USBD_COMPOSITE_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] = {
+  USB_LEN_DEV_QUALIFIER_DESC,
+  USB_DESC_TYPE_DEVICE_QUALIFIER,
+  0x00,
+  0x02,
+  0x00,
+  0x00,
+  0x00,
+  0x40,
+  0x01,
+  0x00,
+};
+
+int cdcMscInitialised;
+
+/**
+  * @brief  USBD_COMPOSITE_Init
+  *         Initialize the COMPOSITE interface
+  * @param  pdev: device instance
+  * @param  cfgidx: Configuration index
+  * @retval status
+  */
+static uint8_t  USBD_COMPOSITE_Init(USBD_HandleTypeDef *pdev,
+                                    uint8_t cfgidx)
+{
+  USBD_MSC.Init(pdev, cfgidx);
+
+  USBD_CDC.Init(pdev, cfgidx);
+
+  pdev->pClassData = &cdcMscInitialised;
+
+  return (uint8_t)USBD_OK;
+}
+
+/**
+  * @brief  USBD_COMPOSITE_Init
+  *         DeInitialize the COMPOSITE layer
+  * @param  pdev: device instance
+  * @param  cfgidx: Configuration index
+  * @retval status
+  */
+static uint8_t  USBD_COMPOSITE_DeInit(USBD_HandleTypeDef *pdev,
+                                      uint8_t cfgidx)
+{
+  USBD_MSC.DeInit(pdev, cfgidx);
+
+  USBD_CDC.DeInit(pdev, cfgidx);
+
+  if (pdev->pClassData == &cdcMscInitialised) {
+    pdev->pClassData = nullptr;
+  }
+
+  return USBD_OK;
+}
+
+/**
+  * @brief  USBD_COMPOSITE_Setup
+  *         Handle the COMPOSITE specific requests
+  * @param  pdev: instance
+  * @param  req: usb requests
+  * @retval status
+  */
+static uint8_t  USBD_COMPOSITE_Setup(USBD_HandleTypeDef *pdev,
+                                     USBD_SetupReqTypedef *req)
+{
+  switch (req->bmRequest & USB_REQ_RECIPIENT_MASK) {
+    case USB_REQ_RECIPIENT_INTERFACE:
+      switch (req->wIndex) {
+        case CDC_ACM_INTERFACE:
+        case CDC_COM_INTERFACE:
+          return USBD_CDC.Setup(pdev, req);
+          break;
+
+        case MSC_INTERFACE:
+          return USBD_MSC.Setup(pdev, req);
+          break;
+
+        // invalid interface
+        default:
+          return USBD_FAIL;
+      }
+      break;
+
+    case USB_REQ_RECIPIENT_ENDPOINT:
+      switch (req->wIndex) {
+        case CDC_IN_EP:
+        case CDC_OUT_EP:
+        case CDC_CMD_EP:
+          return USBD_CDC.Setup(pdev, req);
+
+        case MSC_EPIN_ADDR:
+        case MSC_EPOUT_ADDR:
+          return USBD_MSC.Setup(pdev, req);
+
+        // invalid endpoint
+        default:
+          return USBD_FAIL;
+      }
+      break;
+
+    default:
+      break;
+  }
+
+  return USBD_OK;
+}
+
+
+/**
+  * @brief  USBD_COMPOSITE_GetHSCfgDesc
+  *         return configuration descriptor
+  * @param  length : pointer data length
+  * @retval pointer to descriptor buffer
+  */
+static uint8_t  *USBD_COMPOSITE_GetHSCfgDesc(uint16_t *length)
+{
+  *length = sizeof(USBD_COMPOSITE_HSCfgDesc);
+  return USBD_COMPOSITE_HSCfgDesc;
+}
+
+/**
+  * @brief  USBD_COMPOSITE_GetFSCfgDesc
+  *         return configuration descriptor
+  * @param  length : pointer data length
+  * @retval pointer to descriptor buffer
+  */
+static uint8_t  *USBD_COMPOSITE_GetFSCfgDesc(uint16_t *length)
+{
+  *length = sizeof(USBD_COMPOSITE_FSCfgDesc);
+  return USBD_COMPOSITE_FSCfgDesc;
+}
+
+/**
+  * @brief  USBD_COMPOSITE_GetOtherSpeedCfgDesc
+  *         return configuration descriptor
+  * @param  length : pointer data length
+  * @retval pointer to descriptor buffer
+  */
+static uint8_t  *USBD_COMPOSITE_GetOtherSpeedCfgDesc(uint16_t *length)
+{
+  *length = sizeof(USBD_COMPOSITE_OtherSpeedCfgDesc);
+  return USBD_COMPOSITE_OtherSpeedCfgDesc;
+}
+
+/**
+* @brief  DeviceQualifierDescriptor
+*         return Device Qualifier descriptor
+* @param  length : pointer data length
+* @retval pointer to descriptor buffer
+*/
+uint8_t  *USBD_COMPOSITE_DeviceQualifierDescriptor(uint16_t *length)
+{
+  *length = sizeof(USBD_COMPOSITE_DeviceQualifierDesc);
+  return USBD_COMPOSITE_DeviceQualifierDesc;
+}
+
+
+/**
+  * @brief  USBD_COMPOSITE_DataIn
+  *         handle data IN Stage
+  * @param  pdev: device instance
+  * @param  epnum: endpoint index
+  * @retval status
+  */
+static uint8_t  USBD_COMPOSITE_DataIn(USBD_HandleTypeDef *pdev,
+                                      uint8_t epnum)
+{
+  switch (epnum) {
+    case CDC_IN_EP:
+    case CDC_CMD_EP:
+    case CDC_OUT_EP:
+      return USBD_CDC.DataIn(pdev, epnum);
+
+    case MSC_EPIN_ADDR:
+    case MSC_EPOUT_ADDR:
+      return USBD_MSC.DataIn(pdev, epnum);
+
+    // invalid endpoint
+    default:
+      return USBD_FAIL;
+  }
+}
+
+/**
+  * @brief  USBD_COMPOSITE_EP0_RxReady
+  *         handle EP0 Rx Ready event
+  * @param  pdev: device instance
+  * @retval status
+  */
+static uint8_t  USBD_COMPOSITE_EP0_RxReady(USBD_HandleTypeDef *pdev)
+{
+  // only needed by CDC
+  return USBD_CDC.EP0_RxReady(pdev);
+}
+
+/**
+  * @brief  USBD_COMPOSITE_DataOut
+  *         handle data OUT Stage
+  * @param  pdev: device instance
+  * @param  epnum: endpoint index
+  * @retval status
+  */
+static uint8_t  USBD_COMPOSITE_DataOut(USBD_HandleTypeDef *pdev,
+                                       uint8_t epnum)
+{
+  switch (epnum) {
+    case CDC_IN_EP:
+    case CDC_CMD_EP:
+    case CDC_OUT_EP:
+      return USBD_CDC.DataOut(pdev, epnum);
+
+    case MSC_EPIN_ADDR:
+    case MSC_EPOUT_ADDR:
+      return USBD_MSC.DataOut(pdev, epnum);
+
+    // invalid endpoint
+    default:
+      return USBD_FAIL;
+  }
+}
+
+/**
+* @brief  DeviceQualifierDescriptor
+*         return Device Qualifier descriptor
+* @param  length : pointer data length
+* @retval pointer to descriptor buffer
+*/
+uint8_t  *USBD_COMPOSITE_GetDeviceQualifierDesc(uint16_t *length)
+{
+  *length = sizeof(USBD_COMPOSITE_DeviceQualifierDesc);
+  return USBD_COMPOSITE_DeviceQualifierDesc;
+}
+
+#endif /* USBD_USE_MSC_CLASS */
+#endif /* USBCON */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/cores/arduino/stm32/usb/cdc_msc/usbd_cdc_msc.h b/cores/arduino/stm32/usb/cdc_msc/usbd_cdc_msc.h
new file mode 100644
index 0000000000..e8110535d8
--- /dev/null
+++ b/cores/arduino/stm32/usb/cdc_msc/usbd_cdc_msc.h
@@ -0,0 +1,39 @@
+/**
+  ******************************************************************************
+  * @file    usbd_cdc_msc_core.h
+  * @author  MCD Application Team
+  * @version V1.2.1
+  * @date    17-March-2018
+  * @brief   header file for the usbd_cdc_msc_core.c file.
+  ******************************************************************************
+  * @attention
+  *
+  * © Copyright (c) 2015 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                      
+  *
+  ******************************************************************************
+  */
+
+#ifndef __USB_CDC_MSC_CORE_H_
+#define __USB_CDC_MSC_CORE_H_
+
+#include "usbd_cdc.h"
+#include "usbd_msc.h"
+#include "usbd_ioreq.h"
+
+#define CDC_ACM_INTERFACE   0x0
+#define CDC_COM_INTERFACE   0x1
+#define MSC_INTERFACE       0x2
+
+#define USB_CDC_MSC_CONFIG_DESC_SIZ  (USB_CDC_CONFIG_DESC_SIZ - 9 + 8 + USB_MSC_CONFIG_DESC_SIZ)
+
+extern USBD_ClassTypeDef  USBD_CDC_MSC;
+
+#endif  /* __USB_CDC_MSC_CORE_H_ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/cores/arduino/stm32/usb/msc/usbd_msc.c b/cores/arduino/stm32/usb/msc/usbd_msc.c
new file mode 100644
index 0000000000..742d747c30
--- /dev/null
+++ b/cores/arduino/stm32/usb/msc/usbd_msc.c
@@ -0,0 +1,494 @@
+/**
+  ******************************************************************************
+  * @file    usbd_msc.c
+  * @author  MCD Application Team
+  * @brief   This file provides all the MSC core functions.
+  *
+  * @verbatim
+  *
+  *          ===================================================================
+  *                                MSC Class  Description
+  *          ===================================================================
+  *           This module manages the MSC class V1.0 following the "Universal
+  *           Serial Bus Mass Storage Class (MSC) Bulk-Only Transport (BOT) Version 1.0
+  *           Sep. 31, 1999".
+  *           This driver implements the following aspects of the specification:
+  *             - Bulk-Only Transport protocol
+  *             - Subclass : SCSI transparent command set (ref. SCSI Primary Commands - 3 (SPC-3))
+  *
+  *  @endverbatim
+  *
+  ******************************************************************************
+  * @attention
+  *
+  * © Copyright (c) 2015 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                      www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+/* BSPDependencies
+- "stm32xxxxx_{eval}{discovery}{nucleo_144}.c"
+- "stm32xxxxx_{eval}{discovery}_io.c"
+- "stm32xxxxx_{eval}{discovery}{adafruit}_sd.c"
+EndBSPDependencies */
+
+#include "usbd_ep_conf.h"
+
+#ifdef USBCON
+#ifdef USBD_USE_MSC_CLASS
+
+#include "usbd_msc.h"
+#include "usbd_msc_storage_if.h"
+
+
+uint8_t USBD_MSC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
+uint8_t USBD_MSC_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
+uint8_t USBD_MSC_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
+uint8_t USBD_MSC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum);
+uint8_t USBD_MSC_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum);
+
+uint8_t *USBD_MSC_GetHSCfgDesc(uint16_t *length);
+uint8_t *USBD_MSC_GetFSCfgDesc(uint16_t *length);
+uint8_t *USBD_MSC_GetOtherSpeedCfgDesc(uint16_t *length);
+uint8_t *USBD_MSC_GetDeviceQualifierDescriptor(uint16_t *length);
+
+
+USBD_ClassTypeDef  USBD_MSC = {
+  USBD_MSC_Init,
+  USBD_MSC_DeInit,
+  USBD_MSC_Setup,
+  NULL, /*EP0_TxSent*/
+  NULL, /*EP0_RxReady*/
+  USBD_MSC_DataIn,
+  USBD_MSC_DataOut,
+  NULL, /*SOF */
+  NULL,
+  NULL,
+  USBD_MSC_GetHSCfgDesc,
+  USBD_MSC_GetFSCfgDesc,
+  USBD_MSC_GetOtherSpeedCfgDesc,
+  USBD_MSC_GetDeviceQualifierDescriptor,
+};
+
+/* USB Mass storage device Configuration Descriptor */
+/*   All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
+__ALIGN_BEGIN static uint8_t USBD_MSC_CfgHSDesc[USB_MSC_CONFIG_DESC_SIZ]  __ALIGN_END = {
+
+  0x09,   /* bLength: Configuation Descriptor size */
+  USB_DESC_TYPE_CONFIGURATION,   /* bDescriptorType: Configuration */
+  USB_MSC_CONFIG_DESC_SIZ,
+
+  0x00,
+  0x01,   /* bNumInterfaces: 1 interface */
+  0x01,   /* bConfigurationValue: */
+  0x04,   /* iConfiguration: */
+  0xC0,   /* bmAttributes: */
+  0x32,   /* MaxPower 100 mA */
+
+  /********************  Mass Storage interface ********************/
+  0x09,   /* bLength: Interface Descriptor size */
+  0x04,   /* bDescriptorType: */
+  0x00,   /* bInterfaceNumber: Number of Interface */
+  0x00,   /* bAlternateSetting: Alternate setting */
+  0x02,   /* bNumEndpoints*/
+  0x08,   /* bInterfaceClass: MSC Class */
+  0x06,   /* bInterfaceSubClass : SCSI transparent*/
+  0x50,   /* nInterfaceProtocol */
+  0x05,          /* iInterface: */
+  /********************  Mass Storage Endpoints ********************/
+  0x07,   /*Endpoint descriptor length = 7*/
+  0x05,   /*Endpoint descriptor type */
+  MSC_EPIN_ADDR,   /*Endpoint address (IN, address 1) */
+  0x02,   /*Bulk endpoint type */
+  LOBYTE(MSC_MAX_HS_PACKET),
+  HIBYTE(MSC_MAX_HS_PACKET),
+  0x00,   /*Polling interval in milliseconds */
+
+  0x07,   /*Endpoint descriptor length = 7 */
+  0x05,   /*Endpoint descriptor type */
+  MSC_EPOUT_ADDR,   /*Endpoint address (OUT, address 1) */
+  0x02,   /*Bulk endpoint type */
+  LOBYTE(MSC_MAX_HS_PACKET),
+  HIBYTE(MSC_MAX_HS_PACKET),
+  0x00     /*Polling interval in milliseconds*/
+};
+
+/* USB Mass storage device Configuration Descriptor */
+/* All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
+__ALIGN_BEGIN static uint8_t USBD_MSC_CfgFSDesc[USB_MSC_CONFIG_DESC_SIZ]  __ALIGN_END = {
+  0x09,   /* bLength: Configuation Descriptor size */
+  USB_DESC_TYPE_CONFIGURATION,   /* bDescriptorType: Configuration */
+  USB_MSC_CONFIG_DESC_SIZ,
+
+  0x00,
+  0x01,   /* bNumInterfaces: 1 interface */
+  0x01,   /* bConfigurationValue: */
+  0x04,   /* iConfiguration: */
+  0xC0,   /* bmAttributes: */
+  0x32,   /* MaxPower 100 mA */
+
+  /********************  Mass Storage interface ********************/
+  0x09,   /* bLength: Interface Descriptor size */
+  0x04,   /* bDescriptorType: */
+  0x00,   /* bInterfaceNumber: Number of Interface */
+  0x00,   /* bAlternateSetting: Alternate setting */
+  0x02,   /* bNumEndpoints*/
+  0x08,   /* bInterfaceClass: MSC Class */
+  0x06,   /* bInterfaceSubClass : SCSI transparent*/
+  0x50,   /* nInterfaceProtocol */
+  0x05,          /* iInterface: */
+  /********************  Mass Storage Endpoints ********************/
+  0x07,   /*Endpoint descriptor length = 7*/
+  0x05,   /*Endpoint descriptor type */
+  MSC_EPIN_ADDR,   /*Endpoint address (IN, address 1) */
+  0x02,   /*Bulk endpoint type */
+  LOBYTE(MSC_MAX_FS_PACKET),
+  HIBYTE(MSC_MAX_FS_PACKET),
+  0x00,   /*Polling interval in milliseconds */
+
+  0x07,   /*Endpoint descriptor length = 7 */
+  0x05,   /*Endpoint descriptor type */
+  MSC_EPOUT_ADDR,   /*Endpoint address (OUT, address 1) */
+  0x02,   /*Bulk endpoint type */
+  LOBYTE(MSC_MAX_FS_PACKET),
+  HIBYTE(MSC_MAX_FS_PACKET),
+  0x00     /*Polling interval in milliseconds*/
+};
+
+__ALIGN_BEGIN static uint8_t USBD_MSC_OtherSpeedCfgDesc[USB_MSC_CONFIG_DESC_SIZ]   __ALIGN_END  = {
+  0x09,   /* bLength: Configuation Descriptor size */
+  USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION,
+  USB_MSC_CONFIG_DESC_SIZ,
+
+  0x00,
+  0x01,   /* bNumInterfaces: 1 interface */
+  0x01,   /* bConfigurationValue: */
+  0x04,   /* iConfiguration: */
+  0xC0,   /* bmAttributes: */
+  0x32,   /* MaxPower 100 mA */
+
+  /********************  Mass Storage interface ********************/
+  0x09,   /* bLength: Interface Descriptor size */
+  0x04,   /* bDescriptorType: */
+  0x00,   /* bInterfaceNumber: Number of Interface */
+  0x00,   /* bAlternateSetting: Alternate setting */
+  0x02,   /* bNumEndpoints*/
+  0x08,   /* bInterfaceClass: MSC Class */
+  0x06,   /* bInterfaceSubClass : SCSI transparent command set*/
+  0x50,   /* nInterfaceProtocol */
+  0x05,          /* iInterface: */
+  /********************  Mass Storage Endpoints ********************/
+  0x07,   /*Endpoint descriptor length = 7*/
+  0x05,   /*Endpoint descriptor type */
+  MSC_EPIN_ADDR,   /*Endpoint address (IN, address 1) */
+  0x02,   /*Bulk endpoint type */
+  0x40,
+  0x00,
+  0x00,   /*Polling interval in milliseconds */
+
+  0x07,   /*Endpoint descriptor length = 7 */
+  0x05,   /*Endpoint descriptor type */
+  MSC_EPOUT_ADDR,   /*Endpoint address (OUT, address 1) */
+  0x02,   /*Bulk endpoint type */
+  0x40,
+  0x00,
+  0x00     /*Polling interval in milliseconds*/
+};
+
+/* USB Standard Device Descriptor */
+__ALIGN_BEGIN static uint8_t USBD_MSC_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC]  __ALIGN_END = {
+  USB_LEN_DEV_QUALIFIER_DESC,
+  USB_DESC_TYPE_DEVICE_QUALIFIER,
+  0x00,
+  0x02,
+  0x00,
+  0x00,
+  0x00,
+  MSC_MAX_FS_PACKET,
+  0x01,
+  0x00,
+};
+/**
+  * @}
+  */
+
+USBD_MSC_BOT_HandleTypeDef msc_handle_dat;
+USBD_MSC_BOT_HandleTypeDef *msc_handle = &msc_handle_dat;
+
+USBD_StorageTypeDef *msc_storage = &USBD_MSC_fops;
+
+int mscInitialized;
+
+/**
+  * @brief  USBD_MSC_Init
+  *         Initialize  the mass storage configuration
+  * @param  pdev: device instance
+  * @param  cfgidx: configuration index
+  * @retval status
+  */
+uint8_t USBD_MSC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
+{
+  UNUSED(cfgidx);
+  pdev->pClassData = &mscInitialized;
+
+  if (pdev->dev_speed == USBD_SPEED_HIGH) {
+    /* Open EP OUT */
+    (void)USBD_LL_OpenEP(pdev, MSC_EPOUT_ADDR, USBD_EP_TYPE_BULK, MSC_MAX_HS_PACKET);
+    pdev->ep_out[MSC_EPOUT_ADDR & 0xFU].is_used = 1U;
+
+    /* Open EP IN */
+    (void)USBD_LL_OpenEP(pdev, MSC_EPIN_ADDR, USBD_EP_TYPE_BULK, MSC_MAX_HS_PACKET);
+    pdev->ep_in[MSC_EPIN_ADDR & 0xFU].is_used = 1U;
+  } else {
+    /* Open EP OUT */
+    (void)USBD_LL_OpenEP(pdev, MSC_EPOUT_ADDR, USBD_EP_TYPE_BULK, MSC_MAX_FS_PACKET);
+    pdev->ep_out[MSC_EPOUT_ADDR & 0xFU].is_used = 1U;
+
+    /* Open EP IN */
+    (void)USBD_LL_OpenEP(pdev, MSC_EPIN_ADDR, USBD_EP_TYPE_BULK, MSC_MAX_FS_PACKET);
+    pdev->ep_in[MSC_EPIN_ADDR & 0xFU].is_used = 1U;
+  }
+
+  /* Init the BOT  layer */
+  MSC_BOT_Init(pdev);
+
+  return (uint8_t)USBD_OK;
+}
+
+/**
+  * @brief  USBD_MSC_DeInit
+  *         DeInitialize  the mass storage configuration
+  * @param  pdev: device instance
+  * @param  cfgidx: configuration index
+  * @retval status
+  */
+uint8_t USBD_MSC_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
+{
+  UNUSED(cfgidx);
+
+  /* Close MSC EPs */
+  (void)USBD_LL_CloseEP(pdev, MSC_EPOUT_ADDR);
+  pdev->ep_out[MSC_EPOUT_ADDR & 0xFU].is_used = 0U;
+
+  /* Close EP IN */
+  (void)USBD_LL_CloseEP(pdev, MSC_EPIN_ADDR);
+  pdev->ep_in[MSC_EPIN_ADDR & 0xFU].is_used = 0U;
+
+  /* De-Init the BOT layer */
+  MSC_BOT_DeInit(pdev);
+
+  if (pdev->pClassData == &mscInitialized) {
+    // only mark as uninitialised if we own the initialisation
+    pdev->pClassData = NULL;
+  }
+
+  return (uint8_t)USBD_OK;
+}
+
+/**
+* @brief  USBD_MSC_Setup
+*         Handle the MSC specific requests
+* @param  pdev: device instance
+* @param  req: USB request
+* @retval status
+*/
+uint8_t USBD_MSC_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
+{
+  USBD_MSC_BOT_HandleTypeDef *hmsc = msc_handle;
+  uint8_t ret = USBD_OK;
+  uint16_t status_info = 0U;
+
+  switch (req->bmRequest & USB_REQ_TYPE_MASK) {
+    /* Class request */
+    case USB_REQ_TYPE_CLASS:
+      switch (req->bRequest) {
+        case BOT_GET_MAX_LUN:
+          if ((req->wValue  == 0U) && (req->wLength == 1U) &&
+              ((req->bmRequest & 0x80U) == 0x80U)) {
+            hmsc->max_lun = (uint32_t)msc_storage->GetMaxLun();
+            (void)USBD_CtlSendData(pdev, (uint8_t *)&hmsc->max_lun, 1U);
+          } else {
+            USBD_CtlError(pdev, req);
+            ret = USBD_FAIL;
+          }
+          break;
+
+        case BOT_RESET:
+          if ((req->wValue  == 0U) && (req->wLength == 0U) &&
+              ((req->bmRequest & 0x80U) != 0x80U)) {
+            MSC_BOT_Reset(pdev);
+          } else {
+            USBD_CtlError(pdev, req);
+            ret = USBD_FAIL;
+          }
+          break;
+
+        default:
+          USBD_CtlError(pdev, req);
+          ret = USBD_FAIL;
+          break;
+      }
+      break;
+    /* Interface & Endpoint request */
+    case USB_REQ_TYPE_STANDARD:
+      switch (req->bRequest) {
+        case USB_REQ_GET_STATUS:
+          if (pdev->dev_state == USBD_STATE_CONFIGURED) {
+            (void)USBD_CtlSendData(pdev, (uint8_t *)&status_info, 2U);
+          } else {
+            USBD_CtlError(pdev, req);
+            ret = USBD_FAIL;
+          }
+          break;
+
+        case USB_REQ_GET_INTERFACE:
+          if (pdev->dev_state == USBD_STATE_CONFIGURED) {
+            (void)USBD_CtlSendData(pdev, (uint8_t *)&hmsc->interface, 1U);
+          } else {
+            USBD_CtlError(pdev, req);
+            ret = USBD_FAIL;
+          }
+          break;
+
+        case USB_REQ_SET_INTERFACE:
+          if (pdev->dev_state == USBD_STATE_CONFIGURED) {
+            hmsc->interface = (uint8_t)(req->wValue);
+          } else {
+            USBD_CtlError(pdev, req);
+            ret = USBD_FAIL;
+          }
+          break;
+
+        case USB_REQ_CLEAR_FEATURE:
+          if (pdev->dev_state == USBD_STATE_CONFIGURED) {
+            if (req->wValue == USB_FEATURE_EP_HALT) {
+              /* Flush the FIFO */
+              (void)USBD_LL_FlushEP(pdev, (uint8_t)req->wIndex);
+
+              /* Handle BOT error */
+              MSC_BOT_CplClrFeature(pdev, (uint8_t)req->wIndex);
+            }
+          }
+          break;
+
+        default:
+          USBD_CtlError(pdev, req);
+          ret = USBD_FAIL;
+          break;
+      }
+      break;
+
+    default:
+      USBD_CtlError(pdev, req);
+      ret = USBD_FAIL;
+      break;
+  }
+
+  return (uint8_t)ret;
+}
+
+/**
+* @brief  USBD_MSC_DataIn
+*         handle data IN Stage
+* @param  pdev: device instance
+* @param  epnum: endpoint index
+* @retval status
+*/
+uint8_t USBD_MSC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum)
+{
+  MSC_BOT_DataIn(pdev, epnum);
+
+  return (uint8_t)USBD_OK;
+}
+
+/**
+* @brief  USBD_MSC_DataOut
+*         handle data OUT Stage
+* @param  pdev: device instance
+* @param  epnum: endpoint index
+* @retval status
+*/
+uint8_t USBD_MSC_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
+{
+  MSC_BOT_DataOut(pdev, epnum);
+
+  return (uint8_t)USBD_OK;
+}
+
+/**
+* @brief  USBD_MSC_GetHSCfgDesc
+*         return configuration descriptor
+* @param  length : pointer data length
+* @retval pointer to descriptor buffer
+*/
+uint8_t *USBD_MSC_GetHSCfgDesc(uint16_t *length)
+{
+  *length = (uint16_t)sizeof(USBD_MSC_CfgHSDesc);
+
+  return USBD_MSC_CfgHSDesc;
+}
+
+/**
+* @brief  USBD_MSC_GetFSCfgDesc
+*         return configuration descriptor
+* @param  length : pointer data length
+* @retval pointer to descriptor buffer
+*/
+uint8_t *USBD_MSC_GetFSCfgDesc(uint16_t *length)
+{
+  *length = (uint16_t)sizeof(USBD_MSC_CfgFSDesc);
+
+  return USBD_MSC_CfgFSDesc;
+}
+
+/**
+* @brief  USBD_MSC_GetOtherSpeedCfgDesc
+*         return other speed configuration descriptor
+* @param  length : pointer data length
+* @retval pointer to descriptor buffer
+*/
+uint8_t *USBD_MSC_GetOtherSpeedCfgDesc(uint16_t *length)
+{
+  *length = (uint16_t)sizeof(USBD_MSC_OtherSpeedCfgDesc);
+
+  return USBD_MSC_OtherSpeedCfgDesc;
+}
+/**
+* @brief  DeviceQualifierDescriptor
+*         return Device Qualifier descriptor
+* @param  length : pointer data length
+* @retval pointer to descriptor buffer
+*/
+uint8_t *USBD_MSC_GetDeviceQualifierDescriptor(uint16_t *length)
+{
+  *length = (uint16_t)sizeof(USBD_MSC_DeviceQualifierDesc);
+
+  return USBD_MSC_DeviceQualifierDesc;
+}
+
+/**
+* @brief  USBD_MSC_RegisterStorage
+* @param  fops: storage callback
+* @retval status
+*/
+uint8_t USBD_MSC_RegisterStorage(USBD_HandleTypeDef *pdev, USBD_StorageTypeDef *fops)
+{
+  if (fops == NULL) {
+    return (uint8_t)USBD_FAIL;
+  }
+
+  msc_storage = fops;
+
+  return (uint8_t)USBD_OK;
+}
+
+#endif /* USBD_USE_MSC_CLASS */
+#endif /* USBCON */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/cores/arduino/stm32/usb/msc/usbd_msc.h b/cores/arduino/stm32/usb/msc/usbd_msc.h
new file mode 100644
index 0000000000..a3001d570c
--- /dev/null
+++ b/cores/arduino/stm32/usb/msc/usbd_msc.h
@@ -0,0 +1,100 @@
+/**
+  ******************************************************************************
+  * @file    usbd_msc.h
+  * @author  MCD Application Team
+  * @brief   Header for the usbd_msc.c file
+  ******************************************************************************
+  * @attention
+  *
+  * © Copyright (c) 2015 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                      www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USBD_MSC_H
+#define __USBD_MSC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include  "usbd_msc_bot.h"
+#include  "usbd_msc_scsi.h"
+#include  "usbd_ioreq.h"
+
+/* MSC Class Config */
+#ifndef MSC_MEDIA_PACKET
+#define MSC_MEDIA_PACKET             512U
+#endif /* MSC_MEDIA_PACKET */
+
+#define MSC_MAX_FS_PACKET            0x40U
+#define MSC_MAX_HS_PACKET            0x200U
+
+#define BOT_GET_MAX_LUN              0xFE
+#define BOT_RESET                    0xFF
+#define USB_MSC_CONFIG_DESC_SIZ      32
+
+typedef struct _USBD_STORAGE {
+  int8_t (* Init)(uint8_t lun);
+  int8_t (* GetCapacity)(uint8_t lun, uint32_t *block_num, uint16_t *block_size);
+  int8_t (* IsReady)(uint8_t lun);
+  int8_t (* IsWriteProtected)(uint8_t lun);
+  int8_t (* Read)(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
+  int8_t (* Write)(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
+  int8_t (* GetMaxLun)(void);
+  uint8_t *pInquiry;
+
+} USBD_StorageTypeDef;
+
+
+typedef struct {
+  uint32_t                 max_lun;
+  uint32_t                 interface;
+  uint8_t                  bot_state;
+  uint8_t                  bot_status;
+  uint32_t                 bot_data_length;
+  uint8_t                  bot_data[MSC_MEDIA_PACKET];
+  USBD_MSC_BOT_CBWTypeDef  cbw;
+  USBD_MSC_BOT_CSWTypeDef  csw;
+
+  USBD_SCSI_SenseTypeDef   scsi_sense [SENSE_LIST_DEEPTH];
+  uint8_t                  scsi_sense_head;
+  uint8_t                  scsi_sense_tail;
+  uint8_t                  scsi_medium_state;
+
+  uint16_t                 scsi_blk_size;
+  uint32_t                 scsi_blk_nbr;
+
+  uint32_t                 scsi_blk_addr;
+  uint32_t                 scsi_blk_len;
+}
+USBD_MSC_BOT_HandleTypeDef;
+
+/* Structure for MSC process */
+extern USBD_ClassTypeDef  USBD_MSC;
+#define USBD_MSC_CLASS    &USBD_MSC
+
+/* Handle */
+extern USBD_MSC_BOT_HandleTypeDef *msc_handle;
+extern USBD_StorageTypeDef *msc_storage;
+
+uint8_t  USBD_MSC_RegisterStorage(USBD_HandleTypeDef   *pdev,
+                                  USBD_StorageTypeDef *fops);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __USBD_MSC_H */
+/**
+  * @}
+  */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/cores/arduino/stm32/usb/msc/usbd_msc_bot.c b/cores/arduino/stm32/usb/msc/usbd_msc_bot.c
new file mode 100644
index 0000000000..d3338d2292
--- /dev/null
+++ b/cores/arduino/stm32/usb/msc/usbd_msc_bot.c
@@ -0,0 +1,301 @@
+/**
+  ******************************************************************************
+  * @file    usbd_msc_bot.c
+  * @author  MCD Application Team
+  * @brief   This file provides all the BOT protocol core functions.
+  ******************************************************************************
+  * @attention
+  *
+  * © Copyright (c) 2015 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                      www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+/* BSPDependencies
+- "stm32xxxxx_{eval}{discovery}{nucleo_144}.c"
+- "stm32xxxxx_{eval}{discovery}_io.c"
+- "stm32xxxxx_{eval}{discovery}{adafruit}_sd.c"
+EndBSPDependencies */
+
+#include "usbd_ep_conf.h"
+
+#ifdef USBCON
+#ifdef USBD_USE_MSC_CLASS
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_msc_bot.h"
+#include "usbd_msc.h"
+#include "usbd_msc_scsi.h"
+#include "usbd_ioreq.h"
+
+static void MSC_BOT_SendData(USBD_HandleTypeDef *pdev, uint8_t *pbuf, uint32_t len);
+static void MSC_BOT_CBW_Decode(USBD_HandleTypeDef *pdev);
+static void MSC_BOT_Abort(USBD_HandleTypeDef *pdev);
+
+
+/**
+* @brief  MSC_BOT_Init
+*         Initialize the BOT Process
+* @param  pdev: device instance
+* @retval None
+*/
+void MSC_BOT_Init(USBD_HandleTypeDef *pdev)
+{
+  USBD_MSC_BOT_HandleTypeDef *hmsc = msc_handle;
+
+  hmsc->bot_state = USBD_BOT_IDLE;
+  hmsc->bot_status = USBD_BOT_STATUS_NORMAL;
+
+  hmsc->scsi_sense_tail = 0U;
+  hmsc->scsi_sense_head = 0U;
+  hmsc->scsi_medium_state = SCSI_MEDIUM_UNLOCKED;
+
+  msc_storage->Init(0U);
+
+  (void)USBD_LL_FlushEP(pdev, MSC_EPOUT_ADDR);
+  (void)USBD_LL_FlushEP(pdev, MSC_EPIN_ADDR);
+
+  /* Prapare EP to Receive First BOT Cmd */
+  (void)USBD_LL_PrepareReceive(pdev, MSC_EPOUT_ADDR, (uint8_t *)&hmsc->cbw,
+                               USBD_BOT_CBW_LENGTH);
+}
+
+/**
+* @brief  MSC_BOT_Reset
+*         Reset the BOT Machine
+* @param  pdev: device instance
+* @retval  None
+*/
+void MSC_BOT_Reset(USBD_HandleTypeDef *pdev)
+{
+  USBD_MSC_BOT_HandleTypeDef *hmsc = msc_handle;
+
+  hmsc->bot_state  = USBD_BOT_IDLE;
+  hmsc->bot_status = USBD_BOT_STATUS_RECOVERY;
+
+  (void)USBD_LL_ClearStallEP(pdev, MSC_EPIN_ADDR);
+  (void)USBD_LL_ClearStallEP(pdev, MSC_EPOUT_ADDR);
+
+  /* Prapare EP to Receive First BOT Cmd */
+  (void)USBD_LL_PrepareReceive(pdev, MSC_EPOUT_ADDR, (uint8_t *)&hmsc->cbw,
+                               USBD_BOT_CBW_LENGTH);
+}
+
+/**
+* @brief  MSC_BOT_DeInit
+*         Deinitialize the BOT Machine
+* @param  pdev: device instance
+* @retval None
+*/
+void MSC_BOT_DeInit(USBD_HandleTypeDef  *pdev)
+{
+  USBD_MSC_BOT_HandleTypeDef *hmsc = msc_handle;
+  hmsc->bot_state = USBD_BOT_IDLE;
+}
+
+/**
+* @brief  MSC_BOT_DataIn
+*         Handle BOT IN data stage
+* @param  pdev: device instance
+* @param  epnum: endpoint index
+* @retval None
+*/
+void MSC_BOT_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum)
+{
+  UNUSED(epnum);
+
+  USBD_MSC_BOT_HandleTypeDef *hmsc = msc_handle;
+
+  switch (hmsc->bot_state) {
+    case USBD_BOT_DATA_IN:
+      if (SCSI_ProcessCmd(pdev, hmsc->cbw.bLUN, &hmsc->cbw.CB[0]) < 0) {
+        MSC_BOT_SendCSW(pdev, USBD_CSW_CMD_FAILED);
+      }
+      break;
+
+    case USBD_BOT_SEND_DATA:
+    case USBD_BOT_LAST_DATA_IN:
+      MSC_BOT_SendCSW(pdev, USBD_CSW_CMD_PASSED);
+      break;
+
+    default:
+      break;
+  }
+}
+/**
+* @brief  MSC_BOT_DataOut
+*         Process MSC OUT data
+* @param  pdev: device instance
+* @param  epnum: endpoint index
+* @retval None
+*/
+void MSC_BOT_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
+{
+  UNUSED(epnum);
+
+  USBD_MSC_BOT_HandleTypeDef *hmsc = msc_handle;
+
+  switch (hmsc->bot_state) {
+    case USBD_BOT_IDLE:
+      MSC_BOT_CBW_Decode(pdev);
+      break;
+
+    case USBD_BOT_DATA_OUT:
+      if (SCSI_ProcessCmd(pdev, hmsc->cbw.bLUN, &hmsc->cbw.CB[0]) < 0) {
+        MSC_BOT_SendCSW(pdev, USBD_CSW_CMD_FAILED);
+      }
+      break;
+
+    default:
+      break;
+  }
+}
+
+/**
+* @brief  MSC_BOT_CBW_Decode
+*         Decode the CBW command and set the BOT state machine accordingly
+* @param  pdev: device instance
+* @retval None
+*/
+static void  MSC_BOT_CBW_Decode(USBD_HandleTypeDef  *pdev)
+{
+  USBD_MSC_BOT_HandleTypeDef *hmsc = msc_handle;
+
+  hmsc->csw.dTag = hmsc->cbw.dTag;
+  hmsc->csw.dDataResidue = hmsc->cbw.dDataLength;
+
+  if ((USBD_LL_GetRxDataSize(pdev, MSC_EPOUT_ADDR) != USBD_BOT_CBW_LENGTH) ||
+      (hmsc->cbw.dSignature != USBD_BOT_CBW_SIGNATURE) ||
+      (hmsc->cbw.bLUN > 1U) || (hmsc->cbw.bCBLength < 1U) ||
+      (hmsc->cbw.bCBLength > 16U)) {
+    SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
+
+    hmsc->bot_status = USBD_BOT_STATUS_ERROR;
+    MSC_BOT_Abort(pdev);
+  } else {
+    if (SCSI_ProcessCmd(pdev, hmsc->cbw.bLUN, &hmsc->cbw.CB[0]) < 0) {
+      if (hmsc->bot_state == USBD_BOT_NO_DATA) {
+        MSC_BOT_SendCSW(pdev, USBD_CSW_CMD_FAILED);
+      } else {
+        MSC_BOT_Abort(pdev);
+      }
+    }
+    /* Burst xfer handled internally */
+    else if ((hmsc->bot_state != USBD_BOT_DATA_IN) &&
+             (hmsc->bot_state != USBD_BOT_DATA_OUT) &&
+             (hmsc->bot_state != USBD_BOT_LAST_DATA_IN)) {
+      if (hmsc->bot_data_length > 0U) {
+        MSC_BOT_SendData(pdev, hmsc->bot_data, hmsc->bot_data_length);
+      } else if (hmsc->bot_data_length == 0U) {
+        MSC_BOT_SendCSW(pdev, USBD_CSW_CMD_PASSED);
+      } else {
+        MSC_BOT_Abort(pdev);
+      }
+    } else {
+      return;
+    }
+  }
+}
+
+/**
+* @brief  MSC_BOT_SendData
+*         Send the requested data
+* @param  pdev: device instance
+* @param  buf: pointer to data buffer
+* @param  len: Data Length
+* @retval None
+*/
+static void  MSC_BOT_SendData(USBD_HandleTypeDef *pdev, uint8_t *pbuf, uint32_t len)
+{
+  USBD_MSC_BOT_HandleTypeDef *hmsc = msc_handle;
+
+  uint32_t length = MIN(hmsc->cbw.dDataLength, len);
+
+  hmsc->csw.dDataResidue -= len;
+  hmsc->csw.bStatus = USBD_CSW_CMD_PASSED;
+  hmsc->bot_state = USBD_BOT_SEND_DATA;
+
+  (void)USBD_LL_Transmit(pdev, MSC_EPIN_ADDR, pbuf, length);
+}
+
+/**
+* @brief  MSC_BOT_SendCSW
+*         Send the Command Status Wrapper
+* @param  pdev: device instance
+* @param  status : CSW status
+* @retval None
+*/
+void  MSC_BOT_SendCSW(USBD_HandleTypeDef *pdev, uint8_t CSW_Status)
+{
+  USBD_MSC_BOT_HandleTypeDef *hmsc = msc_handle;
+
+  hmsc->csw.dSignature = USBD_BOT_CSW_SIGNATURE;
+  hmsc->csw.bStatus = CSW_Status;
+  hmsc->bot_state = USBD_BOT_IDLE;
+
+  (void)USBD_LL_Transmit(pdev, MSC_EPIN_ADDR, (uint8_t *)&hmsc->csw,
+                         USBD_BOT_CSW_LENGTH);
+
+  /* Prepare EP to Receive next Cmd */
+  (void)USBD_LL_PrepareReceive(pdev, MSC_EPOUT_ADDR, (uint8_t *)&hmsc->cbw,
+                               USBD_BOT_CBW_LENGTH);
+}
+
+/**
+* @brief  MSC_BOT_Abort
+*         Abort the current transfer
+* @param  pdev: device instance
+* @retval status
+*/
+
+static void  MSC_BOT_Abort(USBD_HandleTypeDef *pdev)
+{
+  USBD_MSC_BOT_HandleTypeDef *hmsc = msc_handle;
+
+  if ((hmsc->cbw.bmFlags == 0U) &&
+      (hmsc->cbw.dDataLength != 0U) &&
+      (hmsc->bot_status == USBD_BOT_STATUS_NORMAL)) {
+    (void)USBD_LL_StallEP(pdev, MSC_EPOUT_ADDR);
+  }
+
+  (void)USBD_LL_StallEP(pdev, MSC_EPIN_ADDR);
+
+  if (hmsc->bot_status == USBD_BOT_STATUS_ERROR) {
+    (void)USBD_LL_StallEP(pdev, MSC_EPIN_ADDR);
+    (void)USBD_LL_StallEP(pdev, MSC_EPOUT_ADDR);
+  }
+}
+
+/**
+* @brief  MSC_BOT_CplClrFeature
+*         Complete the clear feature request
+* @param  pdev: device instance
+* @param  epnum: endpoint index
+* @retval None
+*/
+
+void  MSC_BOT_CplClrFeature(USBD_HandleTypeDef *pdev, uint8_t epnum)
+{
+  USBD_MSC_BOT_HandleTypeDef *hmsc = msc_handle;
+
+  if (hmsc->bot_status == USBD_BOT_STATUS_ERROR) {
+    /* Bad CBW Signature */
+    (void)USBD_LL_StallEP(pdev, MSC_EPIN_ADDR);
+    (void)USBD_LL_StallEP(pdev, MSC_EPOUT_ADDR);
+  } else if (((epnum & 0x80U) == 0x80U) && (hmsc->bot_status != USBD_BOT_STATUS_RECOVERY)) {
+    MSC_BOT_SendCSW(pdev, USBD_CSW_CMD_FAILED);
+  } else {
+    return;
+  }
+}
+
+#endif /* USBD_USE_MSC_CLASS */
+#endif /* USBCON */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/cores/arduino/stm32/usb/msc/usbd_msc_bot.h b/cores/arduino/stm32/usb/msc/usbd_msc_bot.h
new file mode 100644
index 0000000000..de1af53223
--- /dev/null
+++ b/cores/arduino/stm32/usb/msc/usbd_msc_bot.h
@@ -0,0 +1,104 @@
+/**
+  ******************************************************************************
+  * @file    usbd_msc_bot.h
+  * @author  MCD Application Team
+  * @brief   Header for the usbd_msc_bot.c file
+  ******************************************************************************
+  * @attention
+  *
+  * © Copyright (c) 2015 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                      www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USBD_MSC_BOT_H
+#define __USBD_MSC_BOT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_core.h"
+
+#define USBD_BOT_IDLE                      0U       /* Idle state */
+#define USBD_BOT_DATA_OUT                  1U       /* Data Out state */
+#define USBD_BOT_DATA_IN                   2U       /* Data In state */
+#define USBD_BOT_LAST_DATA_IN              3U       /* Last Data In Last */
+#define USBD_BOT_SEND_DATA                 4U       /* Send Immediate data */
+#define USBD_BOT_NO_DATA                   5U       /* No data Stage */
+
+#define USBD_BOT_CBW_SIGNATURE             0x43425355U
+#define USBD_BOT_CSW_SIGNATURE             0x53425355U
+#define USBD_BOT_CBW_LENGTH                31U
+#define USBD_BOT_CSW_LENGTH                13U
+#define USBD_BOT_MAX_DATA                  256U
+
+/* CSW Status Definitions */
+#define USBD_CSW_CMD_PASSED                0x00U
+#define USBD_CSW_CMD_FAILED                0x01U
+#define USBD_CSW_PHASE_ERROR               0x02U
+
+/* BOT Status */
+#define USBD_BOT_STATUS_NORMAL             0U
+#define USBD_BOT_STATUS_RECOVERY           1U
+#define USBD_BOT_STATUS_ERROR              2U
+
+
+#define USBD_DIR_IN                        0U
+#define USBD_DIR_OUT                       1U
+#define USBD_BOTH_DIR                      2U
+
+
+typedef struct {
+  uint32_t dSignature;
+  uint32_t dTag;
+  uint32_t dDataLength;
+  uint8_t  bmFlags;
+  uint8_t  bLUN;
+  uint8_t  bCBLength;
+  uint8_t  CB[16];
+  uint8_t  ReservedForAlign;
+}
+USBD_MSC_BOT_CBWTypeDef;
+
+
+typedef struct {
+  uint32_t dSignature;
+  uint32_t dTag;
+  uint32_t dDataResidue;
+  uint8_t  bStatus;
+  uint8_t  ReservedForAlign[3];
+}
+USBD_MSC_BOT_CSWTypeDef;
+
+void MSC_BOT_Init(USBD_HandleTypeDef  *pdev);
+void MSC_BOT_Reset(USBD_HandleTypeDef  *pdev);
+void MSC_BOT_DeInit(USBD_HandleTypeDef  *pdev);
+void MSC_BOT_DataIn(USBD_HandleTypeDef  *pdev,
+                    uint8_t epnum);
+
+void MSC_BOT_DataOut(USBD_HandleTypeDef  *pdev,
+                     uint8_t epnum);
+
+void MSC_BOT_SendCSW(USBD_HandleTypeDef  *pdev,
+                     uint8_t CSW_Status);
+
+void  MSC_BOT_CplClrFeature(USBD_HandleTypeDef  *pdev,
+                            uint8_t epnum);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBD_MSC_BOT_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/cores/arduino/stm32/usb/msc/usbd_msc_data.c b/cores/arduino/stm32/usb/msc/usbd_msc_data.c
new file mode 100644
index 0000000000..a2ae3c0f31
--- /dev/null
+++ b/cores/arduino/stm32/usb/msc/usbd_msc_data.c
@@ -0,0 +1,120 @@
+/**
+  ******************************************************************************
+  * @file    usbd_msc_data.c
+  * @author  MCD Application Team
+  * @brief   This file provides all the vital inquiry pages and sense data.
+  ******************************************************************************
+  * @attention
+  *
+  * © Copyright (c) 2015 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                      www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+/* BSPDependencies
+- "stm32xxxxx_{eval}{discovery}{nucleo_144}.c"
+- "stm32xxxxx_{eval}{discovery}_io.c"
+- "stm32xxxxx_{eval}{discovery}{adafruit}_sd.c"
+EndBSPDependencies */
+
+#include "usbd_ep_conf.h"
+
+#ifdef USBCON
+#ifdef USBD_USE_MSC_CLASS
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_msc_data.h"
+
+
+/* USB Mass storage Page 0 Inquiry Data */
+uint8_t MSC_Page00_Inquiry_Data[LENGTH_INQUIRY_PAGE00] = {
+  0x00,
+  0x00,
+  0x00,
+  (LENGTH_INQUIRY_PAGE00 - 4U),
+  0x00,
+  0x80
+};
+
+/* USB Mass storage VPD Page 0x80 Inquiry Data for Unit Serial Number */
+uint8_t MSC_Page80_Inquiry_Data[LENGTH_INQUIRY_PAGE80] = {
+  0x00,
+  0x80,
+  0x00,
+  LENGTH_INQUIRY_PAGE80,
+  0x20,     /* Put Product Serial number */
+  0x20,
+  0x20,
+  0x20
+};
+
+/* USB Mass storage sense 6 Data */
+uint8_t MSC_Mode_Sense6_data[MODE_SENSE6_LEN] = {
+  0x22,
+  0x00,
+  0x00,
+  0x00,
+  0x08,
+  0x12,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00
+};
+
+
+/* USB Mass storage sense 10  Data */
+uint8_t MSC_Mode_Sense10_data[MODE_SENSE10_LEN] = {
+  0x00,
+  0x26,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x08,
+  0x12,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00
+};
+
+
+#endif /* USBD_USE_MSC_CLASS */
+#endif /* USBCON */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/cores/arduino/stm32/usb/msc/usbd_msc_data.h b/cores/arduino/stm32/usb/msc/usbd_msc_data.h
new file mode 100644
index 0000000000..24ab8cf1a2
--- /dev/null
+++ b/cores/arduino/stm32/usb/msc/usbd_msc_data.h
@@ -0,0 +1,51 @@
+/**
+  ******************************************************************************
+  * @file    usbd_msc_data.h
+  * @author  MCD Application Team
+  * @brief   Header for the usbd_msc_data.c file
+  ******************************************************************************
+  * @attention
+  *
+  * © Copyright (c) 2015 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                      www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USBD_MSC_DATA_H
+#define __USBD_MSC_DATA_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_conf.h"
+
+
+#define MODE_SENSE6_LEN                    0x17U
+#define MODE_SENSE10_LEN                   0x1BU
+#define LENGTH_INQUIRY_PAGE00              0x06U
+#define LENGTH_INQUIRY_PAGE80              0x08U
+#define LENGTH_FORMAT_CAPACITIES           0x14U
+
+
+extern uint8_t MSC_Page00_Inquiry_Data[LENGTH_INQUIRY_PAGE00];
+extern uint8_t MSC_Page80_Inquiry_Data[LENGTH_INQUIRY_PAGE80];
+extern uint8_t MSC_Mode_Sense6_data[MODE_SENSE6_LEN];
+extern uint8_t MSC_Mode_Sense10_data[MODE_SENSE10_LEN];
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBD_MSC_DATA_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/cores/arduino/stm32/usb/msc/usbd_msc_scsi.c b/cores/arduino/stm32/usb/msc/usbd_msc_scsi.c
new file mode 100644
index 0000000000..269bc30ff4
--- /dev/null
+++ b/cores/arduino/stm32/usb/msc/usbd_msc_scsi.c
@@ -0,0 +1,953 @@
+/**
+  ******************************************************************************
+  * @file    usbd_msc_scsi.c
+  * @author  MCD Application Team
+  * @brief   This file provides all the USBD SCSI layer functions.
+  ******************************************************************************
+  * @attention
+  *
+  * © Copyright (c) 2015 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                      www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+/* BSPDependencies
+- "stm32xxxxx_{eval}{discovery}{nucleo_144}.c"
+- "stm32xxxxx_{eval}{discovery}_io.c"
+- "stm32xxxxx_{eval}{discovery}{adafruit}_sd.c"
+EndBSPDependencies */
+
+#include "usbd_ep_conf.h"
+
+#ifdef USBCON
+#ifdef USBD_USE_MSC_CLASS
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_msc_bot.h"
+#include "usbd_msc_scsi.h"
+#include "usbd_msc.h"
+#include "usbd_msc_data.h"
+
+
+
+static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_Inquiry(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_ReadCapacity16(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_RequestSense(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_AllowPreventRemovable(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_ModeSense6(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_ModeSense10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_Write10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_Write12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_Read12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_CheckAddressRange(USBD_HandleTypeDef *pdev, uint8_t lun,
+                                     uint32_t blk_offset, uint32_t blk_nbr);
+
+static int8_t SCSI_ProcessRead(USBD_HandleTypeDef *pdev, uint8_t lun);
+static int8_t SCSI_ProcessWrite(USBD_HandleTypeDef *pdev, uint8_t lun);
+
+static int8_t SCSI_UpdateBotData(USBD_MSC_BOT_HandleTypeDef *hmsc,
+                                 uint8_t *pBuff, uint16_t length);
+
+/**
+* @brief  SCSI_ProcessCmd
+*         Process SCSI commands
+* @param  pdev: device instance
+* @param  lun: Logical unit number
+* @param  params: Command parameters
+* @retval status
+*/
+int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *cmd)
+{
+  int8_t ret;
+  USBD_MSC_BOT_HandleTypeDef *hmsc = msc_handle;
+
+  switch (cmd[0]) {
+    case SCSI_TEST_UNIT_READY:
+      ret = SCSI_TestUnitReady(pdev, lun, cmd);
+      break;
+
+    case SCSI_REQUEST_SENSE:
+      ret = SCSI_RequestSense(pdev, lun, cmd);
+      break;
+
+    case SCSI_INQUIRY:
+      ret = SCSI_Inquiry(pdev, lun, cmd);
+      break;
+
+    case SCSI_START_STOP_UNIT:
+      ret = SCSI_StartStopUnit(pdev, lun, cmd);
+      break;
+
+    case SCSI_ALLOW_MEDIUM_REMOVAL:
+      ret = SCSI_AllowPreventRemovable(pdev, lun, cmd);
+      break;
+
+    case SCSI_MODE_SENSE6:
+      ret = SCSI_ModeSense6(pdev, lun, cmd);
+      break;
+
+    case SCSI_MODE_SENSE10:
+      ret = SCSI_ModeSense10(pdev, lun, cmd);
+      break;
+
+    case SCSI_READ_FORMAT_CAPACITIES:
+      ret = SCSI_ReadFormatCapacity(pdev, lun, cmd);
+      break;
+
+    case SCSI_READ_CAPACITY10:
+      ret = SCSI_ReadCapacity10(pdev, lun, cmd);
+      break;
+
+    case SCSI_READ_CAPACITY16:
+      ret = SCSI_ReadCapacity16(pdev, lun, cmd);
+      break;
+
+    case SCSI_READ10:
+      ret = SCSI_Read10(pdev, lun, cmd);
+      break;
+
+    case SCSI_READ12:
+      ret = SCSI_Read12(pdev, lun, cmd);
+      break;
+
+    case SCSI_WRITE10:
+      ret = SCSI_Write10(pdev, lun, cmd);
+      break;
+
+    case SCSI_WRITE12:
+      ret = SCSI_Write12(pdev, lun, cmd);
+      break;
+
+    case SCSI_VERIFY10:
+      ret = SCSI_Verify10(pdev, lun, cmd);
+      break;
+
+    default:
+      SCSI_SenseCode(pdev, lun, ILLEGAL_REQUEST, INVALID_CDB);
+      hmsc->bot_status = USBD_BOT_STATUS_ERROR;
+      ret = -1;
+      break;
+  }
+
+  return ret;
+}
+
+
+/**
+* @brief  SCSI_TestUnitReady
+*         Process SCSI Test Unit Ready Command
+* @param  lun: Logical unit number
+* @param  params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+  UNUSED(params);
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = msc_handle;
+
+  /* case 9 : Hi > D0 */
+  if (hmsc->cbw.dDataLength != 0U) {
+    SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
+
+    return -1;
+  }
+
+  if (hmsc->scsi_medium_state == SCSI_MEDIUM_EJECTED) {
+    SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
+    hmsc->bot_state = USBD_BOT_NO_DATA;
+    return -1;
+  }
+
+  if (msc_storage->IsReady(lun) != 0) {
+    SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
+    hmsc->bot_state = USBD_BOT_NO_DATA;
+
+    return -1;
+  }
+  hmsc->bot_data_length = 0U;
+
+  return 0;
+}
+
+
+/**
+* @brief  SCSI_Inquiry
+*         Process Inquiry command
+* @param  lun: Logical unit number
+* @param  params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_Inquiry(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+  uint8_t *pPage;
+  uint16_t len;
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = msc_handle;
+
+  if (hmsc->cbw.dDataLength == 0U) {
+    SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
+    return -1;
+  }
+
+  if ((params[1] & 0x01U) != 0U) {
+    /* Evpd is set */
+    if (params[2] == 0U) {
+      /* Request for Supported Vital Product Data Pages*/
+      (void)SCSI_UpdateBotData(hmsc, MSC_Page00_Inquiry_Data, LENGTH_INQUIRY_PAGE00);
+    } else if (params[2] == 0x80U) {
+      /* Request for VPD page 0x80 Unit Serial Number */
+      (void)SCSI_UpdateBotData(hmsc, MSC_Page80_Inquiry_Data, LENGTH_INQUIRY_PAGE80);
+    } else {
+      /* Request Not supported */
+      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST,
+                     INVALID_FIELED_IN_COMMAND);
+
+      return -1;
+    }
+  } else {
+    pPage = &msc_storage->pInquiry[lun * STANDARD_INQUIRY_DATA_LEN];
+    len = (uint16_t)pPage[4] + 5U;
+
+    if (params[4] <= len) {
+      len = params[4];
+    }
+
+    (void)SCSI_UpdateBotData(hmsc, pPage, len);
+  }
+
+  return 0;
+}
+
+
+/**
+* @brief  SCSI_ReadCapacity10
+*         Process Read Capacity 10 command
+* @param  lun: Logical unit number
+* @param  params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+  UNUSED(params);
+  int8_t ret;
+  USBD_MSC_BOT_HandleTypeDef *hmsc = msc_handle;
+
+  ret = msc_storage->GetCapacity(lun, &hmsc->scsi_blk_nbr, &hmsc->scsi_blk_size);
+
+  if ((ret != 0) || (hmsc->scsi_medium_state == SCSI_MEDIUM_EJECTED)) {
+    SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
+    return -1;
+  }
+
+  hmsc->bot_data[0] = (uint8_t)((hmsc->scsi_blk_nbr - 1U) >> 24);
+  hmsc->bot_data[1] = (uint8_t)((hmsc->scsi_blk_nbr - 1U) >> 16);
+  hmsc->bot_data[2] = (uint8_t)((hmsc->scsi_blk_nbr - 1U) >>  8);
+  hmsc->bot_data[3] = (uint8_t)(hmsc->scsi_blk_nbr - 1U);
+
+  hmsc->bot_data[4] = (uint8_t)(hmsc->scsi_blk_size >>  24);
+  hmsc->bot_data[5] = (uint8_t)(hmsc->scsi_blk_size >>  16);
+  hmsc->bot_data[6] = (uint8_t)(hmsc->scsi_blk_size >>  8);
+  hmsc->bot_data[7] = (uint8_t)(hmsc->scsi_blk_size);
+
+  hmsc->bot_data_length = 8U;
+
+  return 0;
+
+}
+
+
+/**
+* @brief  SCSI_ReadCapacity16
+*         Process Read Capacity 16 command
+* @param  lun: Logical unit number
+* @param  params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_ReadCapacity16(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+  UNUSED(params);
+  uint8_t idx;
+  int8_t ret;
+  USBD_MSC_BOT_HandleTypeDef *hmsc = msc_handle;
+
+  ret = msc_storage->GetCapacity(lun, &hmsc->scsi_blk_nbr, &hmsc->scsi_blk_size);
+
+  if ((ret != 0) || (hmsc->scsi_medium_state == SCSI_MEDIUM_EJECTED)) {
+    SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
+    return -1;
+  }
+
+  hmsc->bot_data_length = ((uint32_t)params[10] << 24) |
+                          ((uint32_t)params[11] << 16) |
+                          ((uint32_t)params[12] <<  8) |
+                          (uint32_t)params[13];
+
+  for (idx = 0U; idx < hmsc->bot_data_length; idx++) {
+    hmsc->bot_data[idx] = 0U;
+  }
+
+  hmsc->bot_data[4] = (uint8_t)((hmsc->scsi_blk_nbr - 1U) >> 24);
+  hmsc->bot_data[5] = (uint8_t)((hmsc->scsi_blk_nbr - 1U) >> 16);
+  hmsc->bot_data[6] = (uint8_t)((hmsc->scsi_blk_nbr - 1U) >>  8);
+  hmsc->bot_data[7] = (uint8_t)(hmsc->scsi_blk_nbr - 1U);
+
+  hmsc->bot_data[8] = (uint8_t)(hmsc->scsi_blk_size >>  24);
+  hmsc->bot_data[9] = (uint8_t)(hmsc->scsi_blk_size >>  16);
+  hmsc->bot_data[10] = (uint8_t)(hmsc->scsi_blk_size >>  8);
+  hmsc->bot_data[11] = (uint8_t)(hmsc->scsi_blk_size);
+
+  hmsc->bot_data_length = ((uint32_t)params[10] << 24) |
+                          ((uint32_t)params[11] << 16) |
+                          ((uint32_t)params[12] <<  8) |
+                          (uint32_t)params[13];
+
+  return 0;
+}
+
+
+/**
+* @brief  SCSI_ReadFormatCapacity
+*         Process Read Format Capacity command
+* @param  lun: Logical unit number
+* @param  params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+  UNUSED(params);
+  uint16_t blk_size;
+  uint32_t blk_nbr;
+  uint16_t i;
+  int8_t ret;
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = msc_handle;
+
+  ret = msc_storage->GetCapacity(lun, &blk_nbr, &blk_size);
+
+  if ((ret != 0) || (hmsc->scsi_medium_state == SCSI_MEDIUM_EJECTED)) {
+    SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
+    return -1;
+  }
+
+  for (i = 0U; i < 12U ; i++) {
+    hmsc->bot_data[i] = 0U;
+  }
+
+  hmsc->bot_data[3] = 0x08U;
+  hmsc->bot_data[4] = (uint8_t)((blk_nbr - 1U) >> 24);
+  hmsc->bot_data[5] = (uint8_t)((blk_nbr - 1U) >> 16);
+  hmsc->bot_data[6] = (uint8_t)((blk_nbr - 1U) >>  8);
+  hmsc->bot_data[7] = (uint8_t)(blk_nbr - 1U);
+
+  hmsc->bot_data[8] = 0x02U;
+  hmsc->bot_data[9] = (uint8_t)(blk_size >>  16);
+  hmsc->bot_data[10] = (uint8_t)(blk_size >>  8);
+  hmsc->bot_data[11] = (uint8_t)(blk_size);
+
+  hmsc->bot_data_length = 12U;
+
+  return 0;
+}
+
+
+/**
+* @brief  SCSI_ModeSense6
+*         Process Mode Sense6 command
+* @param  lun: Logical unit number
+* @param  params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_ModeSense6(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+  UNUSED(lun);
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = msc_handle;
+  uint16_t len = MODE_SENSE6_LEN;
+
+  if (params[4] <= len) {
+    len = params[4];
+  }
+
+  (void)SCSI_UpdateBotData(hmsc, MSC_Mode_Sense6_data, len);
+
+  return 0;
+}
+
+
+/**
+* @brief  SCSI_ModeSense10
+*         Process Mode Sense10 command
+* @param  lun: Logical unit number
+* @param  params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_ModeSense10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+  UNUSED(lun);
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = msc_handle;
+  uint16_t len = MODE_SENSE10_LEN;
+
+  if (params[8] <= len) {
+    len = params[8];
+  }
+
+  (void)SCSI_UpdateBotData(hmsc, MSC_Mode_Sense10_data, len);
+
+  return 0;
+}
+
+
+/**
+* @brief  SCSI_RequestSense
+*         Process Request Sense command
+* @param  lun: Logical unit number
+* @param  params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_RequestSense(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+  UNUSED(lun);
+  uint8_t i;
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = msc_handle;
+
+  if (hmsc->cbw.dDataLength == 0U) {
+    SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
+    return -1;
+  }
+
+  for (i = 0U; i < REQUEST_SENSE_DATA_LEN; i++) {
+    hmsc->bot_data[i] = 0U;
+  }
+
+  hmsc->bot_data[0] = 0x70U;
+  hmsc->bot_data[7] = REQUEST_SENSE_DATA_LEN - 6U;
+
+  if ((hmsc->scsi_sense_head != hmsc->scsi_sense_tail)) {
+    hmsc->bot_data[2] = (uint8_t)hmsc->scsi_sense[hmsc->scsi_sense_head].Skey;
+    hmsc->bot_data[12] = (uint8_t)hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASC;
+    hmsc->bot_data[13] = (uint8_t)hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASCQ;
+    hmsc->scsi_sense_head++;
+
+    if (hmsc->scsi_sense_head == SENSE_LIST_DEEPTH) {
+      hmsc->scsi_sense_head = 0U;
+    }
+  }
+
+  hmsc->bot_data_length = REQUEST_SENSE_DATA_LEN;
+
+  if (params[4] <= REQUEST_SENSE_DATA_LEN) {
+    hmsc->bot_data_length = params[4];
+  }
+
+  return 0;
+}
+
+
+/**
+* @brief  SCSI_SenseCode
+*         Load the last error code in the error list
+* @param  lun: Logical unit number
+* @param  sKey: Sense Key
+* @param  ASC: Additional Sense Code
+* @retval none
+
+*/
+void SCSI_SenseCode(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t sKey, uint8_t ASC)
+{
+  UNUSED(lun);
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = msc_handle;
+
+  hmsc->scsi_sense[hmsc->scsi_sense_tail].Skey = sKey;
+  hmsc->scsi_sense[hmsc->scsi_sense_tail].w.b.ASC = ASC;
+  hmsc->scsi_sense[hmsc->scsi_sense_tail].w.b.ASCQ = 0U;
+  hmsc->scsi_sense_tail++;
+
+  if (hmsc->scsi_sense_tail == SENSE_LIST_DEEPTH) {
+    hmsc->scsi_sense_tail = 0U;
+  }
+}
+
+
+/**
+* @brief  SCSI_StartStopUnit
+*         Process Start Stop Unit command
+* @param  lun: Logical unit number
+* @param  params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+  UNUSED(lun);
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = msc_handle;
+
+  if ((hmsc->scsi_medium_state == SCSI_MEDIUM_LOCKED) && ((params[4] & 0x3U) == 2U)) {
+    SCSI_SenseCode(pdev, lun, ILLEGAL_REQUEST, INVALID_FIELED_IN_COMMAND);
+
+    return -1;
+  }
+
+  if ((params[4] & 0x3U) == 0x1U) {
+    /* START=1 */
+    hmsc->scsi_medium_state = SCSI_MEDIUM_UNLOCKED;
+  } else if ((params[4] & 0x3U) == 0x2U) {
+    /* START=0 and LOEJ Load Eject=1 */
+    hmsc->scsi_medium_state = SCSI_MEDIUM_EJECTED;
+  } else if ((params[4] & 0x3U) == 0x3U) {
+    /* START=1 and LOEJ Load Eject=1 */
+    hmsc->scsi_medium_state = SCSI_MEDIUM_UNLOCKED;
+  } else {
+    /* .. */
+  }
+  hmsc->bot_data_length = 0U;
+
+  return 0;
+}
+
+
+/**
+* @brief  SCSI_AllowPreventRemovable
+*         Process Allow Prevent Removable medium command
+* @param  lun: Logical unit number
+* @param  params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_AllowPreventRemovable(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+  UNUSED(lun);
+  USBD_MSC_BOT_HandleTypeDef *hmsc = msc_handle;
+
+  if (params[4] == 0U) {
+    hmsc->scsi_medium_state = SCSI_MEDIUM_UNLOCKED;
+  } else {
+    hmsc->scsi_medium_state = SCSI_MEDIUM_LOCKED;
+  }
+
+  hmsc->bot_data_length = 0U;
+
+  return 0;
+}
+
+
+/**
+* @brief  SCSI_Read10
+*         Process Read10 command
+* @param  lun: Logical unit number
+* @param  params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = msc_handle;
+
+  if (hmsc->bot_state == USBD_BOT_IDLE) {
+    /* Idle */
+    /* case 10 : Ho <> Di */
+    if ((hmsc->cbw.bmFlags & 0x80U) != 0x80U) {
+      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
+      return -1;
+    }
+
+    if (hmsc->scsi_medium_state == SCSI_MEDIUM_EJECTED) {
+      SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
+
+      return -1;
+    }
+
+    if (msc_storage->IsReady(lun) != 0) {
+      SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
+      return -1;
+    }
+
+    hmsc->scsi_blk_addr = ((uint32_t)params[2] << 24) |
+                          ((uint32_t)params[3] << 16) |
+                          ((uint32_t)params[4] <<  8) |
+                          (uint32_t)params[5];
+
+    hmsc->scsi_blk_len = ((uint32_t)params[7] <<  8) | (uint32_t)params[8];
+
+    if (SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr,
+                               hmsc->scsi_blk_len) < 0) {
+      return -1; /* error */
+    }
+
+    /* cases 4,5 : Hi <> Dn */
+    if (hmsc->cbw.dDataLength != (hmsc->scsi_blk_len * hmsc->scsi_blk_size)) {
+      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
+      return -1;
+    }
+
+    hmsc->bot_state = USBD_BOT_DATA_IN;
+  }
+  hmsc->bot_data_length = MSC_MEDIA_PACKET;
+
+  return SCSI_ProcessRead(pdev, lun);
+}
+
+
+/**
+* @brief  SCSI_Read12
+*         Process Read12 command
+* @param  lun: Logical unit number
+* @param  params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_Read12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+  USBD_MSC_BOT_HandleTypeDef *hmsc = msc_handle;
+
+  if (hmsc->bot_state == USBD_BOT_IDLE) {
+    /* Idle */
+    /* case 10 : Ho <> Di */
+    if ((hmsc->cbw.bmFlags & 0x80U) != 0x80U) {
+      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
+      return -1;
+    }
+
+    if (hmsc->scsi_medium_state == SCSI_MEDIUM_EJECTED) {
+      SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
+      return -1;
+    }
+
+    if (msc_storage->IsReady(lun) != 0) {
+      SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
+      return -1;
+    }
+
+    hmsc->scsi_blk_addr = ((uint32_t)params[2] << 24) |
+                          ((uint32_t)params[3] << 16) |
+                          ((uint32_t)params[4] <<  8) |
+                          (uint32_t)params[5];
+
+    hmsc->scsi_blk_len = ((uint32_t)params[6] << 24) |
+                         ((uint32_t)params[7] << 16) |
+                         ((uint32_t)params[8] << 8) |
+                         (uint32_t)params[9];
+
+    if (SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr,
+                               hmsc->scsi_blk_len) < 0) {
+      return -1; /* error */
+    }
+
+    /* cases 4,5 : Hi <> Dn */
+    if (hmsc->cbw.dDataLength != (hmsc->scsi_blk_len * hmsc->scsi_blk_size)) {
+      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
+      return -1;
+    }
+
+    hmsc->bot_state = USBD_BOT_DATA_IN;
+  }
+  hmsc->bot_data_length = MSC_MEDIA_PACKET;
+
+  return SCSI_ProcessRead(pdev, lun);
+}
+
+
+/**
+* @brief  SCSI_Write10
+*         Process Write10 command
+* @param  lun: Logical unit number
+* @param  params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_Write10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = msc_handle;
+  uint32_t len;
+
+  if (hmsc->bot_state == USBD_BOT_IDLE) {
+    /* Idle */
+    if (hmsc->cbw.dDataLength == 0U) {
+      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
+      return -1;
+    }
+
+    /* case 8 : Hi <> Do */
+    if ((hmsc->cbw.bmFlags & 0x80U) == 0x80U) {
+      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
+      return -1;
+    }
+
+    /* Check whether Media is ready */
+    if (msc_storage->IsReady(lun) != 0) {
+      SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
+      return -1;
+    }
+
+    /* Check If media is write-protected */
+    if (msc_storage->IsWriteProtected(lun) != 0) {
+      SCSI_SenseCode(pdev, lun, NOT_READY, WRITE_PROTECTED);
+      return -1;
+    }
+
+    hmsc->scsi_blk_addr = ((uint32_t)params[2] << 24) |
+                          ((uint32_t)params[3] << 16) |
+                          ((uint32_t)params[4] << 8) |
+                          (uint32_t)params[5];
+
+    hmsc->scsi_blk_len = ((uint32_t)params[7] << 8) |
+                         (uint32_t)params[8];
+
+    /* check if LBA address is in the right range */
+    if (SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr,
+                               hmsc->scsi_blk_len) < 0) {
+      return -1; /* error */
+    }
+
+    len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;
+
+    /* cases 3,11,13 : Hn,Ho <> D0 */
+    if (hmsc->cbw.dDataLength != len) {
+      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
+      return -1;
+    }
+
+    len = MIN(len, MSC_MEDIA_PACKET);
+
+    /* Prepare EP to receive first data packet */
+    hmsc->bot_state = USBD_BOT_DATA_OUT;
+    (void)USBD_LL_PrepareReceive(pdev, MSC_EPOUT_ADDR, hmsc->bot_data, len);
+  } else {
+    /* Write Process ongoing */
+    return SCSI_ProcessWrite(pdev, lun);
+  }
+
+  return 0;
+}
+
+
+/**
+* @brief  SCSI_Write12
+*         Process Write12 command
+* @param  lun: Logical unit number
+* @param  params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_Write12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+  USBD_MSC_BOT_HandleTypeDef *hmsc = msc_handle;
+  uint32_t len;
+
+  if (hmsc->bot_state == USBD_BOT_IDLE) {
+    /* Idle */
+    if (hmsc->cbw.dDataLength == 0U) {
+      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
+      return -1;
+    }
+
+    /* case 8 : Hi <> Do */
+    if ((hmsc->cbw.bmFlags & 0x80U) == 0x80U) {
+      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
+      return -1;
+    }
+
+    /* Check whether Media is ready */
+    if (msc_storage->IsReady(lun) != 0) {
+      SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
+      hmsc->bot_state = USBD_BOT_NO_DATA;
+      return -1;
+    }
+
+    /* Check If media is write-protected */
+    if (msc_storage->IsWriteProtected(lun) != 0) {
+      SCSI_SenseCode(pdev, lun, NOT_READY, WRITE_PROTECTED);
+      hmsc->bot_state = USBD_BOT_NO_DATA;
+      return -1;
+    }
+
+    hmsc->scsi_blk_addr = ((uint32_t)params[2] << 24) |
+                          ((uint32_t)params[3] << 16) |
+                          ((uint32_t)params[4] << 8) |
+                          (uint32_t)params[5];
+
+    hmsc->scsi_blk_len = ((uint32_t)params[6] << 24) |
+                         ((uint32_t)params[7] << 16) |
+                         ((uint32_t)params[8] << 8) |
+                         (uint32_t)params[9];
+
+    /* check if LBA address is in the right range */
+    if (SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr,
+                               hmsc->scsi_blk_len) < 0) {
+      return -1; /* error */
+    }
+
+    len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;
+
+    /* cases 3,11,13 : Hn,Ho <> D0 */
+    if (hmsc->cbw.dDataLength != len) {
+      SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
+      return -1;
+    }
+
+    len = MIN(len, MSC_MEDIA_PACKET);
+
+    /* Prepare EP to receive first data packet */
+    hmsc->bot_state = USBD_BOT_DATA_OUT;
+    (void)USBD_LL_PrepareReceive(pdev, MSC_EPOUT_ADDR, hmsc->bot_data, len);
+  } else {
+    /* Write Process ongoing */
+    return SCSI_ProcessWrite(pdev, lun);
+  }
+
+  return 0;
+}
+
+
+/**
+* @brief  SCSI_Verify10
+*         Process Verify10 command
+* @param  lun: Logical unit number
+* @param  params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = msc_handle;
+
+  if ((params[1] & 0x02U) == 0x02U) {
+    SCSI_SenseCode(pdev, lun, ILLEGAL_REQUEST, INVALID_FIELED_IN_COMMAND);
+    return -1; /* Error, Verify Mode Not supported*/
+  }
+
+  if (SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr,
+                             hmsc->scsi_blk_len) < 0) {
+    return -1; /* error */
+  }
+
+  hmsc->bot_data_length = 0U;
+
+  return 0;
+}
+
+/**
+* @brief  SCSI_CheckAddressRange
+*         Check address range
+* @param  lun: Logical unit number
+* @param  blk_offset: first block address
+* @param  blk_nbr: number of block to be processed
+* @retval status
+*/
+static int8_t SCSI_CheckAddressRange(USBD_HandleTypeDef *pdev, uint8_t lun,
+                                     uint32_t blk_offset, uint32_t blk_nbr)
+{
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = msc_handle;
+
+  if ((blk_offset + blk_nbr) > hmsc->scsi_blk_nbr) {
+    SCSI_SenseCode(pdev, lun, ILLEGAL_REQUEST, ADDRESS_OUT_OF_RANGE);
+    return -1;
+  }
+
+  return 0;
+}
+
+/**
+* @brief  SCSI_ProcessRead
+*         Handle Read Process
+* @param  lun: Logical unit number
+* @retval status
+*/
+static int8_t SCSI_ProcessRead(USBD_HandleTypeDef *pdev, uint8_t lun)
+{
+  USBD_MSC_BOT_HandleTypeDef *hmsc = msc_handle;
+  uint32_t len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;
+
+  len = MIN(len, MSC_MEDIA_PACKET);
+
+  if (msc_storage->Read(lun,
+                        hmsc->bot_data,
+                        hmsc->scsi_blk_addr,
+                        (len / hmsc->scsi_blk_size)) < 0) {
+    SCSI_SenseCode(pdev, lun, HARDWARE_ERROR, UNRECOVERED_READ_ERROR);
+    return -1;
+  }
+
+  (void)USBD_LL_Transmit(pdev, MSC_EPIN_ADDR, hmsc->bot_data, len);
+
+  hmsc->scsi_blk_addr += (len / hmsc->scsi_blk_size);
+  hmsc->scsi_blk_len -= (len / hmsc->scsi_blk_size);
+
+  /* case 6 : Hi = Di */
+  hmsc->csw.dDataResidue -= len;
+
+  if (hmsc->scsi_blk_len == 0U) {
+    hmsc->bot_state = USBD_BOT_LAST_DATA_IN;
+  }
+
+  return 0;
+}
+
+/**
+* @brief  SCSI_ProcessWrite
+*         Handle Write Process
+* @param  lun: Logical unit number
+* @retval status
+*/
+static int8_t SCSI_ProcessWrite(USBD_HandleTypeDef *pdev, uint8_t lun)
+{
+  USBD_MSC_BOT_HandleTypeDef *hmsc = msc_handle;
+  uint32_t len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;
+
+  len = MIN(len, MSC_MEDIA_PACKET);
+
+  if (msc_storage->Write(lun, hmsc->bot_data,
+                         hmsc->scsi_blk_addr,
+                         (len / hmsc->scsi_blk_size)) < 0) {
+    SCSI_SenseCode(pdev, lun, HARDWARE_ERROR, WRITE_FAULT);
+    return -1;
+  }
+
+  hmsc->scsi_blk_addr += (len / hmsc->scsi_blk_size);
+  hmsc->scsi_blk_len -= (len / hmsc->scsi_blk_size);
+
+  /* case 12 : Ho = Do */
+  hmsc->csw.dDataResidue -= len;
+
+  if (hmsc->scsi_blk_len == 0U) {
+    MSC_BOT_SendCSW(pdev, USBD_CSW_CMD_PASSED);
+  } else {
+    len = MIN((hmsc->scsi_blk_len * hmsc->scsi_blk_size), MSC_MEDIA_PACKET);
+
+    /* Prepare EP to Receive next packet */
+    (void)USBD_LL_PrepareReceive(pdev, MSC_EPOUT_ADDR, hmsc->bot_data, len);
+  }
+
+  return 0;
+}
+
+
+/**
+* @brief  SCSI_UpdateBotData
+*         fill the requested Data to transmit buffer
+* @param  hmsc handler
+* @param  params: Data buffer
+* @param  length: Data length
+* @retval status
+*/
+static int8_t SCSI_UpdateBotData(USBD_MSC_BOT_HandleTypeDef *hmsc,
+                                 uint8_t *pBuff, uint16_t length)
+{
+  uint16_t len = length;
+
+  hmsc->bot_data_length = len;
+
+  while (len != 0U) {
+    len--;
+    hmsc->bot_data[len] = pBuff[len];
+  }
+
+  return 0;
+}
+
+
+#endif /* USBD_USE_MSC_CLASS */
+#endif /* USBCON */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/cores/arduino/stm32/usb/msc/usbd_msc_scsi.h b/cores/arduino/stm32/usb/msc/usbd_msc_scsi.h
new file mode 100644
index 0000000000..b39ad35c44
--- /dev/null
+++ b/cores/arduino/stm32/usb/msc/usbd_msc_scsi.h
@@ -0,0 +1,128 @@
+/**
+  ******************************************************************************
+  * @file    usbd_msc_scsi.h
+  * @author  MCD Application Team
+  * @brief   Header for the usbd_msc_scsi.c file
+  ******************************************************************************
+  * @attention
+  *
+  * © Copyright (c) 2015 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                      www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USBD_MSC_SCSI_H
+#define __USBD_MSC_SCSI_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_def.h"
+
+#define SENSE_LIST_DEEPTH                           4U
+
+/* SCSI Commands */
+#define SCSI_FORMAT_UNIT                            0x04U
+#define SCSI_INQUIRY                                0x12U
+#define SCSI_MODE_SELECT6                           0x15U
+#define SCSI_MODE_SELECT10                          0x55U
+#define SCSI_MODE_SENSE6                            0x1AU
+#define SCSI_MODE_SENSE10                           0x5AU
+#define SCSI_ALLOW_MEDIUM_REMOVAL                   0x1EU
+#define SCSI_READ6                                  0x08U
+#define SCSI_READ10                                 0x28U
+#define SCSI_READ12                                 0xA8U
+#define SCSI_READ16                                 0x88U
+
+#define SCSI_READ_CAPACITY10                        0x25U
+#define SCSI_READ_CAPACITY16                        0x9EU
+
+#define SCSI_REQUEST_SENSE                          0x03U
+#define SCSI_START_STOP_UNIT                        0x1BU
+#define SCSI_TEST_UNIT_READY                        0x00U
+#define SCSI_WRITE6                                 0x0AU
+#define SCSI_WRITE10                                0x2AU
+#define SCSI_WRITE12                                0xAAU
+#define SCSI_WRITE16                                0x8AU
+
+#define SCSI_VERIFY10                               0x2FU
+#define SCSI_VERIFY12                               0xAFU
+#define SCSI_VERIFY16                               0x8FU
+
+#define SCSI_SEND_DIAGNOSTIC                        0x1DU
+#define SCSI_READ_FORMAT_CAPACITIES                 0x23U
+
+#define NO_SENSE                                    0U
+#define RECOVERED_ERROR                             1U
+#define NOT_READY                                   2U
+#define MEDIUM_ERROR                                3U
+#define HARDWARE_ERROR                              4U
+#define ILLEGAL_REQUEST                             5U
+#define UNIT_ATTENTION                              6U
+#define DATA_PROTECT                                7U
+#define BLANK_CHECK                                 8U
+#define VENDOR_SPECIFIC                             9U
+#define COPY_ABORTED                                10U
+#define ABORTED_COMMAND                             11U
+#define VOLUME_OVERFLOW                             13U
+#define MISCOMPARE                                  14U
+
+
+#define INVALID_CDB                                 0x20U
+#define INVALID_FIELED_IN_COMMAND                   0x24U
+#define PARAMETER_LIST_LENGTH_ERROR                 0x1AU
+#define INVALID_FIELD_IN_PARAMETER_LIST             0x26U
+#define ADDRESS_OUT_OF_RANGE                        0x21U
+#define MEDIUM_NOT_PRESENT                          0x3AU
+#define MEDIUM_HAVE_CHANGED                         0x28U
+#define WRITE_PROTECTED                             0x27U
+#define UNRECOVERED_READ_ERROR                      0x11U
+#define WRITE_FAULT                                 0x03U
+
+#define READ_FORMAT_CAPACITY_DATA_LEN               0x0CU
+#define READ_CAPACITY10_DATA_LEN                    0x08U
+#define MODE_SENSE10_DATA_LEN                       0x08U
+#define MODE_SENSE6_DATA_LEN                        0x04U
+#define REQUEST_SENSE_DATA_LEN                      0x12U
+#define STANDARD_INQUIRY_DATA_LEN                   0x24U
+#define BLKVFY                                      0x04U
+
+#define SCSI_MEDIUM_UNLOCKED                        0x00U
+#define SCSI_MEDIUM_LOCKED                          0x01U
+#define SCSI_MEDIUM_EJECTED                         0x02U
+
+typedef struct _SENSE_ITEM {
+  uint8_t Skey;
+  union {
+    struct _ASCs {
+      uint8_t ASC;
+      uint8_t ASCQ;
+    } b;
+    uint8_t ASC;
+    uint8_t *pData;
+  } w;
+} USBD_SCSI_SenseTypeDef;
+
+int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *cmd);
+
+void SCSI_SenseCode(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t sKey,
+                    uint8_t ASC);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBD_MSC_SCSI_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/cores/arduino/stm32/usb/msc/usbd_msc_storage_if.cpp b/cores/arduino/stm32/usb/msc/usbd_msc_storage_if.cpp
new file mode 100644
index 0000000000..a614bfe288
--- /dev/null
+++ b/cores/arduino/stm32/usb/msc/usbd_msc_storage_if.cpp
@@ -0,0 +1,189 @@
+/**
+  ******************************************************************************
+  * @file    usbd_msc_storage_template.c
+  * @author  MCD Application Team
+  * @brief   Memory management layer
+  ******************************************************************************
+  * @attention
+  *
+  * © Copyright (c) 2015 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                      www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+#include "usbd_ep_conf.h"
+
+#ifdef USBCON
+#ifdef USBD_USE_MSC_CLASS
+
+/* BSPDependencies
+- "stm32xxxxx_{eval}{discovery}{nucleo_144}.c"
+- "stm32xxxxx_{eval}{discovery}_io.c"
+- "stm32xxxxx_{eval}{discovery}{adafruit}_sd.c"
+EndBSPDependencies */
+
+#include "USBMscHandler.h"
+#include "usbd_msc_storage_if.h"
+
+uint8_t usbMscMaxLun = 0;
+USBMscHandler **ppUsbMscHandlers = nullptr;
+
+int8_t STORAGE_Init(uint8_t lun);
+
+int8_t STORAGE_GetCapacity(uint8_t lun, uint32_t *block_num,
+                           uint16_t *block_size);
+
+int8_t  STORAGE_IsReady(uint8_t lun);
+
+int8_t  STORAGE_IsWriteProtected(uint8_t lun);
+
+int8_t STORAGE_Read(uint8_t lun, uint8_t *buf, uint32_t blk_addr,
+                    uint16_t blk_len);
+
+int8_t STORAGE_Write(uint8_t lun, uint8_t *buf, uint32_t blk_addr,
+                     uint16_t blk_len);
+
+int8_t STORAGE_GetMaxLun(void);
+
+/* USB Mass storage Standard Inquiry Data */
+uint8_t  STORAGE_Inquirydata[] =  /* 36 */
+{
+  /* LUN 0 */
+  0x00,
+  0x80,
+  0x02,
+  0x02,
+  (STANDARD_INQUIRY_DATA_LEN - 5),
+  0x00,
+  0x00,
+  0x00,
+  'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Manufacturer : 8 bytes */
+  'P', 'r', 'o', 'd', 'u', 'c', 't', ' ', /* Product      : 16 Bytes */
+  ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+  '0', '.', '0', '1',                     /* Version      : 4 Bytes */
+};
+
+USBD_StorageTypeDef USBD_MSC_fops = {
+  STORAGE_Init,
+  STORAGE_GetCapacity,
+  STORAGE_IsReady,
+  STORAGE_IsWriteProtected,
+  STORAGE_Read,
+  STORAGE_Write,
+  STORAGE_GetMaxLun,
+  STORAGE_Inquirydata,
+};
+
+#define HANDLER_LUN_CHECK \
+  if (lun > usbMscMaxLun) { \
+    return 1; \
+  }
+
+/*******************************************************************************
+* Function Name  : Read_Memory
+* Description    : Handle the Read operation from the microSD card.
+* Input          : None.
+* Output         : None.
+* Return         : None.
+*******************************************************************************/
+int8_t STORAGE_Init(uint8_t lun)
+{
+  HANDLER_LUN_CHECK
+
+  return !ppUsbMscHandlers[lun]->Init();
+}
+
+/*******************************************************************************
+* Function Name  : Read_Memory
+* Description    : Handle the Read operation from the STORAGE card.
+* Input          : None.
+* Output         : None.
+* Return         : None.
+*******************************************************************************/
+int8_t STORAGE_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
+{
+  HANDLER_LUN_CHECK
+
+  return !ppUsbMscHandlers[lun]->GetCapacity(block_num, block_size);
+}
+
+/*******************************************************************************
+* Function Name  : Read_Memory
+* Description    : Handle the Read operation from the STORAGE card.
+* Input          : None.
+* Output         : None.
+* Return         : 0 if device is ready, otherwise not ready
+*******************************************************************************/
+int8_t  STORAGE_IsReady(uint8_t lun)
+{
+  HANDLER_LUN_CHECK
+
+  return !ppUsbMscHandlers[lun]->IsReady();
+}
+
+/*******************************************************************************
+* Function Name  : Read_Memory
+* Description    : Handle the Read operation from the STORAGE card.
+* Input          : None.
+* Output         : None.
+* Return         : None.
+*******************************************************************************/
+int8_t  STORAGE_IsWriteProtected(uint8_t lun)
+{
+  HANDLER_LUN_CHECK
+
+  return ppUsbMscHandlers[lun]->IsWriteProtected();
+}
+
+/*******************************************************************************
+* Function Name  : Read_Memory
+* Description    : Handle the Read operation from the STORAGE card.
+* Input          : None.
+* Output         : None.
+* Return         : None.
+*******************************************************************************/
+int8_t STORAGE_Read(uint8_t lun, uint8_t *buf,
+                    uint32_t blk_addr, uint16_t blk_len)
+{
+  HANDLER_LUN_CHECK
+
+  return !ppUsbMscHandlers[lun]->Read(buf, blk_addr, blk_len);
+}
+
+/*******************************************************************************
+* Function Name  : Write_Memory
+* Description    : Handle the Write operation to the STORAGE card.
+* Input          : None.
+* Output         : None.
+* Return         : None.
+*******************************************************************************/
+int8_t STORAGE_Write(uint8_t lun, uint8_t *buf,
+                     uint32_t blk_addr, uint16_t blk_len)
+{
+  HANDLER_LUN_CHECK
+
+  return !ppUsbMscHandlers[lun]->Write(buf, blk_addr, blk_len);
+}
+
+/*******************************************************************************
+* Function Name  : Write_Memory
+* Description    : Handle the Write operation to the STORAGE card.
+* Input          : None.
+* Output         : None.
+* Return         : None.
+*******************************************************************************/
+int8_t STORAGE_GetMaxLun(void)
+{
+  return usbMscMaxLun;
+}
+
+#endif /* USBD_USE_MSC_CLASS */
+#endif /* USBCON */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/cores/arduino/stm32/usb/msc/usbd_msc_storage_if.h b/cores/arduino/stm32/usb/msc/usbd_msc_storage_if.h
new file mode 100644
index 0000000000..cddadecda0
--- /dev/null
+++ b/cores/arduino/stm32/usb/msc/usbd_msc_storage_if.h
@@ -0,0 +1,45 @@
+/**
+  ******************************************************************************
+  * @file    usbd_msc_storage.h
+  * @author  MCD Application Team
+  * @brief   Header file for the usbd_msc_storage.c file
+  ******************************************************************************
+  * @attention
+  *
+  * © Copyright (c) 2015 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                      www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USBD_MSC_STORAGE_H
+#define __USBD_MSC_STORAGE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "usbd_msc.h"
+
+extern USBD_StorageTypeDef  USBD_MSC_fops;
+
+#ifdef __cplusplus
+#include "USBMscHandler.h"
+
+extern uint8_t usbMscMaxLun;
+extern USBMscHandler **ppUsbMscHandlers;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBD_MSC_STORAGE_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/cores/arduino/stm32/usb/usbd_conf.c b/cores/arduino/stm32/usb/usbd_conf.c
index 109f2f56f5..3094d3a331 100644
--- a/cores/arduino/stm32/usb/usbd_conf.c
+++ b/cores/arduino/stm32/usb/usbd_conf.c
@@ -514,13 +514,25 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev)
   /* configure EPs FIFOs */
   HAL_PCDEx_SetRxFiFo(&g_hpcd, ep_def[0].ep_size);
   for (uint32_t i = 1; i < (DEV_NUM_EP + 1); i++) {
-    HAL_PCDEx_SetTxFiFo(&g_hpcd, ep_def[i].ep_adress & 0xF, ep_def[i].ep_size);
+    if (ep_def[i].ep_adress & 0xF0U) {
+      HAL_PCDEx_SetTxFiFo(&g_hpcd, ep_def[i].ep_adress & 0xF, ep_def[i].ep_size);
+    }
   }
 #else
+  uint32_t offset = PMA_BASE_OFFSET;
   for (uint32_t i = 0; i < (DEV_NUM_EP + 1); i++) {
-    HAL_PCDEx_PMAConfig(&g_hpcd, ep_def[i].ep_adress, ep_def[i].ep_kind, ep_def[i].ep_size);
+    ep_desc_t *pDesc = &ep_dep[i];
+    uint32_t size = pDesc->ep_size;
+    uint32_t address = offset;
+    if (pDesc->ep_kind == PCD_DBL_BUF) {
+      address = address | ((address + size) << 16U);
+      size *= 2;
+    }
+    HAL_PCDEx_PMAConfig(&g_hpcd, pDesc->ep_adress, pDesc->ep_kind, address);
+    offset += size;
   }
 #endif /* USE_USB_HS */
+
   return USBD_OK;
 }
 
diff --git a/cores/arduino/stm32/usb/usbd_conf.h b/cores/arduino/stm32/usb/usbd_conf.h
index c1a4808380..01ef078aa3 100644
--- a/cores/arduino/stm32/usb/usbd_conf.h
+++ b/cores/arduino/stm32/usb/usbd_conf.h
@@ -40,6 +40,7 @@ extern "C" {
 #include 
 #include 
 
+
 #if defined(USB_BASE)
 
 #if defined(STM32F1xx)
diff --git a/cores/arduino/stm32/usb/usbd_desc.c b/cores/arduino/stm32/usb/usbd_desc.c
index 229112ea5f..3d48f046ed 100644
--- a/cores/arduino/stm32/usb/usbd_desc.c
+++ b/cores/arduino/stm32/usb/usbd_desc.c
@@ -37,7 +37,7 @@
   #define USBD_VID 0x0483
   #if defined(USBD_USE_HID_COMPOSITE)
     #define USBD_PID                      0x5711
-  #elif defined(USBD_USE_CDC)
+  #elif defined(USBD_USE_CDC) || defined(USBD_USE_CDC_MSC)
     #define USBD_PID                      0x5740
   #endif
 #endif /* !USBD_PID && !USBD_VID */
@@ -70,7 +70,7 @@
 #elif defined(USBD_USE_HID_COMPOSITE)
   #define USBD_CLASS_PRODUCT_HS_STRING        CONCATS(BOARD_NAME, "HID in HS Mode")
   #define USBD_CLASS_PRODUCT_FS_STRING        CONCATS(BOARD_NAME, "HID in FS Mode")
-#elif defined(USBD_USE_CDC)
+#elif defined(USBD_USE_CDC) || defined(USBD_USE_CDC_MSC)
   #define USBD_CLASS_PRODUCT_HS_STRING        CONCATS(BOARD_NAME, "CDC in HS Mode")
   #define USBD_CLASS_PRODUCT_FS_STRING        CONCATS(BOARD_NAME, "CDC in FS Mode")
 #else
@@ -85,7 +85,7 @@
   #define USBD_CLASS_INTERFACE_FS_STRING      CONCATS(BOARD_NAME, "HID Interface")
 #endif /* USBD_USE_HID_COMPOSITE */
 
-#ifdef USBD_USE_CDC
+#if defined(USBD_USE_CDC) || defined(USBD_USE_CDC_MSC)
   #define USBD_CLASS_CONFIGURATION_HS_STRING  CONCATS(BOARD_NAME, "CDC Config")
   #define USBD_CLASS_INTERFACE_HS_STRING      CONCATS(BOARD_NAME, "CDC Interface")
   #define USBD_CLASS_CONFIGURATION_FS_STRING  CONCATS(BOARD_NAME, "CDC Config")
@@ -129,81 +129,51 @@ USBD_DescriptorsTypeDef USBD_Desc = {
 #endif
 };
 
-#ifdef USBD_USE_HID_COMPOSITE
-/* USB Standard Device Descriptor */
-__ALIGN_BEGIN uint8_t USBD_Class_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = {
-  0x12,                       /* bLength */
-  USB_DESC_TYPE_DEVICE,       /* bDescriptorType */
+
+#define USB_CDC_CLASS_MULTI 0xEF
+#define CDC_SUBCLASS_ACM    0x02
+#define CDC_PROTOCOL_V25TER 0x01 // Common AT commands
+
+
 #if ((USBD_LPM_ENABLED == 1) || (USBD_CLASS_BOS_ENABLED == 1))
-  0x01,                       /*bcdUSB */     /* changed to USB version 2.01
-                                              in order to support BOS Desc */
+  #define BCD_USB_FLAG 0x01
 #else
-  0x00,                       /* bcdUSB */
+  #define BCD_USB_FLAG 0x00
+#endif
+
+
+#define USBD_CLASS_DEVICE_DESCRIPTOR(_CLASS, _SUBCLASS, _PROTO)                \
+__ALIGN_BEGIN uint8_t USBD_Class_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = { \
+  0x12,                      /* bLength */ \
+  USB_DESC_TYPE_DEVICE,      /* bDescriptorType */ \
+  BCD_USB_FLAG,              /* bcdUSB */ \
+  0x02, \
+  _CLASS,                    /* bDeviceClass */ \
+  _SUBCLASS,                 /* bDeviceSubClass */ \
+  _PROTO,                    /* bDeviceProtocol */ \
+  USB_MAX_EP0_SIZE,          /* bMaxPacketSize */ \
+  LOBYTE(USBD_VID),          /* idVendor */ \
+  HIBYTE(USBD_VID),          /* idVendor */ \
+  LOBYTE(USBD_PID),          /* idProduct */ \
+  HIBYTE(USBD_PID),          /* idProduct */ \
+  0x00,                      /* bcdDevice rel. 0.00 */ \
+  0x00, \
+  USBD_IDX_MFC_STR,          /* Index of manufacturer string */ \
+  USBD_IDX_PRODUCT_STR,      /* Index of product string */ \
+  USBD_IDX_SERIAL_STR,       /* Index of serial number string */ \
+  USBD_MAX_NUM_CONFIGURATION /* bNumConfigurations */ \
+}
+
+#ifdef USBD_USE_HID_COMPOSITE
+  USBD_CLASS_DEVICE_DESCRIPTOR(0x00, 0x00, 0x00);
 #endif
-  0x02,
-  0x00,                       /* bDeviceClass */
-  0x00,                       /* bDeviceSubClass */
-  0x00,                       /* bDeviceProtocol */
-  USB_MAX_EP0_SIZE,           /* bMaxPacketSize */
-  LOBYTE(USBD_VID),           /* idVendor */
-  HIBYTE(USBD_VID),           /* idVendor */
-  LOBYTE(USBD_PID),           /* idProduct */
-  HIBYTE(USBD_PID),           /* idProduct */
-  0x00,                       /* bcdDevice rel. 0.00 */
-  0x00,
-  USBD_IDX_MFC_STR,           /* Index of manufacturer string */
-  USBD_IDX_PRODUCT_STR,       /* Index of product string */
-  USBD_IDX_SERIAL_STR,        /* Index of serial number string */
-  USBD_MAX_NUM_CONFIGURATION  /* bNumConfigurations */
-}; /* USB_DeviceDescriptor */
-#endif /* USBD_USE_HID_COMPOSITE */
 
 #ifdef USBD_USE_CDC
-/* USB Standard Device Descriptor */
-__ALIGN_BEGIN uint8_t USBD_Class_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = {
-  0x12,                       /* bLength */
-  USB_DESC_TYPE_DEVICE,       /* bDescriptorType */
-#if ((USBD_LPM_ENABLED == 1) || (USBD_CLASS_BOS_ENABLED == 1))
-  0x01,                       /*bcdUSB */     /* changed to USB version 2.01
-                                              in order to support BOS Desc */
-#else
-  0x00,                       /* bcdUSB */
+  USBD_CLASS_DEVICE_DESCRIPTOR(0x02, 0x02, 0x00);
 #endif
-  0x02,
-  0x02,                       /* bDeviceClass */
-  0x02,                       /* bDeviceSubClass */
-  0x00,                       /* bDeviceProtocol */
-  USB_MAX_EP0_SIZE,           /* bMaxPacketSize */
-  LOBYTE(USBD_VID),           /* idVendor */
-  HIBYTE(USBD_VID),           /* idVendor */
-  LOBYTE(USBD_PID),           /* idProduct */
-  HIBYTE(USBD_PID),           /* idProduct */
-  0x00,                       /* bcdDevice rel. 0.00 */
-  0x00,
-  USBD_IDX_MFC_STR,           /* Index of manufacturer string */
-  USBD_IDX_PRODUCT_STR,       /* Index of product string */
-  USBD_IDX_SERIAL_STR,        /* Index of serial number string */
-  USBD_MAX_NUM_CONFIGURATION  /* bNumConfigurations */
-}; /* USB_DeviceDescriptor */
-#endif /* USBD_USE_CDC */
 
-/* USB Device LPM BOS descriptor */
-#if (USBD_LPM_ENABLED == 1)
-__ALIGN_BEGIN  uint8_t USBD_BOSDesc[USB_SIZ_BOS_DESC] __ALIGN_END = {
-  0x5,
-  USB_DESC_TYPE_BOS,
-  0xC,
-  0x0,
-  0x1,  /* 1 device capability */
-  /* device capability */
-  0x7,
-  USB_DEVICE_CAPABITY_TYPE,
-  0x2,
-  0x6, /*LPM capability bit set */
-  0x0,
-  0x0,
-  0x0
-};
+#ifdef USBD_USE_CDC_MSC
+  USBD_CLASS_DEVICE_DESCRIPTOR(USB_CDC_CLASS_MULTI, CDC_SUBCLASS_ACM, CDC_PROTOCOL_V25TER);
 #endif
 
 /* USB Device Billboard BOS descriptor Template */
diff --git a/cores/arduino/stm32/usb/usbd_ep_conf.c b/cores/arduino/stm32/usb/usbd_ep_conf.c
index 455afe5ecd..2e72855e5d 100644
--- a/cores/arduino/stm32/usb/usbd_ep_conf.c
+++ b/cores/arduino/stm32/usb/usbd_ep_conf.c
@@ -19,53 +19,86 @@
 /* Includes ------------------------------------------------------------------*/
 #include "usbd_ep_conf.h"
 
-#ifdef USBD_USE_CDC
-const ep_desc_t ep_def[] = {
-#ifdef USE_USB_HS
-  {0x00,       CDC_DATA_HS_MAX_PACKET_SIZE},
-  {0x80,       CDC_DATA_HS_MAX_PACKET_SIZE},
-  {CDC_OUT_EP, CDC_DATA_HS_MAX_PACKET_SIZE},
-  {CDC_IN_EP,  CDC_DATA_HS_MAX_PACKET_SIZE},
-  {CDC_CMD_EP, CDC_CMD_PACKET_SIZE}
-#else /* USE_USB_FS */
-#ifdef USB_OTG_FS
-  {0x00,       CDC_DATA_FS_MAX_PACKET_SIZE},
-  {0x80,       CDC_DATA_FS_MAX_PACKET_SIZE},
-  {CDC_OUT_EP, CDC_DATA_FS_MAX_PACKET_SIZE},
-  {CDC_IN_EP,  CDC_DATA_FS_MAX_PACKET_SIZE},
-  {CDC_CMD_EP, CDC_CMD_PACKET_SIZE}
+#if defined(USB_OTG_FS) || defined(USE_USB_HS)
+  #define EP_DESC(ADDR, SIZE, KIND_TYP) {ADDR, SIZE}
 #else
-  {0x00,       PMA_EP0_OUT_ADDR, PCD_SNG_BUF},
-  {0x80,       PMA_EP0_IN_ADDR,  PCD_SNG_BUF},
-  {CDC_OUT_EP, PMA_CDC_OUT_ADDR, PCD_DBL_BUF},
-  {CDC_IN_EP,  PMA_CDC_IN_ADDR,  PCD_SNG_BUF},
-  {CDC_CMD_EP, PMA_CDC_CMD_ADDR, PCD_SNG_BUF}
-#endif
+  #define EP_DESC(ADDR, SIZE, KIND_TYP)  {ADDR, SIZE, KIND_TYP}
 #endif
-};
+
+// *INDENT-OFF*
+
+#ifdef USBD_USE_CDC
+  #ifdef USE_USB_HS
+    #define CDC_DATA_MAX_PACKET_SIZE  CDC_DATA_HS_MAX_PACKET_SIZE
+  #else /* USE_USB_FS */
+    #define CDC_DATA_MAX_PACKET_SIZE  CDC_DATA_FS_MAX_PACKET_SIZE
+  #endif
+
+
+  const ep_desc_t ep_def[] = {
+    EP_DESC(0x00,       CDC_DATA_MAX_PACKET_SIZE, PCD_SNG_BUF),
+    EP_DESC(0x80,       CDC_DATA_MAX_PACKET_SIZE, PCD_SNG_BUF),
+    EP_DESC(CDC_OUT_EP, CDC_DATA_MAX_PACKET_SIZE, PCD_DBL_BUF),
+    EP_DESC(CDC_IN_EP,  CDC_DATA_MAX_PACKET_SIZE, PCD_SNG_BUF),
+    EP_DESC(CDC_CMD_EP, CDC_CMD_PACKET_SIZE,      PCD_SNG_BUF)
+  };
 #endif /* USBD_USE_CDC */
 
+#ifdef USBD_USE_MSC
+  #ifdef USE_USB_HS
+    #define MSC_DATA_MAX_PACKET_SIZE  MSC_DATA_HS_MAX_PACKET_SIZE
+  #else /* USE_USB_FS */
+    #define MSC_DATA_MAX_PACKET_SIZE  MSC_DATA_FS_MAX_PACKET_SIZE
+  #endif
+
+
+  const ep_desc_t ep_def[] = {
+    EP_DESC(0x00,       CDC_DATA_MAX_PACKET_SIZE, PCD_SNG_BUF),
+    EP_DESC(0x80,       CDC_DATA_MAX_PACKET_SIZE, PCD_SNG_BUF),
+    EP_DESC(MSC_EPIN_ADDR,  MSC_DATA_MAX_PACKET_SIZE, PCD_SNG_BUF),
+    EP_DESC(MSC_EPOUT_ADDR, MSC_DATA_MAX_PACKET_SIZE, PCD_SNG_BUF)
+  };
+#endif /* USBD_USE_MSC */
+
+#ifdef USBD_USE_CDC_MSC
+  #ifdef USE_USB_HS
+    #define CDC_DATA_MAX_PACKET_SIZE  CDC_DATA_HS_MAX_PACKET_SIZE
+    #define MSC_DATA_MAX_PACKET_SIZE  MSC_DATA_HS_MAX_PACKET_SIZE
+  #else /* USE_USB_FS */
+    #define CDC_DATA_MAX_PACKET_SIZE  CDC_DATA_FS_MAX_PACKET_SIZE
+    #define MSC_DATA_MAX_PACKET_SIZE  MSC_DATA_FS_MAX_PACKET_SIZE
+  #endif
+
+
+  const ep_desc_t ep_def[] = {
+    EP_DESC(0x00,       CDC_DATA_MAX_PACKET_SIZE, PCD_SNG_BUF),
+    EP_DESC(0x80,       CDC_DATA_MAX_PACKET_SIZE, PCD_SNG_BUF),
+    EP_DESC(CDC_OUT_EP, CDC_DATA_MAX_PACKET_SIZE, PCD_DBL_BUF),
+    EP_DESC(CDC_IN_EP,  CDC_DATA_MAX_PACKET_SIZE, PCD_SNG_BUF),
+    EP_DESC(CDC_CMD_EP, CDC_CMD_PACKET_SIZE,      PCD_SNG_BUF),
+    EP_DESC(MSC_EPIN_ADDR,  MSC_DATA_MAX_PACKET_SIZE, PCD_SNG_BUF),
+    EP_DESC(MSC_EPOUT_ADDR, MSC_DATA_MAX_PACKET_SIZE, PCD_SNG_BUF)
+  };
+#endif /* USBD_USE_CDC */
+
+
 #ifdef USBD_USE_HID_COMPOSITE
-const ep_desc_t ep_def[] = {
-#if !defined (USB)
-#ifdef USE_USB_HS
-  {0x00,                   USB_HS_MAX_PACKET_SIZE},
-  {0x80,                   USB_HS_MAX_PACKET_SIZE},
-#else
-  {0x00,                   USB_FS_MAX_PACKET_SIZE},
-  {0x80,                   USB_FS_MAX_PACKET_SIZE},
-#endif
-  {HID_MOUSE_EPIN_ADDR,    HID_MOUSE_EPIN_SIZE},
-  {HID_KEYBOARD_EPIN_ADDR, HID_KEYBOARD_EPIN_SIZE},
-#else
-  {0x00,                   PMA_EP0_OUT_ADDR,     PCD_SNG_BUF},
-  {0x80,                   PMA_EP0_IN_ADDR,      PCD_SNG_BUF},
-  {HID_MOUSE_EPIN_ADDR,    PMA_MOUSE_IN_ADDR,    PCD_SNG_BUF},
-  {HID_KEYBOARD_EPIN_ADDR, PMA_KEYBOARD_IN_ADDR, PCD_SNG_BUF},
-#endif
-};
+  #ifdef USE_USB_HS
+    #define HID_MAX_PACKET_SIZE  USB_HS_MAX_PACKET_SIZE
+  #else /* USE_USB_FS */
+    #define HID_MAX_PACKET_SIZE  USB_FS_MAX_PACKET_SIZE
+  #endif
+
+  const ep_desc_t ep_def[] = {
+    EP_DESC(0x00,                   HID_MAX_PACKET_SIZE, PCD_SNG_BUF),
+    EP_DESC(0x80,                   HID_MAX_PACKET_SIZE, PCD_SNG_BUF),
+    EP_DESC(HID_MOUSE_EPIN_ADDR,    HID_MOUSE_EPIN_SIZE, PCD_SNG_BUF),
+    EP_DESC(HID_KEYBOARD_EPIN_ADDR, HID_MOUSE_EPIN_SIZE, PCD_SNG_BUF)
+  };
 #endif /* USBD_USE_HID_COMPOSITE */
 
+// *INDENT-OFF*
+
 #endif /* HAL_PCD_MODULE_ENABLED && USBCON */
 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
 
diff --git a/cores/arduino/stm32/usb/usbd_ep_conf.h b/cores/arduino/stm32/usb/usbd_ep_conf.h
index 354b6f4d0c..75a458b4d1 100644
--- a/cores/arduino/stm32/usb/usbd_ep_conf.h
+++ b/cores/arduino/stm32/usb/usbd_ep_conf.h
@@ -33,9 +33,11 @@ typedef struct {
 #endif
 } ep_desc_t;
 
+// *INDENT-OFF*
 
 /* CDC Endpoints Configurations */
 #ifdef USBD_USE_CDC
+  #define USBD_USE_CDC_CLASS
 
   #define CDC_OUT_EP                    0x01U  /* EP1 for data OUT */
   #define CDC_IN_EP                     0x82U  /* EP1 for data IN */
@@ -49,6 +51,40 @@ typedef struct {
   #define CDC_CMD_PACKET_SIZE                               8U  /* Control Endpoint Packet size */
 #endif /* USBD_USE_CDC */
 
+#ifdef USBD_USE_MSC
+  #define USBD_USE_MSC_CLASS
+
+  #define MSC_EPOUT_ADDR                0x01U /*  EP1 for MSC data IN */
+  #define MSC_EPIN_ADDR                 0x81U /*  EP1 for MSC data IN */
+
+  #define DEV_NUM_EP                    0x04U   /* Device Endpoints number including EP0 IN and EP0 OUT */
+
+  /* MSC Endpoints parameters*/
+  #define MSC_DATA_HS_MAX_PACKET_SIZE   USB_HS_MAX_PACKET_SIZE  /* Endpoint IN & OUT Packet size */
+  #define MSC_DATA_FS_MAX_PACKET_SIZE   USB_FS_MAX_PACKET_SIZE  /* Endpoint IN & OUT Packet size */
+#endif
+
+#ifdef USBD_USE_CDC_MSC
+  #define USBD_USE_CDC_CLASS
+  #define USBD_USE_MSC_CLASS
+
+  #define CDC_OUT_EP                    0x01U /*  EP1 for CDC data OUT */
+  #define CDC_IN_EP                     0x81U /*  EP1 for CDC data IN */
+  #define CDC_CMD_EP                    0x82U /*  EP2 for CDC commands */
+
+  #define MSC_EPOUT_ADDR                0x03U /*  EP3 for MSC data IN */
+  #define MSC_EPIN_ADDR                 0x83U /*  EP3 for MSC data IN */
+
+  #define DEV_NUM_EP                    0x07U   /* Device Endpoints number including EP0 */
+
+  /* CDC Endpoints parameters*/
+  #define CDC_DATA_HS_MAX_PACKET_SIZE   USB_HS_MAX_PACKET_SIZE  /* Endpoint IN & OUT Packet size */
+  #define CDC_DATA_FS_MAX_PACKET_SIZE   USB_FS_MAX_PACKET_SIZE  /* Endpoint IN & OUT Packet size */
+  #define CDC_CMD_PACKET_SIZE                               8U  /* Control Endpoint Packet size */
+  /* MSC Endpoints parameters*/
+  #define MSC_DATA_HS_MAX_PACKET_SIZE   USB_HS_MAX_PACKET_SIZE  /* Endpoint IN & OUT Packet size */
+  #define MSC_DATA_FS_MAX_PACKET_SIZE   USB_FS_MAX_PACKET_SIZE  /* Endpoint IN & OUT Packet size */
+#endif
 
 /* HID composite (Mouse + Keyboard) Endpoints Configurations */
 #ifdef USBD_USE_HID_COMPOSITE
@@ -61,29 +97,19 @@ typedef struct {
   #define DEV_NUM_EP                    0x03U   /* Device Endpoints number including EP0 */
 #endif /* USBD_USE_HID_COMPOSITE */
 
+
 /* Require DEV_NUM_EP to be defined */
 #if defined (USB)
-/* Size in words, byte size divided by 2 */
-#define PMA_EP0_OUT_ADDR    (8 * DEV_NUM_EP)
-#define PMA_EP0_IN_ADDR     (PMA_EP0_OUT_ADDR + USB_MAX_EP0_SIZE)
-
-#ifdef USBD_USE_CDC
-#define PMA_CDC_OUT_BASE    (PMA_EP0_IN_ADDR + USB_MAX_EP0_SIZE)
-#define PMA_CDC_OUT_ADDR    ((PMA_CDC_OUT_BASE + USB_FS_MAX_PACKET_SIZE) | \
-                            (PMA_CDC_OUT_BASE << 16U))
-#define PMA_CDC_IN_ADDR     (PMA_CDC_OUT_BASE + USB_FS_MAX_PACKET_SIZE * 2)
-#define PMA_CDC_CMD_ADDR    (PMA_CDC_IN_ADDR + CDC_CMD_PACKET_SIZE)
-#endif /* USBD_USE_CDC */
-#ifdef USBD_USE_HID_COMPOSITE
-  #define PMA_MOUSE_IN_ADDR   (PMA_EP0_IN_ADDR + HID_MOUSE_EPIN_SIZE)
-  #define PMA_KEYBOARD_IN_ADDR    (PMA_MOUSE_IN_ADDR + HID_KEYBOARD_EPIN_SIZE)
-#endif /* USBD_USE_HID_COMPOSITE */
+  /* Size in words, byte size divided by 2 */
+  #define PMA_BASE_OFFSET     (8 * DEV_NUM_EP)
 #endif /* USB */
 
+// *INDENT-ON*
+
 extern const ep_desc_t ep_def[DEV_NUM_EP + 1];
 
 
 #endif /* USBCON */
 #endif /* __USBD_EP_CONF_H */
 
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
\ No newline at end of file
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/cores/arduino/stm32/usb/usbd_if.c b/cores/arduino/stm32/usb/usbd_if.c
index e579140f72..0ea854909e 100644
--- a/cores/arduino/stm32/usb/usbd_if.c
+++ b/cores/arduino/stm32/usb/usbd_if.c
@@ -155,11 +155,4 @@ WEAK void USBD_reenumerate(void)
 #else /* !defined(USBD_REENUM_DISABLED) */
 WEAK void USBD_reenumerate(void) { }
 #endif
-
-#ifdef USBD_USE_CDC
-void USBD_CDC_init(void)
-{
-  CDC_init();
-}
-#endif /* USBD_USE_CDC */
 #endif /* USBCON */
diff --git a/cores/arduino/stm32/usb/usbd_if.h b/cores/arduino/stm32/usb/usbd_if.h
index dc026240fe..bcd54020e6 100644
--- a/cores/arduino/stm32/usb/usbd_if.h
+++ b/cores/arduino/stm32/usb/usbd_if.h
@@ -24,9 +24,7 @@ extern "C" {
 #endif
 
 void USBD_reenumerate(void);
-#ifdef USBD_USE_CDC
-void USBD_CDC_init(void);
-#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libraries/SrcWrapper/src/stm32/hw_config.c b/libraries/SrcWrapper/src/stm32/hw_config.cpp
similarity index 95%
rename from libraries/SrcWrapper/src/stm32/hw_config.c
rename to libraries/SrcWrapper/src/stm32/hw_config.cpp
index 3434d6da96..6bec1f76f0 100644
--- a/libraries/SrcWrapper/src/stm32/hw_config.c
+++ b/libraries/SrcWrapper/src/stm32/hw_config.cpp
@@ -37,7 +37,8 @@
   */
 #include "stm32_def.h"
 #include "hw_config.h"
-#include "usbd_if.h"
+#include "usbd_ep_conf.h"
+#include "USBSerial.h"
 #include "dwt.h"
 
 #ifdef __cplusplus
@@ -62,8 +63,8 @@ void hw_config_init(void)
   /* Configure the system clock */
   SystemClock_Config();
 
-#if defined (USBCON) && defined(USBD_USE_CDC)
-  USBD_CDC_init();
+#if defined (USBCON) && defined(USBD_USE_CDC_CLASS)
+  SerialUSB.begin();
 #endif
 
 #if defined (STM32MP1xx)
diff --git a/platform.txt b/platform.txt
index 3674dfe7d2..925aa620ea 100644
--- a/platform.txt
+++ b/platform.txt
@@ -9,7 +9,7 @@ version=1.0.0
 
 # STM compile variables
 # ----------------------
-compiler.stm.extra_include="-I{build.source.path}" "-I{build.core.path}/avr" "-I{build.core.path}/stm32" "-I{build.core.path}/stm32/LL" "-I{build.core.path}/stm32/usb" "-I{build.core.path}/stm32/OpenAMP" "-I{build.core.path}/stm32/usb/hid" "-I{build.core.path}/stm32/usb/cdc" "-I{build.system.path}/Drivers/{build.series}_HAL_Driver/Inc" "-I{build.system.path}/Drivers/{build.series}_HAL_Driver/Src" "-I{build.system.path}/{build.series}" "-I{build.system.path}/Middlewares/ST/STM32_USB_Device_Library/Core/Inc" "-I{build.system.path}/Middlewares/ST/STM32_USB_Device_Library/Core/Src" {build.virtio_extra_include}
+compiler.stm.extra_include="-I{build.source.path}" "-I{build.core.path}/avr" "-I{build.core.path}/stm32" "-I{build.core.path}/stm32/LL" "-I{build.core.path}/stm32/usb" "-I{build.core.path}/stm32/OpenAMP" "-I{build.core.path}/stm32/usb/hid" "-I{build.core.path}/stm32/usb/cdc" "-I{build.core.path}/stm32/usb/msc" "-I{build.core.path}/stm32/usb/cdc_msc" "-I{build.system.path}/Drivers/{build.series}_HAL_Driver/Inc" "-I{build.system.path}/Drivers/{build.series}_HAL_Driver/Src" "-I{build.system.path}/{build.series}" "-I{build.system.path}/Middlewares/ST/STM32_USB_Device_Library/Core/Inc" "-I{build.system.path}/Middlewares/ST/STM32_USB_Device_Library/Core/Src" {build.virtio_extra_include}
 
 compiler.warning_flags=-w
 compiler.warning_flags.none=-w
diff --git a/tools/platformio-build.py b/tools/platformio-build.py
index 68b0dfc01c..7bdc40d781 100644
--- a/tools/platformio-build.py
+++ b/tools/platformio-build.py
@@ -86,7 +86,7 @@ def process_usb_configuration(cpp_defines):
     elif "PIO_FRAMEWORK_ARDUINO_ENABLE_HID" in cpp_defines:
         env.Append(CPPDEFINES=["USBD_USE_HID_COMPOSITE"])
 
-    if any(f in env["CPPDEFINES"] for f in ("USBD_USE_CDC", "USBD_USE_HID_COMPOSITE")):
+    if any(f in env["CPPDEFINES"] for f in ["USBCON"]):
         env.Append(CPPDEFINES=["HAL_PCD_MODULE_ENABLED"])
 
 
@@ -170,6 +170,8 @@ def configure_application_offset(mcu, upload_protocol):
         join(FRAMEWORK_DIR, "cores", "arduino", "stm32", "usb"),
         join(FRAMEWORK_DIR, "cores", "arduino", "stm32", "usb", "hid"),
         join(FRAMEWORK_DIR, "cores", "arduino", "stm32", "usb", "cdc"),
+        join(FRAMEWORK_DIR, "cores", "arduino", "stm32", "usb", "msc"),
+        join(FRAMEWORK_DIR, "cores", "arduino", "stm32", "usb", "cdc_msc"),
         join(FRAMEWORK_DIR, "system", "Drivers", series + "_HAL_Driver", "Inc"),
         join(FRAMEWORK_DIR, "system", "Drivers", series + "_HAL_Driver", "Src"),
         join(FRAMEWORK_DIR, "system", series),