Compare commits

..

No commits in common. "master" and "sync-tinyusb" have entirely different histories.

251 changed files with 12011 additions and 30206 deletions

View file

@ -2,5 +2,3 @@ synopsys
sie sie
inout inout
busses busses
thre

View file

@ -46,7 +46,7 @@ body:
- type: input - type: input
attributes: attributes:
label: TinyUSB Library version label: TinyUSB Library version
placeholder: "Release version or commit SHA" placeholder: "Release version or github latest"
validations: validations:
required: true required: true
@ -100,11 +100,3 @@ body:
description: If applicable, add screenshots to help explain your problem. description: If applicable, add screenshots to help explain your problem.
validations: validations:
required: false required: false
- type: checkboxes
attributes:
label: I have checked existing issues, pr, discussion and documentation
description: You agree to check all the resources above before opening a new issue.
options:
- label: I confirm I have checked existing issues, pr, discussion and documentation.
required: true

View file

@ -3,6 +3,3 @@ contact_links:
- name: Adafruit Support Forum - name: Adafruit Support Forum
url: https://forums.adafruit.com url: https://forums.adafruit.com
about: If you have other questions or need help, post it here. about: If you have other questions or need help, post it here.
- name: TinyUSB Arduino Discussion
url: https://github.com/adafruit/Adafruit_TinyUSB_Arduino/discussions
about: If you have other questions or need help, post it here.

View file

@ -3,24 +3,26 @@ name: Build
on: [pull_request, push, repository_dispatch] on: [pull_request, push, repository_dispatch]
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true cancel-in-progress: true
env:
ARDUINO_LIBS: "\"Adafruit SPIFlash\" \"Adafruit seesaw Library\" \"Adafruit NeoPixel\" \"Adafruit Circuit Playground\" \"Adafruit InternalFlash\" \"SdFat - Adafruit Fork\" \"SD\" \"MIDI Library\" \"Pico PIO USB\""
jobs: jobs:
pre-commit: pre-commit:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Run pre-commit - name: Run pre-commit
uses: pre-commit/action@v3.0.1 uses: pre-commit/action@v3.0.0
- name: Checkout adafruit/ci-arduino - name: Checkout adafruit/ci-arduino
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
repository: adafruit/ci-arduino repository: adafruit/ci-arduino
path: ci path: ci
@ -37,9 +39,6 @@ jobs:
PRETTYNAME : "Adafruit TinyUSB Library" PRETTYNAME : "Adafruit TinyUSB Library"
run: bash ci/doxy_gen_and_deploy.sh run: bash ci/doxy_gen_and_deploy.sh
# ---------------------------------------
# build
# ---------------------------------------
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: pre-commit needs: pre-commit
@ -47,28 +46,31 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
arduino-platform: arduino-platform:
# ESP32 ci use dev json # ESP32S3
- 'feather_esp32_v2'
- 'feather_esp32s2'
- 'feather_esp32s3' - 'feather_esp32s3'
- 'esp32p4' # ESP32S2
- 'feather_esp32s2'
# nRF52 # nRF52
- 'cpb' - 'cpb'
- 'nrf52840' - 'nrf52840'
# RP2040 # RP2040
- 'feather_rp2040_tinyusb' - 'feather_rp2040_tinyusb'
- 'pico_rp2040_tinyusb_host'
# SAMD # SAMD
- 'feather_m4_can_tinyusb'
- 'metro_m0_tinyusb' - 'metro_m0_tinyusb'
- 'metro_m4_tinyusb' - 'metro_m4_tinyusb'
# Ch32v2
- 'CH32V20x_EVT'
steps: steps:
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Checkout adafruit/ci-arduino - name: Checkout adafruit/ci-arduino
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
repository: adafruit/ci-arduino repository: adafruit/ci-arduino
path: ci path: ci
@ -76,10 +78,8 @@ jobs:
- name: pre-install - name: pre-install
run: bash ci/actions_install.sh run: bash ci/actions_install.sh
- name: Install Libraries - name: Install Libraries for building examples
run: | run: arduino-cli lib install "Adafruit SPIFlash" "MIDI Library" "Adafruit seesaw Library" "Adafruit NeoPixel" "SdFat - Adafruit Fork" "SD" "Adafruit Circuit Playground" "Adafruit InternalFlash" "Pico PIO USB"
arduino-cli lib install ${{ env.ARDUINO_LIBS }}
arduino-cli lib list
- name: test platforms - name: test platforms
run: python3 ci/build_platform.py ${{ matrix.arduino-platform }} run: python3 ci/build_platform.py ${{ matrix.arduino-platform }}

3
.gitignore vendored
View file

@ -1,5 +1,2 @@
/examples/**/build/ /examples/**/build/
/.development /.development
.idea
platformio.ini
.pio/

View file

@ -15,18 +15,15 @@ Supported device class drivers are:
- Human Interface Device (HID): Generic (In & Out), Keyboard, Mouse, Gamepad etc ... - Human Interface Device (HID): Generic (In & Out), Keyboard, Mouse, Gamepad etc ...
- Mass Storage Class (MSC): with multiple LUNs - Mass Storage Class (MSC): with multiple LUNs
- Musical Instrument Digital Interface (MIDI) - Musical Instrument Digital Interface (MIDI)
- Video (UVC): work in progress
- WebUSB with vendor specific class - WebUSB with vendor specific class
### Host Stack ### Host Stack
Host stack is available with either addition of MAX3421E hardware (e.g [Host FeatherWing](https://www.adafruit.com/product/5858)) or rp2040 core (thanks to [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB)). Supported class driver are: Host support is still work-in-progress but currently available with rp2040 core thanks to [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB). Supported class driver are:
- Communication (CDC): including vendor usb2uart such as FTDI, CP210x, CH34x - Communication (CDC)
- MassStorage class - MassStorage class
Note: Host stack is still work-in-progress
## Supported Cores ## Supported Cores
There are 2 type of supported cores: with and without built-in support for TinyUSB. Built-in support provide seamless integration but requires extra code added to core's source code. Unfortunately it is not always easy or possible to make those modification. There are 2 type of supported cores: with and without built-in support for TinyUSB. Built-in support provide seamless integration but requires extra code added to core's source code. Unfortunately it is not always easy or possible to make those modification.
@ -38,12 +35,9 @@ Following core has TinyUSB as either the primary usb stack or selectable via men
- [adafruit/Adafruit_nRF52_Arduino](https://github.com/adafruit/Adafruit_nRF52_Arduino) - [adafruit/Adafruit_nRF52_Arduino](https://github.com/adafruit/Adafruit_nRF52_Arduino)
- [adafruit/ArduinoCore-samd](https://github.com/adafruit/ArduinoCore-samd) - [adafruit/ArduinoCore-samd](https://github.com/adafruit/ArduinoCore-samd)
- [earlephilhower/arduino-pico](https://github.com/earlephilhower/arduino-pico) - [earlephilhower/arduino-pico](https://github.com/earlephilhower/arduino-pico)
- [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) Host mode using MAX3421E controller should work with all chips. Device mode only support S2/S3/P4 and additional Tools menu are needed - [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32)
- `USB Mode=USB-OTG (TinyUSB)` for S3 and P4
- `USB CDC On Boot=Enabled`, `USB Firmware MSC On Boot=Disabled`, `USB DFU On Boot=Disabled`
- [openwch/arduino_core_ch32](https://github.com/openwch/arduino_core_ch32)
Note: For ESP32 port, version before v3.0 requires all descriptors must be specified in usb objects declaration i.e constructors. Therefore all descriptor-related fields must be part of object declaration and descriptor-related API have no effect afterwards. This limitation is not the case for version from v3.0. ESP32 port relies on Espressif's [esp32-hal-tinyusb.c](https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-tinyusb.c) for building usb descriptors which requires all descriptors must be specified in usb objects declaration i.e constructors. Therefore all descriptor-related fields must be part of object declaration and descriptor-related API have no effect afterwards for this port.
### Cores without built-in support ### Cores without built-in support

View file

View file

@ -1,8 +0,0 @@
feather_esp32_v2
feather_esp32s2
feather_esp32s3
funhouse
magtag
metroesp32s2
esp32p4
pico_rp2040_tinyusb_host

View file

@ -25,9 +25,11 @@
#include <Adafruit_TinyUSB.h> #include <Adafruit_TinyUSB.h>
#define LED LED_BUILTIN
// Create 2nd instance of CDC Ports. // Create 2nd instance of CDC Ports.
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
#error "Currently multiple CDCs on ESP32 is not yet supported" #error "Currnetly multiple CDCs on ESP32-Sx is not yet supported. An PR to update core/esp32/USBCDC and/or pre-built libusb are needed."
// for ESP32, we need to specify instance number when declaring object // for ESP32, we need to specify instance number when declaring object
Adafruit_USBD_CDC USBSer1(1); Adafruit_USBD_CDC USBSer1(1);
#else #else
@ -35,17 +37,13 @@
#endif #endif
void setup() { void setup() {
#ifdef LED_BUILTIN pinMode(LED, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
#endif
Serial.begin(115200); Serial.begin(115200);
// check to see if multiple CDCs are enabled // check to see if multiple CDCs are enabled
if ( CFG_TUD_CDC < 2 ) { if ( CFG_TUD_CDC < 2 ) {
#ifdef LED_BUILTIN digitalWrite(LED, HIGH); // LED on for error indicator
digitalWrite(LED_BUILTIN, HIGH); // LED on for error indicator
#endif
while(1) { while(1) {
Serial.printf("CFG_TUD_CDC must be at least 2, current value is %u\n", CFG_TUD_CDC); Serial.printf("CFG_TUD_CDC must be at least 2, current value is %u\n", CFG_TUD_CDC);
@ -58,13 +56,6 @@ void setup() {
// initialize 2nd CDC interface // initialize 2nd CDC interface
USBSer1.begin(115200); USBSer1.begin(115200);
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
if (TinyUSBDevice.mounted()) {
TinyUSBDevice.detach();
delay(10);
TinyUSBDevice.attach();
}
while (!Serial || !USBSer1) { while (!Serial || !USBSer1) {
if (Serial) { if (Serial) {
Serial.println("Waiting for other USB ports"); Serial.println("Waiting for other USB ports");
@ -98,9 +89,7 @@ void loop() {
if (delay_without_delaying(500)) { if (delay_without_delaying(500)) {
LEDstate = !LEDstate; LEDstate = !LEDstate;
#ifdef LED_BUILTIN digitalWrite(LED, LEDstate);
digitalWrite(LED_BUILTIN, LEDstate);
#endif
} }
} }

View file

@ -1,2 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host

View file

@ -18,40 +18,19 @@
* Note: this will cause device to loose the touch1200 and require * Note: this will cause device to loose the touch1200 and require
* user manual interaction to put device into bootloader/DFU mode. * user manual interaction to put device into bootloader/DFU mode.
*/ */
void setup() {
// Manual begin() is required on core without built-in support e.g. mbed rp2040
if (!TinyUSBDevice.isInitialized()) {
TinyUSBDevice.begin(0);
}
// clear configuration will remove all USB interfaces including CDC (Serial) int led = LED_BUILTIN;
TinyUSBDevice.clearConfiguration();
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration void setup()
if (TinyUSBDevice.mounted()) { {
TinyUSBDevice.detach(); Serial.end();
delay(10); pinMode(led, OUTPUT);
TinyUSBDevice.attach();
}
#ifdef LED_BUILTIN
pinMode(LED_BUILTIN, OUTPUT);
#endif
} }
void loop() { void loop()
#ifdef TINYUSB_NEED_POLLING_TASK {
// Manual call tud_task since it isn't called by Core's background digitalWrite(led, HIGH);
TinyUSBDevice.task(); delay(1000);
#endif digitalWrite(led, LOW);
delay(1000);
// toggle LED
static uint32_t ms = 0;
static uint8_t led_state = 0;
if (millis() - ms > 1000) {
ms = millis();
#ifdef LED_BUILTIN
digitalWrite(LED_BUILTIN, 1-led_state);
#endif
}
} }

View file

@ -1,2 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host

View file

@ -1,41 +0,0 @@
/*********************************************************************
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 echo (convert to upper case) using SerialTinyUSB which
* is available for both core with built-in USB support and without.
* Note: on core with built-in support Serial is alias to SerialTinyUSB
*/
void setup() {
// Manual begin() is required on core without built-in support e.g. mbed rp2040
if (!TinyUSBDevice.isInitialized()) {
TinyUSBDevice.begin(0);
}
}
void loop() {
#ifdef TINYUSB_NEED_POLLING_TASK
// Manual call tud_task since it isn't called by Core's background
TinyUSBDevice.task();
#endif
uint8_t buf[64];
uint32_t count = 0;
while (SerialTinyUSB.available()) {
buf[count++] = (uint8_t) toupper(SerialTinyUSB.read());
}
if (count) {
SerialTinyUSB.write(buf, count);
}
}

View file

@ -0,0 +1,192 @@
/*********************************************************************
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"
//--------------------------------------------------------------------+
// MSC External Flash Config
//--------------------------------------------------------------------+
// Un-comment to run example with custom SPI SPI and SS e.g with FRAM breakout
// #define CUSTOM_CS A5
// #define CUSTOM_SPI SPI
#if defined(CUSTOM_CS) && defined(CUSTOM_SPI)
Adafruit_FlashTransport_SPI flashTransport(CUSTOM_CS, CUSTOM_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;
#elif defined(ARDUINO_ARCH_RP2040)
// RP2040 use same flash device that store code.
// Therefore there is no need to specify the SPI and SS
// Use default (no-args) constructor to be compatible with CircuitPython partition scheme
Adafruit_FlashTransport_RP2040 flashTransport;
// For generic usage:
// Adafruit_FlashTransport_RP2040 flashTransport(start_address, size)
// If start_address and size are both 0, value that match filesystem setting in
// 'Tools->Flash Size' menu selection will be used
#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 Config
//--------------------------------------------------------------------+
// 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. For ESP32 these values cannot be changed after this declaration
// desc report, desc len, protocol, interval, use out endpoint
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_NONE, 2, false);
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY)
const int pin = 4; // Left Button
bool activeState = true;
#elif defined(ARDUINO_FUNHOUSE_ESP32S2)
const int pin = BUTTON_DOWN;
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()
{
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);
// Notes: following commented-out functions has no affect on ESP32
// 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 ( TinyUSBDevice.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();
}

View file

@ -1,2 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host

View file

@ -23,7 +23,6 @@
// 8KB is the smallest size that windows allow to mount // 8KB is the smallest size that windows allow to mount
#define DISK_BLOCK_NUM 16 #define DISK_BLOCK_NUM 16
#define DISK_BLOCK_SIZE 512 #define DISK_BLOCK_SIZE 512
#include "ramdisk.h" #include "ramdisk.h"
Adafruit_USBD_MSC usb_msc; Adafruit_USBD_MSC usb_msc;
@ -34,51 +33,43 @@ Adafruit_USBD_MSC usb_msc;
// HID report descriptor using TinyUSB's template // HID report descriptor using TinyUSB's template
// Single Report (no ID) descriptor // Single Report (no ID) descriptor
uint8_t const desc_hid_report[] = { uint8_t const desc_hid_report[] =
TUD_HID_REPORT_DESC_MOUSE() {
TUD_HID_REPORT_DESC_MOUSE()
}; };
// USB HID object // USB HID object. For ESP32 these values cannot be changed after this declaration
Adafruit_USBD_HID usb_hid; // desc report, desc len, protocol, interval, use out endpoint
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_NONE, 2, false);
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY) #if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY)
const int pin = 4; // Left Button const int pin = 4; // Left Button
bool activeState = true; bool activeState = true;
#elif defined(ARDUINO_FUNHOUSE_ESP32S2) #elif defined(ARDUINO_FUNHOUSE_ESP32S2)
const int pin = BUTTON_DOWN; const int pin = BUTTON_DOWN;
bool activeState = true; bool activeState = true;
#elif defined PIN_BUTTON1 #elif defined PIN_BUTTON1
const int pin = PIN_BUTTON1; const int pin = PIN_BUTTON1;
bool activeState = false; bool activeState = false;
#elif defined(ARDUINO_ARCH_ESP32)
const int pin = 0;
bool activeState = false;
#elif defined(ARDUINO_ARCH_RP2040)
const int pin = D0;
bool activeState = false;
#else #else
const int pin = A0; const int pin = 12;
bool activeState = false; bool activeState = false;
#endif #endif
// the setup function runs once when you press reset or power the board // the setup function runs once when you press reset or power the board
void setup() { void setup()
// Manual begin() is required on core without built-in support e.g. mbed rp2040 {
if (!TinyUSBDevice.isInitialized()) { #if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
TinyUSBDevice.begin(0); // Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
} TinyUSB_Device_Init(0);
#endif
Serial.begin(115200);
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively // 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"); usb_msc.setID("Adafruit", "Mass Storage", "1.0");
// Set disk size // Set disk size
usb_msc.setCapacity(DISK_BLOCK_NUM, DISK_BLOCK_SIZE); usb_msc.setCapacity(DISK_BLOCK_NUM, DISK_BLOCK_SIZE);
@ -87,42 +78,44 @@ void setup() {
// Set Lun ready (RAM disk is always ready) // Set Lun ready (RAM disk is always ready)
usb_msc.setUnitReady(true); usb_msc.setUnitReady(true);
usb_msc.begin(); usb_msc.begin();
// Set up button // Set up button
pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP); pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
// Set up HID // Notes: following commented-out functions has no affect on ESP32
usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report)); // usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
usb_hid.setBootProtocol(HID_ITF_PROTOCOL_NONE);
usb_hid.setPollInterval(2);
usb_hid.begin(); usb_hid.begin();
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration Serial.begin(115200);
if (TinyUSBDevice.mounted()) { while( !TinyUSBDevice.mounted() ) delay(1); // wait for native usb
TinyUSBDevice.detach();
delay(10);
TinyUSBDevice.attach();
}
Serial.println("Adafruit TinyUSB Mouse + Mass Storage (ramdisk) example"); Serial.println("Adafruit TinyUSB Mouse + Mass Storage (ramdisk) example");
} }
void process_hid() { void loop()
{
// poll gpio once each 10 ms
delay(10);
// button is active low // button is active low
uint32_t const btn = (digitalRead(pin) == activeState); uint32_t const btn = (digitalRead(pin) == activeState);
// Remote wakeup // Remote wakeup
if (TinyUSBDevice.suspended() && btn) { if ( TinyUSBDevice.suspended() && btn )
{
// Wake up host if we are in suspend mode // Wake up host if we are in suspend mode
// and REMOTE_WAKEUP feature is enabled by host // and REMOTE_WAKEUP feature is enabled by host
tud_remote_wakeup(); tud_remote_wakeup();
} }
/*------------- Mouse -------------*/ /*------------- Mouse -------------*/
if (usb_hid.ready()) { if ( usb_hid.ready() )
if (btn) { {
if ( btn )
{
int8_t const delta = 5; int8_t const delta = 5;
usb_hid.mouseMove(0, delta, delta); // no ID: right + down usb_hid.mouseMove(0, delta, delta); // no ID: right + down
@ -132,29 +125,11 @@ void process_hid() {
} }
} }
void loop() {
#ifdef TINYUSB_NEED_POLLING_TASK
// Manual call tud_task since it isn't called by Core's background
TinyUSBDevice.task();
#endif
// not enumerated()/mounted() yet: nothing to do
if (!TinyUSBDevice.mounted()) {
return;
}
// poll gpio once each 10 ms
static uint32_t ms = 0;
if (millis() - ms > 10) {
ms = millis();
process_hid();
}
}
// Callback invoked when received READ10 command. // Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and // Copy disk's data to buffer (up to bufsize) and
// return number of copied bytes (must be multiple of block size) // return number of copied bytes (must be multiple of block size)
int32_t msc_read_cb(uint32_t lba, void* buffer, uint32_t bufsize) { int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
{
uint8_t const* addr = msc_disk[lba]; uint8_t const* addr = msc_disk[lba];
memcpy(buffer, addr, bufsize); memcpy(buffer, addr, bufsize);
@ -164,7 +139,8 @@ int32_t msc_read_cb(uint32_t lba, void* buffer, uint32_t bufsize) {
// Callback invoked when received WRITE10 command. // Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and // Process data in buffer to disk's storage and
// return number of written bytes (must be multiple of block size) // 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) { int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
{
uint8_t* addr = msc_disk[lba]; uint8_t* addr = msc_disk[lba];
memcpy(addr, buffer, bufsize); memcpy(addr, buffer, bufsize);
@ -173,6 +149,7 @@ int32_t msc_write_cb(uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
// Callback invoked when WRITE10 command is completed (status received and accepted by host). // Callback invoked when WRITE10 command is completed (status received and accepted by host).
// used to flush any pending cache. // used to flush any pending cache.
void msc_flush_cb(void) { void msc_flush_cb (void)
{
// nothing to do // nothing to do
} }

View file

@ -1,2 +0,0 @@
pico_rp2040_tinyusb_host
CH32V20x_EVT

View file

@ -9,162 +9,154 @@
any redistribution any redistribution
*********************************************************************/ *********************************************************************/
/* This example demonstrates use of both device and host, where
* - Device run on native usb controller (roothub port0)
* - Host depending on MCUs run on either:
* - rp2040: bit-banging 2 GPIOs with the help of Pico-PIO-USB library (roothub port1)
* - samd21/51, nrf52840, esp32: using MAX3421e controller (host shield)
*
* Requirements:
* - For rp2040:
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
* - Provide VBus (5v) and GND for peripheral
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
* - For samd21/51, nrf52840, esp32:
* - Additional MAX2341e USB Host shield or featherwing is required
* - SPI instance, CS pin, INT pin are correctly configured in usbh_helper.h
*/
/* This example demonstrates use of Host Serial (CDC). SerialHost (declared below) is /* This example demonstrates use of Host Serial (CDC). SerialHost (declared below) is
* an object to manage an CDC peripheral connected to our USB Host connector. This example * an object to manage an CDC peripheral connected to our USB Host connector. This example
* will forward all characters from Serial to SerialHost and vice versa. * will forward all characters from Serial to SerialHost and vice versa.
*
* Note:
* - Device run on native usb controller (controller0)
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
* Requirements:
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
* - 2 consecutive GPIOs: D+ is defined by PIN_PIO_USB_HOST_DP, D- = D+ +1
* - Provide VBus (5v) and GND for peripheral
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
*/ */
// nRF52 and ESP32 use freeRTOS, we may need to run USBhost.task() in its own rtos's thread. // pio-usb is required for rp2040 host
// Since USBHost.task() will put loop() into dormant state and prevent followed code from running #include "pio_usb.h"
// until there is USB host event.
#if defined(ARDUINO_NRF52_ADAFRUIT) || defined(ARDUINO_ARCH_ESP32) // TinyUSB lib
#define USE_FREERTOS #include "Adafruit_TinyUSB.h"
// Pin D+ for host, D- = D+ + 1
#ifndef PIN_PIO_USB_HOST_DP
#define PIN_PIO_USB_HOST_DP 20
#endif #endif
// USBHost is defined in usbh_helper.h // Pin for enabling Host VBUS. comment out if not used
#include "usbh_helper.h" #ifndef PIN_PIO_USB_HOST_VBUSEN
#define PIN_PIO_USB_HOST_VBUSEN 22
#endif
#ifndef PIN_PIO_USB_HOST_VBUSEN_STATE
#define PIN_PIO_USB_HOST_VBUSEN_STATE 1
#endif
// USB Host object
Adafruit_USBH_Host USBHost;
// CDC Host object // CDC Host object
Adafruit_USBH_CDC SerialHost; Adafruit_USBH_CDC SerialHost;
// forward Seral <-> SerialHost //--------------------------------------------------------------------+
void forward_serial(void) { // Setup and Loop on Core0
//--------------------------------------------------------------------+
void setup() {
Serial1.begin(115200);
Serial.begin(115200);
while ( !Serial ) delay(10); // wait for native usb
Serial.println("TinyUSB Host Serial Echo Example");
}
void loop()
{
uint8_t buf[64]; uint8_t buf[64];
// Serial -> SerialHost // Serial -> SerialHost
if (Serial.available()) { if (Serial.available()) {
size_t count = Serial.read(buf, sizeof(buf)); size_t count = Serial.read(buf, sizeof(buf));
if (SerialHost && SerialHost.connected()) { if ( SerialHost && SerialHost.connected() ) {
SerialHost.write(buf, count); SerialHost.write(buf, count);
SerialHost.flush(); SerialHost.flush();
} }
} }
// SerialHost -> Serial // SerialHost -> Serial
if (SerialHost.connected() && SerialHost.available()) { if ( SerialHost.connected() && SerialHost.available() ) {
size_t count = SerialHost.read(buf, sizeof(buf)); size_t count = SerialHost.read(buf, sizeof(buf));
Serial.write(buf, count); Serial.write(buf, count);
Serial.flush();
} }
} }
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Using Host shield MAX3421E controller // Setup and Loop on Core1
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
#ifdef USE_FREERTOS
#ifdef ARDUINO_ARCH_ESP32
#define USBH_STACK_SZ 2048
#else
#define USBH_STACK_SZ 200
#endif
void usbhost_rtos_task(void *param) {
(void) param;
while (1) {
USBHost.task();
}
}
#endif
void setup() {
Serial.begin(115200);
// init host stack on controller (rhport) 1
USBHost.begin(1);
// Initialize SerialHost
SerialHost.begin(115200);
#ifdef USE_FREERTOS
// Create a task to run USBHost.task() in background
xTaskCreate(usbhost_rtos_task, "usbh", USBH_STACK_SZ, NULL, 3, NULL);
#endif
// while ( !Serial ) delay(10); // wait for native usb
Serial.println("TinyUSB Host Serial Echo Example");
}
void loop() {
#ifndef USE_FREERTOS
USBHost.task();
#endif
forward_serial();
}
#elif defined(ARDUINO_ARCH_RP2040)
//--------------------------------------------------------------------+
// For RP2040 use both core0 for device stack, core1 for host stack
//--------------------------------------------------------------------+
//------------- Core0 -------------//
void setup() {
Serial.begin(115200);
// while ( !Serial ) delay(10); // wait for native usb
Serial.println("TinyUSB Host Serial Echo Example");
}
void loop() {
forward_serial();
}
//------------- Core1 -------------//
void setup1() { void setup1() {
// configure pio-usb: defined in usbh_helper.h while ( !Serial ) delay(10); // wait for native usb
rp2040_configure_pio_usb(); Serial.println("Core1 setup to run TinyUSB host with pio-usb");
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
uint32_t cpu_hz = clock_get_hz(clk_sys);
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
while ( !Serial ) {
delay(10); // wait for native usb
}
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
while(1) {
delay(1);
}
}
#ifdef PIN_PIO_USB_HOST_VBUSEN
pinMode(PIN_PIO_USB_HOST_VBUSEN, OUTPUT);
// power off first
digitalWrite(PIN_PIO_USB_HOST_VBUSEN, 1-PIN_PIO_USB_HOST_VBUSEN_STATE);
delay(1);
// power on
digitalWrite(PIN_PIO_USB_HOST_VBUSEN, PIN_PIO_USB_HOST_VBUSEN_STATE);
delay(10);
#endif
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
pio_cfg.pin_dp = PIN_PIO_USB_HOST_DP;
USBHost.configure_pio_usb(1, &pio_cfg);
// run host stack on controller (rhport) 1 // run host stack on controller (rhport) 1
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the // Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
// host bit-banging processing works done in core1 to free up core0 for other works // host bit-banging processing works done in core1 to free up core0 for other works
USBHost.begin(1); USBHost.begin(1);
// Initialize SerialHost
SerialHost.begin(115200);
} }
void loop1() { void loop1()
{
USBHost.task(); USBHost.task();
}
#endif // periodically flush SerialHost if connected
if ( SerialHost && SerialHost.connected() ) {
SerialHost.flush();
}
}
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// TinyUSB Host callbacks // TinyUSB Host callbacks
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
extern "C" {
// Invoked when a device with CDC interface is mounted // Invoked when a device with CDC interface is mounted
// idx is index of cdc interface in the internal pool. // idx is index of cdc interface in the internal pool.
void tuh_cdc_mount_cb(uint8_t idx) { void tuh_cdc_mount_cb(uint8_t idx) {
// bind SerialHost object to this interface index // bind SerialHost object to this interface index
SerialHost.mount(idx); SerialHost.setInterfaceIndex(idx);
SerialHost.begin(115200);
Serial.println("SerialHost is connected to a new CDC device"); Serial.println("SerialHost is connected to a new CDC device");
} }
// Invoked when a device with CDC interface is unmounted // Invoked when a device with CDC interface is unmounted
void tuh_cdc_umount_cb(uint8_t idx) { void tuh_cdc_umount_cb(uint8_t idx) {
SerialHost.umount(idx); if (idx == SerialHost.getInterfaceIndex()) {
Serial.println("SerialHost is disconnected"); // unbind SerialHost if this interface is unmounted
} SerialHost.end();
Serial.println("SerialHost is disconnected");
}
} }

View file

@ -1,99 +0,0 @@
/*********************************************************************
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
*********************************************************************/
#ifndef USBH_HELPER_H
#define USBH_HELPER_H
#ifdef ARDUINO_ARCH_RP2040
// pio-usb is required for rp2040 host
#include "pio_usb.h"
// Pin D+ for host, D- = D+ + 1
#ifndef PIN_USB_HOST_DP
#define PIN_USB_HOST_DP 16
#endif
// Pin for enabling Host VBUS. comment out if not used
#ifndef PIN_5V_EN
#define PIN_5V_EN 18
#endif
#ifndef PIN_5V_EN_STATE
#define PIN_5V_EN_STATE 1
#endif
#endif // ARDUINO_ARCH_RP2040
#include "Adafruit_TinyUSB.h"
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
// USB Host using MAX3421E: SPI, CS, INT
#include "SPI.h"
#if defined(ARDUINO_METRO_ESP32S2)
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
Adafruit_USBH_Host USBHost(&SPI, 33, 15);
#else
// Default CS and INT are pin 10, 9
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
#endif
#else
// Native USB Host such as rp2040
Adafruit_USBH_Host USBHost;
#endif
//--------------------------------------------------------------------+
// Helper Functions
//--------------------------------------------------------------------+
#ifdef ARDUINO_ARCH_RP2040
static void rp2040_configure_pio_usb(void) {
//while ( !Serial ) delay(10); // wait for native usb
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
// Check for CPU frequency, must be multiple of 12 Mhz for bit-banging USB
uint32_t cpu_hz = clock_get_hz(clk_sys);
if (cpu_hz % 12000000UL) {
while (!Serial) {
delay(10); // wait for native usb
}
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 12 Mhz\r\n", cpu_hz);
Serial.printf("Change your CPU Clock to 12*n Mhz in Menu->CPU Speed \r\n");
while (1) {
delay(1);
}
}
#ifdef PIN_5V_EN
pinMode(PIN_5V_EN, OUTPUT);
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
#endif
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
pio_cfg.pin_dp = PIN_USB_HOST_DP;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
// For pico-w, PIO is also used to communicate with cyw43
// Therefore we need to alternate the pio-usb configuration
// details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46
pio_cfg.sm_tx = 3;
pio_cfg.sm_rx = 2;
pio_cfg.sm_eop = 3;
pio_cfg.pio_rx_num = 0;
pio_cfg.pio_tx_num = 1;
pio_cfg.tx_ch = 9;
#endif
USBHost.configure_pio_usb(1, &pio_cfg);
}
#endif
#endif

View file

@ -1,2 +0,0 @@
pico_rp2040_tinyusb_host
CH32V20x_EVT

View file

@ -11,64 +11,83 @@
/* This example demonstrates use of both device and host, where /* This example demonstrates use of both device and host, where
* - Device run on native usb controller (roothub port0) * - Device run on native usb controller (controller0)
* - Host depending on MCUs run on either: * - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
* - rp2040: bit-banging 2 GPIOs with the help of Pico-PIO-USB library (roothub port1)
* - samd21/51, nrf52840, esp32: using MAX3421e controller (host shield)
* *
* Requirements: * Requirements:
* - For rp2040: * - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library * - 2 consecutive GPIOs: D+ is defined by PIN_PIO_USB_HOST_DP, D- = D+ +1
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1 * - Provide VBus (5v) and GND for peripheral
* - Provide VBus (5v) and GND for peripheral * - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
* - For samd21/51, nrf52840, esp32:
* - Additional MAX2341e USB Host shield or featherwing is required
* - SPI instance, CS pin, INT pin are correctly configured in usbh_helper.h
*/ */
// USBHost is defined in usbh_helper.h // pio-usb is required for rp2040 host
#include "usbh_helper.h" #include "pio_usb.h"
#include "Adafruit_TinyUSB.h"
// Pin D+ for host, D- = D+ + 1
#ifndef PIN_PIO_USB_HOST_DP
#define PIN_PIO_USB_HOST_DP 20
#endif
// Pin for enabling Host VBUS. comment out if not used
#ifndef PIN_PIO_USB_HOST_VBUSEN
#define PIN_PIO_USB_HOST_VBUSEN 22
#endif
#ifndef PIN_PIO_USB_HOST_VBUSEN_STATE
#define PIN_PIO_USB_HOST_VBUSEN_STATE 1
#endif
// Language ID: English
#define LANGUAGE_ID 0x0409
// USB Host object
Adafruit_USBH_Host USBHost;
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Using Host shield MAX3421E controller // Setup and Loop on Core0
//--------------------------------------------------------------------+
void setup() {
Serial.begin(115200);
// init host stack on controller (rhport) 1
USBHost.begin(1);
// while ( !Serial ) delay(10); // wait for native usb
Serial.println("TinyUSB Dual: HID Device Report Example");
}
void loop() {
USBHost.task();
Serial.flush();
}
#elif defined(ARDUINO_ARCH_RP2040)
//--------------------------------------------------------------------+
// For RP2040 use both core0 for device stack, core1 for host stack
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
//------------- Core0 -------------// void setup()
void setup() { {
Serial1.begin(115200);
Serial.begin(115200); Serial.begin(115200);
//while ( !Serial ) delay(10); // wait for native usb //while ( !Serial ) delay(10); // wait for native usb
Serial.println("TinyUSB Dual: HID Device Report Example");
Serial.println("TinyUSB Dual Device Info Example");
} }
void loop() { void loop()
Serial.flush(); {
} }
//------------- Core1 -------------// //--------------------------------------------------------------------+
// Setup and Loop on Core1
//--------------------------------------------------------------------+
void setup1() { void setup1() {
// configure pio-usb: defined in usbh_helper.h //while ( !Serial ) delay(10); // wait for native usb
rp2040_configure_pio_usb(); Serial.println("Core1 setup to run TinyUSB host with pio-usb");
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
uint32_t cpu_hz = clock_get_hz(clk_sys);
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
while ( !Serial ) delay(10); // wait for native usb
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
while(1) delay(1);
}
#ifdef PIN_PIO_USB_HOST_VBUSEN
pinMode(PIN_PIO_USB_HOST_VBUSEN, OUTPUT);
digitalWrite(PIN_PIO_USB_HOST_VBUSEN, PIN_PIO_USB_HOST_VBUSEN_STATE);
#endif
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
pio_cfg.pin_dp = PIN_PIO_USB_HOST_DP;
USBHost.configure_pio_usb(1, &pio_cfg);
// run host stack on controller (rhport) 1 // run host stack on controller (rhport) 1
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the // Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
@ -76,22 +95,19 @@ void setup1() {
USBHost.begin(1); USBHost.begin(1);
} }
void loop1() { void loop1()
{
USBHost.task(); USBHost.task();
} }
#endif
extern "C" {
// Invoked when device with hid interface is mounted // Invoked when device with hid interface is mounted
// Report descriptor is also available for use. // Report descriptor is also available for use.
// tuh_hid_parse_report_descriptor() can be used to parse common/simple enough // tuh_hid_parse_report_descriptor() can be used to parse common/simple enough
// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, // descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE,
// it will be skipped therefore report_desc = NULL, desc_len = 0 // it will be skipped therefore report_desc = NULL, desc_len = 0
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) { void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
(void) desc_report; (void)desc_report;
(void) desc_len; (void)desc_len;
uint16_t vid, pid; uint16_t vid, pid;
tuh_vid_pid_get(dev_addr, &vid, &pid); tuh_vid_pid_get(dev_addr, &vid, &pid);
@ -119,5 +135,3 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons
Serial.printf("Error: cannot request to receive report\r\n"); Serial.printf("Error: cannot request to receive report\r\n");
} }
} }
} // extern C

View file

@ -1,99 +0,0 @@
/*********************************************************************
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
*********************************************************************/
#ifndef USBH_HELPER_H
#define USBH_HELPER_H
#ifdef ARDUINO_ARCH_RP2040
// pio-usb is required for rp2040 host
#include "pio_usb.h"
// Pin D+ for host, D- = D+ + 1
#ifndef PIN_USB_HOST_DP
#define PIN_USB_HOST_DP 16
#endif
// Pin for enabling Host VBUS. comment out if not used
#ifndef PIN_5V_EN
#define PIN_5V_EN 18
#endif
#ifndef PIN_5V_EN_STATE
#define PIN_5V_EN_STATE 1
#endif
#endif // ARDUINO_ARCH_RP2040
#include "Adafruit_TinyUSB.h"
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
// USB Host using MAX3421E: SPI, CS, INT
#include "SPI.h"
#if defined(ARDUINO_METRO_ESP32S2)
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
Adafruit_USBH_Host USBHost(&SPI, 33, 15);
#else
// Default CS and INT are pin 10, 9
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
#endif
#else
// Native USB Host such as rp2040
Adafruit_USBH_Host USBHost;
#endif
//--------------------------------------------------------------------+
// Helper Functions
//--------------------------------------------------------------------+
#ifdef ARDUINO_ARCH_RP2040
static void rp2040_configure_pio_usb(void) {
//while ( !Serial ) delay(10); // wait for native usb
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
// Check for CPU frequency, must be multiple of 12 Mhz for bit-banging USB
uint32_t cpu_hz = clock_get_hz(clk_sys);
if (cpu_hz % 12000000UL) {
while (!Serial) {
delay(10); // wait for native usb
}
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 12 Mhz\r\n", cpu_hz);
Serial.printf("Change your CPU Clock to 12*n Mhz in Menu->CPU Speed \r\n");
while (1) {
delay(1);
}
}
#ifdef PIN_5V_EN
pinMode(PIN_5V_EN, OUTPUT);
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
#endif
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
pio_cfg.pin_dp = PIN_USB_HOST_DP;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
// For pico-w, PIO is also used to communicate with cyw43
// Therefore we need to alternate the pio-usb configuration
// details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46
pio_cfg.sm_tx = 3;
pio_cfg.sm_rx = 2;
pio_cfg.sm_eop = 3;
pio_cfg.pio_rx_num = 0;
pio_cfg.pio_tx_num = 1;
pio_cfg.tx_ch = 9;
#endif
USBHost.configure_pio_usb(1, &pio_cfg);
}
#endif
#endif

View file

@ -1,3 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host
CH32V20x_EVT

View file

@ -1,184 +0,0 @@
/*********************************************************************
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) 2023 Bill Binko for Adafruit Industries
Based on tremor_filter example by Thach Ha
All text above, and the splash screen below must be included in
any redistribution
*********************************************************************/
/* This example demonstrates use of both device and host, where
* - Device run on native usb controller (roothub port0)
* - Host depending on MCUs run on either:
* - rp2040: bit-banging 2 GPIOs with the help of Pico-PIO-USB library (roothub port1)
* - samd21/51, nrf52840, esp32: using MAX3421e controller (host shield)
*
* Requirements:
* - For rp2040:
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
* - Provide VBus (5v) and GND for peripheral
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
* - For samd21/51, nrf52840, esp32:
* - Additional MAX2341e USB Host shield or featherwing is required
* - SPI instance, CS pin, INT pin are correctly configured in usbh_helper.h
*/
/* Example sketch receive mouse report from host interface (from e.g consumer mouse)
* and reduce large motions due to tremors by applying the natural log function.
* It handles negative values and a dead zone where small values will not be adjusted.
* Adjusted mouse movement are send via device interface (to PC).
*/
// USBHost is defined in usbh_helper.h
#include "usbh_helper.h"
// 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: desc report, desc len, protocol, interval, use out endpoint
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_MOUSE, 2, false);
/* Adjustable parameters for the log_filter() method.
* Adjust for each user (would be ideal to have this adjustable w/o recompiling) */
#define PRESCALE 8.0 // Must be > 0, Higher numbers increase rate of attenuation
#define POSTSCALE 1.5 // Must be > 0, Higher numbers compensate for PRESCALE attenuation
#define DEADZONE 1.0 // Must be > 1, Movements < this magnitude will not be filtered
void setup() {
Serial.begin(115200);
usb_hid.begin();
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
// init host stack on controller (rhport) 1
// For rp2040: this is called in core1's setup1()
USBHost.begin(1);
#endif
//while ( !Serial ) delay(10); // wait for native usb
Serial.println("ATMakers Logarithm Tremor Filter Example");
}
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
//--------------------------------------------------------------------+
// Using Host shield MAX3421E controller
//--------------------------------------------------------------------+
void loop() {
USBHost.task();
Serial.flush();
}
#elif defined(ARDUINO_ARCH_RP2040)
//--------------------------------------------------------------------+
// For RP2040 use both core0 for device stack, core1 for host stack
//--------------------------------------------------------------------+
void loop() {
Serial.flush();
}
//------------- Core1 -------------//
void setup1() {
// configure pio-usb: defined in usbh_helper.h
rp2040_configure_pio_usb();
// run host stack on controller (rhport) 1
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
// host bit-banging processing works done in core1 to free up core0 for other works
USBHost.begin(1);
}
void loop1() {
USBHost.task();
}
#endif
//--------------------------------------------------------------------+
// TinyUSB Host callbacks
//--------------------------------------------------------------------+
extern "C"
{
// Invoked when device with hid interface is mounted
// Report descriptor is also available for use.
// tuh_hid_parse_report_descriptor() can be used to parse common/simple enough
// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE,
// it will be skipped therefore report_desc = NULL, desc_len = 0
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
(void) desc_report;
(void) desc_len;
uint16_t vid, pid;
tuh_vid_pid_get(dev_addr, &vid, &pid);
Serial.printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
Serial.printf("VID = %04x, PID = %04x\r\n", vid, pid);
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
if (itf_protocol == HID_ITF_PROTOCOL_MOUSE) {
Serial.printf("HID Mouse\r\n");
if (!tuh_hid_receive_report(dev_addr, instance)) {
Serial.printf("Error: cannot request to receive report\r\n");
}
}
}
// Invoked when device with hid interface is un-mounted
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
Serial.printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
}
// Invoked when received report from device via interrupt endpoint
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) {
filter_report((hid_mouse_report_t const *) report);
// continue to request to receive report
if (!tuh_hid_receive_report(dev_addr, instance)) {
Serial.printf("Error: cannot request to receive report\r\n");
}
}
} // extern C
//--------------------------------------------------------------------+
// Low pass filter Functions
//--------------------------------------------------------------------+
/*
* log_filter: Reduce large motions due to tremors by applying the natural log function
* Handles negative values and a dead zone where small values will not be adjusted
*/
int8_t log_filter(int8_t val) {
if (val < -1 * DEADZONE) {
return (int8_t) (-1.0 * POSTSCALE * logf(-1.0 * PRESCALE * (float) val));
} else if (val > DEADZONE) {
return (int8_t) (POSTSCALE * logf(PRESCALE * (float) val));
} else {
return val;
}
}
/*
* Adjust HID report by applying log_filter
*/
void filter_report(hid_mouse_report_t const *report) {
int8_t old_x = report->x;
int8_t old_y = report->y;
hid_mouse_report_t filtered_report = *report;
filtered_report.x = log_filter(old_x);
filtered_report.y = log_filter(old_y);
//Serial.printf("%d,%d,%d,%d\n", old_x, filtered_report.x, old_y, filtered_report.y);
usb_hid.sendReport(0, &filtered_report, sizeof(filtered_report));
}

View file

@ -1,99 +0,0 @@
/*********************************************************************
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
*********************************************************************/
#ifndef USBH_HELPER_H
#define USBH_HELPER_H
#ifdef ARDUINO_ARCH_RP2040
// pio-usb is required for rp2040 host
#include "pio_usb.h"
// Pin D+ for host, D- = D+ + 1
#ifndef PIN_USB_HOST_DP
#define PIN_USB_HOST_DP 16
#endif
// Pin for enabling Host VBUS. comment out if not used
#ifndef PIN_5V_EN
#define PIN_5V_EN 18
#endif
#ifndef PIN_5V_EN_STATE
#define PIN_5V_EN_STATE 1
#endif
#endif // ARDUINO_ARCH_RP2040
#include "Adafruit_TinyUSB.h"
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
// USB Host using MAX3421E: SPI, CS, INT
#include "SPI.h"
#if defined(ARDUINO_METRO_ESP32S2)
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
Adafruit_USBH_Host USBHost(&SPI, 33, 15);
#else
// Default CS and INT are pin 10, 9
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
#endif
#else
// Native USB Host such as rp2040
Adafruit_USBH_Host USBHost;
#endif
//--------------------------------------------------------------------+
// Helper Functions
//--------------------------------------------------------------------+
#ifdef ARDUINO_ARCH_RP2040
static void rp2040_configure_pio_usb(void) {
//while ( !Serial ) delay(10); // wait for native usb
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
// Check for CPU frequency, must be multiple of 12 Mhz for bit-banging USB
uint32_t cpu_hz = clock_get_hz(clk_sys);
if (cpu_hz % 12000000UL) {
while (!Serial) {
delay(10); // wait for native usb
}
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 12 Mhz\r\n", cpu_hz);
Serial.printf("Change your CPU Clock to 12*n Mhz in Menu->CPU Speed \r\n");
while (1) {
delay(1);
}
}
#ifdef PIN_5V_EN
pinMode(PIN_5V_EN, OUTPUT);
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
#endif
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
pio_cfg.pin_dp = PIN_USB_HOST_DP;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
// For pico-w, PIO is also used to communicate with cyw43
// Therefore we need to alternate the pio-usb configuration
// details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46
pio_cfg.sm_tx = 3;
pio_cfg.sm_rx = 2;
pio_cfg.sm_eop = 3;
pio_cfg.pio_rx_num = 0;
pio_cfg.pio_tx_num = 1;
pio_cfg.tx_ch = 9;
#endif
USBHost.configure_pio_usb(1, &pio_cfg);
}
#endif
#endif

View file

@ -1,3 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host
CH32V20x_EVT

View file

@ -1,205 +0,0 @@
/*********************************************************************
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 demonstrates use of both device and host, where
* - Device run on native usb controller (roothub port0)
* - Host depending on MCUs run on either:
* - rp2040: bit-banging 2 GPIOs with the help of Pico-PIO-USB library (roothub port1)
* - samd21/51, nrf52840, esp32: using MAX3421e controller (host shield)
*
* Requirements:
* - For rp2040:
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
* - Provide VBus (5v) and GND for peripheral
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
* - For samd21/51, nrf52840, esp32:
* - Additional MAX2341e USB Host shield or featherwing is required
* - SPI instance, CS pin, INT pin are correctly configured in usbh_helper.h
*/
/* Example sketch receive mouse report from host interface (from e.g consumer mouse)
* and apply a butterworth low pass filter with a specific CUTOFF_FREQUENCY on hid mouse movement report.
* Filtered report are send via device interface (to PC) acting as a "Mouse Tremor Filter".
*/
// USBHost is defined in usbh_helper.h
#include "usbh_helper.h"
// 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: desc report, desc len, protocol, interval, use out endpoint
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_MOUSE, 2, false);
//------------- Low pass filter with Butterworth -------------//
// Butterworth low-pass filter coefficients
typedef struct {
float b0, b1, b2, a1, a2;
} butterworth_coeffs_t;
#define SAMPLING_FREQUENCY 100.0 // Hz
#define CUTOFF_FREQUENCY 10.0 // Hz
// x, y
butterworth_coeffs_t coeffs[2];
butterworth_coeffs_t butterworth_lowpass(float cutoff_frequency, float sampling_frequency);
void filter_report(hid_mouse_report_t const *report);
void setup() {
Serial.begin(115200);
usb_hid.begin();
coeffs[0] = butterworth_lowpass(CUTOFF_FREQUENCY, SAMPLING_FREQUENCY);
coeffs[1] = butterworth_lowpass(CUTOFF_FREQUENCY, SAMPLING_FREQUENCY);
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
// init host stack on controller (rhport) 1
// For rp2040: this is called in core1's setup1()
USBHost.begin(1);
#endif
//while ( !Serial ) delay(10); // wait for native usb
Serial.println("TinyUSB Mouse Tremor Filter Example");
}
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
//--------------------------------------------------------------------+
// Using Host shield MAX3421E controller
//--------------------------------------------------------------------+
void loop() {
USBHost.task();
Serial.flush();
}
#elif defined(ARDUINO_ARCH_RP2040)
//--------------------------------------------------------------------+
// For RP2040 use both core0 for device stack, core1 for host stack
//--------------------------------------------------------------------+
void loop() {
Serial.flush();
}
//------------- Core1 -------------//
void setup1() {
// configure pio-usb: defined in usbh_helper.h
rp2040_configure_pio_usb();
// run host stack on controller (rhport) 1
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
// host bit-banging processing works done in core1 to free up core0 for other works
USBHost.begin(1);
}
void loop1() {
USBHost.task();
}
#endif
//--------------------------------------------------------------------+
// TinyUSB Host callbacks
//--------------------------------------------------------------------+
extern "C"
{
// Invoked when device with hid interface is mounted
// Report descriptor is also available for use.
// tuh_hid_parse_report_descriptor() can be used to parse common/simple enough
// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE,
// it will be skipped therefore report_desc = NULL, desc_len = 0
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
(void) desc_report;
(void) desc_len;
uint16_t vid, pid;
tuh_vid_pid_get(dev_addr, &vid, &pid);
Serial.printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
Serial.printf("VID = %04x, PID = %04x\r\n", vid, pid);
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
if (itf_protocol == HID_ITF_PROTOCOL_MOUSE) {
Serial.printf("HID Mouse\r\n");
if (!tuh_hid_receive_report(dev_addr, instance)) {
Serial.printf("Error: cannot request to receive report\r\n");
}
}
}
// Invoked when device with hid interface is un-mounted
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
Serial.printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
}
// Invoked when received report from device via interrupt endpoint
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) {
filter_report((hid_mouse_report_t const *) report);
// continue to request to receive report
if (!tuh_hid_receive_report(dev_addr, instance)) {
Serial.printf("Error: cannot request to receive report\r\n");
}
}
} // extern C
//--------------------------------------------------------------------+
// Low pass filter Functions
//--------------------------------------------------------------------+
butterworth_coeffs_t butterworth_lowpass(float cutoff_frequency, float sampling_frequency) {
butterworth_coeffs_t coe;
float omega = 2.0 * PI * cutoff_frequency / sampling_frequency;
float s = sin(omega);
float t = tan(omega / 2.0);
float alpha = s / (2.0 * t);
coe.b0 = 1.0 / (1.0 + 2.0 * alpha + 2.0 * alpha * alpha);
coe.b1 = 2.0 * coe.b0;
coe.b2 = coe.b0;
coe.a1 = 2.0 * (alpha * alpha - 1.0) * coe.b0;
coe.a2 = (1.0 - 2.0 * alpha + 2.0 * alpha * alpha) * coe.b0;
return coe;
}
float butterworth_filter(float data, butterworth_coeffs_t *coeffs, float *filtered, float *prev1, float *prev2) {
float output = coeffs->b0 * data + coeffs->b1 * (*prev1) + coeffs->b2 * (*prev2) - coeffs->a1 * (*filtered) -
coeffs->a2 * (*prev1);
*prev2 = *prev1;
*prev1 = data;
*filtered = output;
return output;
}
void filter_report(hid_mouse_report_t const *report) {
static float filtered[2] = { 0.0, 0.0 };
static float prev1[2] = { 0.0, 0.0 };
static float prev2[2] = { 0.0, 0.0 };
butterworth_filter(report->x, &coeffs[0], &filtered[0], &prev1[0], &prev2[0]);
butterworth_filter(report->y, &coeffs[1], &filtered[1], &prev1[1], &prev2[1]);
hid_mouse_report_t filtered_report = *report;
filtered_report.x = (int8_t) filtered[0];
filtered_report.y = (int8_t) filtered[1];
usb_hid.sendReport(0, &filtered_report, sizeof(filtered_report));
}

View file

@ -1,99 +0,0 @@
/*********************************************************************
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
*********************************************************************/
#ifndef USBH_HELPER_H
#define USBH_HELPER_H
#ifdef ARDUINO_ARCH_RP2040
// pio-usb is required for rp2040 host
#include "pio_usb.h"
// Pin D+ for host, D- = D+ + 1
#ifndef PIN_USB_HOST_DP
#define PIN_USB_HOST_DP 16
#endif
// Pin for enabling Host VBUS. comment out if not used
#ifndef PIN_5V_EN
#define PIN_5V_EN 18
#endif
#ifndef PIN_5V_EN_STATE
#define PIN_5V_EN_STATE 1
#endif
#endif // ARDUINO_ARCH_RP2040
#include "Adafruit_TinyUSB.h"
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
// USB Host using MAX3421E: SPI, CS, INT
#include "SPI.h"
#if defined(ARDUINO_METRO_ESP32S2)
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
Adafruit_USBH_Host USBHost(&SPI, 33, 15);
#else
// Default CS and INT are pin 10, 9
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
#endif
#else
// Native USB Host such as rp2040
Adafruit_USBH_Host USBHost;
#endif
//--------------------------------------------------------------------+
// Helper Functions
//--------------------------------------------------------------------+
#ifdef ARDUINO_ARCH_RP2040
static void rp2040_configure_pio_usb(void) {
//while ( !Serial ) delay(10); // wait for native usb
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
// Check for CPU frequency, must be multiple of 12 Mhz for bit-banging USB
uint32_t cpu_hz = clock_get_hz(clk_sys);
if (cpu_hz % 12000000UL) {
while (!Serial) {
delay(10); // wait for native usb
}
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 12 Mhz\r\n", cpu_hz);
Serial.printf("Change your CPU Clock to 12*n Mhz in Menu->CPU Speed \r\n");
while (1) {
delay(1);
}
}
#ifdef PIN_5V_EN
pinMode(PIN_5V_EN, OUTPUT);
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
#endif
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
pio_cfg.pin_dp = PIN_USB_HOST_DP;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
// For pico-w, PIO is also used to communicate with cyw43
// Therefore we need to alternate the pio-usb configuration
// details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46
pio_cfg.sm_tx = 3;
pio_cfg.sm_rx = 2;
pio_cfg.sm_eop = 3;
pio_cfg.pio_rx_num = 0;
pio_cfg.pio_tx_num = 1;
pio_cfg.tx_ch = 9;
#endif
USBHost.configure_pio_usb(1, &pio_cfg);
}
#endif
#endif

View file

@ -1,3 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host
CH32V20x_EVT

View file

@ -9,77 +9,103 @@
any redistribution any redistribution
*********************************************************************/ *********************************************************************/
/* This example demonstrates use of both device and host, where
* - Device run on native usb controller (roothub port0)
* - Host depending on MCUs run on either:
* - rp2040: bit-banging 2 GPIOs with the help of Pico-PIO-USB library (roothub port1)
* - samd21/51, nrf52840, esp32: using MAX3421e controller (host shield)
*
* Requirements:
* - For rp2040:
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
* - Provide VBus (5v) and GND for peripheral
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
* - For samd21/51, nrf52840, esp32:
* - Additional MAX2341e USB Host shield or featherwing is required
* - SPI instance, CS pin, INT pin are correctly configured in usbh_helper.h
*/
/* Example sketch receive keyboard report from host interface (from e.g consumer keyboard) /* This example demonstrates use of both device and host, where
* - Device run on native usb controller (controller0)
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
*
* Example sketch receive keyboard report from host interface (from e.g consumer keyboard)
* and remap it to another key and send it via device interface (to PC). For simplicity, * and remap it to another key and send it via device interface (to PC). For simplicity,
* this example only toggle shift key to the report, effectively remap: * this example only toggle shift key to the report, effectively remap:
* - all character key <-> upper case * - all character key <-> upper case
* - number <-> its symbol (with shift) * - number <-> its symbol (with shift)
*
* Requirements:
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
* - 2 consecutive GPIOs: D+ is defined by PIN_PIO_USB_HOST_DP, D- = D+ +1
* - Provide VBus (5v) and GND for peripheral
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
*/ */
// USBHost is defined in usbh_helper.h // pio-usb is required for rp2040 host
#include "usbh_helper.h" #include "pio_usb.h"
#include "Adafruit_TinyUSB.h"
// Pin D+ for host, D- = D+ + 1
#ifndef PIN_PIO_USB_HOST_DP
#define PIN_PIO_USB_HOST_DP 20
#endif
// Pin for enabling Host VBUS. comment out if not used
#ifndef PIN_PIO_USB_HOST_VBUSEN
#define PIN_PIO_USB_HOST_VBUSEN 22
#endif
#ifndef PIN_PIO_USB_HOST_VBUSEN_STATE
#define PIN_PIO_USB_HOST_VBUSEN_STATE 1
#endif
// Language ID: English
#define LANGUAGE_ID 0x0409
// USB Host object
Adafruit_USBH_Host USBHost;
// HID report descriptor using TinyUSB's template // HID report descriptor using TinyUSB's template
// Single Report (no ID) descriptor // Single Report (no ID) descriptor
uint8_t const desc_hid_report[] = { uint8_t const desc_hid_report[] =
TUD_HID_REPORT_DESC_KEYBOARD() {
TUD_HID_REPORT_DESC_KEYBOARD()
}; };
// USB HID object: desc report, desc len, protocol, interval, use out endpoint // USB HID object. For ESP32 these values cannot be changed after this declaration
// desc report, desc len, protocol, interval, use out endpoint
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_KEYBOARD, 2, false); Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_KEYBOARD, 2, false);
void setup() { //--------------------------------------------------------------------+
// Setup and Loop on Core0
//--------------------------------------------------------------------+
void setup()
{
Serial.begin(115200); Serial.begin(115200);
usb_hid.begin(); usb_hid.begin();
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
// init host stack on controller (rhport) 1
// For rp2040: this is called in core1's setup1()
USBHost.begin(1);
#endif
//while ( !Serial ) delay(10); // wait for native usb //while ( !Serial ) delay(10); // wait for native usb
Serial.println("TinyUSB Host HID Remap Example"); Serial.println("TinyUSB Host HID Remap Example");
} }
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 void loop()
//--------------------------------------------------------------------+ {
// Using Host shield MAX3421E controller
//--------------------------------------------------------------------+
void loop() {
USBHost.task();
} }
#elif defined(ARDUINO_ARCH_RP2040)
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// For RP2040 use both core0 for device stack, core1 for host stack // Setup and Loop on Core1
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
void loop() {
// nothing to do
}
//------------- Core1 -------------//
void setup1() { void setup1() {
// configure pio-usb: defined in usbh_helper.h //while ( !Serial ) delay(10); // wait for native usb
rp2040_configure_pio_usb(); Serial.println("Core1 setup to run TinyUSB host with pio-usb");
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
uint32_t cpu_hz = clock_get_hz(clk_sys);
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
while ( !Serial ) delay(10); // wait for native usb
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
while(1) delay(1);
}
#ifdef PIN_PIO_USB_HOST_VBUSEN
pinMode(PIN_PIO_USB_HOST_VBUSEN, OUTPUT);
digitalWrite(PIN_PIO_USB_HOST_VBUSEN, PIN_PIO_USB_HOST_VBUSEN_STATE);
#endif
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
pio_cfg.pin_dp = PIN_PIO_USB_HOST_DP;
USBHost.configure_pio_usb(1, &pio_cfg);
// run host stack on controller (rhport) 1 // run host stack on controller (rhport) 1
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the // Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
@ -87,16 +113,10 @@ void setup1() {
USBHost.begin(1); USBHost.begin(1);
} }
void loop1() { void loop1()
{
USBHost.task(); USBHost.task();
} }
#endif
//--------------------------------------------------------------------+
// TinyUSB Host callbacks
//--------------------------------------------------------------------+
extern "C"
{
// Invoked when device with hid interface is mounted // Invoked when device with hid interface is mounted
// Report descriptor is also available for use. // Report descriptor is also available for use.
@ -104,8 +124,8 @@ extern "C"
// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, // descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE,
// it will be skipped therefore report_desc = NULL, desc_len = 0 // it will be skipped therefore report_desc = NULL, desc_len = 0
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) { void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
(void) desc_report; (void)desc_report;
(void) desc_len; (void)desc_len;
uint16_t vid, pid; uint16_t vid, pid;
tuh_vid_pid_get(dev_addr, &vid, &pid); tuh_vid_pid_get(dev_addr, &vid, &pid);
@ -114,7 +134,7 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_re
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance); uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD) { if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD) {
Serial.printf("HID Keyboard\r\n"); Serial.printf("HID Keyboard\r\n", vid, pid);
if (!tuh_hid_receive_report(dev_addr, instance)) { if (!tuh_hid_receive_report(dev_addr, instance)) {
Serial.printf("Error: cannot request to receive report\r\n"); Serial.printf("Error: cannot request to receive report\r\n");
} }
@ -126,11 +146,12 @@ void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
Serial.printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance); Serial.printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
} }
void remap_key(hid_keyboard_report_t const *original_report, hid_keyboard_report_t *remapped_report) { void remap_key(hid_keyboard_report_t const* original_report, hid_keyboard_report_t* remapped_report)
{
memcpy(remapped_report, original_report, sizeof(hid_keyboard_report_t)); memcpy(remapped_report, original_report, sizeof(hid_keyboard_report_t));
// only remap if not empty report i.e key released // only remap if not empty report i.e key released
for (uint8_t i = 0; i < 6; i++) { for(uint8_t i=0; i<6; i++) {
if (remapped_report->keycode[i] != 0) { if (remapped_report->keycode[i] != 0) {
// Note: we ignore right shift here // Note: we ignore right shift here
remapped_report->modifier ^= KEYBOARD_MODIFIER_LEFTSHIFT; remapped_report->modifier ^= KEYBOARD_MODIFIER_LEFTSHIFT;
@ -141,16 +162,16 @@ void remap_key(hid_keyboard_report_t const *original_report, hid_keyboard_report
// Invoked when received report from device via interrupt endpoint // Invoked when received report from device via interrupt endpoint
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) { void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) {
if (len != 8) { if ( len != 8 ) {
Serial.printf("report len = %u NOT 8, probably something wrong !!\r\n", len); Serial.printf("report len = %u NOT 8, probably something wrong !!\r\n", len);
} else { }else {
hid_keyboard_report_t remapped_report; hid_keyboard_report_t remapped_report;
remap_key((hid_keyboard_report_t const *) report, &remapped_report); remap_key((hid_keyboard_report_t const*) report, &remapped_report);
// send remapped report to PC // send remapped report to PC
// NOTE: for better performance you should save/queue remapped report instead of // NOTE: for better performance you should save/queue remapped report instead of
// blocking wait for usb_hid ready here // blocking wait for usb_hid ready here
while (!usb_hid.ready()) { while ( !usb_hid.ready() ) {
yield(); yield();
} }
@ -162,5 +183,3 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons
Serial.printf("Error: cannot request to receive report\r\n"); Serial.printf("Error: cannot request to receive report\r\n");
} }
} }
}

View file

@ -1,99 +0,0 @@
/*********************************************************************
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
*********************************************************************/
#ifndef USBH_HELPER_H
#define USBH_HELPER_H
#ifdef ARDUINO_ARCH_RP2040
// pio-usb is required for rp2040 host
#include "pio_usb.h"
// Pin D+ for host, D- = D+ + 1
#ifndef PIN_USB_HOST_DP
#define PIN_USB_HOST_DP 16
#endif
// Pin for enabling Host VBUS. comment out if not used
#ifndef PIN_5V_EN
#define PIN_5V_EN 18
#endif
#ifndef PIN_5V_EN_STATE
#define PIN_5V_EN_STATE 1
#endif
#endif // ARDUINO_ARCH_RP2040
#include "Adafruit_TinyUSB.h"
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
// USB Host using MAX3421E: SPI, CS, INT
#include "SPI.h"
#if defined(ARDUINO_METRO_ESP32S2)
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
Adafruit_USBH_Host USBHost(&SPI, 33, 15);
#else
// Default CS and INT are pin 10, 9
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
#endif
#else
// Native USB Host such as rp2040
Adafruit_USBH_Host USBHost;
#endif
//--------------------------------------------------------------------+
// Helper Functions
//--------------------------------------------------------------------+
#ifdef ARDUINO_ARCH_RP2040
static void rp2040_configure_pio_usb(void) {
//while ( !Serial ) delay(10); // wait for native usb
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
// Check for CPU frequency, must be multiple of 12 Mhz for bit-banging USB
uint32_t cpu_hz = clock_get_hz(clk_sys);
if (cpu_hz % 12000000UL) {
while (!Serial) {
delay(10); // wait for native usb
}
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 12 Mhz\r\n", cpu_hz);
Serial.printf("Change your CPU Clock to 12*n Mhz in Menu->CPU Speed \r\n");
while (1) {
delay(1);
}
}
#ifdef PIN_5V_EN
pinMode(PIN_5V_EN, OUTPUT);
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
#endif
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
pio_cfg.pin_dp = PIN_USB_HOST_DP;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
// For pico-w, PIO is also used to communicate with cyw43
// Therefore we need to alternate the pio-usb configuration
// details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46
pio_cfg.sm_tx = 3;
pio_cfg.sm_rx = 2;
pio_cfg.sm_eop = 3;
pio_cfg.pio_rx_num = 0;
pio_cfg.pio_tx_num = 1;
pio_cfg.tx_ch = 9;
#endif
USBHost.configure_pio_usb(1, &pio_cfg);
}
#endif
#endif

View file

@ -1,2 +0,0 @@
pico_rp2040_tinyusb_host
CH32V20x_EVT

View file

@ -11,43 +11,47 @@
/* This example demonstrates use of both device and host, where /* This example demonstrates use of both device and host, where
* - Device run on native usb controller (roothub port0) * - Device run on native usb controller (controller0)
* - Host depending on MCUs run on either: * - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
* - rp2040: bit-banging 2 GPIOs with the help of Pico-PIO-USB library (roothub port1) *
* - samd21/51, nrf52840, esp32: using MAX3421e controller (host shield) * Example will log CPU temperature periodically (ms,value) to USB thumbdrive
* *
* Requirements: * Requirements:
* - For rp2040: * - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library * - 2 consecutive GPIOs: D+ is defined by PIN_PIO_USB_HOST_DP, D- = D+ +1
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1 * - Provide VBus (5v) and GND for peripheral
* - Provide VBus (5v) and GND for peripheral * - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
* - For samd21/51, nrf52840, esp32:
* - Additional MAX2341e USB Host shield or featherwing is required
* - SPI instance, CS pin, INT pin are correctly configured in usbh_helper.h
*/ */
/* Example sketch read analog pin (default A0) and log it to LOG_FILE on the msc device // pio-usb is required for rp2040 host
* every LOG_INTERVAL ms. */ #include "pio_usb.h"
// nRF52 and ESP32 use freeRTOS, we may need to run USBhost.task() in its own rtos's thread.
// Since USBHost.task() will put loop() into dormant state and prevent followed code from running
// until there is USB host event.
#if defined(ARDUINO_NRF52_ADAFRUIT) || defined(ARDUINO_ARCH_ESP32)
#define USE_FREERTOS
#endif
// SdFat is required for using Adafruit_USBH_MSC_SdFatDevice // SdFat is required for using Adafruit_USBH_MSC_SdFatDevice
#include "SdFat_Adafruit_Fork.h" #include "SdFat.h"
// TinyUSB lib
#include "Adafruit_TinyUSB.h"
// Pin D+ for host, D- = D+ + 1
#ifndef PIN_PIO_USB_HOST_DP
#define PIN_PIO_USB_HOST_DP 20
#endif
// Pin for enabling Host VBUS. comment out if not used
#ifndef PIN_PIO_USB_HOST_VBUSEN
#define PIN_PIO_USB_HOST_VBUSEN 22
#endif
#ifndef PIN_PIO_USB_HOST_VBUSEN_STATE
#define PIN_PIO_USB_HOST_VBUSEN_STATE 1
#endif
// USBHost is defined in usbh_helper.h
#include "usbh_helper.h"
#define LOG_FILE "cpu_temp.csv" #define LOG_FILE "cpu_temp.csv"
#define LOG_INTERVAL 5000 #define LOG_INTERVAL 5000
// Analog pin for reading // USB Host object
const int analogPin = A0; Adafruit_USBH_Host USBHost;
// USB Host MSC Block Device object which implemented API for use with SdFat // USB Host MSC Block Device object which implemented API for use with SdFat
Adafruit_USBH_MSC_BlockDevice msc_block_dev; Adafruit_USBH_MSC_BlockDevice msc_block_dev;
@ -59,103 +63,77 @@ File32 f_log;
// if file system is successfully mounted on usb block device // if file system is successfully mounted on usb block device
volatile bool is_mounted = false; volatile bool is_mounted = false;
void data_log(void) { //--------------------------------------------------------------------+
// Setup and Loop on Core0
//--------------------------------------------------------------------+
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(115200);
//while ( !Serial ) delay(10); // wait for native usb
Serial.println("TinyUSB Host MassStorage Data Logger Example");
}
void loop()
{
if (!is_mounted) { if (!is_mounted) {
// nothing to do // nothing to do
return; delay(1000);
}
static unsigned long last_ms = 0;
unsigned long ms = millis();
if ( ms - last_ms < LOG_INTERVAL ) {
return; return;
} }
// Turn on LED when start writing // Turn on LED when start writing
#ifdef LED_BUILTIN
digitalWrite(LED_BUILTIN, HIGH); digitalWrite(LED_BUILTIN, HIGH);
#endif
f_log = fatfs.open(LOG_FILE, O_WRITE | O_APPEND | O_CREAT); f_log = fatfs.open(LOG_FILE, O_WRITE | O_APPEND | O_CREAT);
if (!f_log) { if (!f_log) {
Serial.println("Cannot create file: " LOG_FILE); Serial.println("Cannot create file: " LOG_FILE);
} else { }else {
int value = analogRead(analogPin); float cpu_temp = analogReadTemp();
uint32_t ms = millis();
Serial.printf("%lu,%d\r\n", ms, value); Serial.printf("%u,%.02f\r\n", millis(), cpu_temp);
f_log.printf("%lu,%d\r\n", ms, value); f_log.printf("%u,%.02f\r\n", millis(), cpu_temp);
f_log.close(); f_log.close();
} }
last_ms = ms; delay(LOG_INTERVAL);
Serial.flush();
} }
#ifdef USE_FREERTOS
#ifdef ARDUINO_ARCH_ESP32
#define USBH_STACK_SZ 2048
#else
#define USBH_STACK_SZ 200
#endif
void usbhost_rtos_task(void *param) {
(void) param;
while (1) {
USBHost.task();
}
}
#endif
void setup() {
Serial.begin(115200);
#ifdef LED_BUILTIN
pinMode(LED_BUILTIN, OUTPUT);
#endif
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
// init host stack on controller (rhport) 1
// For rp2040: this is called in core1's setup1()
USBHost.begin(1);
#endif
#ifdef USE_FREERTOS
// Create a task to run USBHost.task() in background
xTaskCreate(usbhost_rtos_task, "usbh", USBH_STACK_SZ, NULL, 3, NULL);
#endif
// while ( !Serial ) delay(10); // wait for native usb
Serial.println("TinyUSB Host MassStorage Data Logger Example");
}
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Using Host shield MAX3421E controller // Setup and Loop on Core1
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
void loop() {
#ifndef USE_FREERTOS
USBHost.task();
#endif
data_log();
}
#elif defined(ARDUINO_ARCH_RP2040)
//--------------------------------------------------------------------+
// For RP2040 use both core0 for device stack, core1 for host stack
//--------------------------------------------------------------------+
void loop() {
data_log();
}
//------------- Core1 -------------//
void setup1() { void setup1() {
// configure pio-usb: defined in usbh_helper.h //while ( !Serial ) delay(10); // wait for native usb
rp2040_configure_pio_usb(); Serial.println("Core1 setup to run TinyUSB host with pio-usb");
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
uint32_t cpu_hz = clock_get_hz(clk_sys);
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
while ( !Serial ) {
delay(10); // wait for native usb
}
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
while(1) {
delay(1);
}
}
#ifdef PIN_PIO_USB_HOST_VBUSEN
pinMode(PIN_PIO_USB_HOST_VBUSEN, OUTPUT);
digitalWrite(PIN_PIO_USB_HOST_VBUSEN, PIN_PIO_USB_HOST_VBUSEN_STATE);
#endif
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
pio_cfg.pin_dp = PIN_PIO_USB_HOST_DP;
USBHost.configure_pio_usb(1, &pio_cfg);
// run host stack on controller (rhport) 1 // run host stack on controller (rhport) 1
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the // Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
@ -163,61 +141,51 @@ void setup1() {
USBHost.begin(1); USBHost.begin(1);
} }
void loop1() { void loop1()
{
USBHost.task(); USBHost.task();
Serial.flush();
} }
#endif
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// TinyUSB Host callbacks // TinyUSB Host callbacks
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
bool write_complete_callback(uint8_t dev_addr, tuh_msc_complete_data_t const *cb_data) {
(void) dev_addr;
(void) cb_data;
#ifdef LED_BUILTIN
// turn off LED after write is complete
// Note this only marks the usb transfer is complete, device can take longer to actual
// write data to physical flash
digitalWrite(LED_BUILTIN, LOW);
#endif
return true;
}
extern "C"
{
// Invoked when device is mounted (configured) // Invoked when device is mounted (configured)
void tuh_mount_cb(uint8_t daddr) { void tuh_mount_cb (uint8_t daddr)
{
(void) daddr; (void) daddr;
} }
/// Invoked when device is unmounted (bus reset/unplugged) /// Invoked when device is unmounted (bus reset/unplugged)
void tuh_umount_cb(uint8_t daddr) { void tuh_umount_cb(uint8_t daddr)
{
(void) daddr; (void) daddr;
} }
// Invoked when a device with MassStorage interface is mounted // Invoked when a device with MassStorage interface is mounted
void tuh_msc_mount_cb(uint8_t dev_addr) { void tuh_msc_mount_cb(uint8_t dev_addr)
{
// Initialize block device with MSC device address // Initialize block device with MSC device address
msc_block_dev.begin(dev_addr); msc_block_dev.begin(dev_addr);
// For simplicity this example only support LUN 0 // For simplicity this example only support LUN 0
msc_block_dev.setActiveLUN(0); msc_block_dev.setActiveLUN(0);
msc_block_dev.setWriteCompleteCallback(write_complete_callback); msc_block_dev.setWriteCompleteCallback(write_complete_callback);
is_mounted = fatfs.begin(&msc_block_dev); is_mounted = fatfs.begin(&msc_block_dev);
if (is_mounted) { if (is_mounted) {
fatfs.ls(&Serial, LS_SIZE); fatfs.ls(&Serial, LS_SIZE);
} else { }else {
Serial.println("Failed to mount mass storage device. Make sure it is formatted as FAT"); Serial.println("Failed to mount mass storage device. Make sure it is formatted as FAT");
} }
} }
// Invoked when a device with MassStorage interface is unmounted // Invoked when a device with MassStorage interface is unmounted
void tuh_msc_umount_cb(uint8_t dev_addr) { void tuh_msc_umount_cb(uint8_t dev_addr)
{
(void) dev_addr; (void) dev_addr;
// unmount file system // unmount file system
@ -228,4 +196,17 @@ void tuh_msc_umount_cb(uint8_t dev_addr) {
msc_block_dev.end(); msc_block_dev.end();
} }
bool write_complete_callback(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data)
{
(void) dev_addr;
(void) cb_data;
// turn off LED after write is complete
// Note this only marks the usb transfer is complete, device can take longer to actual
// write data to physical flash
digitalWrite(LED_BUILTIN, LOW);
return true;
} }

View file

@ -1,99 +0,0 @@
/*********************************************************************
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
*********************************************************************/
#ifndef USBH_HELPER_H
#define USBH_HELPER_H
#ifdef ARDUINO_ARCH_RP2040
// pio-usb is required for rp2040 host
#include "pio_usb.h"
// Pin D+ for host, D- = D+ + 1
#ifndef PIN_USB_HOST_DP
#define PIN_USB_HOST_DP 16
#endif
// Pin for enabling Host VBUS. comment out if not used
#ifndef PIN_5V_EN
#define PIN_5V_EN 18
#endif
#ifndef PIN_5V_EN_STATE
#define PIN_5V_EN_STATE 1
#endif
#endif // ARDUINO_ARCH_RP2040
#include "Adafruit_TinyUSB.h"
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
// USB Host using MAX3421E: SPI, CS, INT
#include "SPI.h"
#if defined(ARDUINO_METRO_ESP32S2)
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
Adafruit_USBH_Host USBHost(&SPI, 33, 15);
#else
// Default CS and INT are pin 10, 9
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
#endif
#else
// Native USB Host such as rp2040
Adafruit_USBH_Host USBHost;
#endif
//--------------------------------------------------------------------+
// Helper Functions
//--------------------------------------------------------------------+
#ifdef ARDUINO_ARCH_RP2040
static void rp2040_configure_pio_usb(void) {
//while ( !Serial ) delay(10); // wait for native usb
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
// Check for CPU frequency, must be multiple of 12 Mhz for bit-banging USB
uint32_t cpu_hz = clock_get_hz(clk_sys);
if (cpu_hz % 12000000UL) {
while (!Serial) {
delay(10); // wait for native usb
}
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 12 Mhz\r\n", cpu_hz);
Serial.printf("Change your CPU Clock to 12*n Mhz in Menu->CPU Speed \r\n");
while (1) {
delay(1);
}
}
#ifdef PIN_5V_EN
pinMode(PIN_5V_EN, OUTPUT);
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
#endif
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
pio_cfg.pin_dp = PIN_USB_HOST_DP;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
// For pico-w, PIO is also used to communicate with cyw43
// Therefore we need to alternate the pio-usb configuration
// details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46
pio_cfg.sm_tx = 3;
pio_cfg.sm_rx = 2;
pio_cfg.sm_eop = 3;
pio_cfg.pio_rx_num = 0;
pio_cfg.pio_tx_num = 1;
pio_cfg.tx_ch = 9;
#endif
USBHost.configure_pio_usb(1, &pio_cfg);
}
#endif
#endif

View file

@ -1,2 +0,0 @@
pico_rp2040_tinyusb_host
CH32V20x_EVT

View file

@ -9,28 +9,43 @@
any redistribution any redistribution
*********************************************************************/ *********************************************************************/
/* This example demonstrates use of both device and host, where /* This example demonstrates use of both device and host, where
* - Device run on native usb controller (roothub port0) * - Device run on native usb controller (controller0)
* - Host depending on MCUs run on either: * - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
* - rp2040: bit-banging 2 GPIOs with the help of Pico-PIO-USB library (roothub port1)
* - samd21/51, nrf52840, esp32: using MAX3421e controller (host shield)
* *
* Requirements: * Requirements:
* - For rp2040: * - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library * - 2 consecutive GPIOs: D+ is defined by PIN_PIO_USB_HOST_DP, D- = D+ +1
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1 * - Provide VBus (5v) and GND for peripheral
* - Provide VBus (5v) and GND for peripheral * - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
* - For samd21/51, nrf52840, esp32:
* - Additional MAX2341e USB Host shield or featherwing is required
* - SPI instance, CS pin, INT pin are correctly configured in usbh_helper.h
*/ */
// SdFat is required for using Adafruit_USBH_MSC_SdFatDevice // pio-usb is required for rp2040 host
#include "SdFat_Adafruit_Fork.h" #include "pio_usb.h"
// USBHost is defined in usbh_helper.h // SdFat is required for using Adafruit_USBH_MSC_SdFatDevice
#include "usbh_helper.h" #include "SdFat.h"
// TinyUSB lib
#include "Adafruit_TinyUSB.h"
// Pin D+ for host, D- = D+ + 1
#ifndef PIN_PIO_USB_HOST_DP
#define PIN_PIO_USB_HOST_DP 20
#endif
// Pin for enabling Host VBUS. comment out if not used
#ifndef PIN_PIO_USB_HOST_VBUSEN
#define PIN_PIO_USB_HOST_VBUSEN 22
#endif
#ifndef PIN_PIO_USB_HOST_VBUSEN_STATE
#define PIN_PIO_USB_HOST_VBUSEN_STATE 1
#endif
// USB Host object
Adafruit_USBH_Host USBHost;
// USB Host MSC Block Device object which implemented API for use with SdFat // USB Host MSC Block Device object which implemented API for use with SdFat
Adafruit_USBH_MSC_BlockDevice msc_block_dev; Adafruit_USBH_MSC_BlockDevice msc_block_dev;
@ -41,40 +56,51 @@ FatVolume fatfs;
// if file system is successfully mounted on usb block device // if file system is successfully mounted on usb block device
bool is_mounted = false; bool is_mounted = false;
void setup() { //--------------------------------------------------------------------+
// Setup and Loop on Core0
//--------------------------------------------------------------------+
void setup()
{
Serial.begin(115200); Serial.begin(115200);
//while ( !Serial ) delay(10); // wait for native usb
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
// init host stack on controller (rhport) 1
// For rp2040: this is called in core1's setup1()
USBHost.begin(1);
#endif
// while ( !Serial ) delay(10); // wait for native usb
Serial.println("TinyUSB Host Mass Storage File Explorer Example"); Serial.println("TinyUSB Host Mass Storage File Explorer Example");
} }
void loop()
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 {
//--------------------------------------------------------------------+
// Using Host shield MAX3421E controller
//--------------------------------------------------------------------+
void loop() {
USBHost.task();
Serial.flush();
} }
#elif defined(ARDUINO_ARCH_RP2040)
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// For RP2040 use both core0 for device stack, core1 for host stack // Setup and Loop on Core1
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
void loop() {
}
//------------- Core1 -------------//
void setup1() { void setup1() {
// configure pio-usb: defined in usbh_helper.h //while ( !Serial ) delay(10); // wait for native usb
rp2040_configure_pio_usb(); Serial.println("Core1 setup to run TinyUSB host with pio-usb");
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
uint32_t cpu_hz = clock_get_hz(clk_sys);
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
while ( !Serial ) {
delay(10); // wait for native usb
}
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
while(1) {
delay(1);
}
}
#ifdef PIN_PIO_USB_HOST_VBUSEN
pinMode(PIN_PIO_USB_HOST_VBUSEN, OUTPUT);
digitalWrite(PIN_PIO_USB_HOST_VBUSEN, PIN_PIO_USB_HOST_VBUSEN_STATE);
#endif
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
pio_cfg.pin_dp = PIN_PIO_USB_HOST_DP;
USBHost.configure_pio_usb(1, &pio_cfg);
// run host stack on controller (rhport) 1 // run host stack on controller (rhport) 1
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the // Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
@ -82,32 +108,30 @@ void setup1() {
USBHost.begin(1); USBHost.begin(1);
} }
void loop1() { void loop1()
{
USBHost.task(); USBHost.task();
} }
#endif
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// TinyUSB Host callbacks // TinyUSB Host callbacks
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
extern "C"
{
// Invoked when device is mounted (configured) // Invoked when device is mounted (configured)
void tuh_mount_cb(uint8_t daddr) { void tuh_mount_cb (uint8_t daddr)
{
(void) daddr; (void) daddr;
} }
/// Invoked when device is unmounted (bus reset/unplugged) /// Invoked when device is unmounted (bus reset/unplugged)
void tuh_umount_cb(uint8_t daddr) { void tuh_umount_cb(uint8_t daddr)
{
(void) daddr; (void) daddr;
} }
// Invoked when a device with MassStorage interface is mounted // Invoked when a device with MassStorage interface is mounted
void tuh_msc_mount_cb(uint8_t dev_addr) { void tuh_msc_mount_cb(uint8_t dev_addr)
Serial.printf("Device attached, address = %d\r\n", dev_addr); {
// Initialize block device with MSC device address // Initialize block device with MSC device address
msc_block_dev.begin(dev_addr); msc_block_dev.begin(dev_addr);
@ -122,8 +146,9 @@ void tuh_msc_mount_cb(uint8_t dev_addr) {
} }
// Invoked when a device with MassStorage interface is unmounted // Invoked when a device with MassStorage interface is unmounted
void tuh_msc_umount_cb(uint8_t dev_addr) { void tuh_msc_umount_cb(uint8_t dev_addr)
Serial.printf("Device removed, address = %d\r\n", dev_addr); {
(void) dev_addr;
// unmount file system // unmount file system
is_mounted = false; is_mounted = false;
@ -133,4 +158,3 @@ void tuh_msc_umount_cb(uint8_t dev_addr) {
msc_block_dev.end(); msc_block_dev.end();
} }
}

View file

@ -1,99 +0,0 @@
/*********************************************************************
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
*********************************************************************/
#ifndef USBH_HELPER_H
#define USBH_HELPER_H
#ifdef ARDUINO_ARCH_RP2040
// pio-usb is required for rp2040 host
#include "pio_usb.h"
// Pin D+ for host, D- = D+ + 1
#ifndef PIN_USB_HOST_DP
#define PIN_USB_HOST_DP 16
#endif
// Pin for enabling Host VBUS. comment out if not used
#ifndef PIN_5V_EN
#define PIN_5V_EN 18
#endif
#ifndef PIN_5V_EN_STATE
#define PIN_5V_EN_STATE 1
#endif
#endif // ARDUINO_ARCH_RP2040
#include "Adafruit_TinyUSB.h"
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
// USB Host using MAX3421E: SPI, CS, INT
#include "SPI.h"
#if defined(ARDUINO_METRO_ESP32S2)
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
Adafruit_USBH_Host USBHost(&SPI, 33, 15);
#else
// Default CS and INT are pin 10, 9
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
#endif
#else
// Native USB Host such as rp2040
Adafruit_USBH_Host USBHost;
#endif
//--------------------------------------------------------------------+
// Helper Functions
//--------------------------------------------------------------------+
#ifdef ARDUINO_ARCH_RP2040
static void rp2040_configure_pio_usb(void) {
//while ( !Serial ) delay(10); // wait for native usb
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
// Check for CPU frequency, must be multiple of 12 Mhz for bit-banging USB
uint32_t cpu_hz = clock_get_hz(clk_sys);
if (cpu_hz % 12000000UL) {
while (!Serial) {
delay(10); // wait for native usb
}
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 12 Mhz\r\n", cpu_hz);
Serial.printf("Change your CPU Clock to 12*n Mhz in Menu->CPU Speed \r\n");
while (1) {
delay(1);
}
}
#ifdef PIN_5V_EN
pinMode(PIN_5V_EN, OUTPUT);
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
#endif
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
pio_cfg.pin_dp = PIN_USB_HOST_DP;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
// For pico-w, PIO is also used to communicate with cyw43
// Therefore we need to alternate the pio-usb configuration
// details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46
pio_cfg.sm_tx = 3;
pio_cfg.sm_rx = 2;
pio_cfg.sm_eop = 3;
pio_cfg.pio_rx_num = 0;
pio_cfg.pio_tx_num = 1;
pio_cfg.tx_ch = 9;
#endif
USBHost.configure_pio_usb(1, &pio_cfg);
}
#endif
#endif

View file

@ -1 +0,0 @@
CH32V20x_EVT

View file

@ -1,268 +0,0 @@
/*********************************************************************
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 demonstrates use of both device and host, where
* - Device run on native usb controller (roothub port0)
* - Host depending on MCUs run on either:
* - rp2040: bit-banging 2 GPIOs with the help of Pico-PIO-USB library (roothub port1)
* - samd21/51, nrf52840, esp32: using MAX3421e controller (host shield)
*
* Requirements:
* - For rp2040:
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
* - Provide VBus (5v) and GND for peripheral
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
* - For samd21/51, nrf52840, esp32:
* - Additional MAX2341e USB Host shield or featherwing is required
* - SPI instance, CS pin, INT pin are correctly configured in usbh_helper.h
*/
/* Host example will get device descriptors of attached devices and print it out via
* device cdc (Serial) as follows:
* Device 1: ID 046d:c52f
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 0200
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x046d
idProduct 0xc52f
bcdDevice 2200
iManufacturer 1 Logitech
iProduct 2 USB Receiver
iSerialNumber 0
bNumConfigurations 1
*
*/
// USBHost is defined in usbh_helper.h
#include "usbh_helper.h"
// Language ID: English
#define LANGUAGE_ID 0x0409
typedef struct {
tusb_desc_device_t desc_device;
uint16_t manufacturer[32];
uint16_t product[48];
uint16_t serial[16];
bool mounted;
} dev_info_t;
// CFG_TUH_DEVICE_MAX is defined by tusb_config header
dev_info_t dev_info[CFG_TUH_DEVICE_MAX] = { 0 };
void setup() {
Serial.begin(115200);
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
// init host stack on controller (rhport) 1
// For rp2040: this is called in core1's setup1()
USBHost.begin(1);
#endif
// while ( !Serial ) delay(10); // wait for native usb
Serial.println("TinyUSB Dual Device Info Example");
}
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
//--------------------------------------------------------------------+
// Using Host shield MAX3421E controller
//--------------------------------------------------------------------+
void loop() {
USBHost.task();
Serial.flush();
}
#elif defined(ARDUINO_ARCH_RP2040)
//--------------------------------------------------------------------+
// For RP2040 use both core0 for device stack, core1 for host stack
//--------------------------------------------------------------------+
//------------- Core0 -------------//
void loop() {
}
//------------- Core1 -------------//
void setup1() {
//while ( !Serial ) delay(10); // wait for native usb
// configure pio-usb: defined in usbh_helper.h
rp2040_configure_pio_usb();
// run host stack on controller (rhport) 1
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
// host bit-banging processing works done in core1 to free up core0 for other works
USBHost.begin(1);
}
void loop1() {
USBHost.task();
Serial.flush();
}
#endif
//--------------------------------------------------------------------+
// TinyUSB Host callbacks
//--------------------------------------------------------------------+
void print_device_descriptor(tuh_xfer_t *xfer);
void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len);
void print_lsusb(void) {
bool no_device = true;
for (uint8_t daddr = 1; daddr < CFG_TUH_DEVICE_MAX + 1; daddr++) {
// TODO can use tuh_mounted(daddr), but tinyusb has an bug
// use local connected flag instead
dev_info_t *dev = &dev_info[daddr - 1];
if (dev->mounted) {
Serial.printf("Device %u: ID %04x:%04x %s %s\r\n", daddr,
dev->desc_device.idVendor, dev->desc_device.idProduct,
(char *) dev->manufacturer, (char *) dev->product);
no_device = false;
}
}
if (no_device) {
Serial.println("No device connected (except hub)");
}
}
// Invoked when device is mounted (configured)
void tuh_mount_cb(uint8_t daddr) {
Serial.printf("Device attached, address = %d\r\n", daddr);
dev_info_t *dev = &dev_info[daddr - 1];
dev->mounted = true;
// Get Device Descriptor
tuh_descriptor_get_device(daddr, &dev->desc_device, 18, print_device_descriptor, 0);
}
/// Invoked when device is unmounted (bus reset/unplugged)
void tuh_umount_cb(uint8_t daddr) {
Serial.printf("Device removed, address = %d\r\n", daddr);
dev_info_t *dev = &dev_info[daddr - 1];
dev->mounted = false;
// print device summary
print_lsusb();
}
void print_device_descriptor(tuh_xfer_t *xfer) {
if (XFER_RESULT_SUCCESS != xfer->result) {
Serial.printf("Failed to get device descriptor\r\n");
return;
}
uint8_t const daddr = xfer->daddr;
dev_info_t *dev = &dev_info[daddr - 1];
tusb_desc_device_t *desc = &dev->desc_device;
Serial.printf("Device %u: ID %04x:%04x\r\n", daddr, desc->idVendor, desc->idProduct);
Serial.printf("Device Descriptor:\r\n");
Serial.printf(" bLength %u\r\n" , desc->bLength);
Serial.printf(" bDescriptorType %u\r\n" , desc->bDescriptorType);
Serial.printf(" bcdUSB %04x\r\n" , desc->bcdUSB);
Serial.printf(" bDeviceClass %u\r\n" , desc->bDeviceClass);
Serial.printf(" bDeviceSubClass %u\r\n" , desc->bDeviceSubClass);
Serial.printf(" bDeviceProtocol %u\r\n" , desc->bDeviceProtocol);
Serial.printf(" bMaxPacketSize0 %u\r\n" , desc->bMaxPacketSize0);
Serial.printf(" idVendor 0x%04x\r\n" , desc->idVendor);
Serial.printf(" idProduct 0x%04x\r\n" , desc->idProduct);
Serial.printf(" bcdDevice %04x\r\n" , desc->bcdDevice);
// Get String descriptor using Sync API
Serial.printf(" iManufacturer %u ", desc->iManufacturer);
if (XFER_RESULT_SUCCESS ==
tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, dev->manufacturer, sizeof(dev->manufacturer))) {
utf16_to_utf8(dev->manufacturer, sizeof(dev->manufacturer));
Serial.printf((char *) dev->manufacturer);
}
Serial.printf("\r\n");
Serial.printf(" iProduct %u ", desc->iProduct);
if (XFER_RESULT_SUCCESS ==
tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, dev->product, sizeof(dev->product))) {
utf16_to_utf8(dev->product, sizeof(dev->product));
Serial.printf((char *) dev->product);
}
Serial.printf("\r\n");
Serial.printf(" iSerialNumber %u ", desc->iSerialNumber);
if (XFER_RESULT_SUCCESS ==
tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, dev->serial, sizeof(dev->serial))) {
utf16_to_utf8(dev->serial, sizeof(dev->serial));
Serial.printf((char *) dev->serial);
}
Serial.printf("\r\n");
Serial.printf(" bNumConfigurations %u\r\n", desc->bNumConfigurations);
// print device summary
print_lsusb();
}
//--------------------------------------------------------------------+
// String Descriptor Helper
//--------------------------------------------------------------------+
static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) {
// TODO: Check for runover.
(void) utf8_len;
// Get the UTF-16 length out of the data itself.
for (size_t i = 0; i < utf16_len; i++) {
uint16_t chr = utf16[i];
if (chr < 0x80) {
*utf8++ = chr & 0xff;
} else if (chr < 0x800) {
*utf8++ = (uint8_t) (0xC0 | (chr >> 6 & 0x1F));
*utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F));
} else {
// TODO: Verify surrogate.
*utf8++ = (uint8_t) (0xE0 | (chr >> 12 & 0x0F));
*utf8++ = (uint8_t) (0x80 | (chr >> 6 & 0x3F));
*utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F));
}
// TODO: Handle UTF-16 code points that take two entries.
}
}
// Count how many bytes a utf-16-le encoded string will take in utf-8.
static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
size_t total_bytes = 0;
for (size_t i = 0; i < len; i++) {
uint16_t chr = buf[i];
if (chr < 0x80) {
total_bytes += 1;
} else if (chr < 0x800) {
total_bytes += 2;
} else {
total_bytes += 3;
}
// TODO: Handle UTF-16 code points that take two entries.
}
return total_bytes;
}
void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len) {
size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
size_t utf8_len = _count_utf8_bytes(temp_buf + 1, utf16_len);
_convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, buf_len);
((uint8_t *) temp_buf)[utf8_len] = '\0';
}

View file

@ -1,99 +0,0 @@
/*********************************************************************
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
*********************************************************************/
#ifndef USBH_HELPER_H
#define USBH_HELPER_H
#ifdef ARDUINO_ARCH_RP2040
// pio-usb is required for rp2040 host
#include "pio_usb.h"
// Pin D+ for host, D- = D+ + 1
#ifndef PIN_USB_HOST_DP
#define PIN_USB_HOST_DP 16
#endif
// Pin for enabling Host VBUS. comment out if not used
#ifndef PIN_5V_EN
#define PIN_5V_EN 18
#endif
#ifndef PIN_5V_EN_STATE
#define PIN_5V_EN_STATE 1
#endif
#endif // ARDUINO_ARCH_RP2040
#include "Adafruit_TinyUSB.h"
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
// USB Host using MAX3421E: SPI, CS, INT
#include "SPI.h"
#if defined(ARDUINO_METRO_ESP32S2)
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
Adafruit_USBH_Host USBHost(&SPI, 33, 15);
#else
// Default CS and INT are pin 10, 9
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
#endif
#else
// Native USB Host such as rp2040
Adafruit_USBH_Host USBHost;
#endif
//--------------------------------------------------------------------+
// Helper Functions
//--------------------------------------------------------------------+
#ifdef ARDUINO_ARCH_RP2040
static void rp2040_configure_pio_usb(void) {
//while ( !Serial ) delay(10); // wait for native usb
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
// Check for CPU frequency, must be multiple of 12 Mhz for bit-banging USB
uint32_t cpu_hz = clock_get_hz(clk_sys);
if (cpu_hz % 12000000UL) {
while (!Serial) {
delay(10); // wait for native usb
}
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 12 Mhz\r\n", cpu_hz);
Serial.printf("Change your CPU Clock to 12*n Mhz in Menu->CPU Speed \r\n");
while (1) {
delay(1);
}
}
#ifdef PIN_5V_EN
pinMode(PIN_5V_EN, OUTPUT);
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
#endif
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
pio_cfg.pin_dp = PIN_USB_HOST_DP;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
// For pico-w, PIO is also used to communicate with cyw43
// Therefore we need to alternate the pio-usb configuration
// details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46
pio_cfg.sm_tx = 3;
pio_cfg.sm_rx = 2;
pio_cfg.sm_eop = 3;
pio_cfg.pio_rx_num = 0;
pio_cfg.pio_tx_num = 1;
pio_cfg.tx_ch = 9;
#endif
USBHost.configure_pio_usb(1, &pio_cfg);
}
#endif
#endif

View file

@ -1,2 +0,0 @@
pico_rp2040_tinyusb_host
CH32V20x_EVT

View file

@ -1,241 +0,0 @@
/*********************************************************************
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 demonstrates use of both device and host, where
* - Device run on native usb controller (roothub port0)
* - Host run on MAX3421E controller (roothub port1) tested with:
* - SAMD21, SAMD51, nRF52840, ESP32S2, ESP32S3, ESP32
* - RP2040: "pio_usb.h" must not be included, otherwise pio-usb will be used as host controller
*
* Requirements:
* - SPI instance, CS pin, INT pin are correctly configured
*/
/* Host example will get device descriptors of attached devices and print it out:
* Device 1: ID 046d:c52f
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 0200
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x046d
idProduct 0xc52f
bcdDevice 2200
iManufacturer 1 Logitech
iProduct 2 USB Receiver
iSerialNumber 0
bNumConfigurations 1
*
*/
#include "Adafruit_TinyUSB.h"
#include "SPI.h"
// USB Host using MAX3421E: SPI, CS, INT
#if defined(ARDUINO_METRO_ESP32S2)
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
Adafruit_USBH_Host USBHost(&SPI, 33, 15);
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32C6)
Adafruit_USBH_Host USBHost(&SPI, 8, 7);
#elif defined(ARDUINO_ESP32C3_DEV)
Adafruit_USBH_Host USBHost(&SPI, 10, 7);
#else
// Default CS and INT are pin 10, 9
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
#endif
// Language ID: English
#define LANGUAGE_ID 0x0409
typedef struct {
tusb_desc_device_t desc_device;
uint16_t manufacturer[32];
uint16_t product[48];
uint16_t serial[16];
bool mounted;
} dev_info_t;
// CFG_TUH_DEVICE_MAX is defined by tusb_config header
dev_info_t dev_info[CFG_TUH_DEVICE_MAX] = { 0 };
//--------------------------------------------------------------------+
// setup() & loop()
//--------------------------------------------------------------------+
void setup() {
Serial.begin(115200);
// init host stack on controller (rhport) 1
USBHost.begin(1);
// while ( !Serial ) delay(10); // wait for native usb
Serial.println("TinyUSB Dual: Device Info Example with MAX3421E");
}
void loop() {
USBHost.task();
Serial.flush();
}
//--------------------------------------------------------------------+
// TinyUSB Host callbacks
//--------------------------------------------------------------------+
void print_device_descriptor(tuh_xfer_t *xfer);
void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len);
void print_lsusb(void) {
bool no_device = true;
for (uint8_t daddr = 1; daddr < CFG_TUH_DEVICE_MAX + 1; daddr++) {
// TODO can use tuh_mounted(daddr), but tinyusb has an bug
// use local connected flag instead
dev_info_t *dev = &dev_info[daddr - 1];
if (dev->mounted) {
Serial.printf("Device %u: ID %04x:%04x %s %s\r\n", daddr,
dev->desc_device.idVendor, dev->desc_device.idProduct,
(char *) dev->manufacturer, (char *) dev->product);
no_device = false;
}
}
if (no_device) {
Serial.println("No device connected (except hub)");
}
}
// Invoked when device is mounted (configured)
void tuh_mount_cb(uint8_t daddr) {
Serial.printf("Device attached, address = %d\r\n", daddr);
dev_info_t *dev = &dev_info[daddr - 1];
dev->mounted = true;
// Get Device Descriptor
tuh_descriptor_get_device(daddr, &dev->desc_device, 18, print_device_descriptor, 0);
}
/// Invoked when device is unmounted (bus reset/unplugged)
void tuh_umount_cb(uint8_t daddr) {
Serial.printf("Device removed, address = %d\r\n", daddr);
dev_info_t *dev = &dev_info[daddr - 1];
dev->mounted = false;
// print device summary
print_lsusb();
}
void print_device_descriptor(tuh_xfer_t *xfer) {
if (XFER_RESULT_SUCCESS != xfer->result) {
Serial.printf("Failed to get device descriptor\r\n");
return;
}
uint8_t const daddr = xfer->daddr;
dev_info_t *dev = &dev_info[daddr - 1];
tusb_desc_device_t *desc = &dev->desc_device;
Serial.printf("Device %u: ID %04x:%04x\r\n", daddr, desc->idVendor, desc->idProduct);
Serial.printf("Device Descriptor:\r\n");
Serial.printf(" bLength %u\r\n" , desc->bLength);
Serial.printf(" bDescriptorType %u\r\n" , desc->bDescriptorType);
Serial.printf(" bcdUSB %04x\r\n" , desc->bcdUSB);
Serial.printf(" bDeviceClass %u\r\n" , desc->bDeviceClass);
Serial.printf(" bDeviceSubClass %u\r\n" , desc->bDeviceSubClass);
Serial.printf(" bDeviceProtocol %u\r\n" , desc->bDeviceProtocol);
Serial.printf(" bMaxPacketSize0 %u\r\n" , desc->bMaxPacketSize0);
Serial.printf(" idVendor 0x%04x\r\n" , desc->idVendor);
Serial.printf(" idProduct 0x%04x\r\n" , desc->idProduct);
Serial.printf(" bcdDevice %04x\r\n" , desc->bcdDevice);
// Get String descriptor using Sync API
Serial.printf(" iManufacturer %u ", desc->iManufacturer);
if (XFER_RESULT_SUCCESS ==
tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, dev->manufacturer, sizeof(dev->manufacturer))) {
utf16_to_utf8(dev->manufacturer, sizeof(dev->manufacturer));
Serial.printf((char *) dev->manufacturer);
}
Serial.printf("\r\n");
Serial.printf(" iProduct %u ", desc->iProduct);
if (XFER_RESULT_SUCCESS ==
tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, dev->product, sizeof(dev->product))) {
utf16_to_utf8(dev->product, sizeof(dev->product));
Serial.printf((char *) dev->product);
}
Serial.printf("\r\n");
Serial.printf(" iSerialNumber %u ", desc->iSerialNumber);
if (XFER_RESULT_SUCCESS ==
tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, dev->serial, sizeof(dev->serial))) {
utf16_to_utf8(dev->serial, sizeof(dev->serial));
Serial.printf((char *) dev->serial);
}
Serial.printf("\r\n");
Serial.printf(" bNumConfigurations %u\r\n", desc->bNumConfigurations);
// print device summary
print_lsusb();
}
//--------------------------------------------------------------------+
// String Descriptor Helper
//--------------------------------------------------------------------+
static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) {
// TODO: Check for runover.
(void) utf8_len;
// Get the UTF-16 length out of the data itself.
for (size_t i = 0; i < utf16_len; i++) {
uint16_t chr = utf16[i];
if (chr < 0x80) {
*utf8++ = chr & 0xff;
} else if (chr < 0x800) {
*utf8++ = (uint8_t) (0xC0 | (chr >> 6 & 0x1F));
*utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F));
} else {
// TODO: Verify surrogate.
*utf8++ = (uint8_t) (0xE0 | (chr >> 12 & 0x0F));
*utf8++ = (uint8_t) (0x80 | (chr >> 6 & 0x3F));
*utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F));
}
// TODO: Handle UTF-16 code points that take two entries.
}
}
// Count how many bytes a utf-16-le encoded string will take in utf-8.
static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
size_t total_bytes = 0;
for (size_t i = 0; i < len; i++) {
uint16_t chr = buf[i];
if (chr < 0x80) {
total_bytes += 1;
} else if (chr < 0x800) {
total_bytes += 2;
} else {
total_bytes += 3;
}
// TODO: Handle UTF-16 code points that take two entries.
}
return total_bytes;
}
void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len) {
size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
size_t utf8_len = _count_utf8_bytes(temp_buf + 1, utf16_len);
_convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, buf_len);
((uint8_t *) temp_buf)[utf8_len] = '\0';
}

View file

@ -0,0 +1,252 @@
/*********************************************************************
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 demonstrates use of both device and host, where
* - Device run on native usb controller (controller0)
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
*
* Requirements:
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
* - 2 consecutive GPIOs: D+ is defined by PIN_PIO_USB_HOST_DP, D- = D+ +1
* - Provide VBus (5v) and GND for peripheral
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
*
* RP2040 host stack will get device descriptors of attached devices and print it out via
* device cdc (Serial) as follows:
* Device 1: ID 046d:c52f
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 0200
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x046d
idProduct 0xc52f
bcdDevice 2200
iManufacturer 1 Logitech
iProduct 2 USB Receiver
iSerialNumber 0
bNumConfigurations 1
*
*/
// pio-usb is required for rp2040 host
#include "pio_usb.h"
#include "Adafruit_TinyUSB.h"
// Pin D+ for host, D- = D+ + 1
#ifndef PIN_PIO_USB_HOST_DP
#define PIN_PIO_USB_HOST_DP 20
#endif
// Pin for enabling Host VBUS. comment out if not used
#ifndef PIN_PIO_USB_HOST_VBUSEN
#define PIN_PIO_USB_HOST_VBUSEN 22
#endif
#ifndef PIN_PIO_USB_HOST_VBUSEN_STATE
#define PIN_PIO_USB_HOST_VBUSEN_STATE 1
#endif
// Language ID: English
#define LANGUAGE_ID 0x0409
// USB Host object
Adafruit_USBH_Host USBHost;
// holding device descriptor
tusb_desc_device_t desc_device;
//--------------------------------------------------------------------+
// Setup and Loop on Core0
//--------------------------------------------------------------------+
// the setup function runs once when you press reset or power the board
void setup()
{
Serial1.begin(115200);
Serial.begin(115200);
//while ( !Serial ) delay(10); // wait for native usb
Serial.println("TinyUSB Dual Device Info Example");
}
void loop()
{
}
//--------------------------------------------------------------------+
// Setup and Loop on Core1
//--------------------------------------------------------------------+
void setup1() {
//while ( !Serial ) delay(10); // wait for native usb
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
uint32_t cpu_hz = clock_get_hz(clk_sys);
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
while ( !Serial ) {
delay(10); // wait for native usb
}
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
while(1) {
delay(1);
}
}
#ifdef PIN_PIO_USB_HOST_VBUSEN
pinMode(PIN_PIO_USB_HOST_VBUSEN, OUTPUT);
digitalWrite(PIN_PIO_USB_HOST_VBUSEN, PIN_PIO_USB_HOST_VBUSEN_STATE);
#endif
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
pio_cfg.pin_dp = PIN_PIO_USB_HOST_DP;
USBHost.configure_pio_usb(1, &pio_cfg);
// run host stack on controller (rhport) 1
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
// host bit-banging processing works done in core1 to free up core0 for other works
USBHost.begin(1);
}
void loop1()
{
USBHost.task();
}
//--------------------------------------------------------------------+
// TinyUSB Host callbacks
//--------------------------------------------------------------------+
// Invoked when device is mounted (configured)
void tuh_mount_cb (uint8_t daddr)
{
Serial.printf("Device attached, address = %d\r\n", daddr);
// Get Device Descriptor
tuh_descriptor_get_device(daddr, &desc_device, 18, print_device_descriptor, 0);
}
/// Invoked when device is unmounted (bus reset/unplugged)
void tuh_umount_cb(uint8_t daddr)
{
Serial.printf("Device removed, address = %d\r\n", daddr);
}
void print_device_descriptor(tuh_xfer_t* xfer)
{
if ( XFER_RESULT_SUCCESS != xfer->result )
{
Serial.printf("Failed to get device descriptor\r\n");
return;
}
uint8_t const daddr = xfer->daddr;
Serial.printf("Device %u: ID %04x:%04x\r\n", daddr, desc_device.idVendor, desc_device.idProduct);
Serial.printf("Device Descriptor:\r\n");
Serial.printf(" bLength %u\r\n" , desc_device.bLength);
Serial.printf(" bDescriptorType %u\r\n" , desc_device.bDescriptorType);
Serial.printf(" bcdUSB %04x\r\n" , desc_device.bcdUSB);
Serial.printf(" bDeviceClass %u\r\n" , desc_device.bDeviceClass);
Serial.printf(" bDeviceSubClass %u\r\n" , desc_device.bDeviceSubClass);
Serial.printf(" bDeviceProtocol %u\r\n" , desc_device.bDeviceProtocol);
Serial.printf(" bMaxPacketSize0 %u\r\n" , desc_device.bMaxPacketSize0);
Serial.printf(" idVendor 0x%04x\r\n" , desc_device.idVendor);
Serial.printf(" idProduct 0x%04x\r\n" , desc_device.idProduct);
Serial.printf(" bcdDevice %04x\r\n" , desc_device.bcdDevice);
// Get String descriptor using Sync API
uint16_t temp_buf[128];
Serial.printf(" iManufacturer %u " , desc_device.iManufacturer);
if (XFER_RESULT_SUCCESS == tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)) )
{
print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
}
Serial.printf("\r\n");
Serial.printf(" iProduct %u " , desc_device.iProduct);
if (XFER_RESULT_SUCCESS == tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)))
{
print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
}
Serial.printf("\r\n");
Serial.printf(" iSerialNumber %u " , desc_device.iSerialNumber);
if (XFER_RESULT_SUCCESS == tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)))
{
print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
}
Serial.printf("\r\n");
Serial.printf(" bNumConfigurations %u\r\n" , desc_device.bNumConfigurations);
}
//--------------------------------------------------------------------+
// String Descriptor Helper
//--------------------------------------------------------------------+
static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) {
// TODO: Check for runover.
(void)utf8_len;
// Get the UTF-16 length out of the data itself.
for (size_t i = 0; i < utf16_len; i++) {
uint16_t chr = utf16[i];
if (chr < 0x80) {
*utf8++ = chr & 0xff;
} else if (chr < 0x800) {
*utf8++ = (uint8_t)(0xC0 | (chr >> 6 & 0x1F));
*utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
} else {
// TODO: Verify surrogate.
*utf8++ = (uint8_t)(0xE0 | (chr >> 12 & 0x0F));
*utf8++ = (uint8_t)(0x80 | (chr >> 6 & 0x3F));
*utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
}
// TODO: Handle UTF-16 code points that take two entries.
}
}
// Count how many bytes a utf-16-le encoded string will take in utf-8.
static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
size_t total_bytes = 0;
for (size_t i = 0; i < len; i++) {
uint16_t chr = buf[i];
if (chr < 0x80) {
total_bytes += 1;
} else if (chr < 0x800) {
total_bytes += 2;
} else {
total_bytes += 3;
}
// TODO: Handle UTF-16 code points that take two entries.
}
return total_bytes;
}
static void print_utf16(uint16_t *temp_buf, size_t buf_len) {
size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
size_t utf8_len = _count_utf8_bytes(temp_buf + 1, utf16_len);
_convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, sizeof(uint16_t) * buf_len);
((uint8_t*) temp_buf)[utf8_len] = '\0';
Serial.printf((char*)temp_buf);
}

View file

@ -1,2 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host

View file

@ -10,73 +10,93 @@
*********************************************************************/ *********************************************************************/
#include "Adafruit_TinyUSB.h" #include "Adafruit_TinyUSB.h"
#include <Adafruit_NeoPixel.h>
/* This sketch demonstrates USB HID keyboard. /* This sketch demonstrates USB HID keyboard.
* - PIN A0-A3 is used to send digit '0' to '3' respectively * - PIN A0-A5 is used to send digit '0' to '5' respectively
* (On the RP2040, pins D0-D5 used) * (On the RP2040, pins D0-D5 used)
* - LED and/or Neopixels will be used as Capslock indicator * - LED and/or Neopixels will be used as Capslock indicator
*/ */
// HID report descriptor using TinyUSB's template // HID report descriptor using TinyUSB's template
// Single Report (no ID) descriptor // Single Report (no ID) descriptor
uint8_t const desc_hid_report[] = { uint8_t const desc_hid_report[] =
TUD_HID_REPORT_DESC_KEYBOARD() {
TUD_HID_REPORT_DESC_KEYBOARD()
}; };
// USB HID object. For ESP32 these values cannot be changed after this declaration // USB HID object. For ESP32 these values cannot be changed after this declaration
// desc report, desc len, protocol, interval, use out endpoint // desc report, desc len, protocol, interval, use out endpoint
Adafruit_USBD_HID usb_hid; Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_KEYBOARD, 2, false);
//------------- Input Pins -------------// //------------- Input Pins -------------//
// Array of pins and its keycode. // Array of pins and its keycode.
// Notes: these pins can be replaced by PIN_BUTTONn if defined in setup() // Notes: these pins can be replaced by PIN_BUTTONn if defined in setup()
#ifdef ARDUINO_ARCH_RP2040 #ifdef ARDUINO_ARCH_RP2040
uint8_t pins[] = { D0, D1, D2, D3 }; uint8_t pins[] = { D0, D1, D2, D3 };
#else #else
uint8_t pins[] = {A0, A1, A2, A3}; uint8_t pins[] = { A0, A1, A2, A3 };
#endif #endif
// number of pins // number of pins
uint8_t pincount = sizeof(pins) / sizeof(pins[0]); uint8_t pincount = sizeof(pins)/sizeof(pins[0]);
// For keycode definition check out https://github.com/hathach/tinyusb/blob/master/src/class/hid/hid.h // For keycode definition check out https://github.com/hathach/tinyusb/blob/master/src/class/hid/hid.h
uint8_t hidcode[] = {HID_KEY_0, HID_KEY_1, HID_KEY_2, HID_KEY_3}; uint8_t hidcode[] = { HID_KEY_ARROW_RIGHT, HID_KEY_ARROW_LEFT, HID_KEY_ARROW_DOWN, HID_KEY_ARROW_UP };
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY) || defined(ARDUINO_FUNHOUSE_ESP32S2) #if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY) || defined(ARDUINO_FUNHOUSE_ESP32S2)
bool activeState = true; bool activeState = true;
#else #else
bool activeState = false; bool activeState = false;
#endif #endif
// the setup function runs once when you press reset or power the board //------------- Neopixel -------------//
void setup() { // #define PIN_NEOPIXEL 8
// Manual begin() is required on core without built-in support e.g. mbed rp2040 #ifdef PIN_NEOPIXEL
if (!TinyUSBDevice.isInitialized()) {
TinyUSBDevice.begin(0);
}
// Setup HID // How many NeoPixels are attached to the Arduino?
usb_hid.setBootProtocol(HID_ITF_PROTOCOL_KEYBOARD); // use on-board defined NEOPIXEL_NUM if existed
usb_hid.setPollInterval(2); #ifndef NEOPIXEL_NUM
usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report)); #define NEOPIXEL_NUM 10
usb_hid.setStringDescriptor("TinyUSB Keyboard"); #endif
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NEOPIXEL_NUM, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);
#endif
// the setup function runs once when you press reset or power the board
void setup()
{
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
// Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
TinyUSB_Device_Init(0);
#endif
// Notes: following commented-out functions has no affect on ESP32
// usb_hid.setBootProtocol(HID_ITF_PROTOCOL_KEYBOARD);
// usb_hid.setPollInterval(2);
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
// usb_hid.setStringDescriptor("TinyUSB Keyboard");
// Set up output report (on control endpoint) for Capslock indicator // Set up output report (on control endpoint) for Capslock indicator
usb_hid.setReportCallback(NULL, hid_report_callback); usb_hid.setReportCallback(NULL, hid_report_callback);
usb_hid.begin(); usb_hid.begin();
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
if (TinyUSBDevice.mounted()) {
TinyUSBDevice.detach();
delay(10);
TinyUSBDevice.attach();
}
// led pin // led pin
#ifdef LED_BUILTIN
pinMode(LED_BUILTIN, OUTPUT); pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW); digitalWrite(LED_BUILTIN, LOW);
// neopixel if existed
#ifdef PIN_NEOPIXEL
pixels.begin();
pixels.setBrightness(50);
#ifdef NEOPIXEL_POWER
pinMode(NEOPIXEL_POWER, OUTPUT);
digitalWrite(NEOPIXEL_POWER, NEOPIXEL_POWER_ON);
#endif
#endif #endif
// overwrite input pin with PIN_BUTTONx // overwrite input pin with PIN_BUTTONx
@ -97,21 +117,32 @@ void setup() {
#endif #endif
// Set up pin as input // Set up pin as input
for (uint8_t i = 0; i < pincount; i++) { for (uint8_t i=0; i<pincount; i++)
{
pinMode(pins[i], activeState ? INPUT_PULLDOWN : INPUT_PULLUP); pinMode(pins[i], activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
} }
// wait until device mounted
while( !TinyUSBDevice.mounted() ) delay(1);
} }
void process_hid() {
void loop()
{
// poll gpio once each 2 ms
delay(2);
// used to avoid send multiple consecutive zero report for keyboard // used to avoid send multiple consecutive zero report for keyboard
static bool keyPressedPreviously = false; static bool keyPressedPreviously = false;
uint8_t count = 0; uint8_t count=0;
uint8_t keycode[6] = {0}; uint8_t keycode[6] = { 0 };
// scan normal key and send report // scan normal key and send report
for (uint8_t i = 0; i < pincount; i++) { for(uint8_t i=0; i < pincount; i++)
if (activeState == digitalRead(pins[i])) { {
if ( activeState == digitalRead(pins[i]) )
{
// if pin is active (low), add its hid code to key report // if pin is active (low), add its hid code to key report
keycode[count++] = hidcode[i]; keycode[count++] = hidcode[i];
@ -120,66 +151,55 @@ void process_hid() {
} }
} }
if (TinyUSBDevice.suspended() && count) { if ( TinyUSBDevice.suspended() && count )
{
// Wake up host if we are in suspend mode // Wake up host if we are in suspend mode
// and REMOTE_WAKEUP feature is enabled by host // and REMOTE_WAKEUP feature is enabled by host
TinyUSBDevice.remoteWakeup(); TinyUSBDevice.remoteWakeup();
} }
// skip if hid is not ready e.g still transferring previous report // skip if hid is not ready e.g still transferring previous report
if (!usb_hid.ready()) return; if ( !usb_hid.ready() ) return;
if (count) { if ( count )
{
// Send report if there is key pressed // Send report if there is key pressed
uint8_t const report_id = 0; uint8_t const report_id = 0;
uint8_t const modifier = 0; uint8_t const modifier = 0;
keyPressedPreviously = true; keyPressedPreviously = true;
usb_hid.keyboardReport(report_id, modifier, keycode); usb_hid.keyboardReport(report_id, modifier, keycode);
} else { }else
{
// Send All-zero report to indicate there is no keys pressed // 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 // 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() // every loop(), only a key is pressed in previous loop()
if (keyPressedPreviously) { if ( keyPressedPreviously )
{
keyPressedPreviously = false; keyPressedPreviously = false;
usb_hid.keyboardRelease(0); usb_hid.keyboardRelease(0);
} }
} }
} }
void loop() {
#ifdef TINYUSB_NEED_POLLING_TASK
// Manual call tud_task since it isn't called by Core's background
TinyUSBDevice.task();
#endif
// not enumerated()/mounted() yet: nothing to do
if (!TinyUSBDevice.mounted()) {
return;
}
// poll gpio once each 2 ms
static uint32_t ms = 0;
if (millis() - ms > 2) {
ms = millis();
process_hid();
}
}
// Output report callback for LED indicator such as Caplocks // 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 hid_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
{
(void) report_id; (void) report_id;
(void) bufsize; (void) bufsize;
// LED indicator is output report with only 1 byte length // LED indicator is output report with only 1 byte length
if (report_type != HID_REPORT_TYPE_OUTPUT) return; if ( report_type != HID_REPORT_TYPE_OUTPUT ) return;
// The LED bit map is as follows: (also defined by KEYBOARD_LED_* ) // The LED bit map is as follows: (also defined by KEYBOARD_LED_* )
// Kana (4) | Compose (3) | ScrollLock (2) | CapsLock (1) | Numlock (0) // Kana (4) | Compose (3) | ScrollLock (2) | CapsLock (1) | Numlock (0)
uint8_t ledIndicator = buffer[0]; uint8_t ledIndicator = buffer[0];
#ifdef LED_BUILTIN
// turn on LED if capslock is set // turn on LED if capslock is set
digitalWrite(LED_BUILTIN, ledIndicator & KEYBOARD_LED_CAPSLOCK); digitalWrite(LED_BUILTIN, ledIndicator & KEYBOARD_LED_CAPSLOCK);
#ifdef PIN_NEOPIXEL
pixels.fill(ledIndicator & KEYBOARD_LED_CAPSLOCK ? 0xff0000 : 0x000000);
pixels.show();
#endif #endif
} }

View file

@ -1,2 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host

View file

@ -19,69 +19,66 @@
* and its active state (when pressed) are different * and its active state (when pressed) are different
*/ */
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY) #if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY)
const int pin = 4; // Left Button const int pin = 4; // Left Button
bool activeState = true; bool activeState = true;
#elif defined(ARDUINO_FUNHOUSE_ESP32S2) #elif defined(ARDUINO_FUNHOUSE_ESP32S2)
const int pin = BUTTON_DOWN; const int pin = BUTTON_DOWN;
bool activeState = true; bool activeState = true;
#elif defined PIN_BUTTON1 #elif defined PIN_BUTTON1
const int pin = PIN_BUTTON1; const int pin = PIN_BUTTON1;
bool activeState = false; bool activeState = false;
#elif defined(ARDUINO_ARCH_ESP32)
const int pin = 0;
bool activeState = false;
#elif defined(ARDUINO_ARCH_RP2040)
const int pin = D0;
bool activeState = false;
#else #else
const int pin = A0; const int pin = 12;
bool activeState = false; bool activeState = false;
#endif #endif
// HID report descriptor using TinyUSB's template // HID report descriptor using TinyUSB's template
// Single Report (no ID) descriptor // Single Report (no ID) descriptor
uint8_t const desc_hid_report[] = { uint8_t const desc_hid_report[] =
TUD_HID_REPORT_DESC_MOUSE() {
TUD_HID_REPORT_DESC_MOUSE()
}; };
// USB HID object // USB HID object. For ESP32 these values cannot be changed after this declaration
Adafruit_USBD_HID usb_hid; // desc report, desc len, protocol, interval, use out endpoint
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_MOUSE, 2, false);
// the setup function runs once when you press reset or power the board // the setup function runs once when you press reset or power the board
void setup() { void setup()
// Manual begin() is required on core without built-in support e.g. mbed rp2040 {
if (!TinyUSBDevice.isInitialized()) { #if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
TinyUSBDevice.begin(0); // Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
} TinyUSB_Device_Init(0);
#endif
Serial.begin(115200);
// Set up button, pullup opposite to active state // Set up button, pullup opposite to active state
pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP); pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
// Set up HID // Notes: following commented-out functions has no affect on ESP32
usb_hid.setBootProtocol(HID_ITF_PROTOCOL_MOUSE); // usb_hid.setBootProtocol(HID_ITF_PROTOCOL_MOUSE);
usb_hid.setPollInterval(2); // usb_hid.setPollInterval(2);
usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report)); // usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
usb_hid.setStringDescriptor("TinyUSB Mouse"); // usb_hid.setStringDescriptor("TinyUSB Mouse");
usb_hid.begin(); usb_hid.begin();
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration Serial.begin(115200);
if (TinyUSBDevice.mounted()) {
TinyUSBDevice.detach(); // wait until device mounted
delay(10); while( !TinyUSBDevice.mounted() ) delay(1);
TinyUSBDevice.attach();
}
Serial.println("Adafruit TinyUSB HID Mouse example"); Serial.println("Adafruit TinyUSB HID Mouse example");
} }
void process_hid() { void loop()
{
// poll gpio once each 10 ms
delay(10);
// Whether button is pressed // Whether button is pressed
bool btn_pressed = (digitalRead(pin) == activeState); bool btn_pressed = (digitalRead(pin) == activeState);
@ -89,34 +86,17 @@ void process_hid() {
if (!btn_pressed) return; if (!btn_pressed) return;
// Remote wakeup // Remote wakeup
if (TinyUSBDevice.suspended()) { if ( TinyUSBDevice.suspended() )
{
// Wake up host if we are in suspend mode // Wake up host if we are in suspend mode
// and REMOTE_WAKEUP feature is enabled by host // and REMOTE_WAKEUP feature is enabled by host
TinyUSBDevice.remoteWakeup(); TinyUSBDevice.remoteWakeup();
} }
if (usb_hid.ready()) { if ( usb_hid.ready() )
{
uint8_t const report_id = 0; // no ID uint8_t const report_id = 0; // no ID
int8_t const delta = 5; int8_t const delta = 5;
usb_hid.mouseMove(report_id, delta, delta); // right + down usb_hid.mouseMove(report_id, delta, delta); // right + down
} }
} }
void loop() {
#ifdef TINYUSB_NEED_POLLING_TASK
// Manual call tud_task since it isn't called by Core's background
TinyUSBDevice.task();
#endif
// not enumerated()/mounted() yet: nothing to do
if (!TinyUSBDevice.mounted()) {
return;
}
// poll gpio once each 10 ms
static uint32_t ms = 0;
if (millis() - ms > 10) {
ms = millis();
process_hid();
}
}

View file

@ -1,2 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host

View file

@ -20,90 +20,83 @@
* and its active state (when pressed) are different * and its active state (when pressed) are different
*/ */
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY) #if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY)
const int pin = 4; // Left Button const int pin = 4; // Left Button
bool activeState = true; bool activeState = true;
#elif defined(ARDUINO_FUNHOUSE_ESP32S2) #elif defined(ARDUINO_FUNHOUSE_ESP32S2)
const int pin = BUTTON_DOWN; const int pin = BUTTON_DOWN;
bool activeState = true; bool activeState = true;
#elif defined PIN_BUTTON1 #elif defined PIN_BUTTON1
const int pin = PIN_BUTTON1; const int pin = PIN_BUTTON1;
bool activeState = false; bool activeState = false;
#elif defined(ARDUINO_ARCH_ESP32)
const int pin = 0;
bool activeState = false;
#elif defined(ARDUINO_ARCH_RP2040)
const int pin = D0;
bool activeState = false;
#else #else
const int pin = A0; const int pin = 12;
bool activeState = false; bool activeState = false;
#endif #endif
// Report ID // Report ID
enum { enum
{
RID_KEYBOARD = 1, RID_KEYBOARD = 1,
RID_MOUSE, RID_MOUSE,
RID_CONSUMER_CONTROL, // Media, volume etc .. RID_CONSUMER_CONTROL, // Media, volume etc ..
}; };
// HID report descriptor using TinyUSB's template // HID report descriptor using TinyUSB's template
uint8_t const desc_hid_report[] = { 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_KEYBOARD( HID_REPORT_ID(RID_KEYBOARD) ),
TUD_HID_REPORT_DESC_CONSUMER(HID_REPORT_ID(RID_CONSUMER_CONTROL)) TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(RID_MOUSE) ),
TUD_HID_REPORT_DESC_CONSUMER( HID_REPORT_ID(RID_CONSUMER_CONTROL) )
}; };
// USB HID object. // USB HID object. For ESP32 these values cannot be changed after this declaration
Adafruit_USBD_HID usb_hid; // desc report, desc len, protocol, interval, use out endpoint
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_NONE, 2, false);
// the setup function runs once when you press reset or power the board // the setup function runs once when you press reset or power the board
void setup() { void setup()
// Manual begin() is required on core without built-in support e.g. mbed rp2040 {
if (!TinyUSBDevice.isInitialized()) { // Notes: following commented-out functions has no affect on ESP32
TinyUSBDevice.begin(0); // usb_hid.setPollInterval(2);
} // usb_hid.setReportDescriptor();
// usb_hid.setStringDescriptor("TinyUSB HID Composite");
Serial.begin(115200);
// Set up HID
usb_hid.setPollInterval(2);
usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
usb_hid.setStringDescriptor("TinyUSB HID Composite");
usb_hid.begin(); usb_hid.begin();
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
if (TinyUSBDevice.mounted()) {
TinyUSBDevice.detach();
delay(10);
TinyUSBDevice.attach();
}
// Set up button, pullup opposite to active state // Set up button, pullup opposite to active state
pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP); pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
Serial.begin(115200);
// wait until device mounted
while( !TinyUSBDevice.mounted() ) delay(1);
Serial.println("Adafruit TinyUSB HID Composite example"); Serial.println("Adafruit TinyUSB HID Composite example");
} }
void process_hid() { void loop()
{
// poll gpio once each 10 ms
delay(10);
// Whether button is pressed // Whether button is pressed
bool btn_pressed = (digitalRead(pin) == activeState); bool btn_pressed = (digitalRead(pin) == activeState);
// Remote wakeup // Remote wakeup
if (TinyUSBDevice.suspended() && btn_pressed) { if ( TinyUSBDevice.suspended() && btn_pressed )
{
// Wake up host if we are in suspend mode // Wake up host if we are in suspend mode
// and REMOTE_WAKEUP feature is enabled by host // and REMOTE_WAKEUP feature is enabled by host
TinyUSBDevice.remoteWakeup(); TinyUSBDevice.remoteWakeup();
} }
/*------------- Mouse -------------*/ /*------------- Mouse -------------*/
if (usb_hid.ready() && btn_pressed) { if ( usb_hid.ready() && btn_pressed )
{
int8_t const delta = 5; int8_t const delta = 5;
usb_hid.mouseMove(RID_MOUSE, delta, delta); // right + down usb_hid.mouseMove(RID_MOUSE, delta, delta); // right + down
@ -112,18 +105,21 @@ void process_hid() {
} }
/*------------- Keyboard -------------*/ /*------------- Keyboard -------------*/
if (usb_hid.ready()) { if ( usb_hid.ready() )
{
// use to send key release report // use to send key release report
static bool has_key = false; static bool has_key = false;
if (btn_pressed) { if ( btn_pressed )
uint8_t keycode[6] = {0}; {
uint8_t keycode[6] = { 0 };
keycode[0] = HID_KEY_A; keycode[0] = HID_KEY_A;
usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode); usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode);
has_key = true; has_key = true;
} else { }else
{
// send empty key report if previously has key pressed // send empty key report if previously has key pressed
if (has_key) usb_hid.keyboardRelease(RID_KEYBOARD); if (has_key) usb_hid.keyboardRelease(RID_KEYBOARD);
has_key = false; has_key = false;
@ -134,7 +130,8 @@ void process_hid() {
} }
/*------------- Consumer Control -------------*/ /*------------- Consumer Control -------------*/
if (usb_hid.ready()) { if ( usb_hid.ready() )
{
// Consumer Control is used to control Media playback, Volume, Brightness etc ... // Consumer Control is used to control Media playback, Volume, Brightness etc ...
// Consumer report is 2-byte containing the control code of the key // 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 // For list of control check out https://github.com/hathach/tinyusb/blob/master/src/class/hid/hid.h
@ -142,33 +139,16 @@ void process_hid() {
// use to send consumer release report // use to send consumer release report
static bool has_consumer_key = false; static bool has_consumer_key = false;
if (btn_pressed) { if ( btn_pressed )
{
// send volume down (0x00EA) // send volume down (0x00EA)
usb_hid.sendReport16(RID_CONSUMER_CONTROL, HID_USAGE_CONSUMER_VOLUME_DECREMENT); usb_hid.sendReport16(RID_CONSUMER_CONTROL, HID_USAGE_CONSUMER_VOLUME_DECREMENT);
has_consumer_key = true; has_consumer_key = true;
} else { }else
{
// release the consume key by sending zero (0x0000) // release the consume key by sending zero (0x0000)
if (has_consumer_key) usb_hid.sendReport16(RID_CONSUMER_CONTROL, 0); if (has_consumer_key) usb_hid.sendReport16(RID_CONSUMER_CONTROL, 0);
has_consumer_key = false; has_consumer_key = false;
} }
} }
} }
void loop() {
#ifdef TINYUSB_NEED_POLLING_TASK
// Manual call tud_task since it isn't called by Core's background
TinyUSBDevice.task();
#endif
// not enumerated()/mounted() yet: nothing to do
if (!TinyUSBDevice.mounted()) {
return;
}
// poll gpio once each 10 ms
static uint32_t ms = 0;
if (millis() - ms > 10) {
ms = millis();
process_hid();
}
}

View file

@ -1,3 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host
CH32V20x_EVT

View file

@ -33,15 +33,17 @@ uint32_t button_mask = (1 << BUTTON_A) | (1 << BUTTON_B) |
Adafruit_seesaw ss; Adafruit_seesaw ss;
// Report ID // Report ID
enum { enum
{
RID_KEYBOARD = 1, RID_KEYBOARD = 1,
RID_MOUSE RID_MOUSE
}; };
// HID report descriptor using TinyUSB's template // HID report descriptor using TinyUSB's template
uint8_t const desc_hid_report[] = { 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_KEYBOARD( HID_REPORT_ID(RID_KEYBOARD) ),
TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(RID_MOUSE) )
}; };
// USB HID object. For ESP32 these values cannot be changed after this declaration // USB HID object. For ESP32 these values cannot be changed after this declaration
@ -51,30 +53,20 @@ Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROT
int last_x, last_y; int last_x, last_y;
// the setup function runs once when you press reset or power the board // the setup function runs once when you press reset or power the board
void setup() { void setup()
// Manual begin() is required on core without built-in support e.g. mbed rp2040 {
if (!TinyUSBDevice.isInitialized()) {
TinyUSBDevice.begin(0);
}
Serial.begin(115200);
// Notes: following commented-out functions has no affect on ESP32 // Notes: following commented-out functions has no affect on ESP32
// usb_hid.setPollInterval(2); // usb_hid.setPollInterval(2);
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report)); // usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
usb_hid.begin(); usb_hid.begin();
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration Serial.begin(115200);
if (TinyUSBDevice.mounted()) {
TinyUSBDevice.detach();
delay(10);
TinyUSBDevice.attach();
}
Serial.println("Adafruit TinyUSB HID Mouse with Joy FeatherWing example"); Serial.println("Adafruit TinyUSB HID Mouse with Joy FeatherWing example");
if (!ss.begin(0x49)) { if(!ss.begin(0x49)){
Serial.println("ERROR! seesaw not found"); Serial.println("ERROR! seesaw not found");
while (1) {} while(1);
} else { } else {
Serial.println("seesaw started"); Serial.println("seesaw started");
Serial.print("version: "); Serial.print("version: ");
@ -85,9 +77,16 @@ void setup() {
last_y = ss.analogRead(2); last_y = ss.analogRead(2);
last_x = ss.analogRead(3); last_x = ss.analogRead(3);
// wait until device mounted
while( !TinyUSBDevice.mounted() ) delay(1);
} }
void process_hid() { void loop()
{
// poll gpio once each 10 ms
delay(10);
// If either analog stick or any buttons is pressed // If either analog stick or any buttons is pressed
bool has_action = false; bool has_action = false;
@ -99,10 +98,12 @@ void process_hid() {
int dx = (x - last_x) / 2; int dx = (x - last_x) / 2;
int dy = (y - last_y) / 2; int dy = (y - last_y) / 2;
if ((abs(dx) > 3) || (abs(dy) > 3)) { if ( (abs(dx) > 3) || (abs(dy) > 3) )
{
has_action = true; has_action = true;
if (usb_hid.ready()) { if ( usb_hid.ready() )
{
usb_hid.mouseMove(RID_MOUSE, dx, dy); // no ID: right + down usb_hid.mouseMove(RID_MOUSE, dx, dy); // no ID: right + down
last_x = x; last_x = x;
@ -113,27 +114,31 @@ void process_hid() {
} }
} }
/*------------- Keyboard -------------*/ /*------------- Keyboard -------------*/
// button is active low, invert read value for convenience // button is active low, invert read value for convenience
uint32_t buttons = ~ss.digitalReadBulk(button_mask); uint32_t buttons = ~ss.digitalReadBulk(button_mask);
if (usb_hid.ready()) { if ( usb_hid.ready() )
{
// use to prevent sending multiple consecutive zero report // use to prevent sending multiple consecutive zero report
static bool has_key = false; static bool has_key = false;
if (buttons & button_mask) { if ( buttons & button_mask )
{
has_action = true; has_action = true;
has_key = true; has_key = true;
uint8_t keycode[6] = {0}; uint8_t keycode[6] = { 0 };
if (buttons & (1 << BUTTON_A)) keycode[0] = HID_KEY_A; if ( buttons & (1 << BUTTON_A) ) keycode[0] = HID_KEY_A;
if (buttons & (1 << BUTTON_B)) keycode[0] = HID_KEY_B; if ( buttons & (1 << BUTTON_B) ) keycode[0] = HID_KEY_B;
if (buttons & (1 << BUTTON_X)) keycode[0] = HID_KEY_X; if ( buttons & (1 << BUTTON_X) ) keycode[0] = HID_KEY_X;
if (buttons & (1 << BUTTON_Y)) keycode[0] = HID_KEY_Y; if ( buttons & (1 << BUTTON_Y) ) keycode[0] = HID_KEY_Y;
usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode); usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode);
} else { }else
{
// send empty key report if previously has key pressed // send empty key report if previously has key pressed
if (has_key) usb_hid.keyboardRelease(RID_KEYBOARD); if (has_key) usb_hid.keyboardRelease(RID_KEYBOARD);
has_key = false; has_key = false;
@ -142,28 +147,10 @@ void process_hid() {
/*------------- Remote Wakeup -------------*/ /*------------- Remote Wakeup -------------*/
// Remote wakeup if PC is suspended and we has user interaction with joy feather wing // Remote wakeup if PC is suspended and we has user interaction with joy feather wing
if (has_action && TinyUSBDevice.suspended()) { if ( has_action && TinyUSBDevice.suspended() )
{
// Wake up only works if REMOTE_WAKEUP feature is enable by host // Wake up only works if REMOTE_WAKEUP feature is enable by host
// Usually this is the case with Mouse/Keyboard device // Usually this is the case with Mouse/Keyboard device
TinyUSBDevice.remoteWakeup(); TinyUSBDevice.remoteWakeup();
} }
} }
void loop() {
#ifdef TINYUSB_NEED_POLLING_TASK
// Manual call tud_task since it isn't called by Core's background
TinyUSBDevice.task();
#endif
// not enumerated()/mounted() yet: nothing to do
if (!TinyUSBDevice.mounted()) {
return;
}
// poll gpio once each 10 ms
static uint32_t ms = 0;
if (millis() - ms > 10) {
ms = millis();
process_hid();
}
}

View file

@ -1,2 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host

View file

@ -1,153 +0,0 @@
/*********************************************************************
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 USB HID interfaces. Pressing the button will
* - 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) || defined(ARDUINO_NRF52840_CIRCUITPLAY)
const int pin = 4; // Left Button
bool activeState = true;
#elif defined(ARDUINO_FUNHOUSE_ESP32S2)
const int pin = BUTTON_DOWN;
bool activeState = true;
#elif defined PIN_BUTTON1
const int pin = PIN_BUTTON1;
bool activeState = false;
#elif defined PIN_BUTTON
const int pin = PIN_BUTTON;
bool activeState = false;
#elif defined(ARDUINO_ARCH_ESP32)
const int pin = 0;
bool activeState = false;
#elif defined(ARDUINO_ARCH_RP2040)
const int pin = D0;
bool activeState = false;
#else
const int pin = A0;
bool activeState = false;
#endif
// HID report descriptor using TinyUSB's template
uint8_t const desc_keyboard_report[] = {
TUD_HID_REPORT_DESC_KEYBOARD()
};
uint8_t const desc_mouse_report[] = {
TUD_HID_REPORT_DESC_MOUSE()
};
// USB HID objects
Adafruit_USBD_HID usb_keyboard;
Adafruit_USBD_HID usb_mouse;
// the setup function runs once when you press reset or power the board
void setup() {
// Manual begin() is required on core without built-in support e.g. mbed rp2040
if (!TinyUSBDevice.isInitialized()) {
TinyUSBDevice.begin(0);
}
Serial.begin(115200);
// HID Keyboard
usb_keyboard.setPollInterval(2);
usb_keyboard.setBootProtocol(HID_ITF_PROTOCOL_KEYBOARD);
usb_keyboard.setReportDescriptor(desc_keyboard_report, sizeof(desc_keyboard_report));
usb_keyboard.setStringDescriptor("TinyUSB HID Keyboard");
usb_keyboard.begin();
// HID Mouse
usb_mouse.setPollInterval(2);
usb_mouse.setBootProtocol(HID_ITF_PROTOCOL_MOUSE);
usb_mouse.setReportDescriptor(desc_mouse_report, sizeof(desc_mouse_report));
usb_mouse.setStringDescriptor("TinyUSB HID Keyboard");
usb_mouse.begin();
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
if (TinyUSBDevice.mounted()) {
TinyUSBDevice.detach();
delay(10);
TinyUSBDevice.attach();
}
// Set up button, pullup opposite to active state
pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
Serial.println("Adafruit TinyUSB HID Composite example");
}
void process_hid() {
// Whether button is pressed
bool btn_pressed = (digitalRead(pin) == activeState);
// Remote wakeup
if (TinyUSBDevice.suspended() && btn_pressed) {
// Wake up host if we are in suspend mode
// and REMOTE_WAKEUP feature is enabled by host
TinyUSBDevice.remoteWakeup();
}
/*------------- Mouse -------------*/
if (usb_mouse.ready() && btn_pressed) {
int8_t const delta = 5;
usb_mouse.mouseMove(0, delta, delta); // right + down
}
/*------------- Keyboard -------------*/
if (usb_keyboard.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_keyboard.keyboardReport(0, 0, keycode);
has_key = true;
} else {
// send empty key report if previously has key pressed
if (has_key) usb_keyboard.keyboardRelease(0);
has_key = false;
}
}
}
void loop() {
#ifdef TINYUSB_NEED_POLLING_TASK
// Manual call tud_task since it isn't called by Core's background
TinyUSBDevice.task();
#endif
// not enumerated()/mounted() yet: nothing to do
if (!TinyUSBDevice.mounted()) {
return;
}
// poll gpio once each 10 ms
static uint32_t ms = 0;
if (millis() - ms > 10) {
ms = millis();
process_hid();
}
}

View file

@ -1,2 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host

View file

@ -22,52 +22,43 @@
// HID report descriptor using TinyUSB's template // HID report descriptor using TinyUSB's template
// Single Report (no ID) descriptor // Single Report (no ID) descriptor
uint8_t const desc_hid_report[] = { uint8_t const desc_hid_report[] =
TUD_HID_REPORT_DESC_GAMEPAD() {
TUD_HID_REPORT_DESC_GAMEPAD()
}; };
// USB HID object // USB HID object. For ESP32 these values cannot be changed after this declaration
Adafruit_USBD_HID usb_hid; // desc report, desc len, protocol, interval, use out endpoint
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_NONE, 2, false);
// Report payload defined in src/class/hid/hid.h // Report payload defined in src/class/hid/hid.h
// - For Gamepad Button Bit Mask see hid_gamepad_button_bm_t // - For Gamepad Button Bit Mask see hid_gamepad_button_bm_t
// - For Gamepad Hat Bit Mask see hid_gamepad_hat_t // - For Gamepad Hat Bit Mask see hid_gamepad_hat_t
hid_gamepad_report_t gp; hid_gamepad_report_t gp;
void setup() { void setup()
// Manual begin() is required on core without built-in support e.g. mbed rp2040 {
if (!TinyUSBDevice.isInitialized()) { #if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
TinyUSBDevice.begin(0); // Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
} TinyUSB_Device_Init(0);
#endif
Serial.begin(115200); Serial.begin(115200);
// Notes: following commented-out functions has no affect on ESP32
// usb_hid.setPollInterval(2);
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
// Setup HID
usb_hid.setPollInterval(2);
usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
usb_hid.begin(); usb_hid.begin();
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration // wait until device mounted
if (TinyUSBDevice.mounted()) { while( !TinyUSBDevice.mounted() ) delay(1);
TinyUSBDevice.detach();
delay(10);
TinyUSBDevice.attach();
}
Serial.println("Adafruit TinyUSB HID Gamepad example"); Serial.println("Adafruit TinyUSB HID Gamepad example");
} }
void loop() { void loop()
#ifdef TINYUSB_NEED_POLLING_TASK {
// Manual call tud_task since it isn't called by Core's background
TinyUSBDevice.task();
#endif
// not enumerated()/mounted() yet: nothing to do
if (!TinyUSBDevice.mounted()) {
return;
}
// // Remote wakeup // // Remote wakeup
// if ( TinyUSBDevice.suspended() && btn ) // if ( TinyUSBDevice.suspended() && btn )
// { // {
@ -76,22 +67,22 @@ void loop() {
// TinyUSBDevice.remoteWakeup(); // TinyUSBDevice.remoteWakeup();
// } // }
if (!usb_hid.ready()) return; if ( !usb_hid.ready() ) return;
// Reset buttons // Reset buttons
Serial.println("No pressing buttons"); Serial.println("No pressing buttons");
gp.x = 0; gp.x = 0;
gp.y = 0; gp.y = 0;
gp.z = 0; gp.z = 0;
gp.rz = 0; gp.rz = 0;
gp.rx = 0; gp.rx = 0;
gp.ry = 0; gp.ry = 0;
gp.hat = 0; gp.hat = 0;
gp.buttons = 0; gp.buttons = 0;
usb_hid.sendReport(0, &gp, sizeof(gp)); usb_hid.sendReport(0, &gp, sizeof(gp));
delay(2000); delay(2000);
// Hat/DPAD UP // Hat/DPAD UP
Serial.println("Hat/DPAD UP"); Serial.println("Hat/DPAD UP");
gp.hat = 1; // GAMEPAD_HAT_UP; gp.hat = 1; // GAMEPAD_HAT_UP;
@ -116,12 +107,12 @@ void loop() {
usb_hid.sendReport(0, &gp, sizeof(gp)); usb_hid.sendReport(0, &gp, sizeof(gp));
delay(2000); delay(2000);
// Hat/DPAD DOWN // Hat/DPAD DOWN
Serial.println("Hat/DPAD DOWN"); Serial.println("Hat/DPAD DOWN");
gp.hat = 5; // GAMEPAD_HAT_DOWN; gp.hat = 5; // GAMEPAD_HAT_DOWN;
usb_hid.sendReport(0, &gp, sizeof(gp)); usb_hid.sendReport(0, &gp, sizeof(gp));
delay(2000); delay(2000);
// Hat/DPAD DOWN LEFT // Hat/DPAD DOWN LEFT
Serial.println("Hat/DPAD DOWN LEFT"); Serial.println("Hat/DPAD DOWN LEFT");
gp.hat = 6; // GAMEPAD_HAT_DOWN_LEFT; gp.hat = 6; // GAMEPAD_HAT_DOWN_LEFT;
@ -146,14 +137,14 @@ void loop() {
usb_hid.sendReport(0, &gp, sizeof(gp)); usb_hid.sendReport(0, &gp, sizeof(gp));
delay(2000); delay(2000);
// Joystick 1 UP // Joystick 1 UP
Serial.println("Joystick 1 UP"); Serial.println("Joystick 1 UP");
gp.x = 0; gp.x = 0;
gp.y = -127; gp.y = -127;
usb_hid.sendReport(0, &gp, sizeof(gp)); usb_hid.sendReport(0, &gp, sizeof(gp));
delay(2000); delay(2000);
// Joystick 1 DOWN // Joystick 1 DOWN
Serial.println("Joystick 1 DOWN"); Serial.println("Joystick 1 DOWN");
gp.x = 0; gp.x = 0;
@ -167,7 +158,7 @@ void loop() {
gp.y = 0; gp.y = 0;
usb_hid.sendReport(0, &gp, sizeof(gp)); usb_hid.sendReport(0, &gp, sizeof(gp));
delay(2000); delay(2000);
// Joystick 1 LEFT // Joystick 1 LEFT
Serial.println("Joystick 1 LEFT"); Serial.println("Joystick 1 LEFT");
gp.x = -127; gp.x = -127;
@ -185,35 +176,35 @@ void loop() {
// Joystick 2 UP // Joystick 2 UP
Serial.println("Joystick 2 UP"); Serial.println("Joystick 2 UP");
gp.z = 0; gp.z = 0;
gp.rz = 127; gp.rz = 127;
usb_hid.sendReport(0, &gp, sizeof(gp)); usb_hid.sendReport(0, &gp, sizeof(gp));
delay(2000); delay(2000);
// Joystick 2 DOWN // Joystick 2 DOWN
Serial.println("Joystick 2 DOWN"); Serial.println("Joystick 2 DOWN");
gp.z = 0; gp.z = 0;
gp.rz = -127; gp.rz = -127;
usb_hid.sendReport(0, &gp, sizeof(gp)); usb_hid.sendReport(0, &gp, sizeof(gp));
delay(2000); delay(2000);
// Joystick 2 RIGHT // Joystick 2 RIGHT
Serial.println("Joystick 2 RIGHT"); Serial.println("Joystick 2 RIGHT");
gp.z = 127; gp.z = 127;
gp.rz = 0; gp.rz = 0;
usb_hid.sendReport(0, &gp, sizeof(gp)); usb_hid.sendReport(0, &gp, sizeof(gp));
delay(2000); delay(2000);
// Joystick 2 LEFT // Joystick 2 LEFT
Serial.println("Joystick 2 LEFT"); Serial.println("Joystick 2 LEFT");
gp.z = -127; gp.z = -127;
gp.rz = 0; gp.rz = 0;
usb_hid.sendReport(0, &gp, sizeof(gp)); usb_hid.sendReport(0, &gp, sizeof(gp));
delay(2000); delay(2000);
// Joystick 2 CENTER // Joystick 2 CENTER
Serial.println("Joystick 2 CENTER"); Serial.println("Joystick 2 CENTER");
gp.z = 0; gp.z = 0;
gp.rz = 0; gp.rz = 0;
usb_hid.sendReport(0, &gp, sizeof(gp)); usb_hid.sendReport(0, &gp, sizeof(gp));
delay(2000); delay(2000);
@ -224,7 +215,7 @@ void loop() {
gp.rx = 127; gp.rx = 127;
usb_hid.sendReport(0, &gp, sizeof(gp)); usb_hid.sendReport(0, &gp, sizeof(gp));
delay(2000); delay(2000);
// Analog Trigger 1 DOWN // Analog Trigger 1 DOWN
Serial.println("Analog Trigger 1 DOWN"); Serial.println("Analog Trigger 1 DOWN");
gp.rx = -127; gp.rx = -127;
@ -243,7 +234,7 @@ void loop() {
gp.ry = 127; gp.ry = 127;
usb_hid.sendReport(0, &gp, sizeof(gp)); usb_hid.sendReport(0, &gp, sizeof(gp));
delay(2000); delay(2000);
// Analog Trigger 2 DOWN // Analog Trigger 2 DOWN
Serial.println("Analog Trigger 2 DOWN"); Serial.println("Analog Trigger 2 DOWN");
gp.ry = -127; gp.ry = -127;
@ -256,11 +247,11 @@ void loop() {
usb_hid.sendReport(0, &gp, sizeof(gp)); usb_hid.sendReport(0, &gp, sizeof(gp));
delay(2000); delay(2000);
// Test buttons (up to 32 buttons) // Test buttons (up to 32 buttons)
for (int i = 0; i < 32; ++i) { for (int i=0; i<32; ++i)
Serial.print("Pressing button "); {
Serial.println(i); Serial.print("Pressing button "); Serial.println(i);
gp.buttons = (1U << i); gp.buttons = (1U << i);
usb_hid.sendReport(0, &gp, sizeof(gp)); usb_hid.sendReport(0, &gp, sizeof(gp));
delay(1000); delay(1000);
@ -269,13 +260,13 @@ void loop() {
// Random touch // Random touch
Serial.println("Random touch"); Serial.println("Random touch");
gp.x = random(-127, 128); gp.x = random(-127, 128);
gp.y = random(-127, 128); gp.y = random(-127, 128);
gp.z = random(-127, 128); gp.z = random(-127, 128);
gp.rz = random(-127, 128); gp.rz = random(-127, 128);
gp.rx = random(-127, 128); gp.rx = random(-127, 128);
gp.ry = random(-127, 128); gp.ry = random(-127, 128);
gp.hat = random(0, 9); gp.hat = random(0, 9);
gp.buttons = random(0, 0xffff); gp.buttons = random(0, 0xffff);
usb_hid.sendReport(0, &gp, sizeof(gp)); usb_hid.sendReport(0, &gp, sizeof(gp));
delay(2000); delay(2000);

View file

@ -1,2 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host

View file

@ -39,51 +39,50 @@
// HID report descriptor using TinyUSB's template // HID report descriptor using TinyUSB's template
// Generic In Out with 64 bytes report (max) // Generic In Out with 64 bytes report (max)
uint8_t const desc_hid_report[] = { uint8_t const desc_hid_report[] =
TUD_HID_REPORT_DESC_GENERIC_INOUT(64) {
TUD_HID_REPORT_DESC_GENERIC_INOUT(64)
}; };
// USB HID object // USB HID object. For ESP32 these values cannot be changed after this declaration
Adafruit_USBD_HID usb_hid; // desc report, desc len, protocol, interval, use out endpoint
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_NONE, 2, true);
// the setup function runs once when you press reset or power the board // the setup function runs once when you press reset or power the board
void setup() { void setup()
// Manual begin() is required on core without built-in support e.g. mbed rp2040 {
if (!TinyUSBDevice.isInitialized()) { #if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
TinyUSBDevice.begin(0); // Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
} TinyUSB_Device_Init(0);
#endif
Serial.begin(115200);
// Notes: following commented-out functions has no affect on ESP32 // Notes: following commented-out functions has no affect on ESP32
usb_hid.enableOutEndpoint(true); // usb_hid.enableOutEndpoint(true);
usb_hid.setPollInterval(2); // usb_hid.setPollInterval(2);
usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report)); // usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
usb_hid.setStringDescriptor("TinyUSB HID Generic"); // usb_hid.setStringDescriptor("TinyUSB HID Generic");
usb_hid.setReportCallback(get_report_callback, set_report_callback); usb_hid.setReportCallback(get_report_callback, set_report_callback);
usb_hid.begin(); usb_hid.begin();
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration Serial.begin(115200);
if (TinyUSBDevice.mounted()) {
TinyUSBDevice.detach(); // wait until device mounted
delay(10); while( !TinyUSBDevice.mounted() ) delay(1);
TinyUSBDevice.attach();
}
Serial.println("Adafruit TinyUSB HID Generic In Out example"); Serial.println("Adafruit TinyUSB HID Generic In Out example");
} }
void loop() { void loop()
#ifdef TINYUSB_NEED_POLLING_TASK {
// Manual call tud_task since it isn't called by Core's background // nothing to do
TinyUSBDevice.task();
#endif
} }
// Invoked when received GET_REPORT control request // Invoked when received GET_REPORT control request
// Application must fill buffer report's content and return its length. // Application must fill buffer report's content and return its length.
// Return zero will cause the stack to STALL request // 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) { 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 // not used in this example
(void) report_id; (void) report_id;
(void) report_type; (void) report_type;
@ -94,7 +93,8 @@ uint16_t get_report_callback(uint8_t report_id, hid_report_type_t report_type, u
// Invoked when received SET_REPORT control request or // Invoked when received SET_REPORT control request or
// received data on OUT endpoint ( Report ID = 0, Type = 0 ) // 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) { 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 // This example doesn't use multiple report and report ID
(void) report_id; (void) report_id;
(void) report_type; (void) report_type;

View file

@ -1,225 +0,0 @@
/*********************************************************************
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 demonstrates use of native controller as host (TinyUSB Host)
* Note:
* - For most mcu with only 1 native usb, Serial is not available. We will use Serial1 instead
*
* Host example will get device descriptors of attached devices and print it out as follows:
Device 1: ID 046d:c52f
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 0200
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x046d
idProduct 0xc52f
bcdDevice 2200
iManufacturer 1 Logitech
iProduct 2 USB Receiver
iSerialNumber 0
bNumConfigurations 1
*
*/
#include "Adafruit_TinyUSB.h"
#ifndef USE_TINYUSB_HOST
#error This example requires usb stack configured as host in "Tools -> USB Stack -> Adafruit TinyUSB Host"
#endif
// Language ID: English
#define LANGUAGE_ID 0x0409
typedef struct {
tusb_desc_device_t desc_device;
uint16_t manufacturer[32];
uint16_t product[48];
uint16_t serial[16];
bool mounted;
} dev_info_t;
// CFG_TUH_DEVICE_MAX is defined by tusb_config header
dev_info_t dev_info[CFG_TUH_DEVICE_MAX] = { 0 };
Adafruit_USBH_Host USBHost;
//--------------------------------------------------------------------+
// setup() & loop()
//--------------------------------------------------------------------+
void setup() {
Serial1.begin(115200);
Serial1.println("TinyUSB Host: Device Info Example");
// Init USB Host on native controller roothub port0
USBHost.begin(0);
}
void loop() {
USBHost.task();
Serial1.flush();
}
//--------------------------------------------------------------------+
// TinyUSB Host callbacks
//--------------------------------------------------------------------+
void print_device_descriptor(tuh_xfer_t *xfer);
void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len);
void print_lsusb(void) {
bool no_device = true;
for (uint8_t daddr = 1; daddr < CFG_TUH_DEVICE_MAX + 1; daddr++) {
// TODO can use tuh_mounted(daddr), but tinyusb has an bug
// use local connected flag instead
dev_info_t *dev = &dev_info[daddr - 1];
if (dev->mounted) {
Serial1.printf("Device %u: ID %04x:%04x %s %s\r\n", daddr,
dev->desc_device.idVendor, dev->desc_device.idProduct,
(char *) dev->manufacturer, (char *) dev->product);
no_device = false;
}
}
if (no_device) {
Serial1.println("No device connected (except hub)");
}
}
// Invoked when device is mounted (configured)
void tuh_mount_cb(uint8_t daddr) {
Serial1.printf("Device attached, address = %d\r\n", daddr);
dev_info_t *dev = &dev_info[daddr - 1];
dev->mounted = true;
// Get Device Descriptor
tuh_descriptor_get_device(daddr, &dev->desc_device, 18, print_device_descriptor, 0);
}
/// Invoked when device is unmounted (bus reset/unplugged)
void tuh_umount_cb(uint8_t daddr) {
Serial1.printf("Device removed, address = %d\r\n", daddr);
dev_info_t *dev = &dev_info[daddr - 1];
dev->mounted = false;
// print device summary
print_lsusb();
}
void print_device_descriptor(tuh_xfer_t *xfer) {
if (XFER_RESULT_SUCCESS != xfer->result) {
Serial1.printf("Failed to get device descriptor\r\n");
return;
}
uint8_t const daddr = xfer->daddr;
dev_info_t *dev = &dev_info[daddr - 1];
tusb_desc_device_t *desc = &dev->desc_device;
Serial1.printf("Device %u: ID %04x:%04x\r\n", daddr, desc->idVendor, desc->idProduct);
Serial1.printf("Device Descriptor:\r\n");
Serial1.printf(" bLength %u\r\n" , desc->bLength);
Serial1.printf(" bDescriptorType %u\r\n" , desc->bDescriptorType);
Serial1.printf(" bcdUSB %04x\r\n" , desc->bcdUSB);
Serial1.printf(" bDeviceClass %u\r\n" , desc->bDeviceClass);
Serial1.printf(" bDeviceSubClass %u\r\n" , desc->bDeviceSubClass);
Serial1.printf(" bDeviceProtocol %u\r\n" , desc->bDeviceProtocol);
Serial1.printf(" bMaxPacketSize0 %u\r\n" , desc->bMaxPacketSize0);
Serial1.printf(" idVendor 0x%04x\r\n" , desc->idVendor);
Serial1.printf(" idProduct 0x%04x\r\n" , desc->idProduct);
Serial1.printf(" bcdDevice %04x\r\n" , desc->bcdDevice);
// Get String descriptor using Sync API
Serial1.printf(" iManufacturer %u ", desc->iManufacturer);
if (XFER_RESULT_SUCCESS ==
tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, dev->manufacturer, sizeof(dev->manufacturer))) {
utf16_to_utf8(dev->manufacturer, sizeof(dev->manufacturer));
Serial1.printf((char *) dev->manufacturer);
}
Serial1.printf("\r\n");
Serial1.printf(" iProduct %u ", desc->iProduct);
if (XFER_RESULT_SUCCESS ==
tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, dev->product, sizeof(dev->product))) {
utf16_to_utf8(dev->product, sizeof(dev->product));
Serial1.printf((char *) dev->product);
}
Serial1.printf("\r\n");
Serial1.printf(" iSerialNumber %u ", desc->iSerialNumber);
if (XFER_RESULT_SUCCESS ==
tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, dev->serial, sizeof(dev->serial))) {
utf16_to_utf8(dev->serial, sizeof(dev->serial));
Serial1.printf((char *) dev->serial);
}
Serial1.printf("\r\n");
Serial1.printf(" bNumConfigurations %u\r\n", desc->bNumConfigurations);
// print device summary
print_lsusb();
}
//--------------------------------------------------------------------+
// String Descriptor Helper
//--------------------------------------------------------------------+
static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) {
// TODO: Check for runover.
(void) utf8_len;
// Get the UTF-16 length out of the data itself.
for (size_t i = 0; i < utf16_len; i++) {
uint16_t chr = utf16[i];
if (chr < 0x80) {
*utf8++ = chr & 0xff;
} else if (chr < 0x800) {
*utf8++ = (uint8_t) (0xC0 | (chr >> 6 & 0x1F));
*utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F));
} else {
// TODO: Verify surrogate.
*utf8++ = (uint8_t) (0xE0 | (chr >> 12 & 0x0F));
*utf8++ = (uint8_t) (0x80 | (chr >> 6 & 0x3F));
*utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F));
}
// TODO: Handle UTF-16 code points that take two entries.
}
}
// Count how many bytes a utf-16-le encoded string will take in utf-8.
static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
size_t total_bytes = 0;
for (size_t i = 0; i < len; i++) {
uint16_t chr = buf[i];
if (chr < 0x80) {
total_bytes += 1;
} else if (chr < 0x800) {
total_bytes += 2;
} else {
total_bytes += 3;
}
// TODO: Handle UTF-16 code points that take two entries.
}
return total_bytes;
}
void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len) {
size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
size_t utf8_len = _count_utf8_bytes(temp_buf + 1, utf16_len);
_convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, buf_len);
((uint8_t *) temp_buf)[utf8_len] = '\0';
}

View file

@ -1,2 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host

View file

@ -19,43 +19,28 @@
// USB MIDI object with 3 ports // USB MIDI object with 3 ports
Adafruit_USBD_MIDI usb_midi(3); Adafruit_USBD_MIDI usb_midi(3);
void setup() { void setup()
#ifdef LED_BUILTIN {
pinMode(LED_BUILTIN, OUTPUT); pinMode(LED_BUILTIN, OUTPUT);
#endif
// Manual begin() is required on core without built-in support e.g. mbed rp2040 #if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
if (!TinyUSBDevice.isInitialized()) { // Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
TinyUSBDevice.begin(0); TinyUSB_Device_Init(0);
} #endif
// Set name for each cable, must be done before usb_midi.begin() // Set name for each cable, must be done before usb_midi.begin()
usb_midi.setCableName(1, "Keyboard"); usb_midi.setCableName(1, "Keyboard");
usb_midi.setCableName(2, "Drum Pads"); usb_midi.setCableName(2, "Drum Pads");
usb_midi.setCableName(3, "Lights"); usb_midi.setCableName(3, "Lights");
usb_midi.begin(); usb_midi.begin();
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
if (TinyUSBDevice.mounted()) {
TinyUSBDevice.detach();
delay(10);
TinyUSBDevice.attach();
}
} }
void loop() { void loop()
#ifdef TINYUSB_NEED_POLLING_TASK {
// Manual call tud_task since it isn't called by Core's background digitalWrite(LED_BUILTIN, HIGH);
TinyUSBDevice.task(); delay(1000);
#endif
// toggle LED digitalWrite(LED_BUILTIN, LOW);
static uint32_t ms = 0; delay(1000);
static uint8_t led_state = 0;
if (millis() - ms > 1000) {
ms = millis();
#ifdef LED_BUILTIN
digitalWrite(LED_BUILTIN, 1-led_state);
#endif
}
} }

View file

@ -1,2 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host

View file

@ -31,74 +31,65 @@ uint32_t position = 0;
// Store example melody as an array of note values // Store example melody as an array of note values
byte note_sequence[] = { 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,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, 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 56,61,64,68,74,78,81,86,90,93,98,102
}; };
void setup() { void setup()
// Manual begin() is required on core without built-in support e.g. mbed rp2040 {
if (!TinyUSBDevice.isInitialized()) { #if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
TinyUSBDevice.begin(0); // Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
} TinyUSB_Device_Init(0);
#endif
Serial.begin(115200); pinMode(LED_BUILTIN, OUTPUT);
usb_midi.setStringDescriptor("TinyUSB MIDI"); //usb_midi.setStringDescriptor("TinyUSB MIDI");
// Initialize MIDI, and listen to all MIDI channels // Initialize MIDI, and listen to all MIDI channels
// This will also call usb_midi's begin() // This will also call usb_midi's begin()
MIDI.begin(MIDI_CHANNEL_OMNI); MIDI.begin(MIDI_CHANNEL_OMNI);
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
if (TinyUSBDevice.mounted()) {
TinyUSBDevice.detach();
delay(10);
TinyUSBDevice.attach();
}
// Attach the handleNoteOn function to the MIDI Library. It will // Attach the handleNoteOn function to the MIDI Library. It will
// be called whenever the Bluefruit receives MIDI Note On messages. // be called whenever the Bluefruit receives MIDI Note On messages.
MIDI.setHandleNoteOn(handleNoteOn); MIDI.setHandleNoteOn(handleNoteOn);
// Do the same for MIDI Note Off messages. // Do the same for MIDI Note Off messages.
MIDI.setHandleNoteOff(handleNoteOff); MIDI.setHandleNoteOff(handleNoteOff);
Serial.begin(115200);
// wait until device mounted
while( !TinyUSBDevice.mounted() ) delay(1);
} }
void loop() { void loop()
#ifdef TINYUSB_NEED_POLLING_TASK {
// Manual call tud_task since it isn't called by Core's background
TinyUSBDevice.task();
#endif
// not enumerated()/mounted() yet: nothing to do
if (!TinyUSBDevice.mounted()) {
return;
}
static uint32_t start_ms = 0; static uint32_t start_ms = 0;
if (millis() - start_ms > 266) { if ( millis() - start_ms > 266 )
{
start_ms += 266; start_ms += 266;
// Setup variables for the current and previous // Setup variables for the current and previous
// positions in the note sequence. // positions in the note sequence.
int previous = position - 1; int previous = position - 1;
// If we currently are at position 0, set the // If we currently are at position 0, set the
// previous position to the last note in the sequence. // previous position to the last note in the sequence.
if (previous < 0) { if (previous < 0) {
previous = sizeof(note_sequence) - 1; previous = sizeof(note_sequence) - 1;
} }
// Send Note On for current position at full velocity (127) on channel 1. // Send Note On for current position at full velocity (127) on channel 1.
MIDI.sendNoteOn(note_sequence[position], 127, 1); MIDI.sendNoteOn(note_sequence[position], 127, 1);
// Send Note Off for previous note. // Send Note Off for previous note.
MIDI.sendNoteOff(note_sequence[previous], 0, 1); MIDI.sendNoteOff(note_sequence[previous], 0, 1);
// Increment position // Increment position
position++; position++;
// If we are at the end of the sequence, start over. // If we are at the end of the sequence, start over.
if (position >= sizeof(note_sequence)) { if (position >= sizeof(note_sequence)) {
position = 0; position = 0;
@ -106,10 +97,11 @@ void loop() {
} }
// read any new MIDI messages // read any new MIDI messages
MIDI.read(); MIDI.read();
} }
void handleNoteOn(byte channel, byte pitch, byte velocity) { void handleNoteOn(byte channel, byte pitch, byte velocity)
{
// Log when a note is pressed. // Log when a note is pressed.
Serial.print("Note on: channel = "); Serial.print("Note on: channel = ");
Serial.print(channel); Serial.print(channel);
@ -121,7 +113,8 @@ void handleNoteOn(byte channel, byte pitch, byte velocity) {
Serial.println(velocity); Serial.println(velocity);
} }
void handleNoteOff(byte channel, byte pitch, byte velocity) { void handleNoteOff(byte channel, byte pitch, byte velocity)
{
// Log when a note is released. // Log when a note is released.
Serial.print("Note off: channel = "); Serial.print("Note off: channel = ");
Serial.print(channel); Serial.print(channel);

View file

@ -32,7 +32,7 @@
*/ */
#include "SPI.h" #include "SPI.h"
#include "SdFat_Adafruit_Fork.h" #include "SdFat.h"
#include "Adafruit_SPIFlash.h" #include "Adafruit_SPIFlash.h"
#include "Adafruit_TinyUSB.h" #include "Adafruit_TinyUSB.h"
@ -93,19 +93,14 @@ void setupMassStorage(void)
// MSC is ready for read/write // MSC is ready for read/write
fs_changed = false; fs_changed = false;
usb_msc.setReadyCallback(0, msc_ready_callback); usb_msc.setReadyCallback(0, msc_ready_callback);
usb_msc.begin();
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration usb_msc.begin();
if (TinyUSBDevice.mounted()) {
TinyUSBDevice.detach();
delay(10);
TinyUSBDevice.attach();
}
// Init file system on the flash // Init file system on the flash
fs_formatted = fatfs.begin(&flash); fs_formatted = fatfs.begin(&flash);
if ( !fs_formatted ) { if ( !fs_formatted )
{
DBG_SERIAL.println("Failed to init files system, flash may not be formatted"); DBG_SERIAL.println("Failed to init files system, flash may not be formatted");
} }
} }

View file

@ -1,3 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host
CH32V20x_EVT

View file

@ -23,7 +23,7 @@
*/ */
#include "SPI.h" #include "SPI.h"
#include "SdFat_Adafruit_Fork.h" #include "SdFat.h"
#include "Adafruit_SPIFlash.h" #include "Adafruit_SPIFlash.h"
#include "Adafruit_TinyUSB.h" #include "Adafruit_TinyUSB.h"
@ -48,12 +48,9 @@ bool fs_formatted = false;
bool fs_changed = true;; bool fs_changed = true;;
// the setup function runs once when you press reset or power the board // the setup function runs once when you press reset or power the board
void setup() { void setup()
#ifdef LED_BUILTIN {
pinMode(LED_BUILTIN, OUTPUT); pinMode(LED_BUILTIN, OUTPUT);
#endif
Serial.begin(115200);
flash.begin(); flash.begin();
@ -71,16 +68,10 @@ void setup() {
usb_msc.begin(); usb_msc.begin();
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
if (TinyUSBDevice.mounted()) {
TinyUSBDevice.detach();
delay(10);
TinyUSBDevice.attach();
}
// Init file system on the flash // Init file system on the flash
fs_formatted = fatfs.begin(&flash); fs_formatted = fatfs.begin(&flash);
Serial.begin(115200);
//while ( !Serial ) delay(10); // wait for native usb //while ( !Serial ) delay(10); // wait for native usb
Serial.println("Adafruit TinyUSB Mass Storage External Flash example"); Serial.println("Adafruit TinyUSB Mass Storage External Flash example");
@ -88,12 +79,15 @@ void setup() {
Serial.print("Flash size: "); Serial.print(flash.size() / 1024); Serial.println(" KB"); Serial.print("Flash size: "); Serial.print(flash.size() / 1024); Serial.println(" KB");
} }
void loop() { void loop()
{
// check if formatted // check if formatted
if ( !fs_formatted ) { if ( !fs_formatted )
{
fs_formatted = fatfs.begin(&flash); fs_formatted = fatfs.begin(&flash);
if (!fs_formatted) { if (!fs_formatted)
{
Serial.println("Failed to init files system, flash may not be formatted"); Serial.println("Failed to init files system, flash may not be formatted");
Serial.println("Please format it as FAT12 with your PC or using Adafruit_SPIFlash's SdFat_format example:"); Serial.println("Please format it as FAT12 with your PC or using Adafruit_SPIFlash's SdFat_format example:");
Serial.println("- https://github.com/adafruit/Adafruit_SPIFlash/tree/master/examples/SdFat_format"); Serial.println("- https://github.com/adafruit/Adafruit_SPIFlash/tree/master/examples/SdFat_format");
@ -104,12 +98,14 @@ void loop() {
} }
} }
if ( fs_changed ) { if ( fs_changed )
{
fs_changed = false; fs_changed = false;
Serial.println("Opening root"); Serial.println("Opening root");
if ( !root.open("/") ) { if ( !root.open("/") )
{
Serial.println("open root failed"); Serial.println("open root failed");
return; return;
} }
@ -119,11 +115,13 @@ void loop() {
// Open next file in root. // Open next file in root.
// Warning, openNext starts at the current directory position // Warning, openNext starts at the current directory position
// so a rewind of the directory may be required. // so a rewind of the directory may be required.
while ( file.openNext(&root, O_RDONLY) ) { while ( file.openNext(&root, O_RDONLY) )
{
file.printFileSize(&Serial); file.printFileSize(&Serial);
Serial.write(' '); Serial.write(' ');
file.printName(&Serial); file.printName(&Serial);
if ( file.isDir() ) { if ( file.isDir() )
{
// Indicate a directory. // Indicate a directory.
Serial.write('/'); Serial.write('/');
} }
@ -141,7 +139,8 @@ void loop() {
// Callback invoked when received READ10 command. // Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and // Copy disk's data to buffer (up to bufsize) and
// return number of copied bytes (must be multiple of block size) // return number of copied bytes (must be multiple of block size)
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) { int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
{
// Note: SPIFLash Block API: readBlocks/writeBlocks/syncBlocks // Note: SPIFLash Block API: readBlocks/writeBlocks/syncBlocks
// already include 4K sector caching internally. We don't need to cache it, yahhhh!! // 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; return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
@ -150,10 +149,9 @@ int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) {
// Callback invoked when received WRITE10 command. // Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and // Process data in buffer to disk's storage and
// return number of written bytes (must be multiple of block size) // 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) { int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
#ifdef LED_BUILTIN {
digitalWrite(LED_BUILTIN, HIGH); digitalWrite(LED_BUILTIN, HIGH);
#endif
// Note: SPIFLash Block API: readBlocks/writeBlocks/syncBlocks // Note: SPIFLash Block API: readBlocks/writeBlocks/syncBlocks
// already include 4K sector caching internally. We don't need to cache it, yahhhh!! // already include 4K sector caching internally. We don't need to cache it, yahhhh!!
@ -162,7 +160,8 @@ int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
// Callback invoked when WRITE10 command is completed (status received and accepted by host). // Callback invoked when WRITE10 command is completed (status received and accepted by host).
// used to flush any pending cache. // used to flush any pending cache.
void msc_flush_cb (void) { void msc_flush_cb (void)
{
// sync with flash // sync with flash
flash.syncBlocks(); flash.syncBlocks();
@ -171,7 +170,5 @@ void msc_flush_cb (void) {
fs_changed = true; fs_changed = true;
#ifdef LED_BUILTIN
digitalWrite(LED_BUILTIN, LOW); digitalWrite(LED_BUILTIN, LOW);
#endif
} }

View file

@ -1,3 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host
CH32V20x_EVT

View file

@ -23,7 +23,7 @@
*/ */
#include "SPI.h" #include "SPI.h"
#include "SdFat_Adafruit_Fork.h" #include "SdFat.h"
#include "Adafruit_SPIFlash.h" #include "Adafruit_SPIFlash.h"
#include "Adafruit_TinyUSB.h" #include "Adafruit_TinyUSB.h"
@ -33,67 +33,42 @@
// for flashTransport definition // for flashTransport definition
#include "flash_config.h" #include "flash_config.h"
Adafruit_SPIFlash flash(&flashTransport); Adafruit_SPIFlash flash(&flashTransport);
// External Flash File system
FatVolume fatfs;
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// SDCard Config // SDCard Config
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
#if defined(ARDUINO_PYPORTAL_M4) || defined(ARDUINO_PYPORTAL_M4_TITANO) #if defined(ARDUINO_PYPORTAL_M4) || defined(ARDUINO_PYPORTAL_M4_TITANO)
// PyPortal has on-board card reader // PyPortal has on-board card reader
#define SDCARD_CS 32 #define SDCARD_CS 32
#define SDCARD_DETECT 33 #define SDCARD_DETECT 33
#define SDCARD_DETECT_ACTIVE HIGH
#elif defined(ARDUINO_ADAFRUIT_METRO_RP2040)
#define SDIO_CLK_PIN 18
#define SDIO_CMD_PIN 19 // MOSI
#define SDIO_DAT0_PIN 20 // DAT1: 21, DAT2: 22, DAT3: 23
#define SDCARD_DETECT 15
#define SDCARD_DETECT_ACTIVE LOW
#elif defined(ARDUINO_ADAFRUIT_METRO_RP2350)
// Note: not working yet (need troubleshoot later)
#define SDIO_CLK_PIN 34
#define SDIO_CMD_PIN 35 // MOSI
#define SDIO_DAT0_PIN 36 // DAT1: 37, DAT2: 38, DAT3: 39
#define SDCARD_DETECT 40
#define SDCARD_DETECT_ACTIVE LOW
#elif defined(ARDUINO_ADAFRUIT_FRUITJAM_RP2350)
#define SDIO_CLK_PIN 34
#define SDIO_CMD_PIN 35 // MOSI
#define SDIO_DAT0_PIN 36 // DAT1: 37, DAT2: 38, DAT3: 39
#define SDCARD_DETECT 33
#define SDCARD_DETECT_ACTIVE LOW
#else #else
// Use SPI, no detect
#define SDCARD_CS 10 #define SDCARD_CS 10
// no detect
#endif #endif
#if defined(SDIO_CLK_PIN) && defined(SDIO_CMD_PIN) && defined(SDIO_DAT0_PIN) // SDCard File system
#define SD_CONFIG SdioConfig(SDIO_CLK_PIN, SDIO_CMD_PIN, SDIO_DAT0_PIN)
#else
#define SD_CONFIG SdSpiConfig(SDCARD_CS, SHARED_SPI, SD_SCK_MHZ(50))
#endif
// File system on SD Card
SdFat sd; SdFat sd;
// USB Mass Storage object // USB Mass Storage object
Adafruit_USBD_MSC usb_msc; Adafruit_USBD_MSC usb_msc;
// Set to true when PC write to flash // Set to true when PC write to flash
bool sd_changed = false;
bool sd_inited = false; bool sd_inited = false;
bool flash_formatted = false;
bool flash_changed = false;
// the setup function runs once when you press reset or power the board // the setup function runs once when you press reset or power the board
void setup() { void setup()
#ifdef LED_BUILTIN {
pinMode(LED_BUILTIN, OUTPUT); pinMode(LED_BUILTIN, OUTPUT);
#endif
Serial.begin(115200); Serial.begin(115200);
// MSC with 2 Logical Units: LUN0: External Flash, LUN1: SDCard // MSC with 2 Logical Units: LUN0: External Flash, LUN1: SDCard
@ -108,20 +83,16 @@ void setup() {
// LUN readiness will always be set later on // LUN readiness will always be set later on
usb_msc.begin(); usb_msc.begin();
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
if (TinyUSBDevice.mounted()) {
TinyUSBDevice.detach();
delay(10);
TinyUSBDevice.attach();
}
//------------- Lun 0 for external flash -------------// //------------- Lun 0 for external flash -------------//
flash.begin(); flash.begin();
flash_formatted = fatfs.begin(&flash);
usb_msc.setCapacity(0, flash.size()/512, 512); 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.setReadWriteCallback(0, external_flash_read_cb, external_flash_write_cb, external_flash_flush_cb);
usb_msc.setUnitReady(0, true); usb_msc.setUnitReady(0, true);
flash_changed = true; // to print contents initially
//------------- Lun 1 for SD card -------------// //------------- Lun 1 for SD card -------------//
#ifdef SDCARD_DETECT #ifdef SDCARD_DETECT
// DETECT pin is available, detect card present on the fly with test unit ready // DETECT pin is available, detect card present on the fly with test unit ready
@ -134,44 +105,58 @@ void setup() {
usb_msc.setUnitReady(1, true); usb_msc.setUnitReady(1, true);
#endif #endif
// while ( !Serial ) delay(10); // wait for native usb // while ( !Serial ) delay(10); // wait for native usb
Serial.println("Adafruit TinyUSB Mass Storage External Flash + SD Card example"); Serial.println("Adafruit TinyUSB Mass Storage External Flash + SD Card example");
delay(1000); delay(1000);
} }
bool init_sdcard(void) { bool init_sdcard(void)
{
Serial.print("Init SDCard ... "); Serial.print("Init SDCard ... ");
if (!sd.begin(SD_CONFIG)) { if ( !sd.begin(SDCARD_CS, SD_SCK_MHZ(50)) )
Serial.println("initialization failed. Things to check:"); {
Serial.println("- is a card inserted?"); Serial.print("Failed ");
Serial.println("- is your wiring correct?"); sd.errorPrint("sd.begin() failed");
Serial.println("- did you change the SDCARD_CS or SDIO pin to match your shield or module?");
return false; return false;
} }
uint32_t block_count = sd.card()->sectorCount(); uint32_t block_count;
#if SD_FAT_VERSION >= 20000
block_count = sd.card()->sectorCount();
#else
block_count = sd.card()->cardSize();
#endif
usb_msc.setCapacity(1, block_count, 512); usb_msc.setCapacity(1, block_count, 512);
usb_msc.setReadWriteCallback(1, sdcard_read_cb, sdcard_write_cb, sdcard_flush_cb); usb_msc.setReadWriteCallback(1, sdcard_read_cb, sdcard_write_cb, sdcard_flush_cb);
sd_changed = true; // to print contents initially
Serial.print("OK, Card size = "); Serial.print("OK, Card size = ");
Serial.print((block_count / (1024 * 1024)) * 512); Serial.print((block_count / (1024*1024)) * 512);
Serial.println(" MB"); Serial.println(" MB");
return true; return true;
} }
void print_rootdir(File32* rdir) { void print_rootdir(File32* rdir)
{
File32 file; File32 file;
// Open next file in root. // Open next file in root.
// Warning, openNext starts at the current directory position // Warning, openNext starts at the current directory position
// so a rewind of the directory may be required. // so a rewind of the directory may be required.
while (file.openNext(rdir, O_RDONLY)) { while ( file.openNext(rdir, O_RDONLY) )
{
file.printFileSize(&Serial); file.printFileSize(&Serial);
Serial.write(' '); Serial.write(' ');
file.printName(&Serial); file.printName(&Serial);
if (file.isDir()) { if ( file.isDir() )
{
// Indicate a directory. // Indicate a directory.
Serial.write('/'); Serial.write('/');
} }
@ -180,8 +165,46 @@ void print_rootdir(File32* rdir) {
} }
} }
void loop() { void loop()
// nothing to do {
if ( flash_changed )
{
if (!flash_formatted)
{
flash_formatted = fatfs.begin(&flash);
}
// skip if still not formatted
if (flash_formatted)
{
File32 root;
root = fatfs.open("/");
Serial.println("Flash contents:");
print_rootdir(&root);
Serial.println();
root.close();
}
flash_changed = false;
}
if ( sd_changed )
{
File32 root;
root = sd.open("/");
Serial.println("SD contents:");
print_rootdir(&root);
Serial.println();
root.close();
sd_changed = false;
}
delay(1000); // refresh every 1 second
} }
@ -189,48 +212,76 @@ void loop() {
// SD Card callbacks // SD Card callbacks
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
int32_t sdcard_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) { int32_t sdcard_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
bool rc = sd.card()->readSectors(lba, (uint8_t*) buffer, bufsize/512); {
bool rc;
#if SD_FAT_VERSION >= 20000
rc = sd.card()->readSectors(lba, (uint8_t*) buffer, bufsize/512);
#else
rc = sd.card()->readBlocks(lba, (uint8_t*) buffer, bufsize/512);
#endif
return rc ? bufsize : -1; return rc ? bufsize : -1;
} }
// Callback invoked when received WRITE10 command. // Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and // Process data in buffer to disk's storage and
// return number of written bytes (must be multiple of block size) // 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) { int32_t sdcard_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
#ifdef LED_BUILTIN {
bool rc;
digitalWrite(LED_BUILTIN, HIGH); digitalWrite(LED_BUILTIN, HIGH);
#if SD_FAT_VERSION >= 20000
rc = sd.card()->writeSectors(lba, buffer, bufsize/512);
#else
rc = sd.card()->writeBlocks(lba, buffer, bufsize/512);
#endif #endif
bool rc = sd.card()->writeSectors(lba, buffer, bufsize/512);
return rc ? bufsize : -1; return rc ? bufsize : -1;
} }
// Callback invoked when WRITE10 command is completed (status received and accepted by host). // Callback invoked when WRITE10 command is completed (status received and accepted by host).
// used to flush any pending cache. // used to flush any pending cache.
void sdcard_flush_cb (void) { void sdcard_flush_cb (void)
{
#if SD_FAT_VERSION >= 20000
sd.card()->syncDevice(); sd.card()->syncDevice();
sd.cacheClear(); // clear file system's cache to force refresh #else
sd.card()->syncBlocks();
#ifdef LED_BUILTIN
digitalWrite(LED_BUILTIN, LOW);
#endif #endif
// clear file system's cache to force refresh
sd.cacheClear();
sd_changed = true;
digitalWrite(LED_BUILTIN, LOW);
} }
#ifdef SDCARD_DETECT #ifdef SDCARD_DETECT
// Invoked when received Test Unit Ready command. // Invoked when received Test Unit Ready command.
// return true allowing host to read/write this LUN e.g SD card inserted // return true allowing host to read/write this LUN e.g SD card inserted
bool sdcard_ready_callback(void) { bool sdcard_ready_callback(void)
{
// Card is inserted // Card is inserted
if (digitalRead(SDCARD_DETECT) == SDCARD_DETECT_ACTIVE) { if ( digitalRead(SDCARD_DETECT) == HIGH )
{
// init SD card if not already // init SD card if not already
if (!sd_inited) { if ( !sd_inited )
{
sd_inited = init_sdcard(); sd_inited = init_sdcard();
} }
} else { }else
{
sd_inited = false; sd_inited = false;
usb_msc.setReadWriteCallback(1, NULL, NULL, NULL); usb_msc.setReadWriteCallback(1, NULL, NULL, NULL);
} }
Serial.println(sd_inited);
return sd_inited; return sd_inited;
} }
#endif #endif
@ -242,7 +293,8 @@ bool sdcard_ready_callback(void) {
// Callback invoked when received READ10 command. // Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and // Copy disk's data to buffer (up to bufsize) and
// return number of copied bytes (must be multiple of block size) // 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) { int32_t external_flash_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
{
// Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks // Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
// already include 4K sector caching internally. We don't need to cache it, yahhhh!! // 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; return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
@ -251,10 +303,9 @@ int32_t external_flash_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) {
// Callback invoked when received WRITE10 command. // Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and // Process data in buffer to disk's storage and
// return number of written bytes (must be multiple of block size) // 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) { int32_t external_flash_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
#ifdef LED_BUILTIN {
digitalWrite(LED_BUILTIN, HIGH); digitalWrite(LED_BUILTIN, HIGH);
#endif
// Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks // Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
// already include 4K sector caching internally. We don't need to cache it, yahhhh!! // already include 4K sector caching internally. We don't need to cache it, yahhhh!!
@ -263,9 +314,14 @@ int32_t external_flash_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize
// Callback invoked when WRITE10 command is completed (status received and accepted by host). // Callback invoked when WRITE10 command is completed (status received and accepted by host).
// used to flush any pending cache. // used to flush any pending cache.
void external_flash_flush_cb (void) { void external_flash_flush_cb (void)
{
flash.syncBlocks(); flash.syncBlocks();
#ifdef LED_BUILTIN
// clear file system's cache to force refresh
fatfs.cacheClear();
flash_changed = true;
digitalWrite(LED_BUILTIN, LOW); digitalWrite(LED_BUILTIN, LOW);
#endif
} }

View file

@ -10,7 +10,7 @@
*********************************************************************/ *********************************************************************/
#include "SPI.h" #include "SPI.h"
#include "SdFat_Adafruit_Fork.h" #include "SdFat.h"
#include "Adafruit_InternalFlash.h" #include "Adafruit_InternalFlash.h"
#include "Adafruit_TinyUSB.h" #include "Adafruit_TinyUSB.h"
@ -35,9 +35,8 @@ Adafruit_USBD_MSC usb_msc;
bool fs_changed; bool fs_changed;
// the setup function runs once when you press reset or power the board // the setup function runs once when you press reset or power the board
void setup() { void setup()
Serial.begin(115200); {
// Initialize internal flash // Initialize internal flash
flash.begin(); flash.begin();
@ -47,30 +46,32 @@ void setup() {
// Set callback // Set callback
usb_msc.setReadWriteCallback(msc_read_callback, msc_write_callback, msc_flush_callback); usb_msc.setReadWriteCallback(msc_read_callback, msc_write_callback, msc_flush_callback);
usb_msc.setWritableCallback(msc_writable_callback); usb_msc.setWritableCallback(msc_writable_callback);
usb_msc.setCapacity(flash.size()/512, 512); // Set disk size, block size should be 512 regardless of flash page size
usb_msc.setUnitReady(true); // Set Lun ready
usb_msc.begin();
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration // Set disk size, block size should be 512 regardless of flash page size
if (TinyUSBDevice.mounted()) { usb_msc.setCapacity(flash.size()/512, 512);
TinyUSBDevice.detach();
delay(10); // Set Lun ready
TinyUSBDevice.attach(); usb_msc.setUnitReady(true);
}
usb_msc.begin();
// Init file system on the flash // Init file system on the flash
fatfs.begin(&flash); fatfs.begin(&flash);
Serial.begin(115200);
//while ( !Serial ) delay(10); // wait for native usb //while ( !Serial ) delay(10); // wait for native usb
fs_changed = true; // to print contents initially fs_changed = true; // to print contents initially
} }
void loop() { void loop()
if ( fs_changed ) { {
if ( fs_changed )
{
fs_changed = false; fs_changed = false;
if ( !root.open("/") ) { if ( !root.open("/") )
{
Serial.println("open root failed"); Serial.println("open root failed");
return; return;
} }
@ -80,11 +81,13 @@ void loop() {
// Open next file in root. // Open next file in root.
// Warning, openNext starts at the current directory position // Warning, openNext starts at the current directory position
// so a rewind of the directory may be required. // so a rewind of the directory may be required.
while ( file.openNext(&root, O_RDONLY) ) { while ( file.openNext(&root, O_RDONLY) )
{
file.printFileSize(&Serial); file.printFileSize(&Serial);
Serial.write(' '); Serial.write(' ');
file.printName(&Serial); file.printName(&Serial);
if ( file.isDir() ) { if ( file.isDir() )
{
// Indicate a directory. // Indicate a directory.
Serial.write('/'); Serial.write('/');
} }
@ -102,7 +105,8 @@ void loop() {
// Callback invoked when received READ10 command. // Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and // Copy disk's data to buffer (up to bufsize) and
// return number of copied bytes (must be multiple of block size) // return number of copied bytes (must be multiple of block size)
int32_t msc_read_callback (uint32_t lba, void* buffer, uint32_t bufsize) { int32_t msc_read_callback (uint32_t lba, void* buffer, uint32_t bufsize)
{
// Note: InternalFlash Block API: readBlocks/writeBlocks/syncBlocks // Note: InternalFlash Block API: readBlocks/writeBlocks/syncBlocks
// already include sector caching (if needed). We don't need to cache it, yahhhh!! // already include sector caching (if needed). We don't need to cache it, yahhhh!!
return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1; return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
@ -111,7 +115,8 @@ int32_t msc_read_callback (uint32_t lba, void* buffer, uint32_t bufsize) {
// Callback invoked when received WRITE10 command. // Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and // Process data in buffer to disk's storage and
// return number of written bytes (must be multiple of block size) // return number of written bytes (must be multiple of block size)
int32_t msc_write_callback (uint32_t lba, uint8_t* buffer, uint32_t bufsize) { int32_t msc_write_callback (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
{
// Note: InternalFlash Block API: readBlocks/writeBlocks/syncBlocks // Note: InternalFlash Block API: readBlocks/writeBlocks/syncBlocks
// already include sector caching (if needed). We don't need to cache it, yahhhh!! // already include sector caching (if needed). We don't need to cache it, yahhhh!!
return flash.writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1; return flash.writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1;
@ -119,7 +124,8 @@ int32_t msc_write_callback (uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
// Callback invoked when WRITE10 command is completed (status received and accepted by host). // Callback invoked when WRITE10 command is completed (status received and accepted by host).
// used to flush any pending cache. // used to flush any pending cache.
void msc_flush_callback (void) { void msc_flush_callback (void)
{
// sync with flash // sync with flash
flash.syncBlocks(); flash.syncBlocks();
@ -131,7 +137,8 @@ void msc_flush_callback (void) {
// Invoked to check if device is writable as part of SCSI WRITE10 // Invoked to check if device is writable as part of SCSI WRITE10
// Default mode is writable // Default mode is writable
bool msc_writable_callback(void) { bool msc_writable_callback(void)
{
// true for writable, false for read-only // true for writable, false for read-only
return true; return true;
} }

View file

@ -1,2 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host

View file

@ -14,7 +14,6 @@
// 8KB is the smallest size that windows allow to mount // 8KB is the smallest size that windows allow to mount
#define DISK_BLOCK_NUM 16 #define DISK_BLOCK_NUM 16
#define DISK_BLOCK_SIZE 512 #define DISK_BLOCK_SIZE 512
#include "ramdisk.h" #include "ramdisk.h"
Adafruit_USBD_MSC usb_msc; Adafruit_USBD_MSC usb_msc;
@ -36,16 +35,12 @@ Adafruit_USBD_MSC usb_msc;
// the setup function runs once when you press reset or power the board // the setup function runs once when you press reset or power the board
void setup() { void setup()
// Manual begin() is required on core without built-in support e.g. mbed rp2040 {
if (!TinyUSBDevice.isInitialized()) { #if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
TinyUSBDevice.begin(0); // Manual begin() is required on core without built-in support for TinyUSB such as
} // - mbed rp2040
TinyUSB_Device_Init(0);
Serial.begin(115200);
#ifdef BTN_EJECT
pinMode(BTN_EJECT, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
#endif #endif
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively // Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
@ -56,35 +51,33 @@ void setup() {
// Set callback // Set callback
usb_msc.setReadWriteCallback(msc_read_callback, msc_write_callback, msc_flush_callback); usb_msc.setReadWriteCallback(msc_read_callback, msc_write_callback, msc_flush_callback);
usb_msc.setStartStopCallback(msc_start_stop_callback);
usb_msc.setReadyCallback(msc_ready_callback);
// Set Lun ready (RAM disk is always ready) // Set Lun ready (RAM disk is always ready)
usb_msc.setUnitReady(true); usb_msc.setUnitReady(true);
#ifdef BTN_EJECT
pinMode(BTN_EJECT, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
usb_msc.setReadyCallback(msc_ready_callback);
#endif
usb_msc.begin(); usb_msc.begin();
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration Serial.begin(115200);
if (TinyUSBDevice.mounted()) { //while ( !Serial ) delay(10); // wait for native usb
TinyUSBDevice.detach();
delay(10);
TinyUSBDevice.attach();
}
// while ( !Serial ) delay(10); // wait for native usb
Serial.println("Adafruit TinyUSB Mass Storage RAM Disk example"); Serial.println("Adafruit TinyUSB Mass Storage RAM Disk example");
} }
void loop() { void loop()
#ifdef TINYUSB_NEED_POLLING_TASK {
// Manual call tud_task since it isn't called by Core's background // nothing to do
TinyUSBDevice.task();
#endif
} }
// Callback invoked when received READ10 command. // Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and // Copy disk's data to buffer (up to bufsize) and
// return number of copied bytes (must be multiple of block size) // return number of copied bytes (must be multiple of block size)
int32_t msc_read_callback(uint32_t lba, void* buffer, uint32_t bufsize) { int32_t msc_read_callback (uint32_t lba, void* buffer, uint32_t bufsize)
{
uint8_t const* addr = msc_disk[lba]; uint8_t const* addr = msc_disk[lba];
memcpy(buffer, addr, bufsize); memcpy(buffer, addr, bufsize);
@ -94,7 +87,8 @@ int32_t msc_read_callback(uint32_t lba, void* buffer, uint32_t bufsize) {
// Callback invoked when received WRITE10 command. // Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and // Process data in buffer to disk's storage and
// return number of written bytes (must be multiple of block size) // return number of written bytes (must be multiple of block size)
int32_t msc_write_callback(uint32_t lba, uint8_t* buffer, uint32_t bufsize) { int32_t msc_write_callback (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
{
uint8_t* addr = msc_disk[lba]; uint8_t* addr = msc_disk[lba];
memcpy(addr, buffer, bufsize); memcpy(addr, buffer, bufsize);
@ -103,22 +97,18 @@ int32_t msc_write_callback(uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
// Callback invoked when WRITE10 command is completed (status received and accepted by host). // Callback invoked when WRITE10 command is completed (status received and accepted by host).
// used to flush any pending cache. // used to flush any pending cache.
void msc_flush_callback(void) { void msc_flush_callback (void)
{
// nothing to do // nothing to do
} }
bool msc_start_stop_callback(uint8_t power_condition, bool start, bool load_eject) {
Serial.printf("Start/Stop callback: power condition %u, start %u, load_eject %u\n", power_condition, start, load_eject);
return true;
}
#ifdef BTN_EJECT
// Invoked when received Test Unit Ready command. // Invoked when received Test Unit Ready command.
// return true allowing host to read/write this LUN e.g SD card inserted // return true allowing host to read/write this LUN e.g SD card inserted
bool msc_ready_callback(void) { bool msc_ready_callback(void)
#ifdef BTN_EJECT {
// button not active --> medium ready // button not active --> medium ready
return digitalRead(BTN_EJECT) != activeState; return digitalRead(BTN_EJECT) != activeState;
#else
return true;
#endif
} }
#endif

View file

@ -1,3 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host
CH32V20x_EVT

View file

@ -14,22 +14,20 @@
// 8KB is the smallest size that windows allow to mount // 8KB is the smallest size that windows allow to mount
#define DISK_BLOCK_NUM 16 #define DISK_BLOCK_NUM 16
#define DISK_BLOCK_SIZE 512 #define DISK_BLOCK_SIZE 512
#include "ramdisk.h" #include "ramdisk.h"
Adafruit_USBD_MSC usb_msc; Adafruit_USBD_MSC usb_msc;
// the setup function runs once when you press reset or power the board // the setup function runs once when you press reset or power the board
void setup() { void setup()
// Manual begin() is required on core without built-in support e.g. mbed rp2040 {
if (!TinyUSBDevice.isInitialized()) { #if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
TinyUSBDevice.begin(0); // Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
} TinyUSB_Device_Init(0);
#endif
Serial.begin(115200);
usb_msc.setMaxLun(2); usb_msc.setMaxLun(2);
// Set disk size and callback for Logical Unit 0 (LUN 0) // Set disk size and callback for Logical Unit 0 (LUN 0)
usb_msc.setID(0, "Adafruit", "Lun0", "1.0"); usb_msc.setID(0, "Adafruit", "Lun0", "1.0");
usb_msc.setCapacity(0, DISK_BLOCK_NUM, DISK_BLOCK_SIZE); usb_msc.setCapacity(0, DISK_BLOCK_NUM, DISK_BLOCK_SIZE);
@ -41,25 +39,18 @@ void setup() {
usb_msc.setCapacity(1, DISK_BLOCK_NUM, DISK_BLOCK_SIZE); 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.setReadWriteCallback(1, ram1_read_cb, ram1_write_cb, ram1_flush_cb);
usb_msc.setUnitReady(1, true); usb_msc.setUnitReady(1, true);
usb_msc.begin(); usb_msc.begin();
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration Serial.begin(115200);
if (TinyUSBDevice.mounted()) {
TinyUSBDevice.detach();
delay(10);
TinyUSBDevice.attach();
}
//while ( !Serial ) delay(10); // wait for native usb //while ( !Serial ) delay(10); // wait for native usb
Serial.println("Adafruit TinyUSB Mass Storage Dual RAM Disks example"); Serial.println("Adafruit TinyUSB Mass Storage Dual RAM Disks example");
} }
void loop() { void loop()
#ifdef TINYUSB_NEED_POLLING_TASK {
// Manual call tud_task since it isn't called by Core's background // nothing to do
TinyUSBDevice.task();
#endif
} }
@ -70,7 +61,8 @@ void loop() {
// Callback invoked when received READ10 command. // Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and // Copy disk's data to buffer (up to bufsize) and
// return number of copied bytes (must be multiple of block size) // return number of copied bytes (must be multiple of block size)
int32_t ram0_read_cb(uint32_t lba, void* buffer, uint32_t bufsize) { int32_t ram0_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
{
uint8_t const* addr = msc_disk0[lba]; uint8_t const* addr = msc_disk0[lba];
memcpy(buffer, addr, bufsize); memcpy(buffer, addr, bufsize);
@ -80,7 +72,8 @@ int32_t ram0_read_cb(uint32_t lba, void* buffer, uint32_t bufsize) {
// Callback invoked when received WRITE10 command. // Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and // Process data in buffer to disk's storage and
// return number of written bytes (must be multiple of block size) // 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) { int32_t ram0_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
{
uint8_t* addr = msc_disk0[lba]; uint8_t* addr = msc_disk0[lba];
memcpy(addr, buffer, bufsize); memcpy(addr, buffer, bufsize);
@ -89,7 +82,8 @@ int32_t ram0_write_cb(uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
// Callback invoked when WRITE10 command is completed (status received and accepted by host). // Callback invoked when WRITE10 command is completed (status received and accepted by host).
// used to flush any pending cache. // used to flush any pending cache.
void ram0_flush_cb(void) { void ram0_flush_cb (void)
{
// nothing to do // nothing to do
} }
@ -101,7 +95,8 @@ void ram0_flush_cb(void) {
// Callback invoked when received READ10 command. // Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and // Copy disk's data to buffer (up to bufsize) and
// return number of copied bytes (must be multiple of block size) // return number of copied bytes (must be multiple of block size)
int32_t ram1_read_cb(uint32_t lba, void* buffer, uint32_t bufsize) { int32_t ram1_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
{
uint8_t const* addr = msc_disk1[lba]; uint8_t const* addr = msc_disk1[lba];
memcpy(buffer, addr, bufsize); memcpy(buffer, addr, bufsize);
@ -111,7 +106,8 @@ int32_t ram1_read_cb(uint32_t lba, void* buffer, uint32_t bufsize) {
// Callback invoked when received WRITE10 command. // Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and // Process data in buffer to disk's storage and
// return number of written bytes (must be multiple of block size) // 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) { int32_t ram1_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
{
uint8_t* addr = msc_disk1[lba]; uint8_t* addr = msc_disk1[lba];
memcpy(addr, buffer, bufsize); memcpy(addr, buffer, bufsize);
@ -120,6 +116,7 @@ int32_t ram1_write_cb(uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
// Callback invoked when WRITE10 command is completed (status received and accepted by host). // Callback invoked when WRITE10 command is completed (status received and accepted by host).
// used to flush any pending cache. // used to flush any pending cache.
void ram1_flush_cb(void) { void ram1_flush_cb (void)
{
// nothing to do // nothing to do
} }

View file

@ -1,10 +0,0 @@
feather_esp32_v2
feather_esp32s2
feather_esp32s3
funhouse
magtag
metroesp32s2
esp32p4
feather_rp2040_tinyusb
pico_rp2040_tinyusb_host
CH32V20x_EVT

View file

@ -26,8 +26,6 @@ SdVolume volume;
// the setup function runs once when you press reset or power the board // the setup function runs once when you press reset or power the board
void setup() void setup()
{ {
Serial.begin(115200);
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively // 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"); usb_msc.setID("Adafruit", "SD Card", "1.0");
@ -39,18 +37,15 @@ void setup()
usb_msc.setUnitReady(false); usb_msc.setUnitReady(false);
usb_msc.begin(); usb_msc.begin();
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration Serial.begin(115200);
if (TinyUSBDevice.mounted()) {
TinyUSBDevice.detach();
delay(10);
TinyUSBDevice.attach();
}
//while ( !Serial ) delay(10); // wait for native usb //while ( !Serial ) delay(10); // wait for native usb
Serial.println("Adafruit TinyUSB Mass Storage SD Card example"); Serial.println("Adafruit TinyUSB Mass Storage SD Card example");
Serial.println("\nInitializing SD card..."); Serial.println("\nInitializing SD card...");
if ( !card.init(SPI_HALF_SPEED, chipSelect) ) { if ( !card.init(SPI_HALF_SPEED, chipSelect) )
{
Serial.println("initialization failed. Things to check:"); Serial.println("initialization failed. Things to check:");
Serial.println("* is a card inserted?"); Serial.println("* is a card inserted?");
Serial.println("* is your wiring correct?"); Serial.println("* is your wiring correct?");
@ -76,14 +71,16 @@ void setup()
usb_msc.setUnitReady(true); usb_msc.setUnitReady(true);
} }
void loop() { void loop()
{
// nothing to do // nothing to do
} }
// Callback invoked when received READ10 command. // Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and // Copy disk's data to buffer (up to bufsize) and
// return number of copied bytes (must be multiple of block size) // return number of copied bytes (must be multiple of block size)
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) { int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
{
(void) bufsize; (void) bufsize;
return card.readBlock(lba, (uint8_t*) buffer) ? 512 : -1; return card.readBlock(lba, (uint8_t*) buffer) ? 512 : -1;
} }
@ -91,13 +88,15 @@ int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) {
// Callback invoked when received WRITE10 command. // Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and // Process data in buffer to disk's storage and
// return number of written bytes (must be multiple of block size) // 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) { int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
{
(void) bufsize; (void) bufsize;
return card.writeBlock(lba, buffer) ? 512 : -1; return card.writeBlock(lba, buffer) ? 512 : -1;
} }
// Callback invoked when WRITE10 command is completed (status received and accepted by host). // Callback invoked when WRITE10 command is completed (status received and accepted by host).
// used to flush any pending cache. // used to flush any pending cache.
void msc_flush_cb (void) { void msc_flush_cb (void)
{
// nothing to do // nothing to do
} }

View file

@ -1,2 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host

View file

@ -10,69 +10,31 @@
*********************************************************************/ *********************************************************************/
/* This example expose SD card as mass storage using /* This example expose SD card as mass storage using
* - SdFat https://github.com/adafruit/SdFat * SdFat Library
*/ */
#include "SPI.h" #include "SPI.h"
#include "SdFat_Adafruit_Fork.h" #include "SdFat.h"
#include "Adafruit_TinyUSB.h" #include "Adafruit_TinyUSB.h"
//--------------------------------------------------------------------+ const int chipSelect = 10;
// SDCard Config
//--------------------------------------------------------------------+
#if defined(ARDUINO_PYPORTAL_M4) || defined(ARDUINO_PYPORTAL_M4_TITANO)
// PyPortal has on-board card reader
#define SDCARD_CS 32
#define SDCARD_DETECT 33
#define SDCARD_DETECT_ACTIVE HIGH
#elif defined(ARDUINO_ADAFRUIT_METRO_RP2040)
#define SDIO_CLK_PIN 18
#define SDIO_CMD_PIN 19 // MOSI
#define SDIO_DAT0_PIN 20 // DAT1: 21, DAT2: 22, DAT3: 23
#define SDCARD_DETECT 15
#define SDCARD_DETECT_ACTIVE LOW
#elif defined(ARDUINO_ADAFRUIT_METRO_RP2350)
#define SDIO_CLK_PIN 34
#define SDIO_CMD_PIN 35 // MOSI
#define SDIO_DAT0_PIN 36 // DAT1: 37, DAT2: 38, DAT3: 39
#define SDCARD_DETECT 40
#define SDCARD_DETECT_ACTIVE LOW
#elif defined(ARDUINO_ADAFRUIT_FRUITJAM_RP2350)
#define SDIO_CLK_PIN 34
#define SDIO_CMD_PIN 35 // MOSI
#define SDIO_DAT0_PIN 36 // DAT1: 37, DAT2: 38, DAT3: 39
#define SDCARD_DETECT 33
#define SDCARD_DETECT_ACTIVE LOW
#else
// Use SPI, no detect
#define SDCARD_CS 10
#endif
#if defined(SDIO_CLK_PIN) && defined(SDIO_CMD_PIN) && defined(SDIO_DAT0_PIN)
#define SD_CONFIG SdioConfig(SDIO_CLK_PIN, SDIO_CMD_PIN, SDIO_DAT0_PIN)
#else
#define SD_CONFIG SdSpiConfig(SDCARD_CS, SHARED_SPI, SD_SCK_MHZ(50))
#endif
// File system on SD Card // File system on SD Card
SdFat sd; SdFat sd;
SdFile root;
SdFile file;
// USB Mass Storage object // USB Mass Storage object
Adafruit_USBD_MSC usb_msc; Adafruit_USBD_MSC usb_msc;
// Set to true when PC write to flash
bool fs_changed;
// the setup function runs once when you press reset or power the board // the setup function runs once when you press reset or power the board
void setup() { void setup()
#ifdef LED_BUILTIN {
pinMode(LED_BUILTIN, OUTPUT); pinMode(LED_BUILTIN, OUTPUT);
#endif
Serial.begin(115200);
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively // 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"); usb_msc.setID("Adafruit", "SD Card", "1.0");
@ -85,27 +47,30 @@ void setup() {
usb_msc.setUnitReady(false); usb_msc.setUnitReady(false);
usb_msc.begin(); usb_msc.begin();
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration Serial.begin(115200);
if (TinyUSBDevice.mounted()) {
TinyUSBDevice.detach();
delay(10);
TinyUSBDevice.attach();
}
//while ( !Serial ) delay(10); // wait for native usb //while ( !Serial ) delay(10); // wait for native usb
Serial.println("Adafruit TinyUSB Mass Storage SD Card example");
Serial.print("\nInitializing SD card ... ");
if (!sd.begin(SD_CONFIG)) { 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("initialization failed. Things to check:");
Serial.println("- is a card inserted?"); Serial.println("* is a card inserted?");
Serial.println("- is your wiring correct?"); Serial.println("* is your wiring correct?");
Serial.println("- did you change the SDCARD_CS or SDIO pin to match your shield or module?"); Serial.println("* did you change the chipSelect pin to match your shield or module?");
while (1) delay(1); while (1) delay(1);
} }
// Size in blocks (512 bytes) // Size in blocks (512 bytes)
#if SD_FAT_VERSION >= 20000
uint32_t block_count = sd.card()->sectorCount(); uint32_t block_count = sd.card()->sectorCount();
#else
uint32_t block_count = sd.card()->cardSize();
#endif
Serial.print("Volume size (MB): "); Serial.print("Volume size (MB): ");
Serial.println((block_count/2) / 1024); Serial.println((block_count/2) / 1024);
@ -114,38 +79,91 @@ void setup() {
// MSC is ready for read/write // MSC is ready for read/write
usb_msc.setUnitReady(true); usb_msc.setUnitReady(true);
fs_changed = true; // to print contents initially
} }
void loop() { void loop()
// noting to do {
if ( fs_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();
fs_changed = false;
delay(1000); // refresh every 0.5 second
}
} }
// Callback invoked when received READ10 command. // Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and // Copy disk's data to buffer (up to bufsize) and
// return number of copied bytes (must be multiple of block size) // return number of copied bytes (must be multiple of block size)
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) { int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
bool rc = sd.card()->readSectors(lba, (uint8_t*) buffer, bufsize/512); {
bool rc;
#if SD_FAT_VERSION >= 20000
rc = sd.card()->readSectors(lba, (uint8_t*) buffer, bufsize/512);
#else
rc = sd.card()->readBlocks(lba, (uint8_t*) buffer, bufsize/512);
#endif
return rc ? bufsize : -1; return rc ? bufsize : -1;
} }
// Callback invoked when received WRITE10 command. // Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and // Process data in buffer to disk's storage and
// return number of written bytes (must be multiple of block size) // 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) { int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
#ifdef LED_BUILTIN {
bool rc;
digitalWrite(LED_BUILTIN, HIGH); digitalWrite(LED_BUILTIN, HIGH);
#if SD_FAT_VERSION >= 20000
rc = sd.card()->writeSectors(lba, buffer, bufsize/512);
#else
rc = sd.card()->writeBlocks(lba, buffer, bufsize/512);
#endif #endif
bool rc = sd.card()->writeSectors(lba, buffer, bufsize/512);
return rc ? bufsize : -1; return rc ? bufsize : -1;
} }
// Callback invoked when WRITE10 command is completed (status received and accepted by host). // Callback invoked when WRITE10 command is completed (status received and accepted by host).
// used to flush any pending cache. // used to flush any pending cache.
void msc_flush_cb (void) { void msc_flush_cb (void)
{
#if SD_FAT_VERSION >= 20000
sd.card()->syncDevice(); sd.card()->syncDevice();
sd.cacheClear(); // clear file system's cache to force refresh #else
sd.card()->syncBlocks();
#ifdef LED_BUILTIN
digitalWrite(LED_BUILTIN, LOW);
#endif #endif
// clear file system's cache to force refresh
sd.cacheClear();
fs_changed = true;
digitalWrite(LED_BUILTIN, LOW);
} }

View file

@ -1,3 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host
CH32V20x_EVT

View file

@ -64,29 +64,15 @@ Adafruit_USBD_I2C::Adafruit_USBD_I2C(TwoWire* wire) {
setStringDescriptor("I2C Interface"); setStringDescriptor("I2C Interface");
} }
uint16_t Adafruit_USBD_I2C::getInterfaceDescriptor(uint8_t itfnum_deprecated, uint8_t* buf, uint16_t bufsize) { uint16_t Adafruit_USBD_I2C::getInterfaceDescriptor(uint8_t itfnum, uint8_t* buf, uint16_t bufsize) {
uint8_t itfnum = 0; uint8_t desc[] = { TUD_VENDOR_DESCRIPTOR(itfnum, 0, 0x00, 0x80, 64) };
uint8_t ep_in = 0;
uint8_t ep_out = 0;
(void) itfnum_deprecated;
// null buffer is used to get the length of descriptor only
if (buf) {
itfnum = TinyUSBDevice.allocInterface(1);
ep_in = TinyUSBDevice.allocEndpoint(TUSB_DIR_IN);
ep_out = TinyUSBDevice.allocEndpoint(TUSB_DIR_OUT);
}
uint8_t const desc[] = { TUD_VENDOR_DESCRIPTOR(itfnum, _strid, ep_out, ep_in, 64) };
uint16_t const len = sizeof(desc); uint16_t const len = sizeof(desc);
if (buf) { if (buf) {
if (bufsize < len) { if (bufsize < len) {
return 0; return 0;
} }
memcpy(buf, desc, len); memcpy(buf, desc, len);
} }
return len; return len;
} }

View file

@ -88,13 +88,11 @@
class Adafruit_USBD_I2C : public Adafruit_USBD_Interface { class Adafruit_USBD_I2C : public Adafruit_USBD_Interface {
public: public:
Adafruit_USBD_I2C(TwoWire* wire); Adafruit_USBD_I2C(TwoWire* wire);
uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t* buf, uint16_t bufsize);
bool begin(uint8_t* buffer, size_t bufsize); bool begin(uint8_t* buffer, size_t bufsize);
bool handleControlTransfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request); bool handleControlTransfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request);
// from Adafruit_USBD_Interface
virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t* buf, uint16_t bufsize);
private: private:
TwoWire* _wire; TwoWire* _wire;
uint8_t _state; uint8_t _state;

View file

@ -63,13 +63,6 @@ void setup() {
// init i2c usb with buffer and size // init i2c usb with buffer and size
i2c_usb.begin(i2c_buf, sizeof(i2c_buf)); i2c_usb.begin(i2c_buf, sizeof(i2c_buf));
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
if (TinyUSBDevice.mounted()) {
TinyUSBDevice.detach();
delay(10);
TinyUSBDevice.attach();
}
} }
void loop() { void loop() {

View file

@ -1,3 +0,0 @@
feather_esp32_v2
pico_rp2040_tinyusb_host
CH32V20x_EVT

Some files were not shown because too many files have changed in this diff Show more