diff --git a/boards.txt b/boards.txt
index 6aee90b5bb9..d9cc12af1d0 100644
--- a/boards.txt
+++ b/boards.txt
@@ -12,6 +12,7 @@ menu.LORAWAN_REGION=LoRaWan Region
 menu.LoRaWanDebugLevel=LoRaWan Debug Level
 menu.LoopCore=Arduino Runs On
 menu.EventsCore=Events Run On
+menu.USBStack=USB Stack
 
 ##############################################################
 ### DO NOT PUT BOARDS ABOVE THE OFFICIAL ESPRESSIF BOARDS! ###
@@ -295,6 +296,11 @@ esp32s2.menu.DebugLevel.debug.build.code_debug=4
 esp32s2.menu.DebugLevel.verbose=Verbose
 esp32s2.menu.DebugLevel.verbose.build.code_debug=5
 
+esp32s2.menu.USBStack.idf=ESP-IDF
+esp32s2.menu.USBStack.idf.build.usbstack_flags=
+esp32s2.menu.USBStack.tinyusb=Adafruit TinyUSB
+esp32s2.menu.USBStack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
+
 ##############################################################
 
 esp32.name=ESP32 Dev Module
@@ -960,6 +966,11 @@ feathers2.menu.DebugLevel.debug.build.code_debug=4
 feathers2.menu.DebugLevel.verbose=Verbose
 feathers2.menu.DebugLevel.verbose.build.code_debug=5
 
+feathers2.menu.USBStack.idf=ESP-IDF
+feathers2.menu.USBStack.idf.build.usbstack_flags=
+feathers2.menu.USBStack.tinyusb=Adafruit TinyUSB
+feathers2.menu.USBStack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
+
 ##############################################################
 
 tinys2.name=UM TinyS2
@@ -1075,6 +1086,11 @@ tinys2.menu.DebugLevel.debug.build.code_debug=4
 tinys2.menu.DebugLevel.verbose=Verbose
 tinys2.menu.DebugLevel.verbose.build.code_debug=5
 
+tinys2.menu.USBStack.idf=ESP-IDF
+tinys2.menu.USBStack.idf.build.usbstack_flags=
+tinys2.menu.USBStack.tinyusb=Adafruit TinyUSB
+tinys2.menu.USBStack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
+
 ##############################################################
 S_ODI_Ultra.name=S.ODI Ultra v1
 
@@ -1261,6 +1277,11 @@ micros2.menu.DebugLevel.debug.build.code_debug=4
 micros2.menu.DebugLevel.verbose=Verbose
 micros2.menu.DebugLevel.verbose.build.code_debug=5
 
+micros2.menu.USBStack.idf=ESP-IDF
+micros2.menu.USBStack.idf.build.usbstack_flags=
+micros2.menu.USBStack.tinyusb=Adafruit TinyUSB
+micros2.menu.USBStack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
+
 ##############################################################
 magicbit.name=MagicBit
 
@@ -2140,6 +2161,11 @@ sparkfun_esp32s2_thing_plus.menu.DebugLevel.debug.build.code_debug=4
 sparkfun_esp32s2_thing_plus.menu.DebugLevel.verbose=Verbose
 sparkfun_esp32s2_thing_plus.menu.DebugLevel.verbose.build.code_debug=5
 
+sparkfun_esp32s2_thing_plus.menu.USBStack.idf=ESP-IDF
+sparkfun_esp32s2_thing_plus.menu.USBStack.idf.build.usbstack_flags=
+sparkfun_esp32s2_thing_plus.menu.USBStack.tinyusb=Adafruit TinyUSB
+sparkfun_esp32s2_thing_plus.menu.USBStack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
+
 ##############################################################
 
 sparkfun_lora_gateway_1-channel.name=SparkFun LoRa Gateway 1-Channel
@@ -3326,7 +3352,7 @@ adafruit_metro_esp32s2.build.core=esp32
 adafruit_metro_esp32s2.build.variant=adafruit_metro_esp32s2
 adafruit_metro_esp32s2.build.board=METRO_ESP32S2
 
-adafruit_metro_esp32s2.build.serial=0
+adafruit_metro_esp32s2.build.serial=1
 adafruit_metro_esp32s2.build.f_cpu=240000000L
 adafruit_metro_esp32s2.build.flash_size=4MB
 adafruit_metro_esp32s2.build.flash_freq=80m
@@ -3449,16 +3475,21 @@ adafruit_metro_esp32s2.menu.DebugLevel.debug.build.code_debug=4
 adafruit_metro_esp32s2.menu.DebugLevel.verbose=Verbose
 adafruit_metro_esp32s2.menu.DebugLevel.verbose.build.code_debug=5
 
+adafruit_metro_esp32s2.menu.USBStack.idf=ESP-IDF
+adafruit_metro_esp32s2.menu.USBStack.idf.build.usbstack_flags=
+adafruit_metro_esp32s2.menu.USBStack.tinyusb=Adafruit TinyUSB
+adafruit_metro_esp32s2.menu.USBStack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
+
 
 ##############################################################
 
 adafruit_magtag29_esp32s2.name=Adafruit MagTag 2.9"
 adafruit_magtag29_esp32s2.vid.0=0x239A
-adafruit_magtag29_esp32s2.pid.0=0x80DF
+adafruit_magtag29_esp32s2.pid.0=0x80E5
 adafruit_magtag29_esp32s2.vid.1=0x239A
-adafruit_magtag29_esp32s2.pid.1=0x00DF
+adafruit_magtag29_esp32s2.pid.1=0x00E5
 adafruit_magtag29_esp32s2.vid.1=0x239A
-adafruit_magtag29_esp32s2.pid.1=0x80E0
+adafruit_magtag29_esp32s2.pid.1=0x80E6
 
 adafruit_magtag29_esp32s2.upload.tool=esptool_py
 adafruit_magtag29_esp32s2.upload.maximum_size=1310720
@@ -3479,7 +3510,7 @@ adafruit_magtag29_esp32s2.build.core=esp32
 adafruit_magtag29_esp32s2.build.variant=adafruit_magtag29_esp32s2
 adafruit_magtag29_esp32s2.build.board=MAGTAG29_ESP32S2
 
-adafruit_magtag29_esp32s2.build.serial=0
+adafruit_magtag29_esp32s2.build.serial=1
 adafruit_magtag29_esp32s2.build.f_cpu=240000000L
 adafruit_magtag29_esp32s2.build.flash_size=4MB
 adafruit_magtag29_esp32s2.build.flash_freq=80m
@@ -3602,6 +3633,11 @@ adafruit_magtag29_esp32s2.menu.DebugLevel.debug.build.code_debug=4
 adafruit_magtag29_esp32s2.menu.DebugLevel.verbose=Verbose
 adafruit_magtag29_esp32s2.menu.DebugLevel.verbose.build.code_debug=5
 
+adafruit_magtag29_esp32s2.menu.USBStack.idf=ESP-IDF
+adafruit_magtag29_esp32s2.menu.USBStack.idf.build.usbstack_flags=
+adafruit_magtag29_esp32s2.menu.USBStack.tinyusb=Adafruit TinyUSB
+adafruit_magtag29_esp32s2.menu.USBStack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
+
 
 ##############################################################
 
@@ -3632,7 +3668,7 @@ adafruit_funhouse_esp32s2.build.core=esp32
 adafruit_funhouse_esp32s2.build.variant=adafruit_funhouse_esp32s2
 adafruit_funhouse_esp32s2.build.board=FUNHOUSE_ESP32S2
 
-adafruit_funhouse_esp32s2.build.serial=0
+adafruit_funhouse_esp32s2.build.serial=1
 adafruit_funhouse_esp32s2.build.f_cpu=240000000L
 adafruit_funhouse_esp32s2.build.flash_size=4MB
 adafruit_funhouse_esp32s2.build.flash_freq=80m
@@ -3755,6 +3791,11 @@ adafruit_funhouse_esp32s2.menu.DebugLevel.debug.build.code_debug=4
 adafruit_funhouse_esp32s2.menu.DebugLevel.verbose=Verbose
 adafruit_funhouse_esp32s2.menu.DebugLevel.verbose.build.code_debug=5
 
+adafruit_funhouse_esp32s2.menu.USBStack.idf=ESP-IDF
+adafruit_funhouse_esp32s2.menu.USBStack.idf.build.usbstack_flags=
+adafruit_funhouse_esp32s2.menu.USBStack.tinyusb=Adafruit TinyUSB
+adafruit_funhouse_esp32s2.menu.USBStack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
+
 
 ##############################################################
 
@@ -3785,7 +3826,7 @@ adafruit_feather_esp32s2_nopsram.build.core=esp32
 adafruit_feather_esp32s2_nopsram.build.variant=adafruit_feather_esp32s2
 adafruit_feather_esp32s2_nopsram.build.board=ADAFRUIT_FEATHER_ESP32S2_NOPSRAM
 
-adafruit_feather_esp32s2_nopsram.build.serial=0
+adafruit_feather_esp32s2_nopsram.build.serial=1
 adafruit_feather_esp32s2_nopsram.build.f_cpu=240000000L
 adafruit_feather_esp32s2_nopsram.build.flash_size=4MB
 adafruit_feather_esp32s2_nopsram.build.flash_freq=80m
@@ -3908,6 +3949,11 @@ adafruit_feather_esp32s2_nopsram.menu.DebugLevel.debug.build.code_debug=4
 adafruit_feather_esp32s2_nopsram.menu.DebugLevel.verbose=Verbose
 adafruit_feather_esp32s2_nopsram.menu.DebugLevel.verbose.build.code_debug=5
 
+adafruit_feather_esp32s2_nopsram.menu.USBStack.idf=ESP-IDF
+adafruit_feather_esp32s2_nopsram.menu.USBStack.idf.build.usbstack_flags=
+adafruit_feather_esp32s2_nopsram.menu.USBStack.tinyusb=Adafruit TinyUSB
+adafruit_feather_esp32s2_nopsram.menu.USBStack.tinyusb.build.usbstack_flags=-DUSE_TINYUSB "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
+
 
 ##############################################################
 
@@ -8851,4 +8897,4 @@ esp32-trueverit-iot-driver-mkii.menu.DebugLevel.debug.build.code_debug=4
 esp32-trueverit-iot-driver-mkii.menu.DebugLevel.verbose=Verbose
 esp32-trueverit-iot-driver-mkii.menu.DebugLevel.verbose.build.code_debug=5
 
-##############################################################
\ No newline at end of file
+##############################################################
diff --git a/cores/esp32/USB.cpp b/cores/esp32/USB.cpp
index 066982f69a0..9ad4b1321ac 100644
--- a/cores/esp32/USB.cpp
+++ b/cores/esp32/USB.cpp
@@ -14,7 +14,7 @@
 #include "esp32-hal.h"
 #include "esp32-hal-tinyusb.h"
 #include "USB.h"
-#if CONFIG_TINYUSB_ENABLED
+#if CONFIG_TINYUSB_ENABLED && !defined(USE_TINYUSB)
 
 #ifndef USB_VID
 #define USB_VID USB_ESPRESSIF_VID
diff --git a/cores/esp32/USB.h b/cores/esp32/USB.h
index 2a5fdb7182e..f651ff1dcd7 100644
--- a/cores/esp32/USB.h
+++ b/cores/esp32/USB.h
@@ -14,7 +14,12 @@
 #pragma once
 
 #include "sdkconfig.h"
-#if CONFIG_TINYUSB_ENABLED
+
+#ifdef USE_TINYUSB // Adafruit TinyUSB is selected in menu
+
+#include "Adafruit_TinyUSB_API.h"
+
+#elif CONFIG_TINYUSB_ENABLED
 
 #include "Arduino.h"
 #include "USBCDC.h"
diff --git a/cores/esp32/USBCDC.cpp b/cores/esp32/USBCDC.cpp
index 36b746ecb40..6e93d5c0ca8 100644
--- a/cores/esp32/USBCDC.cpp
+++ b/cores/esp32/USBCDC.cpp
@@ -15,7 +15,7 @@
 #include "esp32-hal-tinyusb.h"
 #include "USB.h"
 #include "USBCDC.h"
-#if CONFIG_TINYUSB_ENABLED
+#if CONFIG_TINYUSB_ENABLED && !defined(USE_TINYUSB)
 
 ESP_EVENT_DEFINE_BASE(ARDUINO_USB_CDC_EVENTS);
 esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait);
diff --git a/cores/esp32/USBCDC.h b/cores/esp32/USBCDC.h
index 541cf633933..bded8d53b3d 100644
--- a/cores/esp32/USBCDC.h
+++ b/cores/esp32/USBCDC.h
@@ -17,7 +17,13 @@
 
 #include "Stream.h"
 #include "esp32-hal.h"
-#if CONFIG_TINYUSB_CDC_ENABLED
+
+#ifdef USE_TINYUSB
+
+// Adafruit TinyUSB is selected in menu
+#include "Adafruit_USBD_CDC.h"
+
+#elif CONFIG_TINYUSB_CDC_ENABLED
 
 #include "esp_event.h"
 
diff --git a/cores/esp32/esp32-hal-tinyusb.c b/cores/esp32/esp32-hal-tinyusb.c
index cf0bf48f6c8..ee01e1a77c9 100644
--- a/cores/esp32/esp32-hal-tinyusb.c
+++ b/cores/esp32/esp32-hal-tinyusb.c
@@ -1,6 +1,6 @@
 
 #include "sdkconfig.h"
-#if CONFIG_TINYUSB_ENABLED
+#if CONFIG_TINYUSB_ENABLED && !defined(USE_TINYUSB)
 #include <stdlib.h>
 #include <stdbool.h>
 
@@ -140,7 +140,7 @@ static tusb_desc_device_t tinyusb_device_descriptor = {
 static uint32_t tinyusb_string_descriptor_len = 4;
 static char * tinyusb_string_descriptor[MAX_STRING_DESCRIPTORS] = {
         // array of pointer to string descriptors
-        "\x09\x04",   // 0: is supported language is English (0x0409)
+        (char*) "\x09\x04",   // 0: is supported language is English (0x0409)
         USB_DEVICE_MANUFACTURER,// 1: Manufacturer
         USB_DEVICE_PRODUCT,     // 2: Product
         USB_DEVICE_SERIAL,      // 3: Serials, should use chip ID
diff --git a/cores/esp32/esp32-hal-tinyusb.h b/cores/esp32/esp32-hal-tinyusb.h
index abef6410b13..afb088a50d4 100644
--- a/cores/esp32/esp32-hal-tinyusb.h
+++ b/cores/esp32/esp32-hal-tinyusb.h
@@ -16,7 +16,7 @@
 #include "esp32-hal.h"
 
 #if CONFIG_IDF_TARGET_ESP32S2
-#if CONFIG_TINYUSB_ENABLED
+#if CONFIG_TINYUSB_ENABLED && !defined(USE_TINYUSB)
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/cores/esp32/main.cpp b/cores/esp32/main.cpp
index c7ffb8bcb1a..96cd8a3e212 100644
--- a/cores/esp32/main.cpp
+++ b/cores/esp32/main.cpp
@@ -48,7 +48,12 @@ void loopTask(void *pvParameters)
 extern "C" void app_main()
 {
 #if ARDUINO_SERIAL_PORT //Serial used for USB CDC
+#ifdef USE_TINYUSB
+    // Adafruit TinyUSB is selected in menu
+    TinyUSB_Device_Init(0);
+#else
     USB.begin();
+#endif
 #endif
     loopTaskWDTEnabled = false;
     initArduino();
diff --git a/libraries/Adafruit_TinyUSB_Arduino/LICENSE b/libraries/Adafruit_TinyUSB_Arduino/LICENSE
new file mode 100644
index 00000000000..bf05fe8f7d7
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2019 Ha Thach for Adafruit Industries
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/libraries/Adafruit_TinyUSB_Arduino/README.md b/libraries/Adafruit_TinyUSB_Arduino/README.md
new file mode 100644
index 00000000000..2ecc1dec8c8
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/README.md
@@ -0,0 +1,46 @@
+# Adafruit TinyUSB Library for Arduino
+
+[![Build Status](https://github.com/adafruit/Adafruit_TinyUSB_Arduino/workflows/Build/badge.svg)](https://github.com/adafruit/Adafruit_TinyUSB_Arduino/actions) [![License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT)
+
+This library is a Arduino-friendly version of [TinyUSB](https://github.com/hathach/tinyusb) stack. It is designed with structure and APIs that are easily integrated to existing or new Arduino Core. Supported platform including: 
+
+- [Adafruit_nRF52_Arduino](https://github.com/adafruit/Adafruit_nRF52_Arduino)
+- [Adafruit/ArduinoCore-samd](https://github.com/adafruit/ArduinoCore-samd) selectable via menu`Tools->USB Stack->TinyUSB`
+- [earlephilhower/arduino-pico](https://github.com/earlephilhower/arduino-pico) selectable via menu `Tools->USB Stack->Adafruit TinyUSB`
+
+Current class drivers supported are
+
+- Communication (CDC): which is used to implement `Serial` monitor
+- Human Interface Device (HID): Generic (In & Out), Keyboard, Mouse, Gamepad etc ...
+- Mass Storage Class (MSC): with multiple LUNs
+- Musical Instrument Digital Interface (MIDI)
+- WebUSB with vendor specific class
+
+For supported ArduinoCore, to use this library, you only need to have `<Adafruit_TinyUSB.h>` in your sketch. If your ArduinoCore does not support TinyUSB library yet, it is rather simple to port.
+
+## Class Driver API
+
+More document to write ... 
+
+## Porting Guide
+
+It is rather easy if you want to integrate TinyUSB lib to your ArduinoCore.
+
+### ArduinoCore Changes
+
+1. Add this repo as submodule (or have local copy) at your ArduioCore/libraries/Adafruit_TinyUSB_Arduino (much like SPI).
+2. Since Serial as CDC is considered as part of the core, we need to have `#include "Adafruit_USBD_CDC.h"` within your `Arduino.h`. For this to work, your `platform.txt` include path need to have `"-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"`.
+3. In your `main.cpp` before setup() invoke the `TinyUSB_Device_Init(rhport)`. This will initialize usb device hardware and tinyusb stack and also include Serial as an instance of CDC class.
+4. `TinyUSB_Device_Task()` must be called whenever there is new USB event. Depending on your core and MCU with or without RTOS. There are many ways to run the task. For example:
+  - Use USB IRQn to set flag then invoke function later on after exiting IRQ.
+  - Just invoke function after the loop(), within yield(), and delay()
+5. `TinyUSB_Device_FlushCDC()` should also be called often to send out Serial data as well.
+6. Note: For low power platform that make use of WFI()/WFE(), extra care is required before mcu go into low power mode. Check out my PR to circuipython for reference https://github.com/adafruit/circuitpython/pull/2956
+
+### Library Changes
+
+In addition to core changes, library need to be ported to your platform. Don't worry, tinyusb stack has already done most of heavy-lifting. You only need to write a few APIs
+
+1. `TinyUSB_Port_InitDevice()` hardware specific (clock, phy) to enable usb hardware then call tud_init(). This API is called as part of TinyUSB_Device_Init() invocation.
+2. `TinyUSB_Port_EnterDFU()` which is called when device need to enter DFU mode, usually by touch1200 feature
+3. `TinyUSB_Port_GetSerialNumber()` which is called to get unique MCU Serial ID to used as Serial string descriptor.
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/CDC/cdc_multi/cdc_multi.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/CDC/cdc_multi/cdc_multi.ino
new file mode 100644
index 00000000000..8bd8500014b
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/CDC/cdc_multi/cdc_multi.ino
@@ -0,0 +1,91 @@
+/*
+    This example demonstrates the use of multiple USB CDC/ACM "Virtual
+    Serial" ports, using Ha Thach's TinyUSB library, and the port of
+    that library to the Arduino environment
+
+    https://github.com/hathach/tinyusb
+    https://github.com/adafruit/Adafruit_TinyUSB_Arduino
+
+    Written by Bill Westfield (aka WestfW), June 2021.
+    Copyright 2021 by Bill Westfield
+    MIT license, check LICENSE for more information
+
+    The example creates three virtual serial ports.  Text entered on
+    any of the ports will be echoed to the all ports.
+
+    The max number of CDC ports (CFG_TUD_CDC) has to be changed to at
+    least 2, changed in the core tusb_config.h file.
+*/
+
+#include <Adafruit_TinyUSB.h>
+
+#define LED LED_BUILTIN
+
+// Create extra USB Serial Ports.  "Serial" is already created.
+Adafruit_USBD_CDC USBSer1;
+
+void setup() {
+  pinMode(LED, OUTPUT);
+
+  // start up all of the USB Vitual ports, and wait for them to enumerate.
+  Serial.begin(115200);
+  USBSer1.begin(115200);
+
+  while (!Serial || !USBSer1) {
+    if (Serial) {
+      Serial.println("Waiting for other USB ports");
+    }
+
+    if (USBSer1) {
+      USBSer1.println("Waiting for other USB ports");
+    }
+
+    delay(1000);
+  }
+
+  Serial.print("You are port 0\n\r\n0> ");
+  USBSer1.print("You are port 1\n\r\n1> ");
+}
+
+int LEDstate = 0;
+
+void loop() {
+  int ch;
+
+  ch = Serial.read();
+  if (ch > 0) {
+    printAll(ch);
+  }
+
+  ch = USBSer1.read();
+  if (ch > 0) {
+    printAll(ch);
+  }
+
+  if (delay_without_delaying(500)) {
+    LEDstate = !LEDstate;
+    digitalWrite(LED, LEDstate);
+  }
+}
+
+// print to all CDC ports
+void printAll(int ch) {
+  // always lower case
+  Serial.write(tolower(ch));
+
+  // always upper case
+  USBSer1.write(toupper(ch));
+}
+
+// Helper: non-blocking "delay" alternative.
+boolean delay_without_delaying(unsigned long time) {
+  // return false if we're still "delaying", true if time ms has passed.
+  // this should look a lot like "blink without delay"
+  static unsigned long previousmillis = 0;
+  unsigned long currentmillis = millis();
+  if (currentmillis - previousmillis >= time) {
+    previousmillis = currentmillis;
+    return true;
+  }
+  return false;
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/CDC/no_serial/no_serial.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/CDC/no_serial/no_serial.ino
new file mode 100644
index 00000000000..1f04357c7fc
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/CDC/no_serial/no_serial.ino
@@ -0,0 +1,36 @@
+/*********************************************************************
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ Copyright (c) 2019 Ha Thach for Adafruit Industries
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+#include "Adafruit_TinyUSB.h"
+
+/* This sketch demonstrates USB CDC Serial can be dropped by simply
+ * call Serial.end() within setup(). This must be called before any
+ * other USB interfaces (MSC / HID) begin to have a clean configuration
+ *
+ * Note: this will cause device to loose the touch1200 and require
+ * user manual interaction to put device into bootloader/DFU mode.
+ */
+
+int led = LED_BUILTIN;
+
+void setup()
+{
+  Serial.end();
+  pinMode(led, OUTPUT);
+}
+
+void loop()
+{
+  digitalWrite(led, HIGH);
+  delay(1000);
+  digitalWrite(led, LOW);
+  delay(1000);
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/hid_generic_inout_ramdisk/README.md b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/hid_generic_inout_ramdisk/README.md
new file mode 100644
index 00000000000..b963dbd7a86
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/hid_generic_inout_ramdisk/README.md
@@ -0,0 +1 @@
+Check the example host application in `../../HID/hid_generic_inout`
\ No newline at end of file
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/hid_generic_inout_ramdisk/hid_generic_inout_ramdisk.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/hid_generic_inout_ramdisk/hid_generic_inout_ramdisk.ino
new file mode 100644
index 00000000000..b4ecbf34f79
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/hid_generic_inout_ramdisk/hid_generic_inout_ramdisk.ino
@@ -0,0 +1,135 @@
+/*********************************************************************
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ Copyright (c) 2019 Ha Thach for Adafruit Industries
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This example demonstrate HID Generic raw Input & Output.
+ * It will receive data from Host (In endpoint) and echo back (Out endpoint).
+ * HID Report descriptor use vendor for usage page (using template TUD_HID_REPORT_DESC_GENERIC_INOUT)
+ *
+ * There are 2 ways to test the sketch
+ * 1. Using nodejs
+ *    - Install nodejs and nmp to your PC
+ *    - Install execellent node-hid (https://github.com/node-hid/node-hid) by
+ *      $ npm install node-hid
+ *    - Run provided hid test script 
+ *      $ node hid_test.js
+ *    
+ * 2. Using python hidRun 
+ *    - Python and `hid` package is required, for installation please follow https://pypi.org/project/hid/
+ *    - Run provided hid test script to send and receive data to this device.
+ *      $ python3 hid_test.py
+ */
+
+#include "Adafruit_TinyUSB.h"
+
+// 8KB is the smallest size that windows allow to mount
+#define DISK_BLOCK_NUM  16
+#define DISK_BLOCK_SIZE 512
+#include "ramdisk.h"
+
+// HID report descriptor using TinyUSB's template
+// Generic In Out with 64 bytes report (max)
+uint8_t const desc_hid_report[] =
+{
+  TUD_HID_REPORT_DESC_GENERIC_INOUT(64)
+};
+
+Adafruit_USBD_HID usb_hid;
+Adafruit_USBD_MSC usb_msc;
+
+// the setup function runs once when you press reset or power the board
+void setup()
+{
+  usb_msc.setID("Adafruit", "Mass Storage", "1.0");
+  
+  // Set disk size
+  usb_msc.setCapacity(DISK_BLOCK_NUM, DISK_BLOCK_SIZE);
+
+  // Set callback
+  usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
+
+  // Set Lun ready (RAM disk is always ready)
+  usb_msc.setUnitReady(true);
+  
+  usb_msc.begin();
+  
+  usb_hid.enableOutEndpoint(true);
+  usb_hid.setPollInterval(2);
+  usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
+  usb_hid.setReportCallback(get_report_callback, set_report_callback);
+
+  usb_hid.begin();
+
+  Serial.begin(115200);
+  Serial.println("Waiting for USBDevice mount");
+  // wait until device mounted
+  while( !USBDevice.mounted() ) delay(1);
+
+  Serial.println("Adafruit TinyUSB HID Generic In Out example");
+}
+
+void loop()
+{
+  // nothing to do
+}
+
+// Invoked when received GET_REPORT control request
+// Application must fill buffer report's content and return its length.
+// Return zero will cause the stack to STALL request
+uint16_t get_report_callback (uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
+{
+  // not used in this example
+  (void) report_id;
+  (void) report_type;
+  (void) buffer;
+  (void) reqlen;
+  return 0;
+}
+
+// Invoked when received SET_REPORT control request or
+// received data on OUT endpoint ( Report ID = 0, Type = 0 )
+void set_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
+{
+  // This example doesn't use multiple report and report ID
+  (void) report_id;
+  (void) report_type;
+
+  // echo back anything we received from host
+  usb_hid.sendReport(0, buffer, bufsize);
+}
+
+// Callback invoked when received READ10 command.
+// Copy disk's data to buffer (up to bufsize) and 
+// return number of copied bytes (must be multiple of block size) 
+int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
+{
+  uint8_t const* addr = msc_disk[lba];
+  memcpy(buffer, addr, bufsize);
+
+  return bufsize;
+}
+
+// Callback invoked when received WRITE10 command.
+// Process data in buffer to disk's storage and 
+// return number of written bytes (must be multiple of block size)
+int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
+{
+  uint8_t* addr = msc_disk[lba];
+  memcpy(addr, buffer, bufsize);
+
+  return bufsize;
+}
+
+// Callback invoked when WRITE10 command is completed (status received and accepted by host).
+// used to flush any pending cache.
+void msc_flush_cb (void)
+{
+  // nothing to do
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/hid_generic_inout_ramdisk/ramdisk.h b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/hid_generic_inout_ramdisk/ramdisk.h
new file mode 100644
index 00000000000..11aae403563
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/hid_generic_inout_ramdisk/ramdisk.h
@@ -0,0 +1,113 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef RAMDISK_H_
+#define RAMDISK_H_
+
+#define README_CONTENTS                                                        \
+  "This is TinyUSB MassStorage device demo for Arduino on RAM disk."
+
+uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = {
+    //------------- Block0: Boot Sector -------------//
+    // byte_per_sector    = DISK_BLOCK_SIZE; fat12_sector_num_16  =
+    // DISK_BLOCK_NUM; sector_per_cluster = 1; reserved_sectors = 1; fat_num =
+    // 1; fat12_root_entry_num = 16; sector_per_fat     = 1; sector_per_track =
+    // 1; head_num = 1; hidden_sectors = 0; drive_number       = 0x80;
+    // media_type = 0xf8; extended_boot_signature = 0x29; filesystem_type    =
+    // "FAT12   "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC";
+    // FAT magic code at offset 510-511
+    {0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00,
+     0x02, 0x01, 0x01, 0x00, 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00,
+     0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T', 'i', 'n', 'y', 'U', 'S',
+     'B', ' ', 'M', 'S', 'C', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20,
+     0x00, 0x00,
+
+     // Zero up to 2 last bytes of FAT magic code
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x55, 0xAA},
+
+    //------------- Block1: FAT12 Table -------------//
+    {
+        0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third
+                                     // entry is cluster end of readme file
+    },
+
+    //------------- Block2: Root Directory -------------//
+    {
+        // first entry is volume label
+        'T', 'i', 'n', 'y', 'U', 'S', 'B', ' ', 'M', 'S', 'C', 0x08, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        // second entry is readme file
+        'R', 'E', 'A', 'D', 'M', 'E', ' ', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6,
+        0x52, 0x6D, 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43,
+        0x02, 0x00, sizeof(README_CONTENTS) - 1, 0x00, 0x00,
+        0x00 // readme's files size (4 Bytes)
+    },
+
+    //------------- Block3: Readme Content -------------//
+    README_CONTENTS};
+
+#endif /* RAMDISK_H_ */
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/mouse_external_flash/mouse_external_flash.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/mouse_external_flash/mouse_external_flash.ino
new file mode 100644
index 00000000000..83aa4aa88f6
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/mouse_external_flash/mouse_external_flash.ino
@@ -0,0 +1,163 @@
+/*********************************************************************
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ Copyright (c) 2019 Ha Thach for Adafruit Industries
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This sketch demonstrates USB Mass Storage and HID mouse (and CDC)
+ * - Enumerated as disk using on-board external flash
+ * - Press button pin will move mouse toward bottom right of monitor
+ */
+
+#include "SPI.h"
+#include "SdFat.h"
+#include "Adafruit_SPIFlash.h"
+#include "Adafruit_TinyUSB.h"
+
+// Uncomment to run example with FRAM
+// #define FRAM_CS   A5
+// #define FRAM_SPI  SPI
+
+#if defined(FRAM_CS) && defined(FRAM_SPI)
+  Adafruit_FlashTransport_SPI flashTransport(FRAM_CS, FRAM_SPI);
+
+#elif defined(ARDUINO_ARCH_ESP32)
+  // ESP32 use same flash device that store code.
+  // Therefore there is no need to specify the SPI and SS
+  Adafruit_FlashTransport_ESP32 flashTransport;
+
+#else
+  // On-board external flash (QSPI or SPI) macros should already
+  // defined in your board variant if supported
+  // - EXTERNAL_FLASH_USE_QSPI
+  // - EXTERNAL_FLASH_USE_CS/EXTERNAL_FLASH_USE_SPI
+  #if defined(EXTERNAL_FLASH_USE_QSPI)
+    Adafruit_FlashTransport_QSPI flashTransport;
+
+  #elif defined(EXTERNAL_FLASH_USE_SPI)
+    Adafruit_FlashTransport_SPI flashTransport(EXTERNAL_FLASH_USE_CS, EXTERNAL_FLASH_USE_SPI);
+
+  #else
+    #error No QSPI/SPI flash are defined on your board variant.h !
+  #endif
+#endif
+
+Adafruit_SPIFlash flash(&flashTransport);
+
+Adafruit_USBD_MSC usb_msc;
+
+// HID report descriptor using TinyUSB's template
+// Single Report (no ID) descriptor
+uint8_t const desc_hid_report[] =
+{
+  TUD_HID_REPORT_DESC_MOUSE()
+};
+
+Adafruit_USBD_HID usb_hid;
+
+#if defined ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS
+  const int pin = 4; // Left Button
+  bool activeState = true;
+#elif defined ARDUINO_NRF52840_FEATHER
+  const int pin = 7; // UserSw
+  bool activeState = false;
+#else
+  const int pin = 12;
+  bool activeState = false;
+#endif
+
+// the setup function runs once when you press reset or power the board
+void setup()
+{
+  flash.begin();
+
+  pinMode(LED_BUILTIN, OUTPUT);
+
+  // Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
+  usb_msc.setID("Adafruit", "External Flash", "1.0");
+
+  // Set callback
+  usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
+
+  // Set disk size, block size should be 512 regardless of spi flash page size
+  usb_msc.setCapacity(flash.size()/512, 512);
+
+  // MSC is ready for read/write
+  usb_msc.setUnitReady(true);
+  
+  usb_msc.begin();
+
+
+  // Set up button
+  pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
+
+  usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
+  usb_hid.begin();
+
+  Serial.begin(115200);
+  //while ( !Serial ) delay(10);   // wait for native usb
+
+  Serial.println("Adafruit TinyUSB Mouse + Mass Storage (external flash) example");
+}
+
+void loop()
+{
+  // poll gpio once each 10 ms
+  delay(10);
+
+  // button is active low
+  uint32_t const btn = (digitalRead(pin) == activeState);
+
+  // Remote wakeup
+  if ( USBDevice.suspended() && btn )
+  {
+    // Wake up host if we are in suspend mode
+    // and REMOTE_WAKEUP feature is enabled by host
+    tud_remote_wakeup();
+  }
+
+  /*------------- Mouse -------------*/
+  if ( usb_hid.ready() )
+  {
+    if ( btn )
+    {
+      int8_t const delta = 5;
+      usb_hid.mouseMove(0, delta, delta); // no ID: right + down
+
+      // delay a bit before attempt to send keyboard report
+      delay(10);
+    }
+  }
+}
+
+// Callback invoked when received READ10 command.
+// Copy disk's data to buffer (up to bufsize) and 
+// return number of copied bytes (must be multiple of block size) 
+int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
+{
+  // Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
+  // already include 4K sector caching internally. We don't need to cache it, yahhhh!!
+  return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
+}
+
+// Callback invoked when received WRITE10 command.
+// Process data in buffer to disk's storage and 
+// return number of written bytes (must be multiple of block size)
+int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
+{
+  // Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
+  // already include 4K sector caching internally. We don't need to cache it, yahhhh!!
+  return flash.writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1;
+}
+
+// Callback invoked when WRITE10 command is completed (status received and accepted by host).
+// used to flush any pending cache.
+void msc_flush_cb (void)
+{
+  flash.syncBlocks();
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/mouse_ramdisk/mouse_ramdisk.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/mouse_ramdisk/mouse_ramdisk.ino
new file mode 100644
index 00000000000..70a942b48b7
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/mouse_ramdisk/mouse_ramdisk.ino
@@ -0,0 +1,131 @@
+/*********************************************************************
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ Copyright (c) 2019 Ha Thach for Adafruit Industries
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This sketch demonstrates USB Mass Storage and HID mouse (and CDC)
+ * - Enumerated as 8KB flash disk
+ * - Press button pin will move mouse toward bottom right of monitor
+ */
+
+#include "Adafruit_TinyUSB.h"
+
+// 8KB is the smallest size that windows allow to mount
+#define DISK_BLOCK_NUM  16
+#define DISK_BLOCK_SIZE 512
+#include "ramdisk.h"
+
+// HID report descriptor using TinyUSB's template
+// Single Report (no ID) descriptor
+uint8_t const desc_hid_report[] =
+{
+  TUD_HID_REPORT_DESC_MOUSE()
+};
+
+Adafruit_USBD_HID usb_hid;
+Adafruit_USBD_MSC usb_msc;
+
+#if defined ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS || defined ARDUINO_NRF52840_CIRCUITPLAY
+  const int pin = 4; // Left Button
+  bool activeState = true;
+#elif defined PIN_BUTTON1
+  const int pin = PIN_BUTTON1;
+  bool activeState = false;
+#else
+  const int pin = 12;
+  bool activeState = false;
+#endif
+
+// the setup function runs once when you press reset or power the board
+void setup()
+{
+  // Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
+  usb_msc.setID("Adafruit", "Mass Storage", "1.0");
+  
+  // Set disk size
+  usb_msc.setCapacity(DISK_BLOCK_NUM, DISK_BLOCK_SIZE);
+
+  // Set callback
+  usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
+
+  // Set Lun ready (RAM disk is always ready)
+  usb_msc.setUnitReady(true);
+  
+  usb_msc.begin();
+
+  // Set up button
+  pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
+
+  usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
+  usb_hid.begin();
+
+  Serial.begin(115200);
+  while( !USBDevice.mounted() ) delay(1);   // wait for native usb
+
+  Serial.println("Adafruit TinyUSB Mouse + Mass Storage (ramdisk) example");
+}
+
+void loop()
+{
+  // poll gpio once each 10 ms
+  delay(10);
+
+  // button is active low
+  uint32_t const btn = (digitalRead(pin) == activeState);
+
+  // Remote wakeup
+  if ( USBDevice.suspended() && btn )
+  {
+    // Wake up host if we are in suspend mode
+    // and REMOTE_WAKEUP feature is enabled by host
+    tud_remote_wakeup();
+  }
+
+  /*------------- Mouse -------------*/
+  if ( usb_hid.ready() )
+  {
+    if ( btn )
+    {
+      int8_t const delta = 5;
+      usb_hid.mouseMove(0, delta, delta); // no ID: right + down
+
+      // delay a bit before attempt to send keyboard report
+      delay(10);
+    }
+  }
+}
+
+// Callback invoked when received READ10 command.
+// Copy disk's data to buffer (up to bufsize) and 
+// return number of copied bytes (must be multiple of block size) 
+int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
+{
+  uint8_t const* addr = msc_disk[lba];
+  memcpy(buffer, addr, bufsize);
+
+  return bufsize;
+}
+
+// Callback invoked when received WRITE10 command.
+// Process data in buffer to disk's storage and 
+// return number of written bytes (must be multiple of block size)
+int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
+{
+  uint8_t* addr = msc_disk[lba];
+  memcpy(addr, buffer, bufsize);
+
+  return bufsize;
+}
+
+// Callback invoked when WRITE10 command is completed (status received and accepted by host).
+// used to flush any pending cache.
+void msc_flush_cb (void)
+{
+  // nothing to do
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/mouse_ramdisk/ramdisk.h b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/mouse_ramdisk/ramdisk.h
new file mode 100644
index 00000000000..11aae403563
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/Composite/mouse_ramdisk/ramdisk.h
@@ -0,0 +1,113 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef RAMDISK_H_
+#define RAMDISK_H_
+
+#define README_CONTENTS                                                        \
+  "This is TinyUSB MassStorage device demo for Arduino on RAM disk."
+
+uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = {
+    //------------- Block0: Boot Sector -------------//
+    // byte_per_sector    = DISK_BLOCK_SIZE; fat12_sector_num_16  =
+    // DISK_BLOCK_NUM; sector_per_cluster = 1; reserved_sectors = 1; fat_num =
+    // 1; fat12_root_entry_num = 16; sector_per_fat     = 1; sector_per_track =
+    // 1; head_num = 1; hidden_sectors = 0; drive_number       = 0x80;
+    // media_type = 0xf8; extended_boot_signature = 0x29; filesystem_type    =
+    // "FAT12   "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC";
+    // FAT magic code at offset 510-511
+    {0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00,
+     0x02, 0x01, 0x01, 0x00, 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00,
+     0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T', 'i', 'n', 'y', 'U', 'S',
+     'B', ' ', 'M', 'S', 'C', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20,
+     0x00, 0x00,
+
+     // Zero up to 2 last bytes of FAT magic code
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x55, 0xAA},
+
+    //------------- Block1: FAT12 Table -------------//
+    {
+        0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third
+                                     // entry is cluster end of readme file
+    },
+
+    //------------- Block2: Root Directory -------------//
+    {
+        // first entry is volume label
+        'T', 'i', 'n', 'y', 'U', 'S', 'B', ' ', 'M', 'S', 'C', 0x08, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        // second entry is readme file
+        'R', 'E', 'A', 'D', 'M', 'E', ' ', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6,
+        0x52, 0x6D, 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43,
+        0x02, 0x00, sizeof(README_CONTENTS) - 1, 0x00, 0x00,
+        0x00 // readme's files size (4 Bytes)
+    },
+
+    //------------- Block3: Readme Content -------------//
+    README_CONTENTS};
+
+#endif /* RAMDISK_H_ */
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_composite/hid_composite.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_composite/hid_composite.ino
new file mode 100644
index 00000000000..1fe40f02297
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_composite/hid_composite.ino
@@ -0,0 +1,145 @@
+/*********************************************************************
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ Copyright (c) 2019 Ha Thach for Adafruit Industries
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+#include "Adafruit_TinyUSB.h"
+
+/* This sketch demonstrates multiple report USB HID.
+ * Press button pin will move
+ * - mouse toward bottom right of monitor
+ * - send 'a' key
+ *
+ * Depending on the board, the button pin
+ * and its active state (when pressed) are different
+ */
+#if defined ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS
+  const int pin = 4; // Left Button
+  bool activeState = true;
+#elif defined ARDUINO_NRF52840_FEATHER
+  const int pin = 7; // UserSw
+  bool activeState = false;
+#else
+  const int pin = 12;
+  bool activeState = false;
+#endif
+
+
+// Report ID
+enum
+{
+  RID_KEYBOARD = 1,
+  RID_MOUSE,
+  RID_CONSUMER_CONTROL, // Media, volume etc ..
+};
+
+// HID report descriptor using TinyUSB's template
+uint8_t const desc_hid_report[] =
+{
+  TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(RID_KEYBOARD) ),
+  TUD_HID_REPORT_DESC_MOUSE   ( HID_REPORT_ID(RID_MOUSE) ),
+  TUD_HID_REPORT_DESC_CONSUMER( HID_REPORT_ID(RID_CONSUMER_CONTROL) )
+};
+
+// USB HID object
+Adafruit_USBD_HID usb_hid;
+
+// the setup function runs once when you press reset or power the board
+void setup()
+{
+  usb_hid.setPollInterval(2);
+  usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
+  //usb_hid.setStringDescriptor("TinyUSB HID Composite");
+
+  usb_hid.begin();
+
+  // Set up button, pullup opposite to active state
+  pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
+
+  Serial.begin(115200);
+  Serial.println("Adafruit TinyUSB HID Composite example");
+
+  // wait until device mounted
+  while( !USBDevice.mounted() ) delay(1);
+}
+
+void loop()
+{
+  // poll gpio once each 10 ms
+  delay(10);
+
+  // Whether button is pressed
+  bool btn_pressed = (digitalRead(pin) == activeState);
+
+  // Remote wakeup
+  if ( USBDevice.suspended() && btn_pressed )
+  {
+    // Wake up host if we are in suspend mode
+    // and REMOTE_WAKEUP feature is enabled by host
+    USBDevice.remoteWakeup();
+  }
+
+  /*------------- Mouse -------------*/
+  if ( usb_hid.ready() && btn_pressed )
+  {
+    int8_t const delta = 5;
+    usb_hid.mouseMove(RID_MOUSE, delta, delta); // right + down
+
+    // delay a bit before attempt to send keyboard report
+    delay(10);
+  }
+
+  /*------------- Keyboard -------------*/
+  if ( usb_hid.ready() )
+  {
+    // use to send key release report
+    static bool has_key = false;
+
+    if ( btn_pressed )
+    {
+      uint8_t keycode[6] = { 0 };
+      keycode[0] = HID_KEY_A;
+
+      usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode);
+
+      has_key = true;
+    }else
+    {
+      // send empty key report if previously has key pressed
+      if (has_key) usb_hid.keyboardRelease(RID_KEYBOARD);
+      has_key = false;
+    }
+
+    // delay a bit before attempt to send consumer report
+    delay(10);
+  }
+
+  /*------------- Consumer Control -------------*/
+  if ( usb_hid.ready() )
+  {
+    // Consumer Control is used to control Media playback, Volume, Brightness etc ...
+    // Consumer report is 2-byte containing the control code of the key
+    // For list of control check out https://github.com/hathach/tinyusb/blob/master/src/class/hid/hid.h#L544
+
+    // use to send consumer release report
+    static bool has_consumer_key = false;
+
+    if ( btn_pressed )
+    {
+      // send volume down (0x00EA)
+      usb_hid.sendReport16(RID_CONSUMER_CONTROL, HID_USAGE_CONSUMER_VOLUME_DECREMENT);
+      has_consumer_key = true;
+    }else
+    {
+      // release the consume key by sending zero (0x0000)
+      if (has_consumer_key) usb_hid.sendReport16(RID_CONSUMER_CONTROL, 0);
+      has_consumer_key = false;
+    }
+  }
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_composite_joy_featherwing/hid_composite_joy_featherwing.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_composite_joy_featherwing/hid_composite_joy_featherwing.ino
new file mode 100644
index 00000000000..fa058a5c513
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_composite_joy_featherwing/hid_composite_joy_featherwing.ino
@@ -0,0 +1,154 @@
+/*********************************************************************
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ Copyright (c) 2019 Ha Thach for Adafruit Industries
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This sketch demonstrates USB HID Mouse and Keyboard with Joy Feather Wing.
+ * - The analog stick move mouse cursor
+ * - Button A, B, X, Y will send character a, b, x, y
+ * - Any actions will wake up PC host if it is in suspended (standby) mode.
+ *
+ * Joy Feather Wing: https://www.adafruit.com/product/3632
+ *
+ * Following library is required
+ *  - Adafruit_seesaw
+ */
+
+#include "Adafruit_TinyUSB.h"
+#include "Adafruit_seesaw.h"
+
+#define BUTTON_A  6
+#define BUTTON_B  7
+#define BUTTON_Y  9
+#define BUTTON_X  10
+uint32_t button_mask = (1 << BUTTON_A) | (1 << BUTTON_B) |
+                       (1 << BUTTON_Y) | (1 << BUTTON_X);
+
+Adafruit_seesaw ss;
+
+// Report ID
+enum
+{
+  RID_KEYBOARD = 1,
+  RID_MOUSE
+};
+
+// HID report descriptor using TinyUSB's template
+uint8_t const desc_hid_report[] =
+{
+  TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(RID_KEYBOARD) ),
+  TUD_HID_REPORT_DESC_MOUSE   ( HID_REPORT_ID(RID_MOUSE) )
+};
+
+// USB HID object
+Adafruit_USBD_HID usb_hid;
+
+int last_x, last_y;
+
+// the setup function runs once when you press reset or power the board
+void setup()
+{
+  usb_hid.setPollInterval(2);
+  usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
+
+  usb_hid.begin();
+
+  Serial.begin(115200);
+  Serial.println("Adafruit TinyUSB HID Mouse with Joy FeatherWing example");
+
+  if(!ss.begin(0x49)){
+    Serial.println("ERROR! seesaw not found");
+    while(1);
+  } else {
+    Serial.println("seesaw started");
+    Serial.print("version: ");
+    Serial.println(ss.getVersion(), HEX);
+  }
+  ss.pinModeBulk(button_mask, INPUT_PULLUP);
+  ss.setGPIOInterrupts(button_mask, 1);
+
+  last_y = ss.analogRead(2);
+  last_x = ss.analogRead(3);
+
+  // wait until device mounted
+  while( !USBDevice.mounted() ) delay(1);
+}
+
+void loop()
+{
+  // poll gpio once each 10 ms
+  delay(10);
+
+  // If either analog stick or any buttons is pressed
+  bool has_action = false;
+
+  /*------------- Mouse -------------*/
+  int y = ss.analogRead(2);
+  int x = ss.analogRead(3);
+
+  // reduce the delta by half to slow down the cursor move
+  int dx = (x - last_x) / 2;
+  int dy = (y - last_y) / 2;
+
+  if ( (abs(dx) > 3) || (abs(dy) > 3) )
+  {
+    has_action = true;
+
+    if ( usb_hid.ready() )
+    {
+      usb_hid.mouseMove(RID_MOUSE, dx, dy); // no ID: right + down
+
+      last_x = x;
+      last_y = y;
+
+      // delay a bit before attempt to send keyboard report
+      delay(10);
+    }
+  }
+
+
+  /*------------- Keyboard -------------*/
+  // button is active low, invert read value for convenience
+  uint32_t buttons = ~ss.digitalReadBulk(button_mask);
+
+  if ( usb_hid.ready() )
+  {
+    // use to prevent sending multiple consecutive zero report
+    static bool has_key = false;
+
+    if ( buttons & button_mask )
+    {
+      has_action = true;
+      has_key = true;
+
+      uint8_t keycode[6] = { 0 };
+      
+      if ( buttons & (1 << BUTTON_A) ) keycode[0] = HID_KEY_A;
+      if ( buttons & (1 << BUTTON_B) ) keycode[0] = HID_KEY_B;
+      if ( buttons & (1 << BUTTON_X) ) keycode[0] = HID_KEY_X;
+      if ( buttons & (1 << BUTTON_Y) ) keycode[0] = HID_KEY_Y;
+
+      usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode);
+    }else
+    {
+      // send empty key report if previously has key pressed
+      if (has_key) usb_hid.keyboardRelease(RID_KEYBOARD);
+      has_key = false;
+    }
+  }
+
+  /*------------- Remote Wakeup -------------*/
+  // Remote wakeup if PC is suspended and we has user interaction with joy feather wing
+  if ( has_action && USBDevice.suspended() )
+  {
+    // Wake up only works if REMOTE_WAKEUP feature is enable by host
+    // Usually this is the case with Mouse/Keyboard device
+    USBDevice.remoteWakeup();
+  }
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_gamepad/hid_gamepad.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_gamepad/hid_gamepad.ino
new file mode 100644
index 00000000000..334dc9f9910
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_gamepad/hid_gamepad.ino
@@ -0,0 +1,268 @@
+/*********************************************************************
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ Copyright (c) 2021 NeKuNeKo for Adafruit Industries
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+#include "Adafruit_TinyUSB.h"
+
+/* This sketch demonstrates USB HID gamepad use.
+ * This sketch is only valid on boards which have native USB support
+ * and compatibility with Adafruit TinyUSB library. 
+ * For example SAMD21, SAMD51, nRF52840.
+ * 
+ * Make sure you select the TinyUSB USB stack if you have a SAMD board.
+ * You can test the gamepad on a Windows system by pressing WIN+R, writing Joy.cpl and pressing Enter.
+ */
+
+// HID report descriptor using TinyUSB's template
+// Single Report (no ID) descriptor
+uint8_t const desc_hid_report[] =
+{
+  TUD_HID_REPORT_DESC_GAMEPAD()
+};
+
+// USB HID object
+Adafruit_USBD_HID usb_hid;
+
+hid_gamepad_report_t    gp;     // defined in hid.h from Adafruit_TinyUSB_ArduinoCore
+// For Gamepad Button Bit Mask see  hid_gamepad_button_bm_t  typedef defined in hid.h from Adafruit_TinyUSB_ArduinoCore
+// For Gamepad Hat    Bit Mask see  hid_gamepad_hat_bm_t     typedef defined in hid.h from Adafruit_TinyUSB_ArduinoCore
+
+void setup() 
+{
+  Serial.begin(115200);
+  
+  usb_hid.setPollInterval(2);
+  usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
+
+  usb_hid.begin();
+
+  // wait until device mounted
+  while( !USBDevice.mounted() ) delay(1);
+  
+  Serial.println("Adafruit TinyUSB HID Gamepad example");
+}
+
+void loop() 
+{ 
+//  // Remote wakeup
+//  if ( USBDevice.suspended() && btn )
+//  {
+//    // Wake up host if we are in suspend mode
+//    // and REMOTE_WAKEUP feature is enabled by host
+//    USBDevice.remoteWakeup();
+//  }
+
+  if ( !usb_hid.ready() ) return;
+
+
+  // Reset buttons
+  Serial.println("No pressing buttons");
+  gp.x       = 0;
+  gp.y       = 0;
+  gp.z       = 0;
+  gp.rz      = 0;
+  gp.rx      = 0;
+  gp.ry      = 0;
+  gp.hat     = 0;
+  gp.buttons = 0;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+
+  
+  // Hat/DPAD UP
+  Serial.println("Hat/DPAD UP");
+  gp.hat = 1; // GAMEPAD_HAT_UP;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+
+  // Hat/DPAD UP RIGHT
+  Serial.println("Hat/DPAD UP RIGHT");
+  gp.hat = 2; // GAMEPAD_HAT_UP_RIGHT;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+
+  // Hat/DPAD RIGHT
+  Serial.println("Hat/DPAD RIGHT");
+  gp.hat = 3; // GAMEPAD_HAT_RIGHT;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+
+  // Hat/DPAD DOWN RIGHT
+  Serial.println("Hat/DPAD DOWN RIGHT");
+  gp.hat = 4; // GAMEPAD_HAT_DOWN_RIGHT;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+
+   // Hat/DPAD DOWN
+  Serial.println("Hat/DPAD DOWN");
+  gp.hat = 5; // GAMEPAD_HAT_DOWN;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+  
+  // Hat/DPAD DOWN LEFT
+  Serial.println("Hat/DPAD DOWN LEFT");
+  gp.hat = 6; // GAMEPAD_HAT_DOWN_LEFT;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+
+  // Hat/DPAD LEFT
+  Serial.println("Hat/DPAD LEFT");
+  gp.hat = 7; // GAMEPAD_HAT_LEFT;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+
+  // Hat/DPAD UP LEFT
+  Serial.println("Hat/DPAD UP LEFT");
+  gp.hat = 8; // GAMEPAD_HAT_UP_LEFT;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+
+  // Hat/DPAD CENTER
+  Serial.println("Hat/DPAD CENTER");
+  gp.hat = 0; // GAMEPAD_HAT_CENTERED;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+
+  
+  // Joystick 1 UP
+  Serial.println("Joystick 1 UP");
+  gp.x = 0;
+  gp.y = -127;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+  
+  // Joystick 1 DOWN
+  Serial.println("Joystick 1 DOWN");
+  gp.x = 0;
+  gp.y = 127;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+
+  // Joystick 1 RIGHT
+  Serial.println("Joystick 1 RIGHT");
+  gp.x = 127;
+  gp.y = 0;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+  
+  // Joystick 1 LEFT
+  Serial.println("Joystick 1 LEFT");
+  gp.x = -127;
+  gp.y = 0;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+
+  // Joystick 1 CENTER
+  Serial.println("Joystick 1 CENTER");
+  gp.x = 0;
+  gp.y = 0;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+
+
+  // Joystick 2 UP
+  Serial.println("Joystick 2 UP");
+  gp.z  = 0;
+  gp.rz = 127;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+  
+  // Joystick 2 DOWN
+  Serial.println("Joystick 2 DOWN");
+  gp.z  = 0;
+  gp.rz = -127;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+
+  // Joystick 2 RIGHT
+  Serial.println("Joystick 2 RIGHT");
+  gp.z  = 127;
+  gp.rz = 0;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+  
+  // Joystick 2 LEFT
+  Serial.println("Joystick 2 LEFT");
+  gp.z  = -127;
+  gp.rz = 0;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+
+  // Joystick 2 CENTER
+  Serial.println("Joystick 2 CENTER");
+  gp.z  = 0;
+  gp.rz = 0;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+
+
+  // Analog Trigger 1 UP
+  Serial.println("Analog Trigger 1 UP");
+  gp.rx = 127;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+  
+  // Analog Trigger 1 DOWN
+  Serial.println("Analog Trigger 1 DOWN");
+  gp.rx = -127;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+
+  // Analog Trigger 1 CENTER
+  Serial.println("Analog Trigger 1 CENTER");
+  gp.rx = 0;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+
+
+  // Analog Trigger 2 UP
+  Serial.println("Analog Trigger 2 UP");
+  gp.ry = 127;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+  
+  // Analog Trigger 2 DOWN
+  Serial.println("Analog Trigger 2 DOWN");
+  gp.ry = -127;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+
+  // Analog Trigger 2 CENTER
+  Serial.println("Analog Trigger 2 CENTER");
+  gp.ry = 0;
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+
+  
+  // Test buttons (up to 32 buttons)
+  for (int i=0; i<32; ++i)
+  {
+    Serial.print("Pressing button "); Serial.println(i);
+    gp.buttons = (1U << i);
+    usb_hid.sendReport(0, &gp, sizeof(gp));
+    delay(1000);
+  }
+
+
+  // Random touch
+  Serial.println("Random touch");
+  gp.x       = random(-127, 128);
+  gp.y       = random(-127, 128);
+  gp.z       = random(-127, 128);
+  gp.rz      = random(-127, 128);
+  gp.rx      = random(-127, 128);
+  gp.ry      = random(-127, 128);
+  gp.hat     = random(0,      9);
+  gp.buttons = random(0, 0xffff);
+  usb_hid.sendReport(0, &gp, sizeof(gp));
+  delay(2000);
+
+  // */
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/README.md b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/README.md
new file mode 100644
index 00000000000..3749e6b5031
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/README.md
@@ -0,0 +1,10 @@
+Instructions for node.js based example
+
+===Setup===
+
+1. Upload example code to your board
+2. Install node.js if you haven't already
+3. Run `npm install` to install the dependencies
+4. If this should fail on windows try installing the build tools via `npm i -g windows-build-tools`
+5. While the board is connected run `node hid_test.js`
+6. If this should fail make sure the VID and PID of your board is listed in boards.js
\ No newline at end of file
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/boards.js b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/boards.js
new file mode 100644
index 00000000000..bf6365b267d
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/boards.js
@@ -0,0 +1,5 @@
+module.exports = {
+	"Feather_nRF52840":[0X239A,0X8029],
+	"Metro_nRF52840":[0X239A,0X803F],
+	"Circuit_Playground_Express":[0X239A,0X8018],
+}
\ No newline at end of file
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/hid_generic_inout.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/hid_generic_inout.ino
new file mode 100644
index 00000000000..60eacba2a17
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/hid_generic_inout.ino
@@ -0,0 +1,88 @@
+/*********************************************************************
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ Copyright (c) 2019 Ha Thach for Adafruit Industries
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This example demonstrate HID Generic raw Input & Output.
+ * It will receive data from Host (In endpoint) and echo back (Out endpoint).
+ * HID Report descriptor use vendor for usage page (using template TUD_HID_REPORT_DESC_GENERIC_INOUT)
+ *
+ * There are 2 ways to test the sketch
+ * 1. Using nodejs
+ *    - Install nodejs and nmp to your PC
+ *    - Install execellent node-hid (https://github.com/node-hid/node-hid) by
+ *      $ npm install node-hid
+ *    - Run provided hid test script 
+ *      $ node hid_test.js
+ *    
+ * 2. Using python hidRun 
+ *    - Python and `hid` package is required, for installation please follow https://pypi.org/project/hid/
+ *    - Run provided hid test script to send and receive data to this device.
+ *      $ python3 hid_test.py
+ */
+
+#include "Adafruit_TinyUSB.h"
+
+// HID report descriptor using TinyUSB's template
+// Generic In Out with 64 bytes report (max)
+uint8_t const desc_hid_report[] =
+{
+  TUD_HID_REPORT_DESC_GENERIC_INOUT(64)
+};
+
+Adafruit_USBD_HID usb_hid;
+
+// the setup function runs once when you press reset or power the board
+void setup()
+{
+  usb_hid.enableOutEndpoint(true);
+  usb_hid.setPollInterval(2);
+  usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
+  usb_hid.setReportCallback(get_report_callback, set_report_callback);
+  //usb_hid.setStringDescriptor("TinyUSB HID Generic");
+
+  usb_hid.begin();
+
+  Serial.begin(115200);
+
+  // wait until device mounted
+  while( !USBDevice.mounted() ) delay(1);
+
+  Serial.println("Adafruit TinyUSB HID Generic In Out example");
+}
+
+void loop()
+{
+  // nothing to do
+}
+
+// Invoked when received GET_REPORT control request
+// Application must fill buffer report's content and return its length.
+// Return zero will cause the stack to STALL request
+uint16_t get_report_callback (uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
+{
+  // not used in this example
+  (void) report_id;
+  (void) report_type;
+  (void) buffer;
+  (void) reqlen;
+  return 0;
+}
+
+// Invoked when received SET_REPORT control request or
+// received data on OUT endpoint ( Report ID = 0, Type = 0 )
+void set_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
+{
+  // This example doesn't use multiple report and report ID
+  (void) report_id;
+  (void) report_type;
+
+  // echo back anything we received from host
+  usb_hid.sendReport(0, buffer, bufsize);
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/hid_test.js b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/hid_test.js
new file mode 100644
index 00000000000..eed6b78e296
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/hid_test.js
@@ -0,0 +1,71 @@
+// IMPORTANT: install the dependency via 'npm i node-hid' in the same location as the script
+// If the install fails on windows you may need to run 'npm i -g windows-build-tools' first to be able to compile native code needed for this library
+
+var HID = require('node-hid');
+var os = require('os')
+// list of supported devices
+var boards = require('./boards.js')
+
+var isWin = (os.platform() === 'win32');
+var devices = HID.devices();
+
+// this will choose any device found in the boards.js file
+var deviceInfo = devices.find(anySupportedBoard);
+var reportLen = 64;
+
+var message = "Hello World!"
+
+// Turn our string into an array of integers e.g. 'ascii codes', though charCodeAt spits out UTF-16
+// This means if you have characters in your string that are not Latin-1 you will have to add additional logic for character codes above 255
+var messageBuffer = Array.from(message, function(c){return c.charCodeAt(0)});
+
+// Windows wants you to prepend a 0 to whatever you send
+if(isWin){
+	messageBuffer.unshift(0)
+}
+
+// Some OSes expect that you always send a buffer that equals your report length
+// So lets fill up the rest of the buffer with zeros
+var paddingBuf = Array(reportLen-messageBuffer.length);
+paddingBuf.fill(0)
+messageBuffer = messageBuffer.concat(paddingBuf)
+
+// check if we actually found a device and if so send our messageBuffer to it
+if( deviceInfo ) {
+	console.log(deviceInfo)
+	var device = new HID.HID( deviceInfo.path );
+
+	// register an event listener for data coming from the device
+	device.on("data", function(data) {
+		// Print what we get from the device
+		console.log(data.toString('ascii'));
+	});
+
+	// the same for any error that occur
+	device.on("error", function(err) {console.log(err)});
+
+	// send our message to the device every 500ms
+	setInterval(function () {
+		device.write(messageBuffer);
+	},500)
+}
+
+
+function anySupportedBoard(d) {
+	
+	for (var key in boards) {
+	    if (boards.hasOwnProperty(key)) {
+	        if (isDevice(boards[key],d)) {
+	        	console.log("Found " + d.product);
+	        	return true;
+	        }
+	    }
+	}
+	return false;
+}
+
+
+function isDevice(board,d){
+	return d.vendorId==board[0] && d.productId==board[1];
+}
+
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/hid_test.py b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/hid_test.py
new file mode 100644
index 00000000000..04129239bb8
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/hid_test.py
@@ -0,0 +1,18 @@
+# Install python3 HID package https://pypi.org/project/hid/
+import hid
+
+# default is Adafruit VID
+USB_VID = 0x239A
+
+print("Openning HID device with VID = 0x%X" % USB_VID)
+
+for dict in hid.enumerate(USB_VID):
+    print(dict)
+    dev = hid.Device(dict['vendor_id'], dict['product_id'])
+    if dev:
+        while True:
+            # Get input from console and encode to UTF8 for array of chars.
+            str_out = input("Send text to HID Device : ").encode('utf-8')
+            dev.write(str_out)
+            str_in = dev.read(64)
+            print("Received from HID Device:", str_in, '\n')
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/package.json b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/package.json
new file mode 100644
index 00000000000..9047c3279e6
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_generic_inout/package.json
@@ -0,0 +1,14 @@
+{
+  "name": "hid_example",
+  "version": "1.0.0",
+  "description": "Test application for hid_generic_inout example sketch",
+  "main": "hid_test.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "Timon, Tod E. Kurt",
+  "license": "MIT",
+  "dependencies": {
+    "node-hid": "^0.7.9"
+  }
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_keyboard/hid_keyboard.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_keyboard/hid_keyboard.ino
new file mode 100644
index 00000000000..d674eeb5af8
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_keyboard/hid_keyboard.ino
@@ -0,0 +1,141 @@
+/*********************************************************************
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ Copyright (c) 2019 Ha Thach for Adafruit Industries
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+#include "Adafruit_TinyUSB.h"
+
+/* This sketch demonstrates USB HID keyboard.
+ * - PIN A0-A5 is used to send digit '0' to '5' respectively
+ *   (On the RP2040, pins D0-D5 used)
+ * - LED will be used as Caplock indicator
+ */
+
+// HID report descriptor using TinyUSB's template
+// Single Report (no ID) descriptor
+uint8_t const desc_hid_report[] =
+{
+  TUD_HID_REPORT_DESC_KEYBOARD(),
+};
+
+Adafruit_USBD_HID usb_hid;
+
+// Array of pins and its keycode
+// For keycode definition see BLEHidGeneric.h
+#ifdef ARDUINO_ARCH_RP2040
+uint8_t pins[]    = { D0, D1, D2, D3, D4, D5 };
+#else
+uint8_t pins[]    = { A0, A1, A2, A3, A4, A5 };
+#endif
+uint8_t hidcode[] = { HID_KEY_0, HID_KEY_1, HID_KEY_2, HID_KEY_3 , HID_KEY_4, HID_KEY_5 };
+
+uint8_t pincount = sizeof(pins)/sizeof(pins[0]);
+
+// the setup function runs once when you press reset or power the board
+void setup()
+{
+  usb_hid.setPollInterval(2);
+  usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
+  usb_hid.setReportCallback(NULL, hid_report_callback);
+  //usb_hid.setStringDescriptor("TinyUSB Keyboard");
+
+  usb_hid.begin();
+
+  // led pin
+  pinMode(LED_BUILTIN, OUTPUT);
+  digitalWrite(LED_BUILTIN, LOW);
+
+  // Set up pin as input
+  for (uint8_t i=0; i<pincount; i++)
+  {
+    pinMode(pins[i], INPUT_PULLUP);
+  }
+
+  // wait until device mounted
+  while( !USBDevice.mounted() ) delay(1);
+}
+
+
+void loop()
+{
+  // poll gpio once each 2 ms
+  delay(2);
+
+//  // Remote wakeup
+//  if ( USBDevice.suspended() && btn )
+//  {
+//    // Wake up host if we are in suspend mode
+//    // and REMOTE_WAKEUP feature is enabled by host
+//    USBDevice.remoteWakeup();
+//  }
+
+  if ( !usb_hid.ready() ) return;
+
+  static bool keyPressedPreviously = false;
+  bool anyKeyPressed = false;
+
+  uint8_t count=0;
+  uint8_t keycode[6] = { 0 };
+
+  // scan normal key and send report
+  for(uint8_t i=0; i < pincount; i++)
+  {
+    if ( 0 == digitalRead(pins[i]) )
+    {
+      // if pin is active (low), add its hid code to key report
+      keycode[count++] = hidcode[i];
+
+      // 6 is max keycode per report
+      if (count == 6)
+      {
+        usb_hid.keyboardReport(0, 0, keycode);
+        delay(2); // delay for report to send out
+
+        // reset report
+        count = 0;
+        memset(keycode, 0, 6);
+      }
+
+      // used later
+      anyKeyPressed = true;
+      keyPressedPreviously = true;
+    }
+  }
+
+  // Send any remaining keys (not accumulated up to 6)
+  if ( count )
+  {
+    usb_hid.keyboardReport(0, 0, keycode);
+  }
+
+  // Send All-zero report to indicate there is no keys pressed
+  // Most of the time, it is, though we don't need to send zero report
+  // every loop(), only a key is pressed in previous loop()
+  if ( !anyKeyPressed && keyPressedPreviously )
+  {
+    keyPressedPreviously = false;
+    usb_hid.keyboardRelease(0);
+  }
+}
+
+// Output report callback for LED indicator such as Caplocks
+void hid_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
+{
+  (void) report_id;
+  (void) bufsize;
+  // LED indicator is output report with only 1 byte length
+  if ( report_type != HID_REPORT_TYPE_OUTPUT ) return;
+
+  // The LED bit map is as follows: (also defined by KEYBOARD_LED_* )
+  // Kana (4) | Compose (3) | ScrollLock (2) | CapsLock (1) | Numlock (0)
+  uint8_t ledIndicator = buffer[0];
+
+  // turn on LED if caplock is set
+  digitalWrite(LED_BUILTIN, ledIndicator & KEYBOARD_LED_CAPSLOCK);
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_mouse/hid_mouse.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_mouse/hid_mouse.ino
new file mode 100644
index 00000000000..a1cd68d2a80
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/HID/hid_mouse/hid_mouse.ino
@@ -0,0 +1,87 @@
+/*********************************************************************
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ Copyright (c) 2019 Ha Thach for Adafruit Industries
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+#include "Adafruit_TinyUSB.h"
+
+/* This sketch demonstrates USB HID mouse
+ * Press button pin will move
+ * - mouse toward bottom right of monitor
+ * 
+ * Depending on the board, the button pin
+ * and its active state (when pressed) are different
+ */
+#if defined ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS
+  const int pin = 4; // Left Button
+  bool activeState = true;
+#elif defined ARDUINO_NRF52840_FEATHER
+  const int pin = 7; // UserSw
+  bool activeState = false;
+#else
+  const int pin = 12;
+  bool activeState = false;
+#endif
+  
+
+// HID report descriptor using TinyUSB's template
+// Single Report (no ID) descriptor
+uint8_t const desc_hid_report[] =
+{
+  TUD_HID_REPORT_DESC_MOUSE()
+};
+
+// USB HID object
+Adafruit_USBD_HID usb_hid;
+
+// the setup function runs once when you press reset or power the board
+void setup()
+{
+  // Set up button, pullup opposite to active state
+  pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
+
+  usb_hid.setPollInterval(2);
+  usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
+  //usb_hid.setStringDescriptor("TinyUSB Mouse");
+
+  usb_hid.begin();
+
+  Serial.begin(115200);
+
+  // wait until device mounted
+  while( !USBDevice.mounted() ) delay(1);
+
+  Serial.println("Adafruit TinyUSB HID Mouse example");
+}
+
+void loop()
+{
+  // poll gpio once each 10 ms
+  delay(10);
+
+  // Whether button is pressed
+  bool btn_pressed = (digitalRead(pin) == activeState);
+
+  // nothing to do if button is not pressed
+  if (!btn_pressed) return;
+
+  // Remote wakeup
+  if ( USBDevice.suspended() )
+  {
+    // Wake up host if we are in suspend mode
+    // and REMOTE_WAKEUP feature is enabled by host
+    USBDevice.remoteWakeup();
+  }
+
+  if ( usb_hid.ready() )
+  {
+    int8_t const delta = 5;
+    usb_hid.mouseMove(0, delta, delta); // no ID: right + down
+  }
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/MIDI/midi_pizza_box_dj/.cpb.test.only b/libraries/Adafruit_TinyUSB_Arduino/examples/MIDI/midi_pizza_box_dj/.cpb.test.only
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/MIDI/midi_pizza_box_dj/.cpx_ada.test.only b/libraries/Adafruit_TinyUSB_Arduino/examples/MIDI/midi_pizza_box_dj/.cpx_ada.test.only
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/MIDI/midi_pizza_box_dj/midi_pizza_box_dj.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/MIDI/midi_pizza_box_dj/midi_pizza_box_dj.ino
new file mode 100644
index 00000000000..7d4f60f529e
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/MIDI/midi_pizza_box_dj/midi_pizza_box_dj.ino
@@ -0,0 +1,427 @@
+//Circuit Playground PZ-1 Pizza Box DJ
+// by John Park
+// a.k.a. DJ Sternocleidomastoid
+// for Adafruit Industries
+// MIT License
+///////////////////////////////////////////////////////////////////////////////
+// MIDI controller for Traktor, Mixxx and other DJ software
+// Uses TinyUSB to send MIDI over USB
+// 
+// MIDI controller command mapping must be set up in your DJ software, check
+// below for MIDI signal outputs
+//
+// For detail tutorial https://learn.adafruit.com/circuit-playground-pizza-box-dj-controller
+///////////////////////////////////////////////////////////////////////////////
+
+#include <Adafruit_CircuitPlayground.h>
+#include <Wire.h>
+#include <SPI.h>
+#include <Adafruit_TinyUSB.h>
+#include <MIDI.h>
+
+// USB MIDI object
+Adafruit_USBD_MIDI usb_midi;
+
+// Create a new instance of the Arduino MIDI Library,
+// and attach usb_midi as the transport.
+MIDI_CREATE_INSTANCE(Adafruit_USBD_MIDI, usb_midi, usbMIDI);
+
+///////////////////////////////////////////////////////////////////////////////
+//MIDI CC (change control) assignments
+const int CHANNEL         = 14; //MIDI channel 
+const int LEFT_BUTTON_CC  =  4; //Play/Pause Deck A
+const int RIGHT_BUTTON_CC = 19; //MIDI CC for left button: FX 1 On
+const int CAP1_CONTROL    = 1;  //Select/Set+Store Hotcue 2 (1 is load point)
+const int CAP0_CONTROL    = 0;  //Left fader mixes Deck B volume down
+const int CAP2_CONTROL    = 2;  //Delete hotcue 2 point       
+const int CAP3_CONTROL    = 3;  //Remix Trigger 6-1 or Loop Size /2  
+const int CAP12_CONTROL   = 12; //Right fader mixes Deck A volume down
+const int CAP6_CONTROL    = 6;  //Scratch (jog turn) Deck B     
+const int CAP9_CONTROL    = 9;  //Play/Pause Deck B
+const int CAP10_CONTROL   = 10; //Remix Trigger 6-4 or Loop Set 4 bar
+
+int leftButtonState = 0;
+int rightButtonState = 0;
+int leftButtonLastState = 0;
+int rightButtonLastState = 0;
+int cap0State = 0;
+int cap0LastState = 0;
+int cap1State = 0;
+int cap1LastState = 0;
+int cap2State = 0;
+int cap2LastState = 0;
+int cap3State = 0;
+int cap3LastState = 0;
+int cap12State = 0;
+int cap12LastState = 0;
+int cap6State = 0;
+int cap6LastState = 0;
+int cap9State = 0;
+int cap9LastState = 0;
+int cap10State = 0;
+int cap10LastState = 0;
+bool cap1ON = false; //prevents off command from being spewed
+bool cap12ON = false; //prevents off command from being spewed
+bool cap6ON = false; //prevents off command from being spewed
+
+const int CAPMIN = 25; //lowest value that's considered an intentional touch to minimize crosstalk
+const int CAPSLOP = 0; //value of capacitive pad variance that's considered noise
+
+
+///////////////////////////////////////////////////////////////////////////////
+//mic_meter code
+// To keep the display 'lively,' an upper and lower range of volume
+// levels are dynamically adjusted based on recent audio history, and
+// the graph is fit into this range.
+#define  FRAMES 8
+uint16_t lvl[FRAMES],           // Audio level for the prior #FRAMES frames
+         avgLo  = 6,            // Audio volume lower end of range
+         avgHi  = 512,          // Audio volume upper end of range
+         sum    = 256 * FRAMES; // Sum of lvl[] array
+uint8_t  lvlIdx = 0;            // Counter into lvl[] array
+int16_t  peak   = 0;            // Falling dot shows recent max
+int8_t   peakV  = 0;            // Velocity of peak dot
+
+///////////////////////////////////////////////////////////////////////////////
+void setup() {
+
+  usbMIDI.begin();
+  Serial.begin(115200);
+
+  CircuitPlayground.begin();
+  CircuitPlayground.setBrightness(30); //make brighter for performance, up to 255
+  CircuitPlayground.clearPixels();
+  for(uint8_t i=0; i<FRAMES; i++) lvl[i] = 256;
+
+  // Wait until device is enumerated properly before sending MIDI message
+  while( !USBDevice.mounted() ) delay(1);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// COLOR TABLES for animation ----------------------------------------------
+
+const uint8_t PROGMEM
+  reds[]   = { 0x9A, 0x75, 0x00, 0x00, 0x00, 0x65, 0x84, 0x9A, 0xAD, 0xAD },
+  greens[] = { 0x00, 0x00, 0x00, 0x87, 0xB1, 0x9E, 0x87, 0x66, 0x00, 0x00 },
+  blues[]  = { 0x95, 0xD5, 0xFF, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  gamma8[] = { // Gamma correction improves the appearance of midrange colors
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
+    0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06,
+    0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09,
+    0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0E,
+    0x0E, 0x0F, 0x0F, 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14,
+    0x14, 0x15, 0x15, 0x16, 0x16, 0x17, 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1B,
+    0x1B, 0x1C, 0x1D, 0x1D, 0x1E, 0x1F, 0x1F, 0x20, 0x21, 0x22, 0x22, 0x23,
+    0x24, 0x25, 0x26, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2A, 0x2B, 0x2C, 0x2D,
+    0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+    0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x44, 0x45, 0x46,
+    0x47, 0x48, 0x49, 0x4B, 0x4C, 0x4D, 0x4E, 0x50, 0x51, 0x52, 0x54, 0x55,
+    0x56, 0x58, 0x59, 0x5A, 0x5C, 0x5D, 0x5E, 0x60, 0x61, 0x63, 0x64, 0x66,
+    0x67, 0x69, 0x6A, 0x6C, 0x6D, 0x6F, 0x70, 0x72, 0x73, 0x75, 0x77, 0x78,
+    0x7A, 0x7C, 0x7D, 0x7F, 0x81, 0x82, 0x84, 0x86, 0x88, 0x89, 0x8B, 0x8D,
+    0x8F, 0x91, 0x92, 0x94, 0x96, 0x98, 0x9A, 0x9C, 0x9E, 0xA0, 0xA2, 0xA4,
+    0xA6, 0xA8, 0xAA, 0xAC, 0xAE, 0xB0, 0xB2, 0xB4, 0xB6, 0xB8, 0xBA, 0xBC,
+    0xBF, 0xC1, 0xC3, 0xC5, 0xC7, 0xCA, 0xCC, 0xCE, 0xD1, 0xD3, 0xD5, 0xD7,
+    0xDA, 0xDC, 0xDF, 0xE1, 0xE3, 0xE6, 0xE8, 0xEB, 0xED, 0xF0, 0xF2, 0xF5,
+    0xF7, 0xFA, 0xFC, 0xFF };
+///////////////////////////////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////////////////
+void loop() {
+
+  //Sound activated lights
+  uint8_t  i, r, g, b;
+  uint16_t minLvl, maxLvl, a, scaled;
+
+  a           = CircuitPlayground.mic.peak(10); // 10 ms of audio
+  sum        -= lvl[lvlIdx];
+  lvl[lvlIdx] = a;
+  sum        += a;                              // Sum of lvl[] array
+  minLvl = maxLvl = lvl[0];                     // Calc min, max of lvl[]...
+  for(i=1; i<FRAMES; i++) {
+    if(lvl[i] < minLvl)      minLvl = lvl[i];
+    else if(lvl[i] > maxLvl) maxLvl = lvl[i];
+  }
+
+  // Keep some minimum distance between min & max levels,
+  // else the display gets "jumpy."
+  if((maxLvl - minLvl) < 40) {
+    maxLvl = (minLvl < (512-40)) ? minLvl + 40 : 512;
+  }
+  avgLo = (avgLo * 7 + minLvl + 2) / 8; // Dampen min/max levels
+  avgHi = (maxLvl >= avgHi) ?           // (fake rolling averages)
+    (avgHi *  3 + maxLvl + 1) /  4 :    // Fast rise
+    (avgHi * 31 + maxLvl + 8) / 32;     // Slow decay
+
+  a = sum / FRAMES; // Average of lvl[] array
+  if(a <= avgLo) {  // Below min?
+    scaled = 0;     // Bargraph = zero
+  } else {          // Else scale to fixed-point coordspace 0-2560
+    scaled = 2560L * (a - avgLo) / (avgHi - avgLo);
+    if(scaled > 2560) scaled = 2560;
+  }
+  if(scaled >= peak) {            // New peak
+    peakV = (scaled - peak) / 4;  // Give it an upward nudge
+    peak  = scaled;
+  }
+
+  uint8_t  whole  = scaled / 256,    // Full-brightness pixels (0-10)
+           frac   = scaled & 255;    // Brightness of fractional pixel
+  int      whole2 = peak / 256,      // Index of peak pixel
+           frac2  = peak & 255;      // Between-pixels position of peak
+  uint16_t a1, a2;                   // Scaling factors for color blending
+
+  for(i=0; i<10; i++) {              // For each NeoPixel...
+    if(i <= whole) {                 // In currently-lit area?
+      r = pgm_read_byte(&reds[i]),   // Look up pixel color
+      g = pgm_read_byte(&greens[i]),
+      b = pgm_read_byte(&blues[i]);
+      if(i == whole) {               // Fraction pixel at top of range?
+        a1 = (uint16_t)frac + 1;     // Fade toward black
+        r  = (r * a1) >> 8;
+        g  = (g * a1) >> 8;
+        b  = (b * a1) >> 8;
+      }
+    } else {
+      r = g = b = 0;                 // In unlit area
+    }
+    // Composite the peak pixel atop whatever else is happening...
+    if(i == whole2) {                // Peak pixel?
+      a1 = 256 - frac2;              // Existing pixel blend factor 1-256
+      a2 = frac2 + 1;                // Peak pixel blend factor 1-256
+      r  = ((r * a1) + (0x84 * a2)) >> 8; // Will
+      g  = ((g * a1) + (0x87 * a2)) >> 8; // it
+      b  = ((b * a1) + (0xC3 * a2)) >> 8; // blend?
+    } else if(i == (whole2-1)) {     // Just below peak pixel
+      a1 = frac2 + 1;                // Opposite blend ratios to above,
+      a2 = 256 - frac2;              // but same idea
+      r  = ((r * a1) + (0x84 * a2)) >> 8;
+      g  = ((g * a1) + (0x87 * a2)) >> 8;
+      b  = ((b * a1) + (0xC3 * a2)) >> 8;
+    }
+    CircuitPlayground.strip.setPixelColor(i,
+      pgm_read_byte(&gamma8[r]),
+      pgm_read_byte(&gamma8[g]),
+      pgm_read_byte(&gamma8[b]));
+  }
+  CircuitPlayground.strip.show();
+
+  peak += peakV;
+  if(peak <= 0) {
+    peak  = 0;
+    peakV = 0;
+  } else if(peakV >= -126) {
+    peakV -= 2;
+  }
+
+  if(++lvlIdx >= FRAMES) lvlIdx = 0;
+
+///////////////////////////////////////////////////////////////////////////////
+//BUTTONS
+//
+//read the buttons
+  leftButtonState =  (CircuitPlayground.leftButton());  
+  //not pressed = 0, pressed = 1
+  rightButtonState = (CircuitPlayground.rightButton());
+  
+//Left Button
+//compare current button states to previous button states
+  if(leftButtonState != leftButtonLastState){           //the state has changed
+    if(leftButtonState == 1){                           //went from off to on, it's pressed
+      usbMIDI.sendControlChange(LEFT_BUTTON_CC, 1, CHANNEL); //send MIDI note ON command
+      CircuitPlayground.redLED(HIGH); //turn on the red LED
+    }
+    else{                   //the button went from on to off, it isn't pressed
+      usbMIDI.sendControlChange(LEFT_BUTTON_CC, 0, CHANNEL);  //send MIDI note OFF 
+      CircuitPlayground.redLED(LOW);                    //turn off the red LED
+    }
+    leftButtonLastState = leftButtonState;       //toggle
+  }
+
+
+//Right Button
+  if(rightButtonState != rightButtonLastState){           
+    if(rightButtonState == 1){                           
+      usbMIDI.sendControlChange(RIGHT_BUTTON_CC, 1, CHANNEL); 
+      CircuitPlayground.redLED(HIGH); 
+    }
+    else{                                              
+      usbMIDI.sendControlChange(RIGHT_BUTTON_CC, 0, CHANNEL);  
+      CircuitPlayground.redLED(LOW);                    
+    }
+    rightButtonLastState = rightButtonState;              
+  }
+///////////////////////////////////////////////////////////////////////////////
+//Cap sense pads
+//
+//read the capacative pads
+  int cap1  = CircuitPlayground.readCap(1);
+  int cap0  = CircuitPlayground.readCap(0);
+  int cap2  = CircuitPlayground.readCap(2);
+  int cap3  = CircuitPlayground.readCap(3);
+  int cap12 = CircuitPlayground.readCap(12);
+  int cap6  = CircuitPlayground.readCap(6);
+  int cap9  = CircuitPlayground.readCap(9);
+  int cap10 = CircuitPlayground.readCap(10);
+
+  //cap1 Crossfader Deck B
+  
+  if(cap1 > CAPMIN){
+    cap1State=1;
+  }
+  else{
+    cap1State=0;
+  }
+  if(cap1State != cap1LastState){
+    if(cap1State==1){
+      usbMIDI.sendControlChange(CAP1_CONTROL, 127, CHANNEL);
+      CircuitPlayground.redLED(HIGH);
+    }
+    else {
+      usbMIDI.sendControlChange(CAP1_CONTROL, 0, CHANNEL);
+      CircuitPlayground.redLED(LOW);
+    }
+    cap1LastState = cap1State;
+  }
+
+  //cap0 
+  if(cap0 > CAPMIN){
+    cap0State=1;
+  }
+  else{
+    cap0State=0;
+  }
+  if(cap0State != cap0LastState){
+    if(cap0State==1){
+      usbMIDI.sendControlChange(CAP0_CONTROL, 1, CHANNEL);
+      CircuitPlayground.redLED(HIGH);
+    }
+    else {
+      usbMIDI.sendControlChange(CAP0_CONTROL, 0, CHANNEL);
+      CircuitPlayground.redLED(LOW);
+    }
+    cap0LastState = cap0State;
+  }
+
+//cap2
+  if(cap2 > CAPMIN){
+    cap2State=1;
+  }
+  else{
+    cap2State=0;
+  }
+  if(cap2State != cap2LastState){
+    if(cap2State==1){
+      usbMIDI.sendControlChange(CAP2_CONTROL, 1, CHANNEL);
+      CircuitPlayground.redLED(HIGH);
+    }
+    else {
+      usbMIDI.sendControlChange(CAP2_CONTROL, 0, CHANNEL);
+      CircuitPlayground.redLED(LOW);
+    }
+    cap2LastState = cap2State;
+  }
+
+  //cap3
+  if(cap3 > CAPMIN){
+    cap3State=1;
+  }
+  else{
+    cap3State=0;
+  }
+  if(cap3State != cap3LastState){
+    if(cap3State==1){
+      usbMIDI.sendControlChange(CAP3_CONTROL, 1, CHANNEL);
+      CircuitPlayground.redLED(HIGH);
+    }
+    else {
+      usbMIDI.sendControlChange(CAP3_CONTROL, 0, CHANNEL);
+      CircuitPlayground.redLED(LOW);
+    }
+    cap3LastState = cap3State;
+  }
+
+  //cap12 Crossfader Deck B
+
+  if(cap12 > CAPMIN){
+    cap12State=1;
+  }
+  else{
+    cap12State=0;
+  }
+  if(cap12State != cap12LastState){
+    if(cap12State==1){
+      usbMIDI.sendControlChange(CAP12_CONTROL, 127, CHANNEL);
+      CircuitPlayground.redLED(HIGH);
+    }
+    else {
+      usbMIDI.sendControlChange(CAP12_CONTROL, 0, CHANNEL);
+      CircuitPlayground.redLED(LOW);
+    }
+    cap12LastState = cap12State;
+  }
+
+  //cap6
+  if (cap6>CAPMIN){
+    int cap6NewVal = map(CircuitPlayground.readCap(6),0,200,0,127);
+    if (abs(cap6 - cap6NewVal>CAPSLOP)) {
+      cap6 = cap6NewVal;
+      usbMIDI.sendControlChange(CAP6_CONTROL, cap6, CHANNEL);
+      CircuitPlayground.redLED(HIGH);
+      cap6ON = true;
+    }
+    else{
+      if (cap6ON==true){
+        usbMIDI.sendControlChange(CAP6_CONTROL, 0, CHANNEL); //send a 0
+        CircuitPlayground.redLED(LOW);
+        cap6ON=false;
+      }
+    }
+  }
+
+  //cap9
+  if(cap9 > CAPMIN){
+    cap9State=1;
+  }
+  else{
+    cap9State=0;
+  }
+  if(cap9State != cap9LastState){
+    if(cap9State==1){
+      usbMIDI.sendControlChange(CAP9_CONTROL, 1, CHANNEL);
+      CircuitPlayground.redLED(HIGH);
+    }
+    else {
+      usbMIDI.sendControlChange(CAP9_CONTROL, 0, CHANNEL);
+      CircuitPlayground.redLED(LOW);
+    }
+    cap9LastState = cap9State;
+  }
+
+  //cap10
+  if(cap10 > CAPMIN){
+    cap10State=1;
+  }
+  else{
+    cap10State=0;
+  }
+  if(cap10State != cap10LastState){
+    if(cap10State==1){
+      usbMIDI.sendControlChange(CAP10_CONTROL, 1, CHANNEL);
+      CircuitPlayground.redLED(HIGH);
+    }
+    else {
+      usbMIDI.sendControlChange(CAP10_CONTROL, 0, CHANNEL);
+      CircuitPlayground.redLED(LOW);
+    }
+    cap10LastState = cap10State;
+  }
+
+  // MIDI Controllers should discard incoming MIDI messages.
+  while (usbMIDI.read()) {
+  }
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/MIDI/midi_test/midi_test.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/MIDI/midi_test/midi_test.ino
new file mode 100644
index 00000000000..5a40be20fe7
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/MIDI/midi_test/midi_test.ino
@@ -0,0 +1,110 @@
+/*********************************************************************
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ Copyright (c) 2019 Ha Thach for Adafruit Industries
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This sketch is enumerated as USB MIDI device. 
+ * Following library is required
+ * - MIDI Library by Forty Seven Effects
+ *   https://github.com/FortySevenEffects/arduino_midi_library
+ */
+
+#include <Arduino.h>
+#include <Adafruit_TinyUSB.h>
+#include <MIDI.h>
+
+// USB MIDI object
+Adafruit_USBD_MIDI usb_midi;
+
+// Create a new instance of the Arduino MIDI Library,
+// and attach usb_midi as the transport.
+MIDI_CREATE_INSTANCE(Adafruit_USBD_MIDI, usb_midi, MIDI);
+
+// Variable that holds the current position in the sequence.
+uint32_t position = 0;
+
+// Store example melody as an array of note values
+byte note_sequence[] = {
+  74,78,81,86,90,93,98,102,57,61,66,69,73,78,81,85,88,92,97,100,97,92,88,85,81,78,
+  74,69,66,62,57,62,66,69,74,78,81,86,90,93,97,102,97,93,90,85,81,78,73,68,64,61,
+  56,61,64,68,74,78,81,86,90,93,98,102
+};
+
+void setup()
+{
+  pinMode(LED_BUILTIN, OUTPUT);
+  
+  //usb_midi.setStringDescriptor("TinyUSB MIDI");
+
+  // Initialize MIDI, and listen to all MIDI channels
+  // This will also call usb_midi's begin()
+  MIDI.begin(MIDI_CHANNEL_OMNI);
+
+  // Attach the handleNoteOn function to the MIDI Library. It will
+  // be called whenever the Bluefruit receives MIDI Note On messages.
+  MIDI.setHandleNoteOn(handleNoteOn);
+
+  // Do the same for MIDI Note Off messages.
+  MIDI.setHandleNoteOff(handleNoteOff);
+
+  Serial.begin(115200);
+
+  // wait until device mounted
+  while( !USBDevice.mounted() ) delay(1);
+}
+
+void loop()
+{
+  static uint32_t start_ms = 0;
+  if ( millis() - start_ms > 266 )
+  {
+    start_ms += 266;
+    
+    // Setup variables for the current and previous
+    // positions in the note sequence.
+    int previous = position - 1;
+  
+    // If we currently are at position 0, set the
+    // previous position to the last note in the sequence.
+    if (previous < 0) {
+      previous = sizeof(note_sequence) - 1;
+    }
+  
+    // Send Note On for current position at full velocity (127) on channel 1.
+    MIDI.sendNoteOn(note_sequence[position], 127, 1);
+  
+    // Send Note Off for previous note.
+    MIDI.sendNoteOff(note_sequence[previous], 0, 1);
+  
+    // Increment position
+    position++;
+  
+    // If we are at the end of the sequence, start over.
+    if (position >= sizeof(note_sequence)) {
+      position = 0;
+    }
+  }
+
+  // read any new MIDI messages
+  MIDI.read();  
+}
+
+void handleNoteOn(byte channel, byte pitch, byte velocity)
+{
+  // Log when a note is pressed.
+  Serial.printf("Note on: channel = %d, pitch = %d, velocity - %d", channel, pitch, velocity);
+  Serial.println();
+}
+
+void handleNoteOff(byte channel, byte pitch, byte velocity)
+{
+  // Log when a note is released.
+  Serial.printf("Note off: channel = %d, pitch = %d, velocity - %d", channel, pitch, velocity);
+  Serial.println();
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_external_flash/msc_external_flash.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_external_flash/msc_external_flash.ino
new file mode 100644
index 00000000000..fc1663c4f12
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_external_flash/msc_external_flash.ino
@@ -0,0 +1,176 @@
+/*********************************************************************
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ Copyright (c) 2019 Ha Thach for Adafruit Industries
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This example demo how to expose on-board external Flash as USB Mass Storage.
+ * Following library is required
+ *   - Adafruit_SPIFlash https://github.com/adafruit/Adafruit_SPIFlash
+ *   - SdFat https://github.com/adafruit/SdFat
+ *
+ * Note: Adafruit fork of SdFat enabled ENABLE_EXTENDED_TRANSFER_CLASS and FAT12_SUPPORT
+ * in SdFatConfig.h, which is needed to run SdFat on external flash. You can use original
+ * SdFat library and manually change those macros
+ */
+
+#include "SPI.h"
+#include "SdFat.h"
+#include "Adafruit_SPIFlash.h"
+#include "Adafruit_TinyUSB.h"
+
+// Uncomment to run example with FRAM
+// #define FRAM_CS   A5
+// #define FRAM_SPI  SPI
+
+#if defined(FRAM_CS) && defined(FRAM_SPI)
+  Adafruit_FlashTransport_SPI flashTransport(FRAM_CS, FRAM_SPI);
+
+#elif defined(ARDUINO_ARCH_ESP32)
+  // ESP32 use same flash device that store code.
+  // Therefore there is no need to specify the SPI and SS
+  Adafruit_FlashTransport_ESP32 flashTransport;
+
+#else
+  // On-board external flash (QSPI or SPI) macros should already
+  // defined in your board variant if supported
+  // - EXTERNAL_FLASH_USE_QSPI
+  // - EXTERNAL_FLASH_USE_CS/EXTERNAL_FLASH_USE_SPI
+  #if defined(EXTERNAL_FLASH_USE_QSPI)
+    Adafruit_FlashTransport_QSPI flashTransport;
+
+  #elif defined(EXTERNAL_FLASH_USE_SPI)
+    Adafruit_FlashTransport_SPI flashTransport(EXTERNAL_FLASH_USE_CS, EXTERNAL_FLASH_USE_SPI);
+
+  #else
+    #error No QSPI/SPI flash are defined on your board variant.h !
+  #endif
+#endif
+
+Adafruit_SPIFlash flash(&flashTransport);
+
+// file system object from SdFat
+FatFileSystem fatfs;
+
+FatFile root;
+FatFile file;
+
+// USB Mass Storage object
+Adafruit_USBD_MSC usb_msc;
+
+// Set to true when PC write to flash
+bool changed;
+
+// the setup function runs once when you press reset or power the board
+void setup()
+{
+  pinMode(LED_BUILTIN, OUTPUT);
+
+  flash.begin();
+
+  // Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
+  usb_msc.setID("Adafruit", "External Flash", "1.0");
+
+  // Set callback
+  usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
+
+  // Set disk size, block size should be 512 regardless of spi flash page size
+  usb_msc.setCapacity(flash.size()/512, 512);
+
+  // MSC is ready for read/write
+  usb_msc.setUnitReady(true);
+  
+  usb_msc.begin();
+
+  // Init file system on the flash
+  fatfs.begin(&flash);
+
+  Serial.begin(115200);
+  //while ( !Serial ) delay(10);   // wait for native usb
+
+  Serial.println("Adafruit TinyUSB Mass Storage External Flash example");
+  Serial.print("JEDEC ID: "); Serial.println(flash.getJEDECID(), HEX);
+  Serial.print("Flash size: "); Serial.println(flash.size());
+
+  changed = true; // to print contents initially
+}
+
+void loop()
+{
+  if ( changed )
+  {
+    changed = false;
+    
+    if ( !root.open("/") )
+    {
+      Serial.println("open root failed");
+      return;
+    }
+
+    Serial.println("Flash contents:");
+
+    // Open next file in root.
+    // Warning, openNext starts at the current directory position
+    // so a rewind of the directory may be required.
+    while ( file.openNext(&root, O_RDONLY) )
+    {
+      file.printFileSize(&Serial);
+      Serial.write(' ');
+      file.printName(&Serial);
+      if ( file.isDir() )
+      {
+        // Indicate a directory.
+        Serial.write('/');
+      }
+      Serial.println();
+      file.close();
+    }
+
+    root.close();
+
+    Serial.println();
+    delay(1000); // refresh every 0.5 second
+  }
+}
+
+// Callback invoked when received READ10 command.
+// Copy disk's data to buffer (up to bufsize) and 
+// return number of copied bytes (must be multiple of block size) 
+int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
+{
+  // Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
+  // already include 4K sector caching internally. We don't need to cache it, yahhhh!!
+  return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
+}
+
+// Callback invoked when received WRITE10 command.
+// Process data in buffer to disk's storage and 
+// return number of written bytes (must be multiple of block size)
+int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
+{
+  digitalWrite(LED_BUILTIN, HIGH);
+
+  // Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
+  // already include 4K sector caching internally. We don't need to cache it, yahhhh!!
+  return flash.writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1;
+}
+
+// Callback invoked when WRITE10 command is completed (status received and accepted by host).
+// used to flush any pending cache.
+void msc_flush_cb (void)
+{
+  // sync with flash
+  flash.syncBlocks();
+
+  // clear file system's cache to force refresh
+  fatfs.cacheClear();
+
+  changed = true;
+
+  digitalWrite(LED_BUILTIN, LOW);
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_external_flash_sdcard/msc_external_flash_sdcard.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_external_flash_sdcard/msc_external_flash_sdcard.ino
new file mode 100644
index 00000000000..8a5bd26a98a
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_external_flash_sdcard/msc_external_flash_sdcard.ino
@@ -0,0 +1,245 @@
+/*********************************************************************
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ Copyright (c) 2019 Ha Thach for Adafruit Industries
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This example exposes both external flash and SD card as mass storage (dual LUNs)
+ * Following library is required
+ *   - Adafruit_SPIFlash https://github.com/adafruit/Adafruit_SPIFlash
+ *   - SdFat https://github.com/adafruit/SdFat
+ *
+ * Note: Adafruit fork of SdFat enabled ENABLE_EXTENDED_TRANSFER_CLASS and FAT12_SUPPORT
+ * in SdFatConfig.h, which is needed to run SdFat on external flash. You can use original
+ * SdFat library and manually change those macros
+ */
+
+#include "SPI.h"
+#include "SdFat.h"
+#include "Adafruit_SPIFlash.h"
+#include "Adafruit_TinyUSB.h"
+
+// Uncomment to run example with FRAM
+// #define FRAM_CS   A5
+// #define FRAM_SPI  SPI
+
+#if defined(FRAM_CS) && defined(FRAM_SPI)
+  Adafruit_FlashTransport_SPI flashTransport(FRAM_CS, FRAM_SPI);
+
+#elif defined(ARDUINO_ARCH_ESP32)
+  // ESP32 use same flash device that store code.
+  // Therefore there is no need to specify the SPI and SS
+  Adafruit_FlashTransport_ESP32 flashTransport;
+
+#else
+  // On-board external flash (QSPI or SPI) macros should already
+  // defined in your board variant if supported
+  // - EXTERNAL_FLASH_USE_QSPI
+  // - EXTERNAL_FLASH_USE_CS/EXTERNAL_FLASH_USE_SPI
+  #if defined(EXTERNAL_FLASH_USE_QSPI)
+    Adafruit_FlashTransport_QSPI flashTransport;
+
+  #elif defined(EXTERNAL_FLASH_USE_SPI)
+    Adafruit_FlashTransport_SPI flashTransport(EXTERNAL_FLASH_USE_CS, EXTERNAL_FLASH_USE_SPI);
+
+  #else
+    #error No QSPI/SPI flash are defined on your board variant.h !
+  #endif
+#endif
+
+
+Adafruit_SPIFlash flash(&flashTransport);
+
+// File system object on external flash from SdFat
+FatFileSystem fatfs;
+
+const int chipSelect = 10;
+
+// File system on SD Card
+SdFat sd;
+
+// USB Mass Storage object
+Adafruit_USBD_MSC usb_msc;
+
+// Set to true when PC write to flash
+bool sd_changed = false;
+bool flash_changed = false;
+
+// the setup function runs once when you press reset or power the board
+void setup()
+{
+  pinMode(LED_BUILTIN, OUTPUT);
+
+  // MSC with 2 Logical Units
+  usb_msc.setMaxLun(2);
+
+  usb_msc.setID(0, "Adafruit", "External Flash", "1.0");
+  usb_msc.setID(1, "Adafruit", "SD Card", "1.0");
+
+  // Since initialize both external flash and SD card can take time.
+  // If it takes too long, our board could be enumerated as CDC device only
+  // i.e without Mass Storage. To prevent this, we call Mass Storage begin first
+  // LUN readiness will always be set later on
+  usb_msc.begin();
+
+  //------------- Lun 0 for external flash -------------//
+  flash.begin();
+  fatfs.begin(&flash);
+
+  usb_msc.setCapacity(0, flash.size()/512, 512);
+  usb_msc.setReadWriteCallback(0, external_flash_read_cb, external_flash_write_cb, external_flash_flush_cb);
+  usb_msc.setUnitReady(0, true);
+
+  flash_changed = true; // to print contents initially
+
+  //------------- Lun 1 for SD card -------------//
+  if ( sd.begin(chipSelect, SD_SCK_MHZ(50)) )
+  {
+    uint32_t block_count = sd.card()->cardSize();
+    usb_msc.setCapacity(1, block_count, 512);
+    usb_msc.setReadWriteCallback(1, sdcard_read_cb, sdcard_write_cb, sdcard_flush_cb);
+    usb_msc.setUnitReady(1, true);
+
+    sd_changed = true; // to print contents initially
+  }
+
+  Serial.begin(115200);
+  //while ( !Serial ) delay(10);   // wait for native usb
+
+  Serial.println("Adafruit TinyUSB Mass Storage External Flash + SD Card example");
+  delay(1000);
+}
+
+void print_rootdir(File* rdir)
+{
+  File file;
+
+  // Open next file in root.
+  // Warning, openNext starts at the current directory position
+  // so a rewind of the directory may be required.
+  while ( file.openNext(rdir, O_RDONLY) )
+  {
+    file.printFileSize(&Serial);
+    Serial.write(' ');
+    file.printName(&Serial);
+    if ( file.isDir() )
+    {
+      // Indicate a directory.
+      Serial.write('/');
+    }
+    Serial.println();
+    file.close();
+  }
+}
+
+void loop()
+{
+  if ( flash_changed )
+  {
+    File root;
+    root = fatfs.open("/");
+
+    Serial.println("Flash contents:");
+    print_rootdir(&root);
+    Serial.println();
+
+    root.close();
+
+    flash_changed = false;
+  }
+
+  if ( sd_changed )
+  {
+    File root;
+    root = sd.open("/");
+
+    Serial.println("SD contents:");
+    print_rootdir(&root);
+    Serial.println();
+
+    root.close();
+
+    sd_changed = false;
+  }
+
+  delay(1000); // refresh every 1 second
+}
+
+
+//--------------------------------------------------------------------+
+// SD Card callbacks
+//--------------------------------------------------------------------+
+
+int32_t sdcard_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
+{
+  return sd.card()->readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
+}
+
+// Callback invoked when received WRITE10 command.
+// Process data in buffer to disk's storage and 
+// return number of written bytes (must be multiple of block size)
+int32_t sdcard_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
+{
+  digitalWrite(LED_BUILTIN, HIGH);
+
+  return sd.card()->writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1;
+}
+
+// Callback invoked when WRITE10 command is completed (status received and accepted by host).
+// used to flush any pending cache.
+void sdcard_flush_cb (void)
+{
+  sd.card()->syncBlocks();
+
+  // clear file system's cache to force refresh
+  sd.cacheClear();
+
+  sd_changed = true;
+
+  digitalWrite(LED_BUILTIN, LOW);
+}
+
+//--------------------------------------------------------------------+
+// External Flash callbacks
+//--------------------------------------------------------------------+
+
+// Callback invoked when received READ10 command.
+// Copy disk's data to buffer (up to bufsize) and
+// return number of copied bytes (must be multiple of block size)
+int32_t external_flash_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
+{
+  // Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
+  // already include 4K sector caching internally. We don't need to cache it, yahhhh!!
+  return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
+}
+
+// Callback invoked when received WRITE10 command.
+// Process data in buffer to disk's storage and
+// return number of written bytes (must be multiple of block size)
+int32_t external_flash_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
+{
+  digitalWrite(LED_BUILTIN, HIGH);
+
+  // Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
+  // already include 4K sector caching internally. We don't need to cache it, yahhhh!!
+  return flash.writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1;
+}
+
+// Callback invoked when WRITE10 command is completed (status received and accepted by host).
+// used to flush any pending cache.
+void external_flash_flush_cb (void)
+{
+  flash.syncBlocks();
+
+  // clear file system's cache to force refresh
+  fatfs.cacheClear();
+
+  flash_changed = true;
+
+  digitalWrite(LED_BUILTIN, LOW);
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk/msc_ramdisk.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk/msc_ramdisk.ino
new file mode 100644
index 00000000000..0274b6ef769
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk/msc_ramdisk.ino
@@ -0,0 +1,76 @@
+/*********************************************************************
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ Copyright (c) 2019 Ha Thach for Adafruit Industries
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+#include "Adafruit_TinyUSB.h"
+
+// 8KB is the smallest size that windows allow to mount
+#define DISK_BLOCK_NUM  16
+#define DISK_BLOCK_SIZE 512
+#include "ramdisk.h"
+
+Adafruit_USBD_MSC usb_msc;
+
+// the setup function runs once when you press reset or power the board
+void setup()
+{
+  // Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
+  usb_msc.setID("Adafruit", "Mass Storage", "1.0");
+  
+  // Set disk size
+  usb_msc.setCapacity(DISK_BLOCK_NUM, DISK_BLOCK_SIZE);
+
+  // Set callback
+  usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
+
+  // Set Lun ready (RAM disk is always ready)
+  usb_msc.setUnitReady(true);
+  
+  usb_msc.begin();
+
+  Serial.begin(115200);
+  //while ( !Serial ) delay(10);   // wait for native usb
+
+  Serial.println("Adafruit TinyUSB Mass Storage RAM Disk example");
+}
+
+void loop()
+{
+  // nothing to do
+}
+
+// Callback invoked when received READ10 command.
+// Copy disk's data to buffer (up to bufsize) and 
+// return number of copied bytes (must be multiple of block size) 
+int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
+{
+  uint8_t const* addr = msc_disk[lba];
+  memcpy(buffer, addr, bufsize);
+
+  return bufsize;
+}
+
+// Callback invoked when received WRITE10 command.
+// Process data in buffer to disk's storage and 
+// return number of written bytes (must be multiple of block size)
+int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
+{
+  uint8_t* addr = msc_disk[lba];
+  memcpy(addr, buffer, bufsize);
+
+  return bufsize;
+}
+
+// Callback invoked when WRITE10 command is completed (status received and accepted by host).
+// used to flush any pending cache.
+void msc_flush_cb (void)
+{
+  // nothing to do
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk/ramdisk.h b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk/ramdisk.h
new file mode 100644
index 00000000000..11aae403563
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk/ramdisk.h
@@ -0,0 +1,113 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef RAMDISK_H_
+#define RAMDISK_H_
+
+#define README_CONTENTS                                                        \
+  "This is TinyUSB MassStorage device demo for Arduino on RAM disk."
+
+uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = {
+    //------------- Block0: Boot Sector -------------//
+    // byte_per_sector    = DISK_BLOCK_SIZE; fat12_sector_num_16  =
+    // DISK_BLOCK_NUM; sector_per_cluster = 1; reserved_sectors = 1; fat_num =
+    // 1; fat12_root_entry_num = 16; sector_per_fat     = 1; sector_per_track =
+    // 1; head_num = 1; hidden_sectors = 0; drive_number       = 0x80;
+    // media_type = 0xf8; extended_boot_signature = 0x29; filesystem_type    =
+    // "FAT12   "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC";
+    // FAT magic code at offset 510-511
+    {0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00,
+     0x02, 0x01, 0x01, 0x00, 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00,
+     0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T', 'i', 'n', 'y', 'U', 'S',
+     'B', ' ', 'M', 'S', 'C', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20,
+     0x00, 0x00,
+
+     // Zero up to 2 last bytes of FAT magic code
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x55, 0xAA},
+
+    //------------- Block1: FAT12 Table -------------//
+    {
+        0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third
+                                     // entry is cluster end of readme file
+    },
+
+    //------------- Block2: Root Directory -------------//
+    {
+        // first entry is volume label
+        'T', 'i', 'n', 'y', 'U', 'S', 'B', ' ', 'M', 'S', 'C', 0x08, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        // second entry is readme file
+        'R', 'E', 'A', 'D', 'M', 'E', ' ', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6,
+        0x52, 0x6D, 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43,
+        0x02, 0x00, sizeof(README_CONTENTS) - 1, 0x00, 0x00,
+        0x00 // readme's files size (4 Bytes)
+    },
+
+    //------------- Block3: Readme Content -------------//
+    README_CONTENTS};
+
+#endif /* RAMDISK_H_ */
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk_dual/msc_ramdisk_dual.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk_dual/msc_ramdisk_dual.ino
new file mode 100644
index 00000000000..80bb3e220e0
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk_dual/msc_ramdisk_dual.ino
@@ -0,0 +1,117 @@
+/*********************************************************************
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ Copyright (c) 2019 Ha Thach for Adafruit Industries
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+#include "Adafruit_TinyUSB.h"
+
+// 8KB is the smallest size that windows allow to mount
+#define DISK_BLOCK_NUM  16
+#define DISK_BLOCK_SIZE 512
+#include "ramdisk.h"
+
+Adafruit_USBD_MSC usb_msc;
+
+// the setup function runs once when you press reset or power the board
+void setup()
+{
+  usb_msc.setMaxLun(2);
+  
+  // Set disk size and callback for Logical Unit 0 (LUN 0)
+  usb_msc.setID(0, "Adafruit", "Lun0", "1.0");
+  usb_msc.setCapacity(0, DISK_BLOCK_NUM, DISK_BLOCK_SIZE);
+  usb_msc.setReadWriteCallback(0, ram0_read_cb, ram0_write_cb, ram0_flush_cb);
+  usb_msc.setUnitReady(0, true);
+
+  // Set disk size and callback for Logical Unit 1 (LUN 1)
+  usb_msc.setID(1, "Adafruit", "Lun1", "1.0");
+  usb_msc.setCapacity(1, DISK_BLOCK_NUM, DISK_BLOCK_SIZE);
+  usb_msc.setReadWriteCallback(1, ram1_read_cb, ram1_write_cb, ram1_flush_cb);
+  usb_msc.setUnitReady(1, true);
+    
+  usb_msc.begin();
+
+  Serial.begin(115200);
+  //while ( !Serial ) delay(10);   // wait for native usb
+
+  Serial.println("Adafruit TinyUSB Mass Storage Dual RAM Disks example");
+}
+
+void loop()
+{
+  // nothing to do
+}
+
+
+//--------------------------------------------------------------------+
+// LUN 0 callback
+//--------------------------------------------------------------------+
+
+// Callback invoked when received READ10 command.
+// Copy disk's data to buffer (up to bufsize) and 
+// return number of copied bytes (must be multiple of block size) 
+int32_t ram0_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
+{
+  uint8_t const* addr = msc_disk0[lba];
+  memcpy(buffer, addr, bufsize);
+
+  return bufsize;
+}
+
+// Callback invoked when received WRITE10 command.
+// Process data in buffer to disk's storage and 
+// return number of written bytes (must be multiple of block size)
+int32_t ram0_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
+{
+  uint8_t* addr = msc_disk0[lba];
+  memcpy(addr, buffer, bufsize);
+
+  return bufsize;
+}
+
+// Callback invoked when WRITE10 command is completed (status received and accepted by host).
+// used to flush any pending cache.
+void ram0_flush_cb (void)
+{
+  // nothing to do
+}
+
+
+//--------------------------------------------------------------------+
+// LUN 1 callback
+//--------------------------------------------------------------------+
+
+// Callback invoked when received READ10 command.
+// Copy disk's data to buffer (up to bufsize) and 
+// return number of copied bytes (must be multiple of block size) 
+int32_t ram1_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
+{
+  uint8_t const* addr = msc_disk1[lba];
+  memcpy(buffer, addr, bufsize);
+
+  return bufsize;
+}
+
+// Callback invoked when received WRITE10 command.
+// Process data in buffer to disk's storage and 
+// return number of written bytes (must be multiple of block size)
+int32_t ram1_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
+{
+  uint8_t* addr = msc_disk1[lba];
+  memcpy(addr, buffer, bufsize);
+
+  return bufsize;
+}
+
+// Callback invoked when WRITE10 command is completed (status received and accepted by host).
+// used to flush any pending cache.
+void ram1_flush_cb (void)
+{
+  // nothing to do
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk_dual/ramdisk.h b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk_dual/ramdisk.h
new file mode 100644
index 00000000000..6765fe85ddc
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_ramdisk_dual/ramdisk.h
@@ -0,0 +1,204 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef RAMDISK_H_
+#define RAMDISK_H_
+
+//--------------------------------------------------------------------+
+// LUN 0
+//--------------------------------------------------------------------+
+#define README0_CONTENTS                                                       \
+  "LUN0: This is TinyUSB MassStorage device demo for Arduino on RAM disk."
+
+uint8_t msc_disk0[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = {
+    //------------- Block0: Boot Sector -------------//
+    // byte_per_sector    = DISK_BLOCK_SIZE; fat12_sector_num_16  =
+    // DISK_BLOCK_NUM; sector_per_cluster = 1; reserved_sectors = 1; fat_num =
+    // 1; fat12_root_entry_num = 16; sector_per_fat     = 1; sector_per_track =
+    // 1; head_num = 1; hidden_sectors = 0; drive_number       = 0x80;
+    // media_type = 0xf8; extended_boot_signature = 0x29; filesystem_type    =
+    // "FAT12   "; volume_serial_number = 0x1234; volume_label = "TinyUSB 0  ";
+    // FAT magic code at offset 510-511
+    {0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00,
+     0x02, 0x01, 0x01, 0x00, 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00,
+     0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T', 'i', 'n', 'y', 'U', 'S',
+     'B', ' ', '0', ' ', ' ', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20,
+     0x00, 0x00,
+
+     // Zero up to 2 last bytes of FAT magic code
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x55, 0xAA},
+
+    //------------- Block1: FAT12 Table -------------//
+    {
+        0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third
+                                     // entry is cluster end of readme file
+    },
+
+    //------------- Block2: Root Directory -------------//
+    {
+        // first entry is volume label
+        'T', 'i', 'n', 'y', 'U', 'S', 'B', ' ', '0', ' ', ' ', 0x08, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        // second entry is readme file
+        'R', 'E', 'A', 'D', 'M', 'E', '0', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6,
+        0x52, 0x6D, 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43,
+        0x02, 0x00, sizeof(README0_CONTENTS) - 1, 0x00, 0x00,
+        0x00 // readme's files size (4 Bytes)
+    },
+
+    //------------- Block3: Readme Content -------------//
+    README0_CONTENTS};
+
+//--------------------------------------------------------------------+
+// LUN 1
+//--------------------------------------------------------------------+
+#define README1_CONTENTS                                                       \
+  "LUN1: This is TinyUSB MassStorage device demo for Arduino on RAM disk."
+
+uint8_t msc_disk1[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = {
+    //------------- Block0: Boot Sector -------------//
+    // byte_per_sector    = DISK_BLOCK_SIZE; fat12_sector_num_16  =
+    // DISK_BLOCK_NUM; sector_per_cluster = 1; reserved_sectors = 1; fat_num =
+    // 1; fat12_root_entry_num = 16; sector_per_fat     = 1; sector_per_track =
+    // 1; head_num = 1; hidden_sectors = 0; drive_number       = 0x80;
+    // media_type = 0xf8; extended_boot_signature = 0x29; filesystem_type    =
+    // "FAT12   "; volume_serial_number = 0x5678; volume_label = "TinyUSB 1  ";
+    // FAT magic code at offset 510-511
+    {0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00,
+     0x02, 0x01, 0x01, 0x00, 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00,
+     0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x80, 0x00, 0x29, 0x78, 0x56, 0x00, 0x00, 'T', 'i', 'n', 'y', 'U', 'S',
+     'B', ' ', '1', ' ', ' ', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20,
+     0x00, 0x00,
+
+     // Zero up to 2 last bytes of FAT magic code
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x55, 0xAA},
+
+    //------------- Block1: FAT12 Table -------------//
+    {
+        0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third
+                                     // entry is cluster end of readme file
+    },
+
+    //------------- Block2: Root Directory -------------//
+    {
+        // first entry is volume label
+        'T', 'i', 'n', 'y', 'U', 'S', 'B', ' ', '1', ' ', ' ', 0x08, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        // second entry is readme file
+        'R', 'E', 'A', 'D', 'M', 'E', '1', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6,
+        0x52, 0x6D, 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43,
+        0x02, 0x00, sizeof(README1_CONTENTS) - 1, 0x00, 0x00,
+        0x00 // readme's files size (4 Bytes)
+    },
+
+    //------------- Block3: Readme Content -------------//
+    README1_CONTENTS};
+
+#endif /* RAMDISK_H_ */
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_sd/msc_sd.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_sd/msc_sd.ino
new file mode 100644
index 00000000000..adadc49551c
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_sd/msc_sd.ino
@@ -0,0 +1,102 @@
+/*********************************************************************
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ Copyright (c) 2019 Ha Thach for Adafruit Industries
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This example expose SD card as mass storage using
+ * default SD Library
+ */
+
+#include "SD.h"
+#include "Adafruit_TinyUSB.h"
+
+const int chipSelect = 10;
+
+Adafruit_USBD_MSC usb_msc;
+
+Sd2Card card;
+SdVolume volume;
+
+// the setup function runs once when you press reset or power the board
+void setup()
+{
+  // Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
+  usb_msc.setID("Adafruit", "SD Card", "1.0");
+
+  // Set read write callback
+  usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
+
+  // Still initialize MSC but tell usb stack that MSC is not ready to read/write
+  // If we don't initialize, board will be enumerated as CDC only
+  usb_msc.setUnitReady(false);
+  usb_msc.begin();
+
+  Serial.begin(115200);
+  //while ( !Serial ) delay(10);   // wait for native usb
+
+  Serial.println("Adafruit TinyUSB Mass Storage SD Card example");
+
+  Serial.println("\nInitializing SD card...");
+
+  if ( !card.init(SPI_HALF_SPEED, chipSelect) )
+  {
+    Serial.println("initialization failed. Things to check:");
+    Serial.println("* is a card inserted?");
+    Serial.println("* is your wiring correct?");
+    Serial.println("* did you change the chipSelect pin to match your shield or module?");
+    while (1) delay(1);
+  }
+
+  // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
+  if (!volume.init(card)) {
+    Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
+    while (1) delay(1);
+  }
+  
+  uint32_t block_count = volume.blocksPerCluster()*volume.clusterCount();
+
+  Serial.print("Volume size (MB):  ");
+  Serial.println((block_count/2) / 1024);
+
+  // Set disk size, SD block size is always 512
+  usb_msc.setCapacity(block_count, 512);
+
+  // MSC is ready for read/write
+  usb_msc.setUnitReady(true);
+}
+
+void loop()
+{
+  // nothing to do
+}
+
+// Callback invoked when received READ10 command.
+// Copy disk's data to buffer (up to bufsize) and
+// return number of copied bytes (must be multiple of block size)
+int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
+{
+  (void) bufsize;
+  return card.readBlock(lba, (uint8_t*) buffer) ? 512 : -1;
+}
+
+// Callback invoked when received WRITE10 command.
+// Process data in buffer to disk's storage and 
+// return number of written bytes (must be multiple of block size)
+int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
+{
+  (void) bufsize;
+  return card.writeBlock(lba, buffer) ? 512 : -1;
+}
+
+// Callback invoked when WRITE10 command is completed (status received and accepted by host).
+// used to flush any pending cache.
+void msc_flush_cb (void)
+{
+  // nothing to do
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_sdfat/msc_sdfat.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_sdfat/msc_sdfat.ino
new file mode 100644
index 00000000000..b0e43080df1
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/MassStorage/msc_sdfat/msc_sdfat.ino
@@ -0,0 +1,145 @@
+/*********************************************************************
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ Copyright (c) 2019 Ha Thach for Adafruit Industries
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This example expose SD card as mass storage using
+ * SdFat Library
+ */
+
+#include "SPI.h"
+#include "SdFat.h"
+#include "Adafruit_TinyUSB.h"
+
+const int chipSelect = 10;
+
+// File system on SD Card
+SdFat sd;
+
+SdFile root;
+SdFile file;
+
+// USB Mass Storage object
+Adafruit_USBD_MSC usb_msc;
+
+// Set to true when PC write to flash
+bool changed;
+
+// the setup function runs once when you press reset or power the board
+void setup()
+{
+  pinMode(LED_BUILTIN, OUTPUT);
+
+  // Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
+  usb_msc.setID("Adafruit", "SD Card", "1.0");
+
+  // Set read write callback
+  usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
+
+  // Still initialize MSC but tell usb stack that MSC is not ready to read/write
+  // If we don't initialize, board will be enumerated as CDC only
+  usb_msc.setUnitReady(false);
+  usb_msc.begin();
+
+  Serial.begin(115200);
+  //while ( !Serial ) delay(10);   // wait for native usb
+
+  Serial.println("Adafruit TinyUSB Mass Storage SD Card example");
+
+  Serial.print("\nInitializing SD card ... ");
+  Serial.print("CS = "); Serial.println(chipSelect);
+
+  if ( !sd.begin(chipSelect, SD_SCK_MHZ(50)) )
+  {
+    Serial.println("initialization failed. Things to check:");
+    Serial.println("* is a card inserted?");
+    Serial.println("* is your wiring correct?");
+    Serial.println("* did you change the chipSelect pin to match your shield or module?");
+    while (1) delay(1);
+  }
+
+  // Size in blocks (512 bytes)
+  uint32_t block_count = sd.card()->cardSize();
+
+  Serial.print("Volume size (MB):  ");
+  Serial.println((block_count/2) / 1024);
+
+  // Set disk size, SD block size is always 512
+  usb_msc.setCapacity(block_count, 512);
+
+  // MSC is ready for read/write
+  usb_msc.setUnitReady(true);
+
+  changed = true; // to print contents initially
+}
+
+void loop()
+{
+  if ( changed )
+  {
+    root.open("/");
+    Serial.println("SD contents:");
+
+    // Open next file in root.
+    // Warning, openNext starts at the current directory position
+    // so a rewind of the directory may be required.
+    while ( file.openNext(&root, O_RDONLY) )
+    {
+      file.printFileSize(&Serial);
+      Serial.write(' ');
+      file.printName(&Serial);
+      if ( file.isDir() )
+      {
+        // Indicate a directory.
+        Serial.write('/');
+      }
+      Serial.println();
+      file.close();
+    }
+
+    root.close();
+
+    Serial.println();
+
+    changed = false;
+    delay(1000); // refresh every 0.5 second
+  }
+}
+
+// Callback invoked when received READ10 command.
+// Copy disk's data to buffer (up to bufsize) and
+// return number of copied bytes (must be multiple of block size)
+int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
+{
+  return sd.card()->readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
+}
+
+// Callback invoked when received WRITE10 command.
+// Process data in buffer to disk's storage and 
+// return number of written bytes (must be multiple of block size)
+int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
+{
+  digitalWrite(LED_BUILTIN, HIGH);
+
+  return sd.card()->writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1;
+}
+
+// Callback invoked when WRITE10 command is completed (status received and accepted by host).
+// used to flush any pending cache.
+void msc_flush_cb (void)
+{
+  sd.card()->syncBlocks();
+
+  // clear file system's cache to force refresh
+  sd.cacheClear();
+
+  changed = true;
+
+  digitalWrite(LED_BUILTIN, LOW);
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/WebUSB/webusb_rgb/webusb_rgb.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/WebUSB/webusb_rgb/webusb_rgb.ino
new file mode 100644
index 00000000000..a081644ba41
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/WebUSB/webusb_rgb/webusb_rgb.ino
@@ -0,0 +1,110 @@
+/*********************************************************************
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ Copyright (c) 2019 Ha Thach for Adafruit Industries
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This sketch demonstrates WebUSB as web serial with browser with WebUSB support (e.g Chrome).
+ * After enumerated successfully, Browser will pop-up notification
+ * with URL to landing page, click on it to test
+ *  - Click "Connect" and select device, When connected the neopixel LED will change color to Green.
+ *  - When received color from browser in format '#RRGGBB', device will change the color of neopixel accordingly
+ *  
+ * Note: 
+ * - The WebUSB landing page notification is currently disabled in Chrome 
+ * on Windows due to Chromium issue 656702 (https://crbug.com/656702). You have to 
+ * go to landing page (below) to test
+ * 
+ * - On Windows 7 and prior: You need to use Zadig tool to manually bind the 
+ * WebUSB interface with the WinUSB driver for Chrome to access. From windows 8 and 10, this
+ * is done automatically by firmware.
+ */
+
+#include "Adafruit_TinyUSB.h"
+#include <Adafruit_NeoPixel.h>
+
+// Which pin on the Arduino is connected to the NeoPixels?
+// On a Trinket or Gemma we suggest changing this to 1
+// use on-board neopixel PIN_NEOPIXEL if existed
+#ifdef PIN_NEOPIXEL
+  #define PIN      PIN_NEOPIXEL
+#else
+  #define PIN      8
+#endif
+
+// How many NeoPixels are attached to the Arduino?
+#define NUMPIXELS  10
+
+// When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals.
+// Note that for older NeoPixel strips you might need to change the third parameter--see the strandtest
+// example for more information on possible values.
+Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
+
+// USB WebUSB object
+Adafruit_USBD_WebUSB usb_web;
+
+// Landing Page: scheme (0: http, 1: https), url
+WEBUSB_URL_DEF(landingPage, 1 /*https*/, "adafruit.github.io/Adafruit_TinyUSB_Arduino/examples/webusb-rgb/index.html");
+
+// the setup function runs once when you press reset or power the board
+void setup()
+{
+  //usb_web.setStringDescriptor("TinyUSB WebUSB");
+  usb_web.setLandingPage(&landingPage);
+  usb_web.setLineStateCallback(line_state_callback);
+  usb_web.begin();
+
+  Serial.begin(115200);
+
+  // This initializes the NeoPixel with RED
+  pixels.begin();
+  pixels.setBrightness(50);
+  pixels.fill(0xff0000);
+  pixels.show();
+
+  // wait until device mounted
+  while( !USBDevice.mounted() ) delay(1);
+
+  Serial.println("TinyUSB WebUSB RGB example");
+}
+
+// convert a hex character to number
+uint8_t char2num(char c)
+{
+  if (c >= 'a') return c - 'a' + 10;
+  if (c >= 'A') return c - 'A' + 10;
+  return c - '0';  
+}
+
+void loop()
+{
+  // Landing Page 7 characters as hex color '#RRGGBB'
+  if (usb_web.available() < 7) return;
+
+  uint8_t input[7];
+  usb_web.readBytes(input, 7);
+
+  // Print to serial for debugging
+  Serial.write(input, 7);
+  Serial.println();
+
+  uint8_t red   = 16*char2num(input[1]) + char2num(input[2]);
+  uint8_t green = 16*char2num(input[3]) + char2num(input[4]);
+  uint8_t blue  = 16*char2num(input[5]) + char2num(input[6]);
+
+  uint32_t color = (red << 16) | (green << 8) | blue;
+  pixels.fill(color);
+  pixels.show();
+}
+
+void line_state_callback(bool connected)
+{
+  // connected = green, disconnected = red
+  pixels.fill(connected ? 0x00ff00 : 0xff0000);
+  pixels.show();
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/examples/WebUSB/webusb_serial/webusb_serial.ino b/libraries/Adafruit_TinyUSB_Arduino/examples/WebUSB/webusb_serial/webusb_serial.ino
new file mode 100644
index 00000000000..c134710d1d9
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/examples/WebUSB/webusb_serial/webusb_serial.ino
@@ -0,0 +1,81 @@
+/*********************************************************************
+ Adafruit invests time and resources providing this open source code,
+ please support Adafruit and open-source hardware by purchasing
+ products from Adafruit!
+
+ MIT license, check LICENSE for more information
+ Copyright (c) 2019 Ha Thach for Adafruit Industries
+ All text above, and the splash screen below must be included in
+ any redistribution
+*********************************************************************/
+
+/* This sketch demonstrates WebUSB as web serial with browser with WebUSB support (e.g Chrome).
+ * After enumerated successfully, Browser will pop-up notification
+ * with URL to landing page, click on it to test
+ *  - Click "Connect" and select device, When connected the on-board LED will litted up.
+ *  - Any charters received from either webusb/Serial will be echo back to webusb and Serial
+ *  
+ * Note: 
+ * - The WebUSB landing page notification is currently disabled in Chrome 
+ * on Windows due to Chromium issue 656702 (https://crbug.com/656702). You have to 
+ * go to landing page (below) to test
+ * 
+ * - On Windows 7 and prior: You need to use Zadig tool to manually bind the 
+ * WebUSB interface with the WinUSB driver for Chrome to access. From windows 8 and 10, this
+ * is done automatically by firmware.
+ */
+
+#include "Adafruit_TinyUSB.h"
+
+// USB WebUSB object
+Adafruit_USBD_WebUSB usb_web;
+
+// Landing Page: scheme (0: http, 1: https), url
+WEBUSB_URL_DEF(landingPage, 1 /*https*/, "adafruit.github.io/Adafruit_TinyUSB_Arduino/examples/webusb-serial/index.html");
+
+int led_pin = LED_BUILTIN;
+
+// the setup function runs once when you press reset or power the board
+void setup()
+{
+  pinMode(led_pin, OUTPUT);
+  digitalWrite(led_pin, LOW);
+  
+  usb_web.setLandingPage(&landingPage);
+  usb_web.setLineStateCallback(line_state_callback);
+  //usb_web.setStringDescriptor("TinyUSB WebUSB");
+  usb_web.begin();
+
+  Serial.begin(115200);
+
+  // wait until device mounted
+  while( !USBDevice.mounted() ) delay(1);
+
+  Serial.println("TinyUSB WebUSB Serial example");
+}
+
+// function to echo to both Serial and WebUSB
+void echo_all(char chr)
+{
+  Serial.write(chr);
+  // print extra newline for Serial
+  if ( chr == '\r' ) Serial.write('\n');
+  
+  usb_web.write(chr);
+}
+
+void loop()
+{
+  // from WebUSB to both Serial & webUSB
+  if (usb_web.available()) echo_all(usb_web.read());
+
+  // From Serial to both Serial & webUSB
+  if (Serial.available())   echo_all(Serial.read());  
+}
+
+void line_state_callback(bool connected)
+{
+  digitalWrite(led_pin, connected);
+
+  if ( connected ) usb_web.println("TinyUSB WebUSB Serial example");
+}
diff --git a/libraries/Adafruit_TinyUSB_Arduino/library.properties b/libraries/Adafruit_TinyUSB_Arduino/library.properties
new file mode 100644
index 00000000000..2e8e8e96409
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/library.properties
@@ -0,0 +1,11 @@
+name=Adafruit TinyUSB Library
+version=1.3.2
+author=Adafruit
+maintainer=Adafruit <info@adafruit.com>
+sentence=TinyUSB library for Arduino
+paragraph=TinyUSB library for Arduino
+category=Communication
+url=https://github.com/adafruit/Adafruit_TinyUSB_Arduino
+architectures=*
+includes=Adafruit_TinyUSB.h
+depends=Adafruit SPIFlash, MIDI Library, Adafruit seesaw Library, Adafruit NeoPixel, SdFat - Adafruit Fork, SD, Adafruit Circuit Playground
diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/Adafruit_TinyUSB.h b/libraries/Adafruit_TinyUSB_Arduino/src/Adafruit_TinyUSB.h
new file mode 100644
index 00000000000..eab462e03b3
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/src/Adafruit_TinyUSB.h
@@ -0,0 +1,53 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ADAFRUIT_TINYUSB_H_
+#define ADAFRUIT_TINYUSB_H_
+
+// Error message for Core that must select TinyUSB via menu
+#if !defined(USE_TINYUSB) && ( defined(ARDUINO_ARCH_SAMD) || \
+                               (defined(ARDUINO_ARCH_RP2040) && !defined(ARDUINO_ARCH_MBED)) || \
+                               defined(ARDUINO_ARCH_ESP32) )
+#error TinyUSB is not selected, please select it in "Tools->Menu->USB Stack"
+#endif
+
+#include "tusb_option.h"
+
+#if TUSB_OPT_DEVICE_ENABLED
+
+#include "arduino/Adafruit_USBD_Device.h"
+#include "arduino/Adafruit_USBD_CDC.h"
+
+#include "arduino/hid/Adafruit_USBD_HID.h"
+#include "arduino/midi/Adafruit_USBD_MIDI.h"
+#include "arduino/msc/Adafruit_USBD_MSC.h"
+#include "arduino/webusb/Adafruit_USBD_WebUSB.h"
+
+// Initialize device hardware, stack, also Serial as CDC
+// Wrapper for USBDevice.begin(rhport)
+void TinyUSB_Device_Init(uint8_t rhport);
+
+#endif
+
+#endif /* ADAFRUIT_TINYUSB_H_ */
diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_TinyUSB_API.cpp b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_TinyUSB_API.cpp
new file mode 100644
index 00000000000..679361a9890
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_TinyUSB_API.cpp
@@ -0,0 +1,58 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "tusb_option.h"
+
+#if TUSB_OPT_DEVICE_ENABLED
+
+#include "Adafruit_TinyUSB.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+extern "C" {
+
+void TinyUSB_Device_Init(uint8_t rhport) {
+  // Init USB Device controller and stack
+  USBDevice.begin(rhport);
+}
+
+// RP2040 has its own implementation since it needs mutex for dual core
+#ifndef ARDUINO_ARCH_RP2040
+void TinyUSB_Device_Task(void) {
+  // Run tinyusb device task
+  tud_task();
+}
+#endif
+
+void TinyUSB_Device_FlushCDC(void) {
+  uint8_t const cdc_instance = Adafruit_USBD_CDC::getInstanceCount();
+  for (uint8_t instance = 0; instance < cdc_instance; instance++) {
+    tud_cdc_n_write_flush(instance);
+  }
+}
+
+} // extern C
+
+#endif
diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_TinyUSB_API.h b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_TinyUSB_API.h
new file mode 100644
index 00000000000..51b203b120e
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_TinyUSB_API.h
@@ -0,0 +1,72 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ADAFRUIT_TINYUSB_API_H_
+#define ADAFRUIT_TINYUSB_API_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+//--------------------------------------------------------------------+
+// Core API
+// Should be called by BSP Core to initialize, process task
+// Weak function allow compile arduino core before linking with this library
+//--------------------------------------------------------------------+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Called by core/sketch to initialize usb device hardware and stack
+// This also initialize Serial as CDC device
+void TinyUSB_Device_Init(uint8_t rhport) __attribute__((weak));
+
+// Called by core/sketch to handle device event
+void TinyUSB_Device_Task(void) __attribute__((weak));
+
+// Called by core/sketch to flush write on CDC
+void TinyUSB_Device_FlushCDC(void) __attribute__((weak));
+
+#ifdef __cplusplus
+}
+#endif
+
+//--------------------------------------------------------------------+
+// Port API
+// Must be implemented by each BSP core/platform
+//--------------------------------------------------------------------+
+
+// To enter/reboot to bootloader
+// usually when host disconnects cdc at baud 1200 (touch 1200)
+void TinyUSB_Port_EnterDFU(void);
+
+// Init device hardware.
+// Called by TinyUSB_Device_Init()
+void TinyUSB_Port_InitDevice(uint8_t rhport);
+
+// Get unique serial number, needed for Serial String Descriptor
+// Fill serial_id (raw bytes) and return its length (limit to 16 bytes)
+// Note: Serial descriptor can be overwritten by user API
+uint8_t TinyUSB_Port_GetSerialNumber(uint8_t serial_id[16]);
+
+#endif
diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_CDC.cpp b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_CDC.cpp
new file mode 100644
index 00000000000..8beadc635f1
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_CDC.cpp
@@ -0,0 +1,253 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "tusb_option.h"
+
+#if TUSB_OPT_DEVICE_ENABLED && CFG_TUD_CDC
+
+#include "Arduino.h"
+
+#include "Adafruit_TinyUSB_API.h"
+
+#include "Adafruit_USBD_CDC.h"
+#include "Adafruit_USBD_Device.h"
+
+// Starting endpoints; adjusted elsewhere as needed
+#define EPOUT 0x00
+#define EPIN 0x80
+
+// SerialTinyUSB can be macro expanding to "Serial" on supported cores
+Adafruit_USBD_CDC SerialTinyUSB;
+
+//------------- Static member -------------//
+uint8_t Adafruit_USBD_CDC::_instance_count = 0;
+
+uint8_t Adafruit_USBD_CDC::getInstanceCount(void) { return _instance_count; }
+
+Adafruit_USBD_CDC::Adafruit_USBD_CDC(void) { _instance = INVALID_INSTANCE; }
+
+uint16_t Adafruit_USBD_CDC::getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf,
+                                                   uint16_t bufsize) {
+  // CDC is mostly always existed for DFU
+  // usb core will automatically update endpoint number
+  uint8_t desc[] = {TUD_CDC_DESCRIPTOR(itfnum, 0, EPIN, 8, EPOUT, EPIN, 64)};
+  uint16_t const len = sizeof(desc);
+
+  if (bufsize < len) {
+    return 0;
+  }
+
+  memcpy(buf, desc, len);
+  return len;
+}
+
+// Baud and config is ignore in CDC
+void Adafruit_USBD_CDC::begin(uint32_t baud) {
+  (void)baud;
+
+  // already called begin()
+  if (isValid()) {
+    return;
+  }
+
+  // too many instances
+  if (!(_instance_count < CFG_TUD_CDC)) {
+    return;
+  }
+
+  _instance = _instance_count++;
+  this->setStringDescriptor("TinyUSB Serial");
+  USBDevice.addInterface(*this);
+}
+
+void Adafruit_USBD_CDC::begin(uint32_t baud, uint8_t config) {
+  (void)config;
+  this->begin(baud);
+}
+
+void Adafruit_USBD_CDC::end(void) {
+  // Reset configuration descriptor without Serial as CDC
+  USBDevice.clearConfiguration();
+  _instance_count = 0;
+}
+
+uint32_t Adafruit_USBD_CDC::baud(void) {
+  if (!isValid()) {
+    return 0;
+  }
+
+  cdc_line_coding_t coding;
+  tud_cdc_n_get_line_coding(_instance, &coding);
+
+  return coding.bit_rate;
+}
+
+uint8_t Adafruit_USBD_CDC::stopbits(void) {
+  if (!isValid()) {
+    return 0;
+  }
+
+  cdc_line_coding_t coding;
+  tud_cdc_n_get_line_coding(_instance, &coding);
+
+  return coding.stop_bits;
+}
+
+uint8_t Adafruit_USBD_CDC::paritytype(void) {
+  if (!isValid()) {
+    return 0;
+  }
+
+  cdc_line_coding_t coding;
+  tud_cdc_n_get_line_coding(_instance, &coding);
+
+  return coding.parity;
+}
+
+uint8_t Adafruit_USBD_CDC::numbits(void) {
+  if (!isValid()) {
+    return 0;
+  }
+
+  cdc_line_coding_t coding;
+  tud_cdc_n_get_line_coding(_instance, &coding);
+
+  return coding.data_bits;
+}
+
+int Adafruit_USBD_CDC::dtr(void) {
+  if (!isValid()) {
+    return 0;
+  }
+
+  return tud_cdc_n_connected(_instance);
+}
+
+Adafruit_USBD_CDC::operator bool() {
+  if (!isValid()) {
+    return false;
+  }
+
+  bool ret = tud_cdc_n_connected(_instance);
+
+  // Add an yield to run usb background in case sketch block wait as follows
+  // while( !Serial ) {}
+  if (!ret) {
+    yield();
+  }
+  return ret;
+}
+
+int Adafruit_USBD_CDC::available(void) {
+  if (!isValid()) {
+    return 0;
+  }
+
+  uint32_t count = tud_cdc_n_available(_instance);
+
+  // Add an yield to run usb background in case sketch block wait as follows
+  // while( !Serial.available() ) {}
+  if (!count) {
+    yield();
+  }
+
+  return count;
+}
+
+int Adafruit_USBD_CDC::peek(void) {
+  if (!isValid()) {
+    return -1;
+  }
+
+  uint8_t ch;
+  return tud_cdc_n_peek(_instance, &ch) ? (int)ch : -1;
+}
+
+int Adafruit_USBD_CDC::read(void) {
+  if (!isValid()) {
+    return -1;
+  }
+  return (int)tud_cdc_n_read_char(_instance);
+}
+
+void Adafruit_USBD_CDC::flush(void) {
+  if (!isValid()) {
+    return;
+  }
+
+  tud_cdc_n_write_flush(_instance);
+}
+
+size_t Adafruit_USBD_CDC::write(uint8_t ch) { return write(&ch, 1); }
+
+size_t Adafruit_USBD_CDC::write(const uint8_t *buffer, size_t size) {
+  if (!isValid()) {
+    return 0;
+  }
+
+  size_t remain = size;
+  while (remain && tud_cdc_n_connected(_instance)) {
+    size_t wrcount = tud_cdc_n_write(_instance, buffer, remain);
+    remain -= wrcount;
+    buffer += wrcount;
+
+    // Write FIFO is full, run usb background to flush
+    if (remain) {
+      yield();
+    }
+  }
+
+  return size - remain;
+}
+
+int Adafruit_USBD_CDC::availableForWrite(void) {
+  if (!isValid()) {
+    return 0;
+  }
+  return tud_cdc_n_write_available(_instance);
+}
+
+extern "C" {
+
+// Invoked when cdc when line state changed e.g connected/disconnected
+// Use to reset to DFU when disconnect with 1200 bps
+void tud_cdc_line_state_cb(uint8_t instance, bool dtr, bool rts) {
+  (void)rts;
+
+  // DTR = false is counted as disconnected
+  if (!dtr) {
+    // touch1200 only with first CDC instance (Serial)
+    if (instance == 0) {
+      cdc_line_coding_t coding;
+      tud_cdc_get_line_coding(&coding);
+
+      if (coding.bit_rate == 1200) {
+        TinyUSB_Port_EnterDFU();
+      }
+    }
+  }
+}
+}
+
+#endif // TUSB_OPT_DEVICE_ENABLED
diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_CDC.h b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_CDC.h
new file mode 100644
index 00000000000..7c8f1f65131
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_CDC.h
@@ -0,0 +1,98 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ADAFRUIT_USBD_CDC_H_
+#define ADAFRUIT_USBD_CDC_H_
+
+#include "Adafruit_TinyUSB_API.h"
+
+#ifdef __cplusplus
+
+#include "Adafruit_USBD_Interface.h"
+#include "Stream.h"
+
+class Adafruit_USBD_CDC : public Stream, public Adafruit_USBD_Interface {
+public:
+  Adafruit_USBD_CDC(void);
+
+  static uint8_t getInstanceCount(void);
+
+  // fron Adafruit_USBD_Interface
+  virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf,
+                                          uint16_t bufsize);
+
+  void setPins(uint8_t pin_rx, uint8_t pin_tx) {
+    (void)pin_rx;
+    (void)pin_tx;
+  }
+  void begin(uint32_t baud);
+  void begin(uint32_t baud, uint8_t config);
+  void end(void);
+
+  // return line coding set by host
+  uint32_t baud(void);
+  uint8_t stopbits(void);
+  uint8_t paritytype(void);
+  uint8_t numbits(void);
+  int dtr(void);
+
+  // Stream API
+  virtual int available(void);
+  virtual int peek(void);
+  virtual int read(void);
+  virtual void flush(void);
+  virtual size_t write(uint8_t);
+
+  virtual size_t write(const uint8_t *buffer, size_t size);
+  size_t write(const char *buffer, size_t size) {
+    return write((const uint8_t *)buffer, size);
+  }
+
+  virtual int availableForWrite(void);
+  using Print::write; // pull in write(str) from Print
+  operator bool();
+
+private:
+  enum { INVALID_INSTANCE = 0xffu };
+  static uint8_t _instance_count;
+
+  uint8_t _instance;
+
+  bool isValid(void) { return _instance != INVALID_INSTANCE; }
+};
+
+// "Serial" is used with TinyUSB CDC
+#if defined(USE_TINYUSB) &&                                                    \
+    !(defined(ARDUINO_ARCH_ESP32) && ARDUINO_SERIAL_PORT == 0)
+extern Adafruit_USBD_CDC Serial;
+#define SerialTinyUSB Serial
+#endif
+
+// Serial is probably used with HW Uart
+#ifndef SerialTinyUSB
+extern Adafruit_USBD_CDC SerialTinyUSB;
+#endif
+
+#endif // __cplusplus
+#endif
diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_Device.cpp b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_Device.cpp
new file mode 100644
index 00000000000..6ad4f127e7a
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_Device.cpp
@@ -0,0 +1,480 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "tusb_option.h"
+
+#if TUSB_OPT_DEVICE_ENABLED
+
+#include "Adafruit_TinyUSB_API.h"
+
+#include "Adafruit_USBD_CDC.h"
+#include "Adafruit_USBD_Device.h"
+
+// USB Information can be defined in variant file e.g pins_arduino.h
+#include "Arduino.h"
+
+#ifndef USB_VID
+#define USB_VID 0xcafe
+#endif
+
+#ifndef USB_PID
+#define USB_PID 0xcafe
+#endif
+
+#ifndef USB_MANUFACTURER
+#define USB_MANUFACTURER "Unknown"
+#endif
+
+#ifndef USB_PRODUCT
+#define USB_PRODUCT "Unknown"
+#endif
+
+#ifndef USB_LANGUAGE
+#define USB_LANGUAGE 0x0409 // default is English
+#endif
+
+#ifndef USB_CONFIG_POWER
+#define USB_CONFIG_POWER 100
+#endif
+
+enum { STRID_LANGUAGE = 0, STRID_MANUFACTURER, STRID_PRODUCT, STRID_SERIAL };
+
+Adafruit_USBD_Device USBDevice;
+
+Adafruit_USBD_Device::Adafruit_USBD_Device(void) {}
+
+void Adafruit_USBD_Device::clearConfiguration(void) {
+  tusb_desc_device_t const desc_dev = {.bLength = sizeof(tusb_desc_device_t),
+                                       .bDescriptorType = TUSB_DESC_DEVICE,
+                                       .bcdUSB = 0x0200,
+                                       .bDeviceClass = 0,
+                                       .bDeviceSubClass = 0,
+                                       .bDeviceProtocol = 0,
+                                       .bMaxPacketSize0 =
+                                           CFG_TUD_ENDPOINT0_SIZE,
+                                       .idVendor = USB_VID,
+                                       .idProduct = USB_PID,
+                                       .bcdDevice = 0x0100,
+                                       .iManufacturer = STRID_MANUFACTURER,
+                                       .iProduct = STRID_PRODUCT,
+                                       .iSerialNumber = STRID_SERIAL,
+                                       .bNumConfigurations = 0x01};
+
+  _desc_device = desc_dev;
+
+  // Config number, interface count, string index, total length,
+  // attribute (bit 7 set to 1), power in mA.
+  // Note: Total Length Interface Number will be updated later
+  uint8_t const dev_cfg[sizeof(tusb_desc_configuration_t)] = {
+      TUD_CONFIG_DESCRIPTOR(1, 0, 0, sizeof(tusb_desc_configuration_t),
+                            TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP | TU_BIT(7),
+                            100),
+  };
+
+  memcpy(_desc_cfg_buffer, dev_cfg, sizeof(tusb_desc_configuration_t));
+  _desc_cfg = _desc_cfg_buffer;
+  _desc_cfg_maxlen = sizeof(_desc_cfg_buffer);
+  _desc_cfg_len = sizeof(tusb_desc_configuration_t);
+
+  _itf_count = 0;
+  _epin_count = _epout_count = 1;
+
+  memset(_desc_str_arr, 0, sizeof(_desc_str_arr));
+  _desc_str_arr[STRID_LANGUAGE] = (const char *)((uint32_t)USB_LANGUAGE);
+  _desc_str_arr[STRID_MANUFACTURER] = USB_MANUFACTURER;
+  _desc_str_arr[STRID_PRODUCT] = USB_PRODUCT;
+  // STRID_SERIAL is platform dependent
+
+  _desc_str_count = 4;
+}
+
+// Add interface descriptor
+// - Interface number will be updated to match current count
+// - Endpoint number is updated to be unique
+bool Adafruit_USBD_Device::addInterface(Adafruit_USBD_Interface &itf) {
+  uint8_t *desc = _desc_cfg + _desc_cfg_len;
+  uint16_t const len = itf.getInterfaceDescriptor(
+      _itf_count, desc, _desc_cfg_maxlen - _desc_cfg_len);
+  uint8_t *desc_end = desc + len;
+
+  const char *desc_str = itf.getStringDescriptor();
+
+  if (!len) {
+    return false;
+  }
+
+  // Parse interface descriptor to update
+  // - Interface Number & string descriptor
+  // - Endpoint address
+  while (desc < desc_end) {
+    if (desc[1] == TUSB_DESC_INTERFACE) {
+      tusb_desc_interface_t *desc_itf = (tusb_desc_interface_t *)desc;
+      if (desc_itf->bAlternateSetting == 0) {
+        _itf_count++;
+        if (desc_str && (_desc_str_count < STRING_DESCRIPTOR_MAX)) {
+          _desc_str_arr[_desc_str_count] = desc_str;
+          desc_itf->iInterface = _desc_str_count;
+          _desc_str_count++;
+
+          // only assign string index to first interface
+          desc_str = NULL;
+        }
+      }
+    } else if (desc[1] == TUSB_DESC_ENDPOINT) {
+      tusb_desc_endpoint_t *desc_ep = (tusb_desc_endpoint_t *)desc;
+      desc_ep->bEndpointAddress |=
+          (desc_ep->bEndpointAddress & 0x80) ? _epin_count++ : _epout_count++;
+    }
+
+    if (desc[0] == 0) {
+      return false;
+    }
+
+    desc += desc[0]; // next
+  }
+
+  _desc_cfg_len += len;
+
+  // Update configuration descriptor
+  tusb_desc_configuration_t *config = (tusb_desc_configuration_t *)_desc_cfg;
+  config->wTotalLength = _desc_cfg_len;
+  config->bNumInterfaces = _itf_count;
+
+  return true;
+}
+
+void Adafruit_USBD_Device::setConfigurationBuffer(uint8_t *buf,
+                                                  uint32_t buflen) {
+  if (buflen < _desc_cfg_maxlen) {
+    return;
+  }
+
+  memcpy(buf, _desc_cfg, _desc_cfg_len);
+  _desc_cfg = buf;
+  _desc_cfg_maxlen = buflen;
+}
+
+void Adafruit_USBD_Device::setID(uint16_t vid, uint16_t pid) {
+  _desc_device.idVendor = vid;
+  _desc_device.idProduct = pid;
+}
+
+void Adafruit_USBD_Device::setVersion(uint16_t bcd) {
+  _desc_device.bcdUSB = bcd;
+}
+
+void Adafruit_USBD_Device::setDeviceVersion(uint16_t bcd) {
+  _desc_device.bcdDevice = bcd;
+}
+
+void Adafruit_USBD_Device::setLanguageDescriptor(uint16_t language_id) {
+  _desc_str_arr[STRID_LANGUAGE] = (const char *)((uint32_t)language_id);
+}
+
+void Adafruit_USBD_Device::setManufacturerDescriptor(const char *s) {
+  _desc_str_arr[STRID_MANUFACTURER] = s;
+}
+
+void Adafruit_USBD_Device::setProductDescriptor(const char *s) {
+  _desc_str_arr[STRID_PRODUCT] = s;
+}
+
+uint8_t Adafruit_USBD_Device::getSerialDescriptor(uint16_t *serial_utf16) {
+  uint8_t serial_id[16] __attribute__((aligned(4)));
+  uint8_t const serial_len = TinyUSB_Port_GetSerialNumber(serial_id);
+
+  for (uint8_t i = 0; i < serial_len; i++) {
+    for (uint8_t j = 0; j < 2; j++) {
+      const char nibble_to_hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
+                                      '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+      uint8_t nibble = (serial_id[i] >> (j * 4)) & 0xf;
+      serial_utf16[1 + i * 2 + (1 - j)] = nibble_to_hex[nibble]; // UTF-16-LE
+    }
+  }
+
+  return 2 * serial_len;
+}
+
+bool Adafruit_USBD_Device::begin(uint8_t rhport) {
+  clearConfiguration();
+
+  // Serial is always added by default
+  // Use Interface Association Descriptor (IAD) for CDC
+  // As required by USB Specs IAD's subclass must be common class (2) and
+  // protocol must be IAD (1)
+  _desc_device.bDeviceClass = TUSB_CLASS_MISC;
+  _desc_device.bDeviceSubClass = MISC_SUBCLASS_COMMON;
+  _desc_device.bDeviceProtocol = MISC_PROTOCOL_IAD;
+
+  SerialTinyUSB.begin(115200);
+
+  // Init device hardware and call tusb_init()
+  TinyUSB_Port_InitDevice(rhport);
+
+  return true;
+}
+
+void Adafruit_USBD_Device::task(void) { tud_task(); }
+
+bool Adafruit_USBD_Device::mounted(void) { return tud_mounted(); }
+
+bool Adafruit_USBD_Device::suspended(void) { return tud_suspended(); }
+
+bool Adafruit_USBD_Device::ready(void) { return tud_ready(); }
+
+bool Adafruit_USBD_Device::remoteWakeup(void) { return tud_remote_wakeup(); }
+
+bool Adafruit_USBD_Device::detach(void) { return tud_disconnect(); }
+
+bool Adafruit_USBD_Device::attach(void) { return tud_connect(); }
+
+static int strcpy_utf16(const char *s, uint16_t *buf, int bufsize);
+uint16_t const *Adafruit_USBD_Device::descriptor_string_cb(uint8_t index,
+                                                           uint16_t langid) {
+  (void)langid;
+
+  uint8_t chr_count;
+
+  switch (index) {
+  case STRID_LANGUAGE:
+    _desc_str[1] = ((uint16_t)((uint32_t)_desc_str_arr[STRID_LANGUAGE]));
+    chr_count = 1;
+    break;
+
+  case STRID_SERIAL:
+    chr_count = getSerialDescriptor(_desc_str);
+    break;
+
+  default:
+    // Invalid index
+    if (index >= _desc_str_count) {
+      return NULL;
+    }
+
+    chr_count = strcpy_utf16(_desc_str_arr[index], _desc_str + 1, 32);
+    break;
+  }
+
+  // first byte is length (including header), second byte is string type
+  _desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * chr_count + 2);
+
+  return _desc_str;
+}
+
+//--------------------------------------------------------------------+
+// TinyUSB stack callbacks
+//--------------------------------------------------------------------+
+extern "C" {
+
+// Invoked when received GET DEVICE DESCRIPTOR
+// Application return pointer to descriptor
+uint8_t const *tud_descriptor_device_cb(void) {
+  return (uint8_t const *)&USBDevice._desc_device;
+}
+
+// Invoked when received GET CONFIGURATION DESCRIPTOR
+// Application return pointer to descriptor, whose contents must exist long
+// enough for transfer to complete
+uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
+  (void)index;
+  return USBDevice._desc_cfg;
+}
+
+// Invoked when received GET STRING DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long
+// enough for transfer to complete Note: the 0xEE index string is a Microsoft
+// OS 1.0 Descriptors.
+// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
+uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
+  return USBDevice.descriptor_string_cb(index, langid);
+}
+
+} // extern C
+
+//--------------------------------------------------------------------+
+// Helper
+//--------------------------------------------------------------------+
+constexpr static inline bool isInvalidUtf8Octet(uint8_t t) {
+  // see bullets in https://tools.ietf.org/html/rfc3629#section-1
+  return (t == 0xc0) || (t == 0xC1) || (t >= 0xF5);
+}
+
+//
+// This function has an UNWRITTEN CONTRACT that the buffer is either:
+// 1. Pre-validated as legal UTF-8, -OR-
+// 2. has a trailing zero-value octet/byte/uint8_t  (aka null-terminated string)
+//
+// If the above are not true, this decoder may read past the end of the
+// allocated buffer, by up to three bytes.
+//
+// U+1F47F == 👿 ("IMP")
+//         == 0001_1111_0100_0111_1111 ==> requires four-byte encoding in UTF-8
+//            AABB BBBB CCCC CCDD DDDD ==> 0xF0 0x9F 0x91 0xBF
+//
+// Example sandwich and safety variables are there to cover the
+// two most-common stack layouts for declared variables, in unoptimized
+// code, so that the bytes surrounding those allocated for 'evilUTF8'
+// are guaranteed to be non-zero and valid UTF8 continuation octets.
+//     uint8_t safety1      = 0;
+//     uint8_t sandwich1[4] = { 0x81, 0x82, 0x83, 0x84 };
+//     uint8_t evilUTF8[5]  = { 0xF0, 0x9F, 0x91, 0xBF, 0xF9 };
+//     uint8_t sandwich2[4] = { 0x85, 0x86, 0x87, 0x88 };
+//     uint8_t safety2      = 0;
+//
+// NOTE: evilUTF8 could just contain a single byte 0xF9 ....
+//
+// Attempting to decode evilUTF8 will progress to whatever is next to it on the
+// stack. The above should work when optimizations are turned
+//
+static int8_t utf8Codepoint(const uint8_t *utf8, uint32_t *codepointp) {
+  const uint32_t CODEPOINT_LOWEST_SURROGATE_HALF = 0xD800;
+  const uint32_t CODEPOINT_HIGHEST_SURROGATE_HALF = 0xDFFF;
+
+  *codepointp = 0xFFFD; // always initialize output to known value ... 0xFFFD
+                        // (REPLACEMENT CHARACTER) seems the natural choice
+  uint32_t codepoint;
+  int len;
+
+  // The upper bits define both the length of additional bytes for the
+  // multi-byte encoding, as well as defining how many bits of the first byte
+  // are included in the codepoint. Each additional byte starts with 0b10xxxxxx,
+  // encoding six additional bits for the codepoint.
+  //
+  // For key summary points, see:
+  // * https://tools.ietf.org/html/rfc3629#section-3
+  //
+  if (isInvalidUtf8Octet(utf8[0])) {
+    // do not allow illegal octet sequences (e.g., 0xC0 0x80
+    // should NOT decode to NULL)
+    return -1;
+  }
+
+  if (utf8[0] < 0x80) {
+    // characters 0000 0000..0000 007F (up to  7 significant bits)
+    len = 1;
+    codepoint = utf8[0];
+  } else if ((utf8[0] & 0xe0) == 0xc0) {
+    // characters 0000 0080..0000 07FF
+    // (up to 11 significant bits, so first byte encodes five bits)
+    len = 2;
+    codepoint = utf8[0] & 0x1f;
+  } else if ((utf8[0] & 0xf0) == 0xe0) {
+    // characters 0000 8000..0000 FFFF
+    // (up to 16 significant bits, so first byte encodes four bits)
+    len = 3;
+    codepoint = utf8[0] & 0x0f;
+  } else if ((utf8[0] & 0xf8) == 0xf0) {
+    // characters 0001 0000..0010 FFFF
+    // (up to 21 significantbits, so first byte encodes three bits)
+    len = 4;
+    codepoint = utf8[0] & 0x07;
+  } else {
+    // UTF-8 is defined to only map to Unicode -- 0x00000000..0x0010FFFF
+    // 5-byte and 6-byte sequences are not legal per RFC3629
+    return -1;
+  }
+
+  for (int i = 1; i < len; i++) {
+    if ((utf8[i] & 0xc0) != 0x80) {
+      // the additional bytes in a valid UTF-8 multi-byte encoding cannot have
+      // either of the top two bits set This is more restrictive than
+      // isInvalidUtf8Octet()
+      return -1;
+    }
+    codepoint <<= 6; // each continuation byte adds six bits to the codepoint
+    codepoint |= utf8[i] & 0x3f; // mask off the top two continuation bits, and
+                                 // add the six relevant bits
+  }
+
+  // explicit validation to prevent overlong encodings
+  if ((len == 1) && (codepoint > 0x00007F)) {
+    return -1;
+  } else if ((len == 2) && ((codepoint < 0x000080) || (codepoint > 0x0007FF))) {
+    return -1;
+  } else if ((len == 3) && ((codepoint < 0x000800) || (codepoint > 0x00FFFF))) {
+    return -1;
+  } else if ((len == 4) && ((codepoint < 0x010000) || (codepoint > 0x10FFFF))) {
+    // "You might expect larger code points than U+10FFFF
+    // to be expressible, but Unicode is limited in Sections 12
+    // of RFC3629 to match the limits of UTF-16." -- Wikipedia UTF-8 note
+    // See https://tools.ietf.org/html/rfc3629#section-12
+    return -1;
+  }
+
+  // high and low surrogate halves (U+D800 through U+DFFF) used by UTF-16 are
+  // not legal Unicode values ... see RFC 3629.
+  if ((codepoint >= CODEPOINT_LOWEST_SURROGATE_HALF) &&
+      (codepoint <= CODEPOINT_HIGHEST_SURROGATE_HALF)) {
+    return -1;
+  }
+
+  *codepointp = codepoint;
+  return len;
+}
+
+static int strcpy_utf16(const char *s, uint16_t *buf, int bufsize) {
+  int i = 0;
+  int buflen = 0;
+
+  while (s[i] != 0) {
+    uint32_t codepoint;
+    int8_t utf8len = utf8Codepoint((const uint8_t *)s + i, &codepoint);
+
+    if (utf8len < 0) {
+      // Invalid utf8 sequence, skip it
+      i++;
+      continue;
+    }
+
+    i += utf8len;
+
+    if (codepoint <= 0xffff) {
+      if (buflen == bufsize)
+        break;
+
+      buf[buflen++] = codepoint;
+
+    } else {
+      if (buflen + 1 >= bufsize)
+        break;
+
+      // Surrogate pair
+      codepoint -= 0x10000;
+      buf[buflen++] = (codepoint >> 10) + 0xd800;
+      buf[buflen++] = (codepoint & 0x3ff) + 0xdc00;
+    }
+  }
+
+  return buflen;
+}
+
+// TODO just for compiling, will move to DFU specific file
+#if CFG_TUD_DFU_RUNTIME
+void tud_dfu_runtime_reboot_to_dfu_cb(void) {
+  // TinyUSB_Port_EnterDFU();
+}
+#endif
+
+#endif // TUSB_OPT_DEVICE_ENABLED
diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_Device.h b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_Device.h
new file mode 100644
index 00000000000..c061afeca0e
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_Device.h
@@ -0,0 +1,112 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ADAFRUIT_USBD_DEVICE_H_
+#define ADAFRUIT_USBD_DEVICE_H_
+
+#include "Adafruit_USBD_Interface.h"
+#include "tusb.h"
+
+class Adafruit_USBD_Device {
+private:
+  enum { STRING_DESCRIPTOR_MAX = 8 };
+
+  // Device descriptor
+  tusb_desc_device_t _desc_device __attribute__((aligned(4)));
+
+  // Configuration descriptor
+  uint8_t *_desc_cfg;
+  uint8_t _desc_cfg_buffer[256];
+  uint16_t _desc_cfg_len;
+  uint16_t _desc_cfg_maxlen;
+
+  uint8_t _itf_count;
+
+  uint8_t _epin_count;
+  uint8_t _epout_count;
+
+  // String descriptor
+  const char *_desc_str_arr[STRING_DESCRIPTOR_MAX];
+  uint8_t _desc_str_count;
+  uint16_t _desc_str[32 + 1]; // up to 32 unicode characters with headers
+
+public:
+  Adafruit_USBD_Device(void);
+
+  //------------- Device descriptor -------------//
+
+  // Set VID, PID
+  void setID(uint16_t vid, uint16_t pid);
+
+  // Set bcdUSB version e.g 1.0, 2.0, 2.1
+  void setVersion(uint16_t bcd);
+
+  // Set bcdDevice version
+  void setDeviceVersion(uint16_t bcd);
+
+  //------------- Configuration descriptor -------------//
+
+  // Add an new interface
+  bool addInterface(Adafruit_USBD_Interface &itf);
+
+  // Clear/Reset configuration descriptor
+  void clearConfiguration(void);
+
+  // Provide user buffer for configuration descriptor, needed if total length >
+  // 256
+  void setConfigurationBuffer(uint8_t *buf, uint32_t buflen);
+
+  //------------- String descriptor -------------//
+  void setLanguageDescriptor(uint16_t language_id);
+  void setManufacturerDescriptor(const char *s);
+  void setProductDescriptor(const char *s);
+  uint8_t getSerialDescriptor(uint16_t *serial_utf16);
+
+  //------------- Control -------------//
+
+  bool begin(uint8_t rhport = 0);
+  void task(void);
+
+  // physical disable/enable pull-up
+  bool detach(void);
+  bool attach(void);
+
+  //------------- status -------------//
+  bool mounted(void);
+  bool suspended(void);
+  bool ready(void);
+  bool remoteWakeup(void);
+
+private:
+  uint16_t const *descriptor_string_cb(uint8_t index, uint16_t langid);
+
+  friend uint8_t const *tud_descriptor_device_cb(void);
+  friend uint8_t const *tud_descriptor_configuration_cb(uint8_t index);
+  friend uint16_t const *tud_descriptor_string_cb(uint8_t index,
+                                                  uint16_t langid);
+};
+
+extern Adafruit_USBD_Device USBDevice;
+
+#endif /* ADAFRUIT_USBD_DEVICE_H_ */
diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_Interface.h b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_Interface.h
new file mode 100644
index 00000000000..94c14c383f5
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/Adafruit_USBD_Interface.h
@@ -0,0 +1,47 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Ha Thach (tinyusb.org) for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ADAFRUIT_USBD_INTERFACE_H_
+#define ADAFRUIT_USBD_INTERFACE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+class Adafruit_USBD_Interface {
+protected:
+  const char *_desc_str;
+
+public:
+  Adafruit_USBD_Interface(void) { _desc_str = NULL; }
+
+  // Get Interface Descriptor
+  // Device fill descriptor and return its length
+  virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf,
+                                          uint16_t bufsize) = 0;
+
+  void setStringDescriptor(const char *str) { _desc_str = str; }
+  const char *getStringDescriptor(void) { return _desc_str; }
+};
+
+#endif
diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/hid/Adafruit_USBD_HID.cpp b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/hid/Adafruit_USBD_HID.cpp
new file mode 100644
index 00000000000..4a463bc8ea6
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/hid/Adafruit_USBD_HID.cpp
@@ -0,0 +1,241 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "tusb_option.h"
+
+#if TUSB_OPT_DEVICE_ENABLED && CFG_TUD_HID
+
+#include "Adafruit_USBD_HID.h"
+
+#define EPOUT 0x00
+#define EPIN 0x80
+
+uint8_t const _ascii2keycode[128][2] = {HID_ASCII_TO_KEYCODE};
+
+static Adafruit_USBD_HID *_hid_dev = NULL;
+
+//------------- IMPLEMENTATION -------------//
+Adafruit_USBD_HID::Adafruit_USBD_HID(void) {
+  _interval_ms = 10;
+  _protocol = HID_ITF_PROTOCOL_NONE;
+
+  _out_endpoint = false;
+  _mouse_button = 0;
+
+  _desc_report = NULL;
+  _desc_report_len = 0;
+
+  _get_report_cb = NULL;
+  _set_report_cb = NULL;
+}
+
+void Adafruit_USBD_HID::setPollInterval(uint8_t interval_ms) {
+  _interval_ms = interval_ms;
+}
+
+void Adafruit_USBD_HID::setBootProtocol(uint8_t protocol) {
+  _protocol = protocol;
+}
+
+void Adafruit_USBD_HID::enableOutEndpoint(bool enable) {
+  _out_endpoint = enable;
+}
+
+void Adafruit_USBD_HID::setReportDescriptor(uint8_t const *desc_report,
+                                            uint16_t len) {
+  _desc_report = desc_report;
+  _desc_report_len = len;
+}
+
+void Adafruit_USBD_HID::setReportCallback(get_report_callback_t get_report,
+                                          set_report_callback_t set_report) {
+  _get_report_cb = get_report;
+  _set_report_cb = set_report;
+}
+
+uint16_t Adafruit_USBD_HID::getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf,
+                                                   uint16_t bufsize) {
+  if (!_desc_report_len) {
+    return 0;
+  }
+
+  // usb core will automatically update endpoint number
+  uint8_t const desc_inout[] = {
+      TUD_HID_INOUT_DESCRIPTOR(itfnum, 0, _protocol, _desc_report_len, EPIN,
+                               EPOUT, CFG_TUD_HID_EP_BUFSIZE, _interval_ms)};
+  uint8_t const desc_in_only[] = {
+      TUD_HID_DESCRIPTOR(itfnum, 0, _protocol, _desc_report_len, EPIN,
+                         CFG_TUD_HID_EP_BUFSIZE, _interval_ms)};
+
+  uint8_t const *desc;
+  uint16_t len;
+
+  if (_out_endpoint) {
+    desc = desc_inout;
+    len = sizeof(desc_inout);
+  } else {
+    desc = desc_in_only;
+    len = sizeof(desc_in_only);
+  }
+
+  if (bufsize < len) {
+    return 0;
+  }
+
+  memcpy(buf, desc, len);
+  return len;
+}
+
+bool Adafruit_USBD_HID::begin(void) {
+  if (!USBDevice.addInterface(*this)) {
+    return false;
+  }
+
+  _hid_dev = this;
+  return true;
+}
+
+bool Adafruit_USBD_HID::ready(void) { return tud_hid_ready(); }
+
+bool Adafruit_USBD_HID::sendReport(uint8_t report_id, void const *report,
+                                   uint8_t len) {
+  return tud_hid_report(report_id, report, len);
+}
+
+bool Adafruit_USBD_HID::sendReport8(uint8_t report_id, uint8_t num) {
+  return tud_hid_report(report_id, &num, sizeof(num));
+}
+
+bool Adafruit_USBD_HID::sendReport16(uint8_t report_id, uint16_t num) {
+  return tud_hid_report(report_id, &num, sizeof(num));
+}
+
+bool Adafruit_USBD_HID::sendReport32(uint8_t report_id, uint32_t num) {
+  return tud_hid_report(report_id, &num, sizeof(num));
+}
+
+//------------- TinyUSB callbacks -------------//
+extern "C" {
+
+// Invoked when received GET HID REPORT DESCRIPTOR
+// Application return pointer to descriptor, whose contents must exist long
+// enough for transfer to complete
+uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf) {
+  (void)itf;
+
+  if (!_hid_dev) {
+    return NULL;
+  }
+
+  return _hid_dev->_desc_report;
+}
+
+// Invoked when received GET_REPORT control request
+// Application must fill buffer report's content and return its length.
+// Return zero will cause the stack to STALL request
+uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id,
+                               hid_report_type_t report_type, uint8_t *buffer,
+                               uint16_t reqlen) {
+  (void)itf;
+
+  if (!(_hid_dev && _hid_dev->_get_report_cb)) {
+    return 0;
+  }
+
+  return _hid_dev->_get_report_cb(report_id, report_type, buffer, reqlen);
+}
+
+// Invoked when received SET_REPORT control request or
+// received data on OUT endpoint ( Report ID = 0, Type = 0 )
+void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id,
+                           hid_report_type_t report_type, uint8_t const *buffer,
+                           uint16_t bufsize) {
+  (void)itf;
+
+  if (!(_hid_dev && _hid_dev->_set_report_cb)) {
+    return;
+  }
+
+  _hid_dev->_set_report_cb(report_id, report_type, buffer, bufsize);
+}
+
+} // extern "C"
+
+//--------------------------------------------------------------------+
+// Keyboard
+//--------------------------------------------------------------------+
+
+bool Adafruit_USBD_HID::keyboardReport(uint8_t report_id, uint8_t modifier,
+                                       uint8_t keycode[6]) {
+  return tud_hid_keyboard_report(report_id, modifier, keycode);
+}
+
+bool Adafruit_USBD_HID::keyboardPress(uint8_t report_id, char ch) {
+  uint8_t keycode[6] = {0};
+  uint8_t modifier = 0;
+  uint8_t uch = (uint8_t)ch;
+
+  if (_ascii2keycode[uch][0]) {
+    modifier = KEYBOARD_MODIFIER_LEFTSHIFT;
+  }
+  keycode[0] = _ascii2keycode[uch][1];
+
+  return tud_hid_keyboard_report(report_id, modifier, keycode);
+}
+
+bool Adafruit_USBD_HID::keyboardRelease(uint8_t report_id) {
+  return tud_hid_keyboard_report(report_id, 0, NULL);
+}
+
+//--------------------------------------------------------------------+
+// Mouse
+//--------------------------------------------------------------------+
+
+bool Adafruit_USBD_HID::mouseReport(uint8_t report_id, uint8_t buttons,
+                                    int8_t x, int8_t y, int8_t vertical,
+                                    int8_t horizontal) {
+  // cache mouse button for other API such as move, scroll
+  _mouse_button = buttons;
+
+  return tud_hid_mouse_report(report_id, buttons, x, y, vertical, horizontal);
+}
+
+bool Adafruit_USBD_HID::mouseMove(uint8_t report_id, int8_t x, int8_t y) {
+  return tud_hid_mouse_report(report_id, _mouse_button, x, y, 0, 0);
+}
+
+bool Adafruit_USBD_HID::mouseScroll(uint8_t report_id, int8_t scroll,
+                                    int8_t pan) {
+  return tud_hid_mouse_report(report_id, _mouse_button, 0, 0, scroll, pan);
+}
+
+bool Adafruit_USBD_HID::mouseButtonPress(uint8_t report_id, uint8_t buttons) {
+  return tud_hid_mouse_report(report_id, buttons, 0, 0, 0, 0);
+}
+
+bool Adafruit_USBD_HID::mouseButtonRelease(uint8_t report_id) {
+  return tud_hid_mouse_report(report_id, 0, 0, 0, 0, 0);
+}
+
+#endif // TUSB_OPT_DEVICE_ENABLED
diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/hid/Adafruit_USBD_HID.h b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/hid/Adafruit_USBD_HID.h
new file mode 100644
index 00000000000..90be492d758
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/hid/Adafruit_USBD_HID.h
@@ -0,0 +1,97 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ADAFRUIT_USBD_HID_H_
+#define ADAFRUIT_USBD_HID_H_
+
+#include "arduino/Adafruit_USBD_Device.h"
+
+class Adafruit_USBD_HID : public Adafruit_USBD_Interface {
+public:
+  typedef uint16_t (*get_report_callback_t)(uint8_t report_id,
+                                            hid_report_type_t report_type,
+                                            uint8_t *buffer, uint16_t reqlen);
+  typedef void (*set_report_callback_t)(uint8_t report_id,
+                                        hid_report_type_t report_type,
+                                        uint8_t const *buffer,
+                                        uint16_t bufsize);
+
+  Adafruit_USBD_HID(void);
+
+  void setPollInterval(uint8_t interval_ms);
+  void setBootProtocol(uint8_t protocol); // 0: None, 1: Keyboard, 2:Mouse
+  void enableOutEndpoint(bool enable);
+  void setReportDescriptor(uint8_t const *desc_report, uint16_t len);
+  void setReportCallback(get_report_callback_t get_report,
+                         set_report_callback_t set_report);
+
+  bool begin(void);
+
+  bool ready(void);
+  bool sendReport(uint8_t report_id, void const *report, uint8_t len);
+
+  // Report helpers
+  bool sendReport8(uint8_t report_id, uint8_t num);
+  bool sendReport16(uint8_t report_id, uint16_t num);
+  bool sendReport32(uint8_t report_id, uint32_t num);
+
+  //------------- Keyboard API -------------//
+  bool keyboardReport(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]);
+  bool keyboardPress(uint8_t report_id, char ch);
+  bool keyboardRelease(uint8_t report_id);
+
+  //------------- Mouse API -------------//
+  bool mouseReport(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y,
+                   int8_t vertical, int8_t horizontal);
+  bool mouseMove(uint8_t report_id, int8_t x, int8_t y);
+  bool mouseScroll(uint8_t report_id, int8_t scroll, int8_t pan);
+  bool mouseButtonPress(uint8_t report_id, uint8_t buttons);
+  bool mouseButtonRelease(uint8_t report_id);
+
+  // from Adafruit_USBD_Interface
+  virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf,
+                                          uint16_t bufsize);
+
+private:
+  uint8_t _interval_ms;
+  uint8_t _protocol;
+  bool _out_endpoint;
+  uint8_t _mouse_button;
+
+  uint16_t _desc_report_len;
+  uint8_t const *_desc_report;
+
+  get_report_callback_t _get_report_cb;
+  set_report_callback_t _set_report_cb;
+
+  friend uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id,
+                                        hid_report_type_t report_type,
+                                        uint8_t *buffer, uint16_t reqlen);
+  friend void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id,
+                                    hid_report_type_t report_type,
+                                    uint8_t const *buffer, uint16_t bufsize);
+  friend uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf);
+};
+
+#endif /* ADAFRUIT_USBD_HID_H_ */
diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/midi/Adafruit_USBD_MIDI.cpp b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/midi/Adafruit_USBD_MIDI.cpp
new file mode 100644
index 00000000000..7a6b91761f0
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/midi/Adafruit_USBD_MIDI.cpp
@@ -0,0 +1,129 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 hathach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "tusb_option.h"
+
+#if TUSB_OPT_DEVICE_ENABLED && CFG_TUD_MIDI
+
+#include "Adafruit_USBD_MIDI.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+#define EPOUT 0x00
+#define EPIN 0x80
+#define EPSIZE 64
+
+Adafruit_USBD_MIDI::Adafruit_USBD_MIDI(void) : _n_cables(1) {}
+
+void Adafruit_USBD_MIDI::setCables(uint8_t n_cables) { _n_cables = n_cables; }
+
+bool Adafruit_USBD_MIDI::begin(void) {
+  if (!USBDevice.addInterface(*this))
+    return false;
+
+  return true;
+}
+
+uint16_t Adafruit_USBD_MIDI::getInterfaceDescriptor(uint8_t itfnum,
+                                                    uint8_t *buf,
+                                                    uint16_t bufsize) {
+  uint16_t len = 0;
+
+  if (bufsize < TUD_MIDI_DESC_HEAD_LEN + TUD_MIDI_DESC_JACK_LEN * _n_cables +
+                    TUD_MIDI_DESC_EP_LEN(_n_cables) * 2)
+    return 0;
+
+  {
+    uint8_t desc[] = {TUD_MIDI_DESC_HEAD(itfnum, 0, _n_cables)};
+    memcpy(buf + len, desc, sizeof(desc));
+    len += sizeof(desc);
+  }
+
+  for (uint8_t i = 1; i <= _n_cables; i++) {
+    uint8_t jack[] = {TUD_MIDI_DESC_JACK(i)};
+    memcpy(buf + len, jack, sizeof(jack));
+    len += sizeof(jack);
+  }
+
+  // Endpoint OUT + jack mapping - usb core will automatically update endpoint
+  // number
+  {
+    uint8_t desc[] = {TUD_MIDI_DESC_EP(EPOUT, EPSIZE, _n_cables)};
+    memcpy(buf + len, desc, sizeof(desc));
+    len += sizeof(desc);
+  }
+
+  for (uint8_t i = 1; i <= _n_cables; i++) {
+    uint8_t jack[] = {TUD_MIDI_JACKID_IN_EMB(i)};
+    memcpy(buf + len, jack, sizeof(jack));
+    len += sizeof(jack);
+  }
+
+  // Endpoint IN + jack mapping - usb core will automatically update endpoint
+  // number
+  {
+    uint8_t desc[] = {TUD_MIDI_DESC_EP(EPIN, EPSIZE, _n_cables)};
+    memcpy(buf + len, desc, sizeof(desc));
+    len += sizeof(desc);
+  }
+
+  for (uint8_t i = 1; i <= _n_cables; i++) {
+    uint8_t jack[] = {TUD_MIDI_JACKID_OUT_EMB(i)};
+    memcpy(buf + len, jack, sizeof(jack));
+    len += sizeof(jack);
+  }
+
+  return len;
+}
+
+int Adafruit_USBD_MIDI::read(void) {
+  uint8_t ch;
+  return tud_midi_stream_read(&ch, 1) ? (int)ch : (-1);
+}
+
+size_t Adafruit_USBD_MIDI::write(uint8_t b) {
+  return tud_midi_stream_write(0, &b, 1);
+}
+
+int Adafruit_USBD_MIDI::available(void) { return tud_midi_available(); }
+
+int Adafruit_USBD_MIDI::peek(void) {
+  // MIDI Library doen't use peek
+  return -1;
+}
+
+void Adafruit_USBD_MIDI::flush(void) {
+  // MIDI Library doen't use flush
+}
+
+bool Adafruit_USBD_MIDI::writePacket(const uint8_t packet[4]) {
+  return tud_midi_packet_write(packet);
+}
+
+bool Adafruit_USBD_MIDI::readPacket(uint8_t packet[4]) {
+  return tud_midi_packet_read(packet);
+}
+
+#endif // TUSB_OPT_DEVICE_ENABLED
diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/midi/Adafruit_USBD_MIDI.h b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/midi/Adafruit_USBD_MIDI.h
new file mode 100644
index 00000000000..4741e8abadf
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/midi/Adafruit_USBD_MIDI.h
@@ -0,0 +1,66 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 hathach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ADAFRUIT_USBD_MIDI_H_
+#define ADAFRUIT_USBD_MIDI_H_
+
+#include "Stream.h"
+#include "arduino/Adafruit_USBD_Device.h"
+
+class Adafruit_USBD_MIDI : public Stream, public Adafruit_USBD_Interface {
+public:
+  Adafruit_USBD_MIDI(void);
+
+  bool begin(void);
+
+  // for MIDI library
+  bool begin(uint32_t baud) {
+    (void)baud;
+    return begin();
+  }
+
+  // Stream interface to use with MIDI Library
+  virtual int read(void);
+  virtual size_t write(uint8_t b);
+  virtual int available(void);
+  virtual int peek(void);
+  virtual void flush(void);
+
+  using Stream::write;
+
+  // Raw MIDI USB packet interface.
+  bool writePacket(const uint8_t packet[4]);
+  bool readPacket(uint8_t packet[4]);
+
+  // from Adafruit_USBD_Interface
+  virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf,
+                                          uint16_t bufsize);
+
+  void setCables(uint8_t n_cables);
+
+private:
+  uint8_t _n_cables;
+};
+
+#endif /* ADAFRUIT_USBD_MIDI_H_ */
diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/msc/Adafruit_USBD_MSC.cpp b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/msc/Adafruit_USBD_MSC.cpp
new file mode 100644
index 00000000000..2b1583031c2
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/msc/Adafruit_USBD_MSC.cpp
@@ -0,0 +1,235 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "tusb_option.h"
+
+#if TUSB_OPT_DEVICE_ENABLED && CFG_TUD_MSC
+
+#include "Adafruit_USBD_MSC.h"
+
+#define EPOUT 0x00
+#define EPIN 0x80
+#define EPSIZE 64 // TODO must be 512 for highspeed device
+
+static Adafruit_USBD_MSC *_msc_dev = NULL;
+
+Adafruit_USBD_MSC::Adafruit_USBD_MSC(void) {
+  _maxlun = 1;
+  memset(_lun, 0, sizeof(_lun));
+}
+
+uint16_t Adafruit_USBD_MSC::getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf,
+                                                   uint16_t bufsize) {
+  // usb core will automatically update endpoint number
+  uint8_t desc[] = {TUD_MSC_DESCRIPTOR(itfnum, 0, EPOUT, EPIN, EPSIZE)};
+  uint16_t const len = sizeof(desc);
+
+  if (bufsize < len) {
+    return 0;
+  }
+
+  memcpy(buf, desc, len);
+  return len;
+}
+
+void Adafruit_USBD_MSC::setMaxLun(uint8_t maxlun) { _maxlun = maxlun; }
+
+uint8_t Adafruit_USBD_MSC::getMaxLun(void) { return _maxlun; }
+
+void Adafruit_USBD_MSC::setID(uint8_t lun, const char *vendor_id,
+                              const char *product_id, const char *product_rev) {
+  _lun[lun]._inquiry_vid = vendor_id;
+  _lun[lun]._inquiry_pid = product_id;
+  _lun[lun]._inquiry_rev = product_rev;
+}
+
+void Adafruit_USBD_MSC::setCapacity(uint8_t lun, uint32_t block_count,
+                                    uint16_t block_size) {
+  _lun[lun].block_count = block_count;
+  _lun[lun].block_size = block_size;
+}
+
+void Adafruit_USBD_MSC::setUnitReady(uint8_t lun, bool ready) {
+  _lun[lun].unit_ready = ready;
+}
+
+void Adafruit_USBD_MSC::setReadWriteCallback(uint8_t lun, read_callback_t rd_cb,
+                                             write_callback_t wr_cb,
+                                             flush_callback_t fl_cb) {
+  _lun[lun].rd_cb = rd_cb;
+  _lun[lun].wr_cb = wr_cb;
+  _lun[lun].fl_cb = fl_cb;
+}
+
+void Adafruit_USBD_MSC::setReadyCallback(uint8_t lun, ready_callback_t cb) {
+  _lun[lun].ready_cb = cb;
+}
+
+bool Adafruit_USBD_MSC::begin(void) {
+  if (!USBDevice.addInterface(*this)) {
+    return false;
+  }
+
+  _msc_dev = this;
+  return true;
+}
+
+//------------- TinyUSB callbacks -------------//
+extern "C" {
+
+// Invoked to determine max LUN
+uint8_t tud_msc_get_maxlun_cb(void) {
+  if (!_msc_dev) {
+    return 0;
+  }
+  return _msc_dev->getMaxLun();
+}
+
+// Invoked when received SCSI_CMD_INQUIRY
+// Application fill vendor id, product id and revision with string up to 8, 16,
+// 4 characters respectively
+void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8],
+                        uint8_t product_id[16], uint8_t product_rev[4]) {
+  if (!_msc_dev) {
+    return;
+  }
+
+  // If not set use default ID "Adafruit - Mass Storage - 1.0"
+  const char *vid =
+      (_msc_dev->_lun[lun]._inquiry_vid ? _msc_dev->_lun[lun]._inquiry_vid
+                                        : "Adafruit");
+  const char *pid =
+      (_msc_dev->_lun[lun]._inquiry_pid ? _msc_dev->_lun[lun]._inquiry_pid
+                                        : "Mass Storage");
+  const char *rev =
+      (_msc_dev->_lun[lun]._inquiry_rev ? _msc_dev->_lun[lun]._inquiry_rev
+                                        : "1.0");
+
+  memcpy(vendor_id, vid, tu_min32(strlen(vid), 8));
+  memcpy(product_id, pid, tu_min32(strlen(pid), 16));
+  memcpy(product_rev, rev, tu_min32(strlen(rev), 4));
+}
+
+// Invoked when received Test Unit Ready command.
+// return true allowing host to read/write this LUN e.g SD card inserted
+bool tud_msc_test_unit_ready_cb(uint8_t lun) {
+  if (!_msc_dev) {
+    return false;
+  }
+
+  if (_msc_dev->_lun[lun].ready_cb) {
+    _msc_dev->_lun[lun].unit_ready = _msc_dev->_lun[lun].ready_cb();
+  }
+
+  return _msc_dev->_lun[lun].unit_ready;
+}
+
+// Callback invoked to determine disk's size
+void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count,
+                         uint16_t *block_size) {
+  if (!_msc_dev) {
+    return;
+  }
+
+  *block_count = _msc_dev->_lun[lun].block_count;
+  *block_size = _msc_dev->_lun[lun].block_size;
+}
+
+// Callback invoked when received an SCSI command not in built-in list below
+// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
+// - READ10 and WRITE10 has their own callbacks
+int32_t tud_msc_scsi_cb(uint8_t lun, const uint8_t scsi_cmd[16], void *buffer,
+                        uint16_t bufsize) {
+  const void *response = NULL;
+  uint16_t resplen = 0;
+
+  switch (scsi_cmd[0]) {
+  case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
+    // Host is about to read/write etc ... better not to disconnect disk
+    resplen = 0;
+    break;
+
+  default:
+    // Set Sense = Invalid Command Operation
+    tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
+
+    // negative means error -> tinyusb could stall and/or response with failed
+    // status
+    resplen = -1;
+    break;
+  }
+
+  // return len must not larger than bufsize
+  if (resplen > bufsize) {
+    resplen = bufsize;
+  }
+
+  // copy response to stack's buffer if any
+  if (response && resplen) {
+    memcpy(buffer, response, resplen);
+  }
+
+  return resplen;
+}
+
+// Callback invoked when received READ10 command.
+// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
+int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset,
+                          void *buffer, uint32_t bufsize) {
+  (void)offset;
+
+  if (!(_msc_dev && _msc_dev->_lun[lun].rd_cb)) {
+    return -1;
+  }
+
+  return _msc_dev->_lun[lun].rd_cb(lba, buffer, bufsize);
+}
+
+// Callback invoked when received WRITE10 command.
+// Process data in buffer to disk's storage and return number of written bytes
+int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset,
+                           uint8_t *buffer, uint32_t bufsize) {
+  (void)offset;
+
+  if (!(_msc_dev && _msc_dev->_lun[lun].wr_cb)) {
+    return -1;
+  }
+
+  return _msc_dev->_lun[lun].wr_cb(lba, buffer, bufsize);
+}
+
+// Callback invoked when WRITE10 command is completed (status received and
+// accepted by host). used to flush any pending cache.
+void tud_msc_write10_complete_cb(uint8_t lun) {
+  if (!(_msc_dev && _msc_dev->_lun[lun].fl_cb)) {
+    return;
+  }
+
+  // flush pending cache when write10 is complete
+  return _msc_dev->_lun[lun].fl_cb();
+}
+
+} // extern "C"
+
+#endif // TUSB_OPT_DEVICE_ENABLED
diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/msc/Adafruit_USBD_MSC.h b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/msc/Adafruit_USBD_MSC.h
new file mode 100644
index 00000000000..5bd8f062919
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/msc/Adafruit_USBD_MSC.h
@@ -0,0 +1,112 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ADAFRUIT_USBD_MSC_H_
+#define ADAFRUIT_USBD_MSC_H_
+
+#include "arduino/Adafruit_USBD_Device.h"
+
+class Adafruit_USBD_MSC : public Adafruit_USBD_Interface {
+public:
+  typedef int32_t (*read_callback_t)(uint32_t lba, void *buffer,
+                                     uint32_t bufsize);
+  typedef int32_t (*write_callback_t)(uint32_t lba, uint8_t *buffer,
+                                      uint32_t bufsize);
+  typedef void (*flush_callback_t)(void);
+  typedef bool (*ready_callback_t)(void);
+
+  Adafruit_USBD_MSC(void);
+
+  bool begin(void);
+
+  void setMaxLun(uint8_t maxlun);
+  uint8_t getMaxLun(void);
+
+  //------------- Multiple LUN API -------------//
+  void setID(uint8_t lun, const char *vendor_id, const char *product_id,
+             const char *product_rev);
+  void setCapacity(uint8_t lun, uint32_t block_count, uint16_t block_size);
+  void setUnitReady(uint8_t lun, bool ready);
+  void setReadWriteCallback(uint8_t lun, read_callback_t rd_cb,
+                            write_callback_t wr_cb, flush_callback_t fl_cb);
+  void setReadyCallback(uint8_t lun, ready_callback_t cb);
+
+  //------------- Single LUN API -------------//
+  void setID(const char *vendor_id, const char *product_id,
+             const char *product_rev) {
+    setID(0, vendor_id, product_id, product_rev);
+  }
+
+  void setCapacity(uint32_t block_count, uint16_t block_size) {
+    setCapacity(0, block_count, block_size);
+  }
+
+  void setUnitReady(bool ready) { setUnitReady(0, ready); }
+
+  void setReadWriteCallback(read_callback_t rd_cb, write_callback_t wr_cb,
+                            flush_callback_t fl_cb) {
+    setReadWriteCallback(0, rd_cb, wr_cb, fl_cb);
+  }
+
+  void setReadyCallback(ready_callback_t cb) { setReadyCallback(0, cb); }
+
+  // from Adafruit_USBD_Interface
+  virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf,
+                                          uint16_t bufsize);
+
+private:
+  enum { MAX_LUN = 2 };
+  struct {
+    read_callback_t rd_cb;
+    write_callback_t wr_cb;
+    flush_callback_t fl_cb;
+    ready_callback_t ready_cb;
+
+    const char *_inquiry_vid;
+    const char *_inquiry_pid;
+    const char *_inquiry_rev;
+
+    uint32_t block_count;
+    uint16_t block_size;
+    bool unit_ready;
+
+  } _lun[MAX_LUN];
+
+  uint8_t _maxlun;
+
+  // Make all tinyusb callback friend to access private data
+  friend void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8],
+                                 uint8_t product_id[16],
+                                 uint8_t product_rev[4]);
+  friend bool tud_msc_test_unit_ready_cb(uint8_t lun);
+  friend void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count,
+                                  uint16_t *block_size);
+  friend int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset,
+                                   void *buffer, uint32_t bufsize);
+  friend int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset,
+                                    uint8_t *buffer, uint32_t bufsize);
+  friend void tud_msc_write10_complete_cb(uint8_t lun);
+};
+
+#endif /* ADAFRUIT_USBD_MSC_H_ */
diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/ports/esp32/Adafruit_TinyUSB_esp32.cpp b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/ports/esp32/Adafruit_TinyUSB_esp32.cpp
new file mode 100644
index 00000000000..33952bf0360
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/ports/esp32/Adafruit_TinyUSB_esp32.cpp
@@ -0,0 +1,169 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019, hathach for Adafruit
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "tusb_option.h"
+
+#if defined(ARDUINO_ARCH_ESP32) && TUSB_OPT_DEVICE_ENABLED
+
+#include "sdkconfig.h"
+
+#include "soc/soc.h"
+
+#include "soc/efuse_reg.h"
+#include "soc/periph_defs.h"
+#include "soc/rtc_cntl_reg.h"
+
+#include "soc/system_reg.h"
+#include "soc/timer_group_struct.h"
+#include "soc/usb_periph.h"
+#include "soc/usb_reg.h"
+#include "soc/usb_struct.h"
+#include "soc/usb_wrap_reg.h"
+#include "soc/usb_wrap_struct.h"
+
+#include "hal/usb_hal.h"
+
+// compiler error with gpio_ll_get_drive_capability()
+// invalid conversion from 'uint32_t' {aka 'unsigned int'} to 'gpio_drive_cap_t'
+// [-fpermissive] #include "hal/gpio_ll.h"
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+#include "driver/gpio.h"
+#include "driver/periph_ctrl.h"
+
+#include "esp_efuse.h"
+#include "esp_efuse_table.h"
+#include "esp_rom_gpio.h"
+
+#include "esp32-hal.h"
+
+#include "esp32s2/rom/usb/chip_usb_dw_wrapper.h"
+#include "esp32s2/rom/usb/usb_dc.h"
+#include "esp32s2/rom/usb/usb_persist.h"
+
+#include "arduino/Adafruit_TinyUSB_API.h"
+#include "arduino/Adafruit_USBD_Device.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+static void configure_pins(usb_hal_context_t *usb) {
+  for (const usb_iopin_dsc_t *iopin = usb_periph_iopins; iopin->pin != -1;
+       ++iopin) {
+    if ((usb->use_external_phy) || (iopin->ext_phy_only == 0)) {
+      esp_rom_gpio_pad_select_gpio(iopin->pin);
+      if (iopin->is_output) {
+        esp_rom_gpio_connect_out_signal(iopin->pin, iopin->func, false, false);
+      } else {
+        esp_rom_gpio_connect_in_signal(iopin->pin, iopin->func, false);
+        if ((iopin->pin != GPIO_FUNC_IN_LOW) &&
+            (iopin->pin != GPIO_FUNC_IN_HIGH)) {
+          // workaround for compiler error with including "hal/gpio_ll.h"
+          // gpio_ll_input_enable(&GPIO, (gpio_num_t) iopin->pin);
+          PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[iopin->pin]);
+        }
+      }
+      esp_rom_gpio_pad_unhold(iopin->pin);
+    }
+  }
+  if (!usb->use_external_phy) {
+    gpio_set_drive_capability((gpio_num_t)USBPHY_DM_NUM, GPIO_DRIVE_CAP_3);
+    gpio_set_drive_capability((gpio_num_t)USBPHY_DP_NUM, GPIO_DRIVE_CAP_3);
+  }
+}
+
+//--------------------------------------------------------------------+
+// Porting API
+//--------------------------------------------------------------------+
+
+#define USBD_STACK_SZ (4096)
+
+// USB Device Driver task
+// This top level thread processes all usb events and invokes callbacks
+static void usb_device_task(void *param) {
+  (void)param;
+  // RTOS forever loop
+  while (1) {
+    tud_task();
+  }
+}
+
+void TinyUSB_Port_InitDevice(uint8_t rhport) {
+  (void)rhport;
+
+  // Reset USB module
+  periph_module_reset(PERIPH_USB_MODULE);
+  periph_module_enable(PERIPH_USB_MODULE);
+
+  usb_hal_context_t hal = {.use_external_phy = false};
+  usb_hal_init(&hal);
+  configure_pins(&hal);
+
+  // reset core, should be in dcd_esp32sx.c (do that later with more proper
+  // testing)
+  USB0.grstctl |= USB_CSFTRST;
+  while ((USB0.grstctl & USB_CSFTRST) == USB_CSFTRST) {
+  }
+
+  tusb_init();
+
+  // Create a task for tinyusb device stack
+  xTaskCreate(usb_device_task, "usbd", USBD_STACK_SZ, NULL,
+              configMAX_PRIORITIES - 1, NULL);
+}
+
+void TinyUSB_Port_EnterDFU(void) {
+  // Reset to Bootloader
+
+  // Reset USB Core
+  USB0.grstctl |= USB_CSFTRST;
+  while ((USB0.grstctl & USB_CSFTRST) == USB_CSFTRST) {
+  }
+
+  REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT);
+  esp_restart();
+}
+
+uint8_t TinyUSB_Port_GetSerialNumber(uint8_t serial_id[16]) {
+  /* Get the MAC address */
+  const uint32_t mac0 =
+      __builtin_bswap32(REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_0_REG, EFUSE_MAC_0));
+  const uint16_t mac1 = __builtin_bswap16(
+      (uint16_t)REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_1_REG, EFUSE_MAC_1));
+
+  memcpy(serial_id, &mac1, 2);
+  memcpy(serial_id + 2, &mac0, 4);
+
+  return 6;
+}
+
+extern "C" void yield(void) {
+  TinyUSB_Device_FlushCDC();
+  vPortYield();
+}
+
+#endif // USE_TINYUSB
diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/webusb/Adafruit_USBD_WebUSB.cpp b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/webusb/Adafruit_USBD_WebUSB.cpp
new file mode 100644
index 00000000000..9d53bc21f36
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/webusb/Adafruit_USBD_WebUSB.cpp
@@ -0,0 +1,308 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 hathach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "tusb_option.h"
+
+#if TUSB_OPT_DEVICE_ENABLED && CFG_TUD_VENDOR
+
+#include "Adafruit_USBD_WebUSB.h"
+#include "Arduino.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+#define EPOUT 0x00
+#define EPIN 0x80
+#define EPSIZE 64
+
+enum { VENDOR_REQUEST_WEBUSB = 1, VENDOR_REQUEST_MICROSOFT = 2 };
+
+static Adafruit_USBD_WebUSB *_webusb_dev = NULL;
+
+//--------------------------------------------------------------------+
+// BOS Descriptor
+//--------------------------------------------------------------------+
+
+/* Microsoft OS 2.0 registry property descriptor
+Per MS requirements
+https://msdn.microsoft.com/en-us/library/windows/hardware/hh450799(v=vs.85).aspx
+device should create DeviceInterfaceGUIDs. It can be done by driver and
+in case of real PnP solution device should expose MS "Microsoft OS 2.0
+registry property descriptor". Such descriptor can insert any record
+into Windows registry per device/configuration/interface. In our case it
+will insert "DeviceInterfaceGUIDs" multistring property.
+
+GUID is freshly generated and should be OK to use.
+
+https://developers.google.com/web/fundamentals/native-hardware/build-for-webusb/
+(Section Microsoft OS compatibility descriptors)
+*/
+
+#define BOS_TOTAL_LEN                                                          \
+  (TUD_BOS_DESC_LEN + TUD_BOS_WEBUSB_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN)
+
+#define MS_OS_20_DESC_LEN 0xB2
+
+// BOS Descriptor is required for webUSB
+uint8_t const desc_bos[] = {
+    // total length, number of device caps
+    TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2),
+
+    // Vendor Code, iLandingPage
+    TUD_BOS_WEBUSB_DESCRIPTOR(VENDOR_REQUEST_WEBUSB, 1),
+
+    // Microsoft OS 2.0 descriptor
+    TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, VENDOR_REQUEST_MICROSOFT)};
+
+uint8_t const *tud_descriptor_bos_cb(void) { return desc_bos; }
+
+uint8_t desc_ms_os_20[] = {
+    // Set header: length, type, windows version, total length
+    U16_TO_U8S_LE(0x000A), U16_TO_U8S_LE(MS_OS_20_SET_HEADER_DESCRIPTOR),
+    U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(MS_OS_20_DESC_LEN),
+
+    // Configuration subset header: length, type, configuration index, reserved,
+    // configuration total length
+    U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_CONFIGURATION),
+    0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN - 0x0A),
+
+    // Function Subset header: length, type, first interface, reserved, subset
+    // length
+    U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_FUNCTION),
+    0 /*itf num*/, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN - 0x0A - 0x08),
+
+    // MS OS 2.0 Compatible ID descriptor: length, type, compatible ID, sub
+    // compatible ID
+    U16_TO_U8S_LE(0x0014), U16_TO_U8S_LE(MS_OS_20_FEATURE_COMPATBLE_ID), 'W',
+    'I', 'N', 'U', 'S', 'B', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, // sub-compatible
+
+    // MS OS 2.0 Registry property descriptor: length, type
+    U16_TO_U8S_LE(MS_OS_20_DESC_LEN - 0x0A - 0x08 - 0x08 - 0x14),
+    U16_TO_U8S_LE(MS_OS_20_FEATURE_REG_PROPERTY), U16_TO_U8S_LE(0x0007),
+    U16_TO_U8S_LE(0x002A), // wPropertyDataType, wPropertyNameLength and
+                           // PropertyName "DeviceInterfaceGUIDs\0" in UTF-16
+    'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00,
+    'n', 0x00, 't', 0x00, 'e', 0x00, 'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00,
+    'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 0x00,
+    0x00,
+    U16_TO_U8S_LE(0x0050), // wPropertyDataLength
+    // bPropertyData: “{975F44D9-0D08-43FD-8B3E-127CA8AFFF9D}”.
+    '{', 0x00, '9', 0x00, '7', 0x00, '5', 0x00, 'F', 0x00, '4', 0x00, '4', 0x00,
+    'D', 0x00, '9', 0x00, '-', 0x00, '0', 0x00, 'D', 0x00, '0', 0x00, '8', 0x00,
+    '-', 0x00, '4', 0x00, '3', 0x00, 'F', 0x00, 'D', 0x00, '-', 0x00, '8', 0x00,
+    'B', 0x00, '3', 0x00, 'E', 0x00, '-', 0x00, '1', 0x00, '2', 0x00, '7', 0x00,
+    'C', 0x00, 'A', 0x00, '8', 0x00, 'A', 0x00, 'F', 0x00, 'F', 0x00, 'F', 0x00,
+    '9', 0x00, 'D', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00};
+
+TU_VERIFY_STATIC(sizeof(desc_ms_os_20) == MS_OS_20_DESC_LEN, "Incorrect size");
+
+//------------- IMPLEMENTATION -------------//
+
+Adafruit_USBD_WebUSB::Adafruit_USBD_WebUSB(void) {
+  _connected = false;
+  _url = NULL;
+  _linestate_cb = NULL;
+}
+
+bool Adafruit_USBD_WebUSB::begin(void) {
+  if (!USBDevice.addInterface(*this))
+    return false;
+
+  // WebUSB requires to change USB version from 2.0 to 2.1
+  USBDevice.setVersion(0x0210);
+
+  _webusb_dev = this;
+  return true;
+}
+
+bool Adafruit_USBD_WebUSB::setLandingPage(const void *url) {
+  _url = (const uint8_t *)url;
+  return true;
+}
+
+void Adafruit_USBD_WebUSB::setLineStateCallback(linestate_callback_t fp) {
+  _linestate_cb = fp;
+}
+
+uint16_t Adafruit_USBD_WebUSB::getInterfaceDescriptor(uint8_t itfnum,
+                                                      uint8_t *buf,
+                                                      uint16_t bufsize) {
+  // usb core will automatically update endpoint number
+  uint8_t desc[] = {TUD_VENDOR_DESCRIPTOR(itfnum, 0, EPOUT, EPIN, 64)};
+  uint16_t const len = sizeof(desc);
+
+  if (bufsize < len) {
+    return 0;
+  }
+
+  memcpy(buf, desc, len);
+
+  // update the bFirstInterface in MS OS 2.0 descriptor
+  // that is binded to WinUSB driver
+  desc_ms_os_20[0x0a + 0x08 + 4] = itfnum;
+
+  return len;
+}
+
+bool Adafruit_USBD_WebUSB::connected(void) {
+  return tud_vendor_mounted() && _connected;
+}
+
+Adafruit_USBD_WebUSB::operator bool() {
+  // Add an yield to run usb background in case sketch block wait as follows
+  // while( !webusb ) {}
+  if (!connected()) {
+    yield();
+  }
+
+  return connected();
+}
+
+int Adafruit_USBD_WebUSB::available(void) {
+  uint32_t count = tud_vendor_available();
+
+  // Add an yield to run usb background in case sketch block wait as follows
+  // while( !webusb.available() ) {}
+  if (!count) {
+    yield();
+  }
+
+  return count;
+}
+
+int Adafruit_USBD_WebUSB::read(void) {
+  uint8_t ch;
+  return tud_vendor_read(&ch, 1) ? (int)ch : -1;
+}
+
+size_t Adafruit_USBD_WebUSB::write(uint8_t b) { return this->write(&b, 1); }
+
+size_t Adafruit_USBD_WebUSB::write(const uint8_t *buffer, size_t size) {
+  size_t remain = size;
+  while (remain && _connected) {
+    size_t wrcount = tud_vendor_write(buffer, remain);
+    remain -= wrcount;
+    buffer += wrcount;
+
+    // Write FIFO is full, run usb background to flush
+    if (remain) {
+      yield();
+    }
+  }
+
+  return size - remain;
+}
+
+int Adafruit_USBD_WebUSB::peek(void) {
+  uint8_t ch;
+  return tud_vendor_peek(&ch) ? (int)ch : -1;
+}
+
+void Adafruit_USBD_WebUSB::flush(void) {}
+
+extern "C" {
+
+// Invoked when a control transfer occurred on an interface of this class
+// Driver response accordingly to the request and the transfer stage
+// (setup/data/ack) return false to stall control endpoint (e.g unsupported
+// request)
+bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage,
+                                tusb_control_request_t const *request) {
+  if (!_webusb_dev) {
+    return false;
+  }
+
+  // nothing to with DATA & ACK stage
+  if (stage != CONTROL_STAGE_SETUP) {
+    return true;
+  }
+
+  switch (request->bmRequestType_bit.type) {
+  case TUSB_REQ_TYPE_VENDOR:
+    switch (request->bRequest) {
+    case VENDOR_REQUEST_WEBUSB:
+      // match vendor request in BOS descriptor
+      // Get landing page url
+      if (!_webusb_dev->_url) {
+        return false;
+      }
+      return tud_control_xfer(rhport, request, (void *)_webusb_dev->_url,
+                              _webusb_dev->_url[0]);
+
+    case VENDOR_REQUEST_MICROSOFT:
+      if (request->wIndex == 7) {
+        // Get Microsoft OS 2.0 compatible descriptor
+        uint16_t total_len;
+        memcpy(&total_len, desc_ms_os_20 + 8, 2);
+
+        return tud_control_xfer(rhport, request, (void *)desc_ms_os_20,
+                                total_len);
+      } else {
+        return false;
+      }
+
+    default:
+      break;
+    }
+    break;
+
+  case TUSB_REQ_TYPE_CLASS:
+    if (request->bRequest == 0x22) {
+      // Webserial simulate the CDC_REQUEST_SET_CONTROL_LINE_STATE (0x22) to
+      // connect and disconnect.
+      _webusb_dev->_connected = (request->wValue != 0);
+
+      // response with status OK
+      tud_control_status(rhport, request);
+
+      // invoked callback if any (TODO should be done at ACK stage)
+      if (_webusb_dev->_linestate_cb) {
+        _webusb_dev->_linestate_cb(_webusb_dev->_connected);
+      }
+
+      return true;
+    }
+    break;
+
+  default:
+    // stall unknown request
+    return false;
+  }
+
+  return true;
+}
+
+// Invoked when DATA Stage of VENDOR's request is complete
+bool tud_vendor_control_complete_cb(uint8_t rhport,
+                                    tusb_control_request_t const *request) {
+  (void)rhport;
+  (void)request;
+
+  // nothing to do
+  return true;
+}
+}
+
+#endif // TUSB_OPT_DEVICE_ENABLED
diff --git a/libraries/Adafruit_TinyUSB_Arduino/src/arduino/webusb/Adafruit_USBD_WebUSB.h b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/webusb/Adafruit_USBD_WebUSB.h
new file mode 100644
index 00000000000..556ec5b060a
--- /dev/null
+++ b/libraries/Adafruit_TinyUSB_Arduino/src/arduino/webusb/Adafruit_USBD_WebUSB.h
@@ -0,0 +1,78 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 hathach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef ADAFRUIT_USBD_WEBUSB_H_
+#define ADAFRUIT_USBD_WEBUSB_H_
+
+#include "Stream.h"
+#include "arduino/Adafruit_USBD_Device.h"
+
+#define WEBUSB_URL_DEF(_name, _scheme, _url)                                   \
+  struct TU_ATTR_PACKED {                                                      \
+    uint8_t bLength;                                                           \
+    uint8_t bDescriptorType;                                                   \
+    uint8_t bScheme;                                                           \
+    char url[3 + sizeof(_url)];                                                \
+  } const _name = {3 + sizeof(_url) - 1, 3, _scheme, _url}
+
+class Adafruit_USBD_WebUSB : public Stream, public Adafruit_USBD_Interface {
+public:
+  typedef void (*linestate_callback_t)(bool connected);
+  Adafruit_USBD_WebUSB(void);
+
+  bool begin(void);
+
+  bool setLandingPage(const void *url);
+  void setLineStateCallback(linestate_callback_t fp);
+
+  // Stream interface to use with MIDI Library
+  virtual int read(void);
+  virtual int available(void);
+  virtual int peek(void);
+  virtual void flush(void);
+  virtual size_t write(uint8_t b);
+
+  virtual size_t write(const uint8_t *buffer, size_t size);
+  size_t write(const char *buffer, size_t size) {
+    return write((const uint8_t *)buffer, size);
+  }
+
+  bool connected(void);
+  operator bool();
+
+  // from Adafruit_USBD_Interface
+  virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf,
+                                          uint16_t bufsize);
+
+private:
+  bool _connected;
+  const uint8_t *_url;
+  linestate_callback_t _linestate_cb;
+
+  // Make all tinyusb callback friend to access private data
+  friend bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage,
+                                         tusb_control_request_t const *request);
+};
+
+#endif /* ADAFRUIT_USBD_WEBUSB_H_ */
diff --git a/platform.txt b/platform.txt
index 8f828b7ebd8..20816d35c7a 100644
--- a/platform.txt
+++ b/platform.txt
@@ -45,7 +45,7 @@ compiler.cpp.flags.esp32s2=-mlongcalls -ffunction-sections -fdata-sections -Wno-
 compiler.S.flags.esp32s2=-ffunction-sections -fdata-sections -Wno-error=unused-function -Wno-error=unused-variable -Wno-error=deprecated-declarations -Wno-unused-parameter -Wno-sign-compare -ggdb -O2 -fstack-protector -fstrict-volatile-bitfields -Wno-error=unused-but-set-variable  -x assembler-with-cpp -MMD -c
 compiler.c.elf.flags.esp32s2=-T esp32s2.rom.ld -T esp32s2.rom.api.ld -T esp32s2.rom.libgcc.ld -T esp32s2.rom.newlib-funcs.ld -T esp32s2.rom.newlib-data.ld -T esp32s2.rom.spiflash.ld -T esp32s2_out.ld -T esp32s2.project.ld -T esp32s2.peripherals.ld  -mlongcalls -Wl,--cref -Wl,--gc-sections -fno-rtti -fno-lto -u esp_app_desc -u pthread_include_pthread_impl -u pthread_include_pthread_cond_impl -u pthread_include_pthread_local_storage_impl -u ld_include_panic_highint_hdl -u start_app -u __ubsan_include -Wl,--wrap=longjmp -u vfs_include_syscalls_impl -u call_user_start_cpu0 -Wl,--undefined=uxTopUsedPriority -u app_main -u newlib_include_heap_impl -u newlib_include_syscalls_impl -u newlib_include_pthread_impl -u __cxa_guard_dummy 
 compiler.ar.flags.esp32s2=cru
-build.extra_flags.esp32s2=-DARDUINO_SERIAL_PORT={build.serial}
+build.extra_flags.esp32s2=-DARDUINO_SERIAL_PORT={build.serial} {build.usbstack_flags}
 #
 # ESP32S2 Support End
 #
@@ -109,6 +109,7 @@ build.code_debug=0
 build.defines=
 build.loop_core=
 build.event_core=
+build.usbstack_flags=
 build.extra_flags=-DESP32 -DCORE_DEBUG_LEVEL={build.code_debug} {build.loop_core} {build.event_core} {build.defines} {build.extra_flags.{build.mcu}}
 
 # Custom build options
diff --git a/variants/adafruit_feather_esp32s2/pins_arduino.h b/variants/adafruit_feather_esp32s2/pins_arduino.h
index f84ab6fe0e2..3839a547756 100644
--- a/variants/adafruit_feather_esp32s2/pins_arduino.h
+++ b/variants/adafruit_feather_esp32s2/pins_arduino.h
@@ -7,7 +7,7 @@
 #define USB_VID 0x239A
 #define USB_PID 0x80EB
 #define USB_MANUFACTURER "Adafruit"
-#define USB_PRODUCT "Adafruit Feather ESP32-S2"
+#define USB_PRODUCT "Feather ESP32-S2"
 #define USB_SERIAL ""
 
 
diff --git a/variants/adafruit_funhouse_esp32s2/pins_arduino.h b/variants/adafruit_funhouse_esp32s2/pins_arduino.h
index bef0a830970..2079d70b3de 100644
--- a/variants/adafruit_funhouse_esp32s2/pins_arduino.h
+++ b/variants/adafruit_funhouse_esp32s2/pins_arduino.h
@@ -8,7 +8,7 @@
 #define USB_PID 0x80F9
 
 #define USB_MANUFACTURER "Adafruit"
-#define USB_PRODUCT "Adafruit Funhouse ESP32-S2"
+#define USB_PRODUCT "FunHouse ESP32-S2"
 #define USB_SERIAL ""
 
 
diff --git a/variants/adafruit_magtag29_esp32s2/pins_arduino.h b/variants/adafruit_magtag29_esp32s2/pins_arduino.h
index c015aff6864..a401024f8f8 100644
--- a/variants/adafruit_magtag29_esp32s2/pins_arduino.h
+++ b/variants/adafruit_magtag29_esp32s2/pins_arduino.h
@@ -5,7 +5,7 @@
 
 
 #define USB_VID 0x239A
-#define USB_PID 0x80DF
+#define USB_PID 0x80E5
 #define USB_MANUFACTURER "Adafruit"
 #define USB_PRODUCT "EPD MagTag 2.9\" ESP32-S2"
 #define USB_SERIAL ""
diff --git a/variants/esp32s2/pins_arduino.h b/variants/esp32s2/pins_arduino.h
index 85b7455d491..5dc08f2efe2 100644
--- a/variants/esp32s2/pins_arduino.h
+++ b/variants/esp32s2/pins_arduino.h
@@ -3,6 +3,11 @@
 
 #include <stdint.h>
 
+#define USB_VID            0x303A
+#define USB_PID            0x0002
+#define USB_MANUFACTURER   "Espressif Systems"
+#define USB_PRODUCT        "ESP32S2_DEV"
+
 #define EXTERNAL_NUM_INTERRUPTS 46
 #define NUM_DIGITAL_PINS        48
 #define NUM_ANALOG_INPUTS       20