Compare commits
No commits in common. "master" and "sync-tinyusb" have entirely different histories.
master
...
sync-tinyu
251 changed files with 12011 additions and 30206 deletions
|
|
@ -2,5 +2,3 @@ synopsys
|
||||||
sie
|
sie
|
||||||
inout
|
inout
|
||||||
busses
|
busses
|
||||||
thre
|
|
||||||
|
|
||||||
|
|
|
||||||
10
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
10
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
|
@ -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
|
|
||||||
|
|
|
||||||
3
.github/ISSUE_TEMPLATE/config.yml
vendored
3
.github/ISSUE_TEMPLATE/config.yml
vendored
|
|
@ -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.
|
|
||||||
|
|
|
||||||
46
.github/workflows/githubci.yml
vendored
46
.github/workflows/githubci.yml
vendored
|
|
@ -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
3
.gitignore
vendored
|
|
@ -1,5 +1,2 @@
|
||||||
/examples/**/build/
|
/examples/**/build/
|
||||||
/.development
|
/.development
|
||||||
.idea
|
|
||||||
platformio.ini
|
|
||||||
.pio/
|
|
||||||
|
|
|
||||||
14
README.md
14
README.md
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
0
examples/CDC/cdc_multi/.feather_esp32s3.test.skip
Normal file
0
examples/CDC/cdc_multi/.feather_esp32s3.test.skip
Normal file
0
examples/CDC/cdc_multi/.funhouse.test.skip
Normal file
0
examples/CDC/cdc_multi/.funhouse.test.skip
Normal file
0
examples/CDC/cdc_multi/.magtag.test.skip
Normal file
0
examples/CDC/cdc_multi/.magtag.test.skip
Normal file
0
examples/CDC/cdc_multi/.metroesp32s2.test.skip
Normal file
0
examples/CDC/cdc_multi/.metroesp32s2.test.skip
Normal file
|
|
@ -1,8 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
feather_esp32s2
|
|
||||||
feather_esp32s3
|
|
||||||
funhouse
|
|
||||||
magtag
|
|
||||||
metroesp32s2
|
|
||||||
esp32p4
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
192
examples/Composite/mouse_external_flash/mouse_external_flash.ino
Normal file
192
examples/Composite/mouse_external_flash/mouse_external_flash.ino
Normal 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();
|
||||||
|
}
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
CH32V20x_EVT
|
|
||||||
|
|
@ -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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
CH32V20x_EVT
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
CH32V20x_EVT
|
|
||||||
|
|
@ -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));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
CH32V20x_EVT
|
|
||||||
|
|
@ -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));
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
CH32V20x_EVT
|
|
||||||
|
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
CH32V20x_EVT
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
CH32V20x_EVT
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
CH32V20x_EVT
|
|
||||||
|
|
@ -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';
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
CH32V20x_EVT
|
|
||||||
|
|
@ -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';
|
|
||||||
}
|
|
||||||
252
examples/DualRole/device_info_rp2040/device_info_rp2040.ino
Normal file
252
examples/DualRole/device_info_rp2040/device_info_rp2040.ino
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
CH32V20x_EVT
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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';
|
|
||||||
}
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
CH32V20x_EVT
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
CH32V20x_EVT
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
CH32V20x_EVT
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
0
examples/MassStorage/msc_sd/.feather_esp32s2.test.skip
Normal file
0
examples/MassStorage/msc_sd/.feather_esp32s2.test.skip
Normal file
0
examples/MassStorage/msc_sd/.feather_esp32s3.test.skip
Normal file
0
examples/MassStorage/msc_sd/.feather_esp32s3.test.skip
Normal file
0
examples/MassStorage/msc_sd/.funhouse.test.skip
Normal file
0
examples/MassStorage/msc_sd/.funhouse.test.skip
Normal file
0
examples/MassStorage/msc_sd/.magtag.test.skip
Normal file
0
examples/MassStorage/msc_sd/.magtag.test.skip
Normal file
0
examples/MassStorage/msc_sd/.metroesp32s2.test.skip
Normal file
0
examples/MassStorage/msc_sd/.metroesp32s2.test.skip
Normal 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
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
feather_esp32_v2
|
|
||||||
pico_rp2040_tinyusb_host
|
|
||||||
CH32V20x_EVT
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -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
Loading…
Reference in a new issue