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
|
||||
inout
|
||||
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
|
||||
attributes:
|
||||
label: TinyUSB Library version
|
||||
placeholder: "Release version or commit SHA"
|
||||
placeholder: "Release version or github latest"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
|
@ -100,11 +100,3 @@ body:
|
|||
description: If applicable, add screenshots to help explain your problem.
|
||||
validations:
|
||||
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
|
||||
url: https://forums.adafruit.com
|
||||
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]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
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:
|
||||
pre-commit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Run pre-commit
|
||||
uses: pre-commit/action@v3.0.1
|
||||
uses: pre-commit/action@v3.0.0
|
||||
|
||||
- name: Checkout adafruit/ci-arduino
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: adafruit/ci-arduino
|
||||
path: ci
|
||||
|
|
@ -37,9 +39,6 @@ jobs:
|
|||
PRETTYNAME : "Adafruit TinyUSB Library"
|
||||
run: bash ci/doxy_gen_and_deploy.sh
|
||||
|
||||
# ---------------------------------------
|
||||
# build
|
||||
# ---------------------------------------
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre-commit
|
||||
|
|
@ -47,28 +46,31 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
arduino-platform:
|
||||
# ESP32 ci use dev json
|
||||
- 'feather_esp32_v2'
|
||||
- 'feather_esp32s2'
|
||||
# ESP32S3
|
||||
- 'feather_esp32s3'
|
||||
- 'esp32p4'
|
||||
# ESP32S2
|
||||
- 'feather_esp32s2'
|
||||
# nRF52
|
||||
- 'cpb'
|
||||
- 'nrf52840'
|
||||
# RP2040
|
||||
- 'feather_rp2040_tinyusb'
|
||||
- 'pico_rp2040_tinyusb_host'
|
||||
# SAMD
|
||||
- 'feather_m4_can_tinyusb'
|
||||
- 'metro_m0_tinyusb'
|
||||
- 'metro_m4_tinyusb'
|
||||
# Ch32v2
|
||||
- 'CH32V20x_EVT'
|
||||
|
||||
steps:
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Checkout adafruit/ci-arduino
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: adafruit/ci-arduino
|
||||
path: ci
|
||||
|
|
@ -76,10 +78,8 @@ jobs:
|
|||
- name: pre-install
|
||||
run: bash ci/actions_install.sh
|
||||
|
||||
- name: Install Libraries
|
||||
run: |
|
||||
arduino-cli lib install ${{ env.ARDUINO_LIBS }}
|
||||
arduino-cli lib list
|
||||
- name: Install Libraries for building examples
|
||||
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"
|
||||
|
||||
- name: test platforms
|
||||
run: python3 ci/build_platform.py ${{ matrix.arduino-platform }}
|
||||
|
|
|
|||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,5 +1,2 @@
|
|||
/examples/**/build/
|
||||
/.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 ...
|
||||
- Mass Storage Class (MSC): with multiple LUNs
|
||||
- Musical Instrument Digital Interface (MIDI)
|
||||
- Video (UVC): work in progress
|
||||
- WebUSB with vendor specific class
|
||||
|
||||
### 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
|
||||
|
||||
Note: Host stack is still work-in-progress
|
||||
|
||||
## 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.
|
||||
|
|
@ -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/ArduinoCore-samd](https://github.com/adafruit/ArduinoCore-samd)
|
||||
- [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
|
||||
- `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)
|
||||
- [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32)
|
||||
|
||||
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
|
||||
|
||||
|
|
|
|||
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>
|
||||
|
||||
#define LED LED_BUILTIN
|
||||
|
||||
// Create 2nd instance of CDC Ports.
|
||||
#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
|
||||
Adafruit_USBD_CDC USBSer1(1);
|
||||
#else
|
||||
|
|
@ -35,17 +37,13 @@
|
|||
#endif
|
||||
|
||||
void setup() {
|
||||
#ifdef LED_BUILTIN
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
#endif
|
||||
pinMode(LED, OUTPUT);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// check to see if multiple CDCs are enabled
|
||||
if ( CFG_TUD_CDC < 2 ) {
|
||||
#ifdef LED_BUILTIN
|
||||
digitalWrite(LED_BUILTIN, HIGH); // LED on for error indicator
|
||||
#endif
|
||||
digitalWrite(LED, HIGH); // LED on for error indicator
|
||||
|
||||
while(1) {
|
||||
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
|
||||
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) {
|
||||
if (Serial) {
|
||||
Serial.println("Waiting for other USB ports");
|
||||
|
|
@ -98,9 +89,7 @@ void loop() {
|
|||
|
||||
if (delay_without_delaying(500)) {
|
||||
LEDstate = !LEDstate;
|
||||
#ifdef LED_BUILTIN
|
||||
digitalWrite(LED_BUILTIN, LEDstate);
|
||||
#endif
|
||||
digitalWrite(LED, LEDstate);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
* 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)
|
||||
TinyUSBDevice.clearConfiguration();
|
||||
int led = LED_BUILTIN;
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
#ifdef LED_BUILTIN
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
#endif
|
||||
void setup()
|
||||
{
|
||||
Serial.end();
|
||||
pinMode(led, OUTPUT);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
#ifdef TINYUSB_NEED_POLLING_TASK
|
||||
// Manual call tud_task since it isn't called by Core's background
|
||||
TinyUSBDevice.task();
|
||||
#endif
|
||||
|
||||
// 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
|
||||
}
|
||||
void loop()
|
||||
{
|
||||
digitalWrite(led, HIGH);
|
||||
delay(1000);
|
||||
digitalWrite(led, LOW);
|
||||
delay(1000);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#define DISK_BLOCK_NUM 16
|
||||
#define DISK_BLOCK_SIZE 512
|
||||
|
||||
#include "ramdisk.h"
|
||||
|
||||
Adafruit_USBD_MSC usb_msc;
|
||||
|
|
@ -34,47 +33,39 @@ Adafruit_USBD_MSC usb_msc;
|
|||
|
||||
// HID report descriptor using TinyUSB's template
|
||||
// Single Report (no ID) descriptor
|
||||
uint8_t const desc_hid_report[] = {
|
||||
TUD_HID_REPORT_DESC_MOUSE()
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_MOUSE()
|
||||
};
|
||||
|
||||
// USB HID object
|
||||
Adafruit_USBD_HID usb_hid;
|
||||
// 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;
|
||||
const int pin = 4; // Left Button
|
||||
bool activeState = true;
|
||||
|
||||
#elif defined(ARDUINO_FUNHOUSE_ESP32S2)
|
||||
const int pin = BUTTON_DOWN;
|
||||
bool activeState = true;
|
||||
const int pin = BUTTON_DOWN;
|
||||
bool activeState = true;
|
||||
|
||||
#elif defined PIN_BUTTON1
|
||||
const int pin = PIN_BUTTON1;
|
||||
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;
|
||||
const int pin = PIN_BUTTON1;
|
||||
bool activeState = false;
|
||||
|
||||
#else
|
||||
const int pin = A0;
|
||||
bool activeState = false;
|
||||
const int pin = 12;
|
||||
bool activeState = false;
|
||||
#endif
|
||||
|
||||
|
||||
// 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);
|
||||
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
|
||||
|
||||
// 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");
|
||||
|
|
@ -93,36 +84,38 @@ void setup() {
|
|||
// Set up button
|
||||
pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
||||
|
||||
// Set up HID
|
||||
usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||
usb_hid.setBootProtocol(HID_ITF_PROTOCOL_NONE);
|
||||
usb_hid.setPollInterval(2);
|
||||
// Notes: following commented-out functions has no affect on ESP32
|
||||
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||
|
||||
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();
|
||||
}
|
||||
Serial.begin(115200);
|
||||
while( !TinyUSBDevice.mounted() ) delay(1); // wait for native usb
|
||||
|
||||
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
|
||||
uint32_t const btn = (digitalRead(pin) == activeState);
|
||||
|
||||
// Remote wakeup
|
||||
if (TinyUSBDevice.suspended() && btn) {
|
||||
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) {
|
||||
if ( usb_hid.ready() )
|
||||
{
|
||||
if ( btn )
|
||||
{
|
||||
int8_t const delta = 5;
|
||||
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.
|
||||
// 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) {
|
||||
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
uint8_t const* addr = msc_disk[lba];
|
||||
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.
|
||||
// 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) {
|
||||
int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
uint8_t* addr = msc_disk[lba];
|
||||
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).
|
||||
// used to flush any pending cache.
|
||||
void msc_flush_cb(void) {
|
||||
void msc_flush_cb (void)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
pico_rp2040_tinyusb_host
|
||||
CH32V20x_EVT
|
||||
|
|
@ -9,162 +9,154 @@
|
|||
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
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
// 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
|
||||
// pio-usb is required for rp2040 host
|
||||
#include "pio_usb.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
|
||||
|
||||
// USBHost is defined in usbh_helper.h
|
||||
#include "usbh_helper.h"
|
||||
// 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;
|
||||
|
||||
// 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];
|
||||
|
||||
// Serial -> SerialHost
|
||||
if (Serial.available()) {
|
||||
size_t count = Serial.read(buf, sizeof(buf));
|
||||
if (SerialHost && SerialHost.connected()) {
|
||||
if ( SerialHost && SerialHost.connected() ) {
|
||||
SerialHost.write(buf, count);
|
||||
SerialHost.flush();
|
||||
}
|
||||
}
|
||||
|
||||
// SerialHost -> Serial
|
||||
if (SerialHost.connected() && SerialHost.available()) {
|
||||
if ( SerialHost.connected() && SerialHost.available() ) {
|
||||
size_t count = SerialHost.read(buf, sizeof(buf));
|
||||
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() {
|
||||
// configure pio-usb: defined in usbh_helper.h
|
||||
rp2040_configure_pio_usb();
|
||||
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);
|
||||
|
||||
// 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
|
||||
// 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);
|
||||
|
||||
// Initialize SerialHost
|
||||
SerialHost.begin(115200);
|
||||
}
|
||||
|
||||
void loop1() {
|
||||
void loop1()
|
||||
{
|
||||
USBHost.task();
|
||||
}
|
||||
|
||||
#endif
|
||||
// periodically flush SerialHost if connected
|
||||
if ( SerialHost && SerialHost.connected() ) {
|
||||
SerialHost.flush();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// TinyUSB Host callbacks
|
||||
//--------------------------------------------------------------------+
|
||||
extern "C" {
|
||||
|
||||
// Invoked when a device with CDC interface is mounted
|
||||
// idx is index of cdc interface in the internal pool.
|
||||
void tuh_cdc_mount_cb(uint8_t idx) {
|
||||
// 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");
|
||||
}
|
||||
|
||||
// Invoked when a device with CDC interface is unmounted
|
||||
void tuh_cdc_umount_cb(uint8_t idx) {
|
||||
SerialHost.umount(idx);
|
||||
Serial.println("SerialHost is disconnected");
|
||||
}
|
||||
if (idx == SerialHost.getInterfaceIndex()) {
|
||||
// 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
|
||||
* - 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)
|
||||
* - Device run on native usb controller (controller0)
|
||||
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
|
||||
*
|
||||
* 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
|
||||
* - [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
|
||||
#include "usbh_helper.h"
|
||||
// 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;
|
||||
|
||||
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||
//--------------------------------------------------------------------+
|
||||
// Using Host shield MAX3421E controller
|
||||
//--------------------------------------------------------------------+
|
||||
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
|
||||
// Setup and Loop on Core0
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//------------- Core0 -------------//
|
||||
void setup() {
|
||||
void setup()
|
||||
{
|
||||
Serial1.begin(115200);
|
||||
|
||||
Serial.begin(115200);
|
||||
//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() {
|
||||
Serial.flush();
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
//------------- Core1 -------------//
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core1
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void setup1() {
|
||||
// configure pio-usb: defined in usbh_helper.h
|
||||
rp2040_configure_pio_usb();
|
||||
//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
|
||||
|
|
@ -76,22 +95,19 @@ void setup1() {
|
|||
USBHost.begin(1);
|
||||
}
|
||||
|
||||
void loop1() {
|
||||
void loop1()
|
||||
{
|
||||
USBHost.task();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
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;
|
||||
(void)desc_report;
|
||||
(void)desc_len;
|
||||
uint16_t 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");
|
||||
}
|
||||
}
|
||||
|
||||
} // 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
|
||||
*********************************************************************/
|
||||
|
||||
/* 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,
|
||||
* this example only toggle shift key to the report, effectively remap:
|
||||
* - all character key <-> upper case
|
||||
* - 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
|
||||
#include "usbh_helper.h"
|
||||
// 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;
|
||||
|
||||
// HID report descriptor using TinyUSB's template
|
||||
// Single Report (no ID) descriptor
|
||||
uint8_t const desc_hid_report[] = {
|
||||
TUD_HID_REPORT_DESC_KEYBOARD()
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
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);
|
||||
|
||||
void setup() {
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core0
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
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("TinyUSB Host HID Remap Example");
|
||||
}
|
||||
|
||||
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||
//--------------------------------------------------------------------+
|
||||
// Using Host shield MAX3421E controller
|
||||
//--------------------------------------------------------------------+
|
||||
void loop() {
|
||||
USBHost.task();
|
||||
void loop()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#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() {
|
||||
// configure pio-usb: defined in usbh_helper.h
|
||||
rp2040_configure_pio_usb();
|
||||
//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
|
||||
|
|
@ -87,16 +113,10 @@ void setup1() {
|
|||
USBHost.begin(1);
|
||||
}
|
||||
|
||||
void loop1() {
|
||||
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.
|
||||
|
|
@ -104,8 +124,8 @@ extern "C"
|
|||
// 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;
|
||||
(void)desc_report;
|
||||
(void)desc_len;
|
||||
uint16_t 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);
|
||||
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)) {
|
||||
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);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
// 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) {
|
||||
// Note: we ignore right shift here
|
||||
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
|
||||
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);
|
||||
} else {
|
||||
}else {
|
||||
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
|
||||
// NOTE: for better performance you should save/queue remapped report instead of
|
||||
// blocking wait for usb_hid ready here
|
||||
while (!usb_hid.ready()) {
|
||||
while ( !usb_hid.ready() ) {
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
* - 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)
|
||||
* - Device run on native usb controller (controller0)
|
||||
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
|
||||
*
|
||||
* Example will log CPU temperature periodically (ms,value) to USB thumbdrive
|
||||
*
|
||||
* 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
|
||||
* - [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"
|
||||
*/
|
||||
|
||||
/* Example sketch read analog pin (default A0) and log it to LOG_FILE on the msc device
|
||||
* every LOG_INTERVAL ms. */
|
||||
|
||||
// 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
|
||||
// pio-usb is required for rp2040 host
|
||||
#include "pio_usb.h"
|
||||
|
||||
// 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_INTERVAL 5000
|
||||
|
||||
// Analog pin for reading
|
||||
const int analogPin = A0;
|
||||
// USB Host object
|
||||
Adafruit_USBH_Host USBHost;
|
||||
|
||||
// USB Host MSC Block Device object which implemented API for use with SdFat
|
||||
Adafruit_USBH_MSC_BlockDevice msc_block_dev;
|
||||
|
|
@ -59,103 +63,77 @@ File32 f_log;
|
|||
// if file system is successfully mounted on usb block device
|
||||
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) {
|
||||
// nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
static unsigned long last_ms = 0;
|
||||
unsigned long ms = millis();
|
||||
|
||||
if ( ms - last_ms < LOG_INTERVAL ) {
|
||||
delay(1000);
|
||||
return;
|
||||
}
|
||||
|
||||
// Turn on LED when start writing
|
||||
#ifdef LED_BUILTIN
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
#endif
|
||||
|
||||
f_log = fatfs.open(LOG_FILE, O_WRITE | O_APPEND | O_CREAT);
|
||||
|
||||
if (!f_log) {
|
||||
Serial.println("Cannot create file: " LOG_FILE);
|
||||
} else {
|
||||
int value = analogRead(analogPin);
|
||||
}else {
|
||||
float cpu_temp = analogReadTemp();
|
||||
uint32_t ms = millis();
|
||||
|
||||
Serial.printf("%lu,%d\r\n", ms, value);
|
||||
f_log.printf("%lu,%d\r\n", ms, value);
|
||||
Serial.printf("%u,%.02f\r\n", millis(), cpu_temp);
|
||||
f_log.printf("%u,%.02f\r\n", millis(), cpu_temp);
|
||||
|
||||
f_log.close();
|
||||
}
|
||||
|
||||
last_ms = ms;
|
||||
Serial.flush();
|
||||
delay(LOG_INTERVAL);
|
||||
}
|
||||
|
||||
#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() {
|
||||
// configure pio-usb: defined in usbh_helper.h
|
||||
rp2040_configure_pio_usb();
|
||||
//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
|
||||
|
|
@ -163,61 +141,51 @@ void setup1() {
|
|||
USBHost.begin(1);
|
||||
}
|
||||
|
||||
void loop1() {
|
||||
void loop1()
|
||||
{
|
||||
USBHost.task();
|
||||
Serial.flush();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// 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)
|
||||
void tuh_mount_cb(uint8_t daddr) {
|
||||
void tuh_mount_cb (uint8_t daddr)
|
||||
{
|
||||
(void) daddr;
|
||||
}
|
||||
|
||||
/// Invoked when device is unmounted (bus reset/unplugged)
|
||||
void tuh_umount_cb(uint8_t daddr) {
|
||||
void tuh_umount_cb(uint8_t daddr)
|
||||
{
|
||||
(void) daddr;
|
||||
}
|
||||
|
||||
// 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
|
||||
msc_block_dev.begin(dev_addr);
|
||||
|
||||
// For simplicity this example only support LUN 0
|
||||
msc_block_dev.setActiveLUN(0);
|
||||
|
||||
msc_block_dev.setWriteCompleteCallback(write_complete_callback);
|
||||
|
||||
is_mounted = fatfs.begin(&msc_block_dev);
|
||||
|
||||
if (is_mounted) {
|
||||
fatfs.ls(&Serial, LS_SIZE);
|
||||
} else {
|
||||
}else {
|
||||
Serial.println("Failed to mount mass storage device. Make sure it is formatted as FAT");
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
// unmount file system
|
||||
|
|
@ -228,4 +196,17 @@ void tuh_msc_umount_cb(uint8_t dev_addr) {
|
|||
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
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
/* 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)
|
||||
* - Device run on native usb controller (controller0)
|
||||
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
|
||||
*
|
||||
* 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
|
||||
* - [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"
|
||||
*/
|
||||
|
||||
// SdFat is required for using Adafruit_USBH_MSC_SdFatDevice
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
// pio-usb is required for rp2040 host
|
||||
#include "pio_usb.h"
|
||||
|
||||
// USBHost is defined in usbh_helper.h
|
||||
#include "usbh_helper.h"
|
||||
// SdFat is required for using Adafruit_USBH_MSC_SdFatDevice
|
||||
#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
|
||||
Adafruit_USBH_MSC_BlockDevice msc_block_dev;
|
||||
|
|
@ -41,40 +56,51 @@ FatVolume fatfs;
|
|||
// if file system is successfully mounted on usb block device
|
||||
bool is_mounted = false;
|
||||
|
||||
void setup() {
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core0
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void setup()
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||
//--------------------------------------------------------------------+
|
||||
// Using Host shield MAX3421E controller
|
||||
//--------------------------------------------------------------------+
|
||||
void loop() {
|
||||
USBHost.task();
|
||||
Serial.flush();
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
#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() {
|
||||
// configure pio-usb: defined in usbh_helper.h
|
||||
rp2040_configure_pio_usb();
|
||||
//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
|
||||
|
|
@ -82,32 +108,30 @@ void setup1() {
|
|||
USBHost.begin(1);
|
||||
}
|
||||
|
||||
void loop1() {
|
||||
void loop1()
|
||||
{
|
||||
USBHost.task();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// TinyUSB Host callbacks
|
||||
//--------------------------------------------------------------------+
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// Invoked when device is mounted (configured)
|
||||
void tuh_mount_cb(uint8_t daddr) {
|
||||
void tuh_mount_cb (uint8_t daddr)
|
||||
{
|
||||
(void) daddr;
|
||||
}
|
||||
|
||||
/// Invoked when device is unmounted (bus reset/unplugged)
|
||||
void tuh_umount_cb(uint8_t daddr) {
|
||||
void tuh_umount_cb(uint8_t daddr)
|
||||
{
|
||||
(void) daddr;
|
||||
}
|
||||
|
||||
// Invoked when a device with MassStorage interface is mounted
|
||||
void tuh_msc_mount_cb(uint8_t dev_addr) {
|
||||
Serial.printf("Device attached, address = %d\r\n", dev_addr);
|
||||
|
||||
void tuh_msc_mount_cb(uint8_t dev_addr)
|
||||
{
|
||||
// Initialize block device with MSC device address
|
||||
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
|
||||
void tuh_msc_umount_cb(uint8_t dev_addr) {
|
||||
Serial.printf("Device removed, address = %d\r\n", dev_addr);
|
||||
void tuh_msc_umount_cb(uint8_t dev_addr)
|
||||
{
|
||||
(void) dev_addr;
|
||||
|
||||
// unmount file system
|
||||
is_mounted = false;
|
||||
|
|
@ -133,4 +158,3 @@ void tuh_msc_umount_cb(uint8_t dev_addr) {
|
|||
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_NeoPixel.h>
|
||||
|
||||
/* 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)
|
||||
* - LED and/or Neopixels will be used as Capslock indicator
|
||||
*/
|
||||
|
||||
// HID report descriptor using TinyUSB's template
|
||||
// Single Report (no ID) descriptor
|
||||
uint8_t const desc_hid_report[] = {
|
||||
TUD_HID_REPORT_DESC_KEYBOARD()
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_KEYBOARD()
|
||||
};
|
||||
|
||||
// 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;
|
||||
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_KEYBOARD, 2, false);
|
||||
|
||||
//------------- Input Pins -------------//
|
||||
// Array of pins and its keycode.
|
||||
// Notes: these pins can be replaced by PIN_BUTTONn if defined in setup()
|
||||
#ifdef ARDUINO_ARCH_RP2040
|
||||
uint8_t pins[] = { D0, D1, D2, D3 };
|
||||
uint8_t pins[] = { D0, D1, D2, D3 };
|
||||
#else
|
||||
uint8_t pins[] = {A0, A1, A2, A3};
|
||||
uint8_t pins[] = { A0, A1, A2, A3 };
|
||||
#endif
|
||||
|
||||
// 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
|
||||
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)
|
||||
bool activeState = true;
|
||||
bool activeState = true;
|
||||
#else
|
||||
bool activeState = false;
|
||||
bool activeState = false;
|
||||
#endif
|
||||
|
||||
// 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);
|
||||
}
|
||||
//------------- Neopixel -------------//
|
||||
// #define PIN_NEOPIXEL 8
|
||||
#ifdef PIN_NEOPIXEL
|
||||
|
||||
// Setup HID
|
||||
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");
|
||||
// How many NeoPixels are attached to the Arduino?
|
||||
// use on-board defined NEOPIXEL_NUM if existed
|
||||
#ifndef NEOPIXEL_NUM
|
||||
#define NEOPIXEL_NUM 10
|
||||
#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
|
||||
usb_hid.setReportCallback(NULL, hid_report_callback);
|
||||
|
||||
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
|
||||
#ifdef LED_BUILTIN
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
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
|
||||
|
||||
// overwrite input pin with PIN_BUTTONx
|
||||
|
|
@ -97,21 +117,32 @@ void setup() {
|
|||
#endif
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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
|
||||
static bool keyPressedPreviously = false;
|
||||
|
||||
uint8_t count = 0;
|
||||
uint8_t keycode[6] = {0};
|
||||
uint8_t count=0;
|
||||
uint8_t keycode[6] = { 0 };
|
||||
|
||||
// scan normal key and send report
|
||||
for (uint8_t i = 0; i < pincount; i++) {
|
||||
if (activeState == digitalRead(pins[i])) {
|
||||
for(uint8_t i=0; i < pincount; i++)
|
||||
{
|
||||
if ( activeState == digitalRead(pins[i]) )
|
||||
{
|
||||
// if pin is active (low), add its hid code to key report
|
||||
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
|
||||
// and REMOTE_WAKEUP feature is enabled by host
|
||||
TinyUSBDevice.remoteWakeup();
|
||||
}
|
||||
|
||||
// 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
|
||||
uint8_t const report_id = 0;
|
||||
uint8_t const modifier = 0;
|
||||
|
||||
keyPressedPreviously = true;
|
||||
usb_hid.keyboardReport(report_id, modifier, keycode);
|
||||
} else {
|
||||
}else
|
||||
{
|
||||
// Send All-zero report to indicate there is no keys pressed
|
||||
// Most of the time, it is, though we don't need to send zero report
|
||||
// every loop(), only a key is pressed in previous loop()
|
||||
if (keyPressedPreviously) {
|
||||
if ( keyPressedPreviously )
|
||||
{
|
||||
keyPressedPreviously = false;
|
||||
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
|
||||
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) bufsize;
|
||||
|
||||
// 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_* )
|
||||
// Kana (4) | Compose (3) | ScrollLock (2) | CapsLock (1) | Numlock (0)
|
||||
uint8_t ledIndicator = buffer[0];
|
||||
|
||||
#ifdef LED_BUILTIN
|
||||
// turn on LED if capslock is set
|
||||
digitalWrite(LED_BUILTIN, ledIndicator & KEYBOARD_LED_CAPSLOCK);
|
||||
|
||||
#ifdef PIN_NEOPIXEL
|
||||
pixels.fill(ledIndicator & KEYBOARD_LED_CAPSLOCK ? 0xff0000 : 0x000000);
|
||||
pixels.show();
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
feather_esp32_v2
|
||||
pico_rp2040_tinyusb_host
|
||||
|
|
@ -19,69 +19,66 @@
|
|||
* 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;
|
||||
const int pin = 4; // Left Button
|
||||
bool activeState = true;
|
||||
|
||||
#elif defined(ARDUINO_FUNHOUSE_ESP32S2)
|
||||
const int pin = BUTTON_DOWN;
|
||||
bool activeState = true;
|
||||
const int pin = BUTTON_DOWN;
|
||||
bool activeState = true;
|
||||
|
||||
#elif defined PIN_BUTTON1
|
||||
const int pin = PIN_BUTTON1;
|
||||
bool activeState = false;
|
||||
const int pin = PIN_BUTTON1;
|
||||
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;
|
||||
const int pin = 12;
|
||||
bool activeState = false;
|
||||
#endif
|
||||
|
||||
|
||||
// HID report descriptor using TinyUSB's template
|
||||
// Single Report (no ID) descriptor
|
||||
uint8_t const desc_hid_report[] = {
|
||||
TUD_HID_REPORT_DESC_MOUSE()
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_MOUSE()
|
||||
};
|
||||
|
||||
// USB HID object
|
||||
Adafruit_USBD_HID usb_hid;
|
||||
// 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_MOUSE, 2, false);
|
||||
|
||||
// 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);
|
||||
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
|
||||
|
||||
// Set up button, pullup opposite to active state
|
||||
pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
||||
|
||||
// Set up HID
|
||||
usb_hid.setBootProtocol(HID_ITF_PROTOCOL_MOUSE);
|
||||
usb_hid.setPollInterval(2);
|
||||
usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||
usb_hid.setStringDescriptor("TinyUSB Mouse");
|
||||
// Notes: following commented-out functions has no affect on ESP32
|
||||
// usb_hid.setBootProtocol(HID_ITF_PROTOCOL_MOUSE);
|
||||
// usb_hid.setPollInterval(2);
|
||||
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||
// usb_hid.setStringDescriptor("TinyUSB Mouse");
|
||||
|
||||
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();
|
||||
}
|
||||
Serial.begin(115200);
|
||||
|
||||
// wait until device mounted
|
||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
||||
|
||||
Serial.println("Adafruit TinyUSB HID Mouse example");
|
||||
}
|
||||
|
||||
void process_hid() {
|
||||
void loop()
|
||||
{
|
||||
// poll gpio once each 10 ms
|
||||
delay(10);
|
||||
|
||||
// Whether button is pressed
|
||||
bool btn_pressed = (digitalRead(pin) == activeState);
|
||||
|
||||
|
|
@ -89,34 +86,17 @@ void process_hid() {
|
|||
if (!btn_pressed) return;
|
||||
|
||||
// Remote wakeup
|
||||
if (TinyUSBDevice.suspended()) {
|
||||
if ( TinyUSBDevice.suspended() )
|
||||
{
|
||||
// Wake up host if we are in suspend mode
|
||||
// and REMOTE_WAKEUP feature is enabled by host
|
||||
TinyUSBDevice.remoteWakeup();
|
||||
}
|
||||
|
||||
if (usb_hid.ready()) {
|
||||
if ( usb_hid.ready() )
|
||||
{
|
||||
uint8_t const report_id = 0; // no ID
|
||||
int8_t const delta = 5;
|
||||
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
|
||||
*/
|
||||
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY)
|
||||
const int pin = 4; // Left Button
|
||||
bool activeState = true;
|
||||
const int pin = 4; // Left Button
|
||||
bool activeState = true;
|
||||
|
||||
#elif defined(ARDUINO_FUNHOUSE_ESP32S2)
|
||||
const int pin = BUTTON_DOWN;
|
||||
bool activeState = true;
|
||||
const int pin = BUTTON_DOWN;
|
||||
bool activeState = true;
|
||||
|
||||
#elif defined PIN_BUTTON1
|
||||
const int pin = PIN_BUTTON1;
|
||||
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;
|
||||
const int pin = PIN_BUTTON1;
|
||||
bool activeState = false;
|
||||
|
||||
#else
|
||||
const int pin = A0;
|
||||
bool activeState = false;
|
||||
|
||||
const int pin = 12;
|
||||
bool activeState = false;
|
||||
#endif
|
||||
|
||||
|
||||
// Report ID
|
||||
enum {
|
||||
enum
|
||||
{
|
||||
RID_KEYBOARD = 1,
|
||||
RID_MOUSE,
|
||||
RID_CONSUMER_CONTROL, // Media, volume etc ..
|
||||
};
|
||||
|
||||
// HID report descriptor using TinyUSB's template
|
||||
uint8_t const desc_hid_report[] = {
|
||||
TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(RID_KEYBOARD)),
|
||||
TUD_HID_REPORT_DESC_MOUSE (HID_REPORT_ID(RID_MOUSE)),
|
||||
TUD_HID_REPORT_DESC_CONSUMER(HID_REPORT_ID(RID_CONSUMER_CONTROL))
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(RID_KEYBOARD) ),
|
||||
TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(RID_MOUSE) ),
|
||||
TUD_HID_REPORT_DESC_CONSUMER( HID_REPORT_ID(RID_CONSUMER_CONTROL) )
|
||||
};
|
||||
|
||||
// USB HID object.
|
||||
Adafruit_USBD_HID usb_hid;
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
void setup()
|
||||
{
|
||||
// Notes: following commented-out functions has no affect on ESP32
|
||||
// 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();
|
||||
|
||||
// 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.begin(115200);
|
||||
|
||||
// wait until device mounted
|
||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
||||
|
||||
Serial.println("Adafruit TinyUSB HID Composite example");
|
||||
}
|
||||
|
||||
void process_hid() {
|
||||
void loop()
|
||||
{
|
||||
// poll gpio once each 10 ms
|
||||
delay(10);
|
||||
|
||||
// Whether button is pressed
|
||||
bool btn_pressed = (digitalRead(pin) == activeState);
|
||||
|
||||
// Remote wakeup
|
||||
if (TinyUSBDevice.suspended() && btn_pressed) {
|
||||
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_hid.ready() && btn_pressed) {
|
||||
if ( usb_hid.ready() && btn_pressed )
|
||||
{
|
||||
int8_t const delta = 5;
|
||||
usb_hid.mouseMove(RID_MOUSE, delta, delta); // right + down
|
||||
|
||||
|
|
@ -112,18 +105,21 @@ void process_hid() {
|
|||
}
|
||||
|
||||
/*------------- Keyboard -------------*/
|
||||
if (usb_hid.ready()) {
|
||||
if ( usb_hid.ready() )
|
||||
{
|
||||
// use to send key release report
|
||||
static bool has_key = false;
|
||||
|
||||
if (btn_pressed) {
|
||||
uint8_t keycode[6] = {0};
|
||||
if ( btn_pressed )
|
||||
{
|
||||
uint8_t keycode[6] = { 0 };
|
||||
keycode[0] = HID_KEY_A;
|
||||
|
||||
usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode);
|
||||
|
||||
has_key = true;
|
||||
} else {
|
||||
}else
|
||||
{
|
||||
// send empty key report if previously has key pressed
|
||||
if (has_key) usb_hid.keyboardRelease(RID_KEYBOARD);
|
||||
has_key = false;
|
||||
|
|
@ -134,7 +130,8 @@ void process_hid() {
|
|||
}
|
||||
|
||||
/*------------- Consumer Control -------------*/
|
||||
if (usb_hid.ready()) {
|
||||
if ( usb_hid.ready() )
|
||||
{
|
||||
// Consumer Control is used to control Media playback, Volume, Brightness etc ...
|
||||
// Consumer report is 2-byte containing the control code of the key
|
||||
// For list of control check out https://github.com/hathach/tinyusb/blob/master/src/class/hid/hid.h
|
||||
|
|
@ -142,33 +139,16 @@ void process_hid() {
|
|||
// use to send consumer release report
|
||||
static bool has_consumer_key = false;
|
||||
|
||||
if (btn_pressed) {
|
||||
if ( btn_pressed )
|
||||
{
|
||||
// send volume down (0x00EA)
|
||||
usb_hid.sendReport16(RID_CONSUMER_CONTROL, HID_USAGE_CONSUMER_VOLUME_DECREMENT);
|
||||
has_consumer_key = true;
|
||||
} else {
|
||||
}else
|
||||
{
|
||||
// release the consume key by sending zero (0x0000)
|
||||
if (has_consumer_key) usb_hid.sendReport16(RID_CONSUMER_CONTROL, 0);
|
||||
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;
|
||||
|
||||
// Report ID
|
||||
enum {
|
||||
enum
|
||||
{
|
||||
RID_KEYBOARD = 1,
|
||||
RID_MOUSE
|
||||
};
|
||||
|
||||
// HID report descriptor using TinyUSB's template
|
||||
uint8_t const desc_hid_report[] = {
|
||||
TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(RID_KEYBOARD)),
|
||||
TUD_HID_REPORT_DESC_MOUSE (HID_REPORT_ID(RID_MOUSE))
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(RID_KEYBOARD) ),
|
||||
TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(RID_MOUSE) )
|
||||
};
|
||||
|
||||
// USB HID object. 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;
|
||||
|
||||
// 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);
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Notes: following commented-out functions has no affect on ESP32
|
||||
// usb_hid.setPollInterval(2);
|
||||
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println("Adafruit TinyUSB HID Mouse with Joy FeatherWing example");
|
||||
|
||||
if (!ss.begin(0x49)) {
|
||||
if(!ss.begin(0x49)){
|
||||
Serial.println("ERROR! seesaw not found");
|
||||
while (1) {}
|
||||
while(1);
|
||||
} else {
|
||||
Serial.println("seesaw started");
|
||||
Serial.print("version: ");
|
||||
|
|
@ -85,9 +77,16 @@ void setup() {
|
|||
|
||||
last_y = ss.analogRead(2);
|
||||
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
|
||||
bool has_action = false;
|
||||
|
||||
|
|
@ -99,10 +98,12 @@ void process_hid() {
|
|||
int dx = (x - last_x) / 2;
|
||||
int dy = (y - last_y) / 2;
|
||||
|
||||
if ((abs(dx) > 3) || (abs(dy) > 3)) {
|
||||
if ( (abs(dx) > 3) || (abs(dy) > 3) )
|
||||
{
|
||||
has_action = true;
|
||||
|
||||
if (usb_hid.ready()) {
|
||||
if ( usb_hid.ready() )
|
||||
{
|
||||
usb_hid.mouseMove(RID_MOUSE, dx, dy); // no ID: right + down
|
||||
|
||||
last_x = x;
|
||||
|
|
@ -113,27 +114,31 @@ void process_hid() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/*------------- Keyboard -------------*/
|
||||
// button is active low, invert read value for convenience
|
||||
uint32_t buttons = ~ss.digitalReadBulk(button_mask);
|
||||
|
||||
if (usb_hid.ready()) {
|
||||
if ( usb_hid.ready() )
|
||||
{
|
||||
// use to prevent sending multiple consecutive zero report
|
||||
static bool has_key = false;
|
||||
|
||||
if (buttons & button_mask) {
|
||||
if ( buttons & button_mask )
|
||||
{
|
||||
has_action = 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_B)) keycode[0] = HID_KEY_B;
|
||||
if (buttons & (1 << BUTTON_X)) keycode[0] = HID_KEY_X;
|
||||
if (buttons & (1 << BUTTON_Y)) keycode[0] = HID_KEY_Y;
|
||||
if ( buttons & (1 << BUTTON_A) ) keycode[0] = HID_KEY_A;
|
||||
if ( buttons & (1 << BUTTON_B) ) keycode[0] = HID_KEY_B;
|
||||
if ( buttons & (1 << BUTTON_X) ) keycode[0] = HID_KEY_X;
|
||||
if ( buttons & (1 << BUTTON_Y) ) keycode[0] = HID_KEY_Y;
|
||||
|
||||
usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode);
|
||||
} else {
|
||||
}else
|
||||
{
|
||||
// send empty key report if previously has key pressed
|
||||
if (has_key) usb_hid.keyboardRelease(RID_KEYBOARD);
|
||||
has_key = false;
|
||||
|
|
@ -142,28 +147,10 @@ void process_hid() {
|
|||
|
||||
/*------------- Remote Wakeup -------------*/
|
||||
// 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
|
||||
// Usually this is the case with Mouse/Keyboard device
|
||||
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
|
||||
// Single Report (no ID) descriptor
|
||||
uint8_t const desc_hid_report[] = {
|
||||
TUD_HID_REPORT_DESC_GAMEPAD()
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_GAMEPAD()
|
||||
};
|
||||
|
||||
// USB HID object
|
||||
Adafruit_USBD_HID usb_hid;
|
||||
// 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);
|
||||
|
||||
// Report payload defined in src/class/hid/hid.h
|
||||
// - For Gamepad Button Bit Mask see hid_gamepad_button_bm_t
|
||||
// - For Gamepad Hat Bit Mask see hid_gamepad_hat_t
|
||||
hid_gamepad_report_t gp;
|
||||
hid_gamepad_report_t gp;
|
||||
|
||||
void setup() {
|
||||
// Manual begin() is required on core without built-in support e.g. mbed rp2040
|
||||
if (!TinyUSBDevice.isInitialized()) {
|
||||
TinyUSBDevice.begin(0);
|
||||
}
|
||||
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
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// Setup HID
|
||||
usb_hid.setPollInterval(2);
|
||||
usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||
// Notes: following commented-out functions has no affect on ESP32
|
||||
// usb_hid.setPollInterval(2);
|
||||
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||
|
||||
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();
|
||||
}
|
||||
// wait until device mounted
|
||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
||||
|
||||
Serial.println("Adafruit TinyUSB HID Gamepad example");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// // Remote wakeup
|
||||
// if ( TinyUSBDevice.suspended() && btn )
|
||||
// {
|
||||
|
|
@ -76,17 +67,17 @@ void loop() {
|
|||
// TinyUSBDevice.remoteWakeup();
|
||||
// }
|
||||
|
||||
if (!usb_hid.ready()) return;
|
||||
if ( !usb_hid.ready() ) return;
|
||||
|
||||
// Reset buttons
|
||||
Serial.println("No pressing buttons");
|
||||
gp.x = 0;
|
||||
gp.y = 0;
|
||||
gp.z = 0;
|
||||
gp.rz = 0;
|
||||
gp.rx = 0;
|
||||
gp.ry = 0;
|
||||
gp.hat = 0;
|
||||
gp.x = 0;
|
||||
gp.y = 0;
|
||||
gp.z = 0;
|
||||
gp.rz = 0;
|
||||
gp.rx = 0;
|
||||
gp.ry = 0;
|
||||
gp.hat = 0;
|
||||
gp.buttons = 0;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
|
@ -116,7 +107,7 @@ void loop() {
|
|||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Hat/DPAD DOWN
|
||||
// Hat/DPAD DOWN
|
||||
Serial.println("Hat/DPAD DOWN");
|
||||
gp.hat = 5; // GAMEPAD_HAT_DOWN;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
|
|
@ -185,35 +176,35 @@ void loop() {
|
|||
|
||||
// Joystick 2 UP
|
||||
Serial.println("Joystick 2 UP");
|
||||
gp.z = 0;
|
||||
gp.z = 0;
|
||||
gp.rz = 127;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Joystick 2 DOWN
|
||||
Serial.println("Joystick 2 DOWN");
|
||||
gp.z = 0;
|
||||
gp.z = 0;
|
||||
gp.rz = -127;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Joystick 2 RIGHT
|
||||
Serial.println("Joystick 2 RIGHT");
|
||||
gp.z = 127;
|
||||
gp.z = 127;
|
||||
gp.rz = 0;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Joystick 2 LEFT
|
||||
Serial.println("Joystick 2 LEFT");
|
||||
gp.z = -127;
|
||||
gp.z = -127;
|
||||
gp.rz = 0;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Joystick 2 CENTER
|
||||
Serial.println("Joystick 2 CENTER");
|
||||
gp.z = 0;
|
||||
gp.z = 0;
|
||||
gp.rz = 0;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
|
@ -258,9 +249,9 @@ void loop() {
|
|||
|
||||
|
||||
// Test buttons (up to 32 buttons)
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
Serial.print("Pressing button ");
|
||||
Serial.println(i);
|
||||
for (int i=0; i<32; ++i)
|
||||
{
|
||||
Serial.print("Pressing button "); Serial.println(i);
|
||||
gp.buttons = (1U << i);
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(1000);
|
||||
|
|
@ -269,13 +260,13 @@ void loop() {
|
|||
|
||||
// Random touch
|
||||
Serial.println("Random touch");
|
||||
gp.x = random(-127, 128);
|
||||
gp.y = random(-127, 128);
|
||||
gp.z = random(-127, 128);
|
||||
gp.rz = random(-127, 128);
|
||||
gp.rx = random(-127, 128);
|
||||
gp.ry = random(-127, 128);
|
||||
gp.hat = random(0, 9);
|
||||
gp.x = random(-127, 128);
|
||||
gp.y = random(-127, 128);
|
||||
gp.z = random(-127, 128);
|
||||
gp.rz = random(-127, 128);
|
||||
gp.rx = random(-127, 128);
|
||||
gp.ry = random(-127, 128);
|
||||
gp.hat = random(0, 9);
|
||||
gp.buttons = random(0, 0xffff);
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
feather_esp32_v2
|
||||
pico_rp2040_tinyusb_host
|
||||
|
|
@ -39,51 +39,50 @@
|
|||
|
||||
// HID report descriptor using TinyUSB's template
|
||||
// Generic In Out with 64 bytes report (max)
|
||||
uint8_t const desc_hid_report[] = {
|
||||
TUD_HID_REPORT_DESC_GENERIC_INOUT(64)
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_GENERIC_INOUT(64)
|
||||
};
|
||||
|
||||
// USB HID object
|
||||
Adafruit_USBD_HID usb_hid;
|
||||
// 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, true);
|
||||
|
||||
// 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);
|
||||
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.enableOutEndpoint(true);
|
||||
usb_hid.setPollInterval(2);
|
||||
usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||
usb_hid.setStringDescriptor("TinyUSB HID Generic");
|
||||
// usb_hid.enableOutEndpoint(true);
|
||||
// usb_hid.setPollInterval(2);
|
||||
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||
// usb_hid.setStringDescriptor("TinyUSB HID Generic");
|
||||
|
||||
usb_hid.setReportCallback(get_report_callback, set_report_callback);
|
||||
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();
|
||||
}
|
||||
Serial.begin(115200);
|
||||
|
||||
// wait until device mounted
|
||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
||||
|
||||
Serial.println("Adafruit TinyUSB HID Generic In Out example");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
#ifdef TINYUSB_NEED_POLLING_TASK
|
||||
// Manual call tud_task since it isn't called by Core's background
|
||||
TinyUSBDevice.task();
|
||||
#endif
|
||||
void loop()
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
// Invoked when received GET_REPORT control request
|
||||
// Application must fill buffer report's content and return its length.
|
||||
// Return zero will cause the stack to STALL request
|
||||
uint16_t get_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) {
|
||||
uint16_t get_report_callback (uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
|
||||
{
|
||||
// not used in this example
|
||||
(void) report_id;
|
||||
(void) report_type;
|
||||
|
|
@ -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
|
||||
// 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
|
||||
(void) report_id;
|
||||
(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
|
||||
Adafruit_USBD_MIDI usb_midi(3);
|
||||
|
||||
void setup() {
|
||||
#ifdef LED_BUILTIN
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
#endif
|
||||
|
||||
// Manual begin() is required on core without built-in support e.g. mbed rp2040
|
||||
if (!TinyUSBDevice.isInitialized()) {
|
||||
TinyUSBDevice.begin(0);
|
||||
}
|
||||
#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
|
||||
|
||||
// Set name for each cable, must be done before usb_midi.begin()
|
||||
usb_midi.setCableName(1, "Keyboard");
|
||||
usb_midi.setCableName(2, "Drum Pads");
|
||||
usb_midi.setCableName(3, "Lights");
|
||||
|
||||
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() {
|
||||
#ifdef TINYUSB_NEED_POLLING_TASK
|
||||
// Manual call tud_task since it isn't called by Core's background
|
||||
TinyUSBDevice.task();
|
||||
#endif
|
||||
void loop()
|
||||
{
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
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
|
||||
}
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
delay(1000);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
feather_esp32_v2
|
||||
pico_rp2040_tinyusb_host
|
||||
|
|
@ -31,53 +31,44 @@ uint32_t position = 0;
|
|||
|
||||
// Store example melody as an array of note values
|
||||
byte note_sequence[] = {
|
||||
74, 78, 81, 86, 90, 93, 98, 102, 57, 61, 66, 69, 73, 78, 81, 85, 88, 92, 97, 100, 97, 92, 88, 85, 81, 78,
|
||||
74, 69, 66, 62, 57, 62, 66, 69, 74, 78, 81, 86, 90, 93, 97, 102, 97, 93, 90, 85, 81, 78, 73, 68, 64, 61,
|
||||
56, 61, 64, 68, 74, 78, 81, 86, 90, 93, 98, 102
|
||||
74,78,81,86,90,93,98,102,57,61,66,69,73,78,81,85,88,92,97,100,97,92,88,85,81,78,
|
||||
74,69,66,62,57,62,66,69,74,78,81,86,90,93,97,102,97,93,90,85,81,78,73,68,64,61,
|
||||
56,61,64,68,74,78,81,86,90,93,98,102
|
||||
};
|
||||
|
||||
void setup() {
|
||||
// Manual begin() is required on core without built-in support e.g. mbed rp2040
|
||||
if (!TinyUSBDevice.isInitialized()) {
|
||||
TinyUSBDevice.begin(0);
|
||||
}
|
||||
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
|
||||
|
||||
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
|
||||
// This will also call usb_midi's begin()
|
||||
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
|
||||
// be called whenever the Bluefruit receives MIDI Note On messages.
|
||||
MIDI.setHandleNoteOn(handleNoteOn);
|
||||
|
||||
// Do the same for MIDI Note Off messages.
|
||||
MIDI.setHandleNoteOff(handleNoteOff);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// wait until device mounted
|
||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
static uint32_t start_ms = 0;
|
||||
if (millis() - start_ms > 266) {
|
||||
if ( millis() - start_ms > 266 )
|
||||
{
|
||||
start_ms += 266;
|
||||
|
||||
// Setup variables for the current and previous
|
||||
|
|
@ -109,7 +100,8 @@ void loop() {
|
|||
MIDI.read();
|
||||
}
|
||||
|
||||
void handleNoteOn(byte channel, byte pitch, byte velocity) {
|
||||
void handleNoteOn(byte channel, byte pitch, byte velocity)
|
||||
{
|
||||
// Log when a note is pressed.
|
||||
Serial.print("Note on: channel = ");
|
||||
Serial.print(channel);
|
||||
|
|
@ -121,7 +113,8 @@ void handleNoteOn(byte channel, byte pitch, byte 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.
|
||||
Serial.print("Note off: channel = ");
|
||||
Serial.print(channel);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
*/
|
||||
|
||||
#include "SPI.h"
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
#include "SdFat.h"
|
||||
#include "Adafruit_SPIFlash.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
|
|
@ -93,19 +93,14 @@ void setupMassStorage(void)
|
|||
// MSC is ready for read/write
|
||||
fs_changed = false;
|
||||
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
|
||||
if (TinyUSBDevice.mounted()) {
|
||||
TinyUSBDevice.detach();
|
||||
delay(10);
|
||||
TinyUSBDevice.attach();
|
||||
}
|
||||
usb_msc.begin();
|
||||
|
||||
// Init file system on the 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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
feather_esp32_v2
|
||||
pico_rp2040_tinyusb_host
|
||||
CH32V20x_EVT
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
*/
|
||||
|
||||
#include "SPI.h"
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
#include "SdFat.h"
|
||||
#include "Adafruit_SPIFlash.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
|
|
@ -48,12 +48,9 @@ bool fs_formatted = false;
|
|||
bool fs_changed = true;;
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup() {
|
||||
#ifdef LED_BUILTIN
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
#endif
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
flash.begin();
|
||||
|
||||
|
|
@ -71,16 +68,10 @@ void setup() {
|
|||
|
||||
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
|
||||
fs_formatted = fatfs.begin(&flash);
|
||||
|
||||
Serial.begin(115200);
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
void loop()
|
||||
{
|
||||
// check if formatted
|
||||
if ( !fs_formatted ) {
|
||||
if ( !fs_formatted )
|
||||
{
|
||||
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("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");
|
||||
|
|
@ -104,12 +98,14 @@ void loop() {
|
|||
}
|
||||
}
|
||||
|
||||
if ( fs_changed ) {
|
||||
if ( fs_changed )
|
||||
{
|
||||
fs_changed = false;
|
||||
|
||||
Serial.println("Opening root");
|
||||
|
||||
if ( !root.open("/") ) {
|
||||
if ( !root.open("/") )
|
||||
{
|
||||
Serial.println("open root failed");
|
||||
return;
|
||||
}
|
||||
|
|
@ -119,11 +115,13 @@ void loop() {
|
|||
// 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) ) {
|
||||
while ( file.openNext(&root, O_RDONLY) )
|
||||
{
|
||||
file.printFileSize(&Serial);
|
||||
Serial.write(' ');
|
||||
file.printName(&Serial);
|
||||
if ( file.isDir() ) {
|
||||
if ( file.isDir() )
|
||||
{
|
||||
// Indicate a directory.
|
||||
Serial.write('/');
|
||||
}
|
||||
|
|
@ -141,7 +139,8 @@ void loop() {
|
|||
// 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) {
|
||||
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
// Note: SPIFLash Block 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;
|
||||
|
|
@ -150,10 +149,9 @@ int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) {
|
|||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and
|
||||
// return number of written bytes (must be multiple of block size)
|
||||
int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
|
||||
#ifdef LED_BUILTIN
|
||||
int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
#endif
|
||||
|
||||
// Note: SPIFLash Block API: readBlocks/writeBlocks/syncBlocks
|
||||
// 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).
|
||||
// used to flush any pending cache.
|
||||
void msc_flush_cb (void) {
|
||||
void msc_flush_cb (void)
|
||||
{
|
||||
// sync with flash
|
||||
flash.syncBlocks();
|
||||
|
||||
|
|
@ -171,7 +170,5 @@ void msc_flush_cb (void) {
|
|||
|
||||
fs_changed = true;
|
||||
|
||||
#ifdef LED_BUILTIN
|
||||
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 "SdFat_Adafruit_Fork.h"
|
||||
#include "SdFat.h"
|
||||
#include "Adafruit_SPIFlash.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
|
|
@ -33,67 +33,42 @@
|
|||
|
||||
// for flashTransport definition
|
||||
#include "flash_config.h"
|
||||
|
||||
Adafruit_SPIFlash flash(&flashTransport);
|
||||
|
||||
// External Flash File system
|
||||
FatVolume fatfs;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// 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)
|
||||
// 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
|
||||
|
||||
#define SDCARD_CS 32
|
||||
#define SDCARD_DETECT 33
|
||||
#else
|
||||
// Use SPI, no detect
|
||||
#define SDCARD_CS 10
|
||||
// no detect
|
||||
#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
|
||||
// SDCard File system
|
||||
SdFat sd;
|
||||
|
||||
// USB Mass Storage object
|
||||
Adafruit_USBD_MSC usb_msc;
|
||||
|
||||
// Set to true when PC write to flash
|
||||
bool sd_changed = 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
|
||||
void setup() {
|
||||
#ifdef LED_BUILTIN
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
#endif
|
||||
Serial.begin(115200);
|
||||
|
||||
// MSC with 2 Logical Units: LUN0: External Flash, LUN1: SDCard
|
||||
|
|
@ -108,20 +83,16 @@ void setup() {
|
|||
// LUN readiness will always be set later on
|
||||
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 -------------//
|
||||
flash.begin();
|
||||
flash_formatted = fatfs.begin(&flash);
|
||||
|
||||
usb_msc.setCapacity(0, flash.size()/512, 512);
|
||||
usb_msc.setReadWriteCallback(0, external_flash_read_cb, external_flash_write_cb, external_flash_flush_cb);
|
||||
usb_msc.setUnitReady(0, true);
|
||||
|
||||
flash_changed = true; // to print contents initially
|
||||
|
||||
//------------- Lun 1 for SD card -------------//
|
||||
#ifdef SDCARD_DETECT
|
||||
// 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);
|
||||
#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");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
bool init_sdcard(void) {
|
||||
bool init_sdcard(void)
|
||||
{
|
||||
Serial.print("Init SDCard ... ");
|
||||
|
||||
if (!sd.begin(SD_CONFIG)) {
|
||||
Serial.println("initialization failed. Things to check:");
|
||||
Serial.println("- is a card inserted?");
|
||||
Serial.println("- is your wiring correct?");
|
||||
Serial.println("- did you change the SDCARD_CS or SDIO pin to match your shield or module?");
|
||||
if ( !sd.begin(SDCARD_CS, SD_SCK_MHZ(50)) )
|
||||
{
|
||||
Serial.print("Failed ");
|
||||
sd.errorPrint("sd.begin() failed");
|
||||
|
||||
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.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((block_count / (1024 * 1024)) * 512);
|
||||
Serial.print((block_count / (1024*1024)) * 512);
|
||||
Serial.println(" MB");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void print_rootdir(File32* rdir) {
|
||||
void print_rootdir(File32* rdir)
|
||||
{
|
||||
File32 file;
|
||||
|
||||
// Open next file in root.
|
||||
// Warning, openNext starts at the current directory position
|
||||
// so a rewind of the directory may be required.
|
||||
while (file.openNext(rdir, O_RDONLY)) {
|
||||
while ( file.openNext(rdir, O_RDONLY) )
|
||||
{
|
||||
file.printFileSize(&Serial);
|
||||
Serial.write(' ');
|
||||
file.printName(&Serial);
|
||||
if (file.isDir()) {
|
||||
if ( file.isDir() )
|
||||
{
|
||||
// Indicate a directory.
|
||||
Serial.write('/');
|
||||
}
|
||||
|
|
@ -180,8 +165,46 @@ void print_rootdir(File32* rdir) {
|
|||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// nothing to do
|
||||
void loop()
|
||||
{
|
||||
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
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
int32_t sdcard_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) {
|
||||
bool rc = sd.card()->readSectors(lba, (uint8_t*) buffer, bufsize/512);
|
||||
int32_t sdcard_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and
|
||||
// return number of written bytes (must be multiple of block size)
|
||||
int32_t sdcard_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
|
||||
#ifdef LED_BUILTIN
|
||||
int32_t sdcard_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
bool rc;
|
||||
|
||||
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
|
||||
bool rc = sd.card()->writeSectors(lba, buffer, bufsize/512);
|
||||
|
||||
return rc ? bufsize : -1;
|
||||
}
|
||||
|
||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||
// used to flush any pending cache.
|
||||
void sdcard_flush_cb (void) {
|
||||
void sdcard_flush_cb (void)
|
||||
{
|
||||
#if SD_FAT_VERSION >= 20000
|
||||
sd.card()->syncDevice();
|
||||
sd.cacheClear(); // clear file system's cache to force refresh
|
||||
|
||||
#ifdef LED_BUILTIN
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
#else
|
||||
sd.card()->syncBlocks();
|
||||
#endif
|
||||
|
||||
// clear file system's cache to force refresh
|
||||
sd.cacheClear();
|
||||
|
||||
sd_changed = true;
|
||||
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
}
|
||||
|
||||
#ifdef SDCARD_DETECT
|
||||
// Invoked when received Test Unit Ready command.
|
||||
// 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
|
||||
if (digitalRead(SDCARD_DETECT) == SDCARD_DETECT_ACTIVE) {
|
||||
if ( digitalRead(SDCARD_DETECT) == HIGH )
|
||||
{
|
||||
// init SD card if not already
|
||||
if (!sd_inited) {
|
||||
if ( !sd_inited )
|
||||
{
|
||||
sd_inited = init_sdcard();
|
||||
}
|
||||
} else {
|
||||
}else
|
||||
{
|
||||
sd_inited = false;
|
||||
usb_msc.setReadWriteCallback(1, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
Serial.println(sd_inited);
|
||||
|
||||
return sd_inited;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -242,7 +293,8 @@ bool sdcard_ready_callback(void) {
|
|||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and
|
||||
// return number of copied bytes (must be multiple of block size)
|
||||
int32_t external_flash_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) {
|
||||
int32_t external_flash_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
// Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
|
||||
// already include 4K sector caching internally. We don't need to cache it, yahhhh!!
|
||||
return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
|
||||
|
|
@ -251,10 +303,9 @@ int32_t external_flash_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) {
|
|||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and
|
||||
// return number of written bytes (must be multiple of block size)
|
||||
int32_t external_flash_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
|
||||
#ifdef LED_BUILTIN
|
||||
int32_t external_flash_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
#endif
|
||||
|
||||
// Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
|
||||
// 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).
|
||||
// used to flush any pending cache.
|
||||
void external_flash_flush_cb (void) {
|
||||
void external_flash_flush_cb (void)
|
||||
{
|
||||
flash.syncBlocks();
|
||||
#ifdef LED_BUILTIN
|
||||
|
||||
// clear file system's cache to force refresh
|
||||
fatfs.cacheClear();
|
||||
|
||||
flash_changed = true;
|
||||
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
*********************************************************************/
|
||||
|
||||
#include "SPI.h"
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
#include "SdFat.h"
|
||||
#include "Adafruit_InternalFlash.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
|
|
@ -35,9 +35,8 @@ Adafruit_USBD_MSC usb_msc;
|
|||
bool fs_changed;
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Initialize internal flash
|
||||
flash.begin();
|
||||
|
||||
|
|
@ -47,30 +46,32 @@ void setup() {
|
|||
// Set callback
|
||||
usb_msc.setReadWriteCallback(msc_read_callback, msc_write_callback, msc_flush_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
|
||||
if (TinyUSBDevice.mounted()) {
|
||||
TinyUSBDevice.detach();
|
||||
delay(10);
|
||||
TinyUSBDevice.attach();
|
||||
}
|
||||
// Set disk size, block size should be 512 regardless of flash page size
|
||||
usb_msc.setCapacity(flash.size()/512, 512);
|
||||
|
||||
// Set Lun ready
|
||||
usb_msc.setUnitReady(true);
|
||||
|
||||
usb_msc.begin();
|
||||
|
||||
// Init file system on the flash
|
||||
fatfs.begin(&flash);
|
||||
|
||||
Serial.begin(115200);
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
|
||||
fs_changed = true; // to print contents initially
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if ( fs_changed ) {
|
||||
void loop()
|
||||
{
|
||||
if ( fs_changed )
|
||||
{
|
||||
fs_changed = false;
|
||||
|
||||
if ( !root.open("/") ) {
|
||||
if ( !root.open("/") )
|
||||
{
|
||||
Serial.println("open root failed");
|
||||
return;
|
||||
}
|
||||
|
|
@ -80,11 +81,13 @@ void loop() {
|
|||
// 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) ) {
|
||||
while ( file.openNext(&root, O_RDONLY) )
|
||||
{
|
||||
file.printFileSize(&Serial);
|
||||
Serial.write(' ');
|
||||
file.printName(&Serial);
|
||||
if ( file.isDir() ) {
|
||||
if ( file.isDir() )
|
||||
{
|
||||
// Indicate a directory.
|
||||
Serial.write('/');
|
||||
}
|
||||
|
|
@ -102,7 +105,8 @@ void loop() {
|
|||
// 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_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
|
||||
// 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;
|
||||
|
|
@ -111,7 +115,8 @@ int32_t msc_read_callback (uint32_t lba, void* buffer, uint32_t bufsize) {
|
|||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and
|
||||
// return number of written bytes (must be multiple of block size)
|
||||
int32_t msc_write_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
|
||||
// already include sector caching (if needed). We don't need to cache it, yahhhh!!
|
||||
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).
|
||||
// used to flush any pending cache.
|
||||
void msc_flush_callback (void) {
|
||||
void msc_flush_callback (void)
|
||||
{
|
||||
// sync with flash
|
||||
flash.syncBlocks();
|
||||
|
||||
|
|
@ -131,7 +137,8 @@ void msc_flush_callback (void) {
|
|||
|
||||
// Invoked to check if device is writable as part of SCSI WRITE10
|
||||
// Default mode is writable
|
||||
bool msc_writable_callback(void) {
|
||||
bool msc_writable_callback(void)
|
||||
{
|
||||
// true for writable, false for read-only
|
||||
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
|
||||
#define DISK_BLOCK_NUM 16
|
||||
#define DISK_BLOCK_SIZE 512
|
||||
|
||||
#include "ramdisk.h"
|
||||
|
||||
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
|
||||
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);
|
||||
|
||||
#ifdef BTN_EJECT
|
||||
pinMode(BTN_EJECT, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
||||
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
|
||||
|
||||
// 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
|
||||
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)
|
||||
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();
|
||||
|
||||
// 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();
|
||||
}
|
||||
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 RAM Disk example");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
#ifdef TINYUSB_NEED_POLLING_TASK
|
||||
// Manual call tud_task since it isn't called by Core's background
|
||||
TinyUSBDevice.task();
|
||||
#endif
|
||||
void loop()
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and
|
||||
// return number of copied bytes (must be multiple of block size)
|
||||
int32_t msc_read_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];
|
||||
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.
|
||||
// Process data in buffer to disk's storage and
|
||||
// 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];
|
||||
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).
|
||||
// used to flush any pending cache.
|
||||
void msc_flush_callback(void) {
|
||||
void msc_flush_callback (void)
|
||||
{
|
||||
// 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.
|
||||
// return true allowing host to read/write this LUN e.g SD card inserted
|
||||
bool msc_ready_callback(void) {
|
||||
#ifdef BTN_EJECT
|
||||
bool msc_ready_callback(void)
|
||||
{
|
||||
// button not active --> medium ready
|
||||
return digitalRead(BTN_EJECT) != activeState;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
feather_esp32_v2
|
||||
pico_rp2040_tinyusb_host
|
||||
CH32V20x_EVT
|
||||
|
|
@ -14,19 +14,17 @@
|
|||
// 8KB is the smallest size that windows allow to mount
|
||||
#define DISK_BLOCK_NUM 16
|
||||
#define DISK_BLOCK_SIZE 512
|
||||
|
||||
#include "ramdisk.h"
|
||||
|
||||
Adafruit_USBD_MSC usb_msc;
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup() {
|
||||
// Manual begin() is required on core without built-in support e.g. mbed rp2040
|
||||
if (!TinyUSBDevice.isInitialized()) {
|
||||
TinyUSBDevice.begin(0);
|
||||
}
|
||||
|
||||
Serial.begin(115200);
|
||||
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
|
||||
|
||||
usb_msc.setMaxLun(2);
|
||||
|
||||
|
|
@ -44,22 +42,15 @@ void setup() {
|
|||
|
||||
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();
|
||||
}
|
||||
|
||||
Serial.begin(115200);
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
|
||||
Serial.println("Adafruit TinyUSB Mass Storage Dual RAM Disks example");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
#ifdef TINYUSB_NEED_POLLING_TASK
|
||||
// Manual call tud_task since it isn't called by Core's background
|
||||
TinyUSBDevice.task();
|
||||
#endif
|
||||
void loop()
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -70,7 +61,8 @@ void loop() {
|
|||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and
|
||||
// return number of copied bytes (must be multiple of block size)
|
||||
int32_t ram0_read_cb(uint32_t lba, void* buffer, uint32_t bufsize) {
|
||||
int32_t ram0_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
uint8_t const* addr = msc_disk0[lba];
|
||||
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.
|
||||
// Process data in buffer to disk's storage and
|
||||
// return number of written bytes (must be multiple of block size)
|
||||
int32_t ram0_write_cb(uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
|
||||
int32_t ram0_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
uint8_t* addr = msc_disk0[lba];
|
||||
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).
|
||||
// used to flush any pending cache.
|
||||
void ram0_flush_cb(void) {
|
||||
void ram0_flush_cb (void)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +95,8 @@ void ram0_flush_cb(void) {
|
|||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and
|
||||
// return number of copied bytes (must be multiple of block size)
|
||||
int32_t ram1_read_cb(uint32_t lba, void* buffer, uint32_t bufsize) {
|
||||
int32_t ram1_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
uint8_t const* addr = msc_disk1[lba];
|
||||
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.
|
||||
// Process data in buffer to disk's storage and
|
||||
// return number of written bytes (must be multiple of block size)
|
||||
int32_t ram1_write_cb(uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
|
||||
int32_t ram1_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
uint8_t* addr = msc_disk1[lba];
|
||||
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).
|
||||
// used to flush any pending cache.
|
||||
void ram1_flush_cb(void) {
|
||||
void ram1_flush_cb (void)
|
||||
{
|
||||
// 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
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
||||
// 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");
|
||||
|
||||
|
|
@ -39,18 +37,15 @@ void setup()
|
|||
usb_msc.setUnitReady(false);
|
||||
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();
|
||||
}
|
||||
|
||||
Serial.begin(115200);
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
|
||||
Serial.println("Adafruit TinyUSB Mass Storage SD Card example");
|
||||
|
||||
Serial.println("\nInitializing SD card...");
|
||||
|
||||
if ( !card.init(SPI_HALF_SPEED, chipSelect) ) {
|
||||
if ( !card.init(SPI_HALF_SPEED, chipSelect) )
|
||||
{
|
||||
Serial.println("initialization failed. Things to check:");
|
||||
Serial.println("* is a card inserted?");
|
||||
Serial.println("* is your wiring correct?");
|
||||
|
|
@ -76,14 +71,16 @@ void setup()
|
|||
usb_msc.setUnitReady(true);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
void loop()
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and
|
||||
// return number of copied bytes (must be multiple of block size)
|
||||
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) {
|
||||
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
(void) bufsize;
|
||||
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.
|
||||
// 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) {
|
||||
int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
(void) bufsize;
|
||||
return card.writeBlock(lba, buffer) ? 512 : -1;
|
||||
}
|
||||
|
||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||
// used to flush any pending cache.
|
||||
void msc_flush_cb (void) {
|
||||
void msc_flush_cb (void)
|
||||
{
|
||||
// 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
|
||||
* - SdFat https://github.com/adafruit/SdFat
|
||||
* SdFat Library
|
||||
*/
|
||||
|
||||
#include "SPI.h"
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
#include "SdFat.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// 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
|
||||
const int chipSelect = 10;
|
||||
|
||||
// File system on SD Card
|
||||
SdFat sd;
|
||||
|
||||
SdFile root;
|
||||
SdFile file;
|
||||
|
||||
// USB Mass Storage object
|
||||
Adafruit_USBD_MSC usb_msc;
|
||||
|
||||
// Set to true when PC write to flash
|
||||
bool fs_changed;
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup() {
|
||||
#ifdef LED_BUILTIN
|
||||
void setup()
|
||||
{
|
||||
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
|
||||
usb_msc.setID("Adafruit", "SD Card", "1.0");
|
||||
|
|
@ -85,27 +47,30 @@ void setup() {
|
|||
usb_msc.setUnitReady(false);
|
||||
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();
|
||||
}
|
||||
|
||||
Serial.begin(115200);
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
Serial.println("Adafruit TinyUSB Mass Storage SD Card example");
|
||||
Serial.print("\nInitializing SD card ... ");
|
||||
|
||||
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("- is a card inserted?");
|
||||
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("* is a card inserted?");
|
||||
Serial.println("* is your wiring correct?");
|
||||
Serial.println("* did you change the chipSelect pin to match your shield or module?");
|
||||
while (1) delay(1);
|
||||
}
|
||||
|
||||
// Size in blocks (512 bytes)
|
||||
#if SD_FAT_VERSION >= 20000
|
||||
uint32_t block_count = sd.card()->sectorCount();
|
||||
#else
|
||||
uint32_t block_count = sd.card()->cardSize();
|
||||
#endif
|
||||
|
||||
Serial.print("Volume size (MB): ");
|
||||
Serial.println((block_count/2) / 1024);
|
||||
|
||||
|
|
@ -114,38 +79,91 @@ void setup() {
|
|||
|
||||
// MSC is ready for read/write
|
||||
usb_msc.setUnitReady(true);
|
||||
|
||||
fs_changed = true; // to print contents initially
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// noting to do
|
||||
void loop()
|
||||
{
|
||||
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.
|
||||
// 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) {
|
||||
bool rc = sd.card()->readSectors(lba, (uint8_t*) buffer, bufsize/512);
|
||||
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
#ifdef LED_BUILTIN
|
||||
int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
bool rc;
|
||||
|
||||
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
|
||||
bool rc = sd.card()->writeSectors(lba, buffer, bufsize/512);
|
||||
|
||||
return rc ? 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) {
|
||||
void msc_flush_cb (void)
|
||||
{
|
||||
#if SD_FAT_VERSION >= 20000
|
||||
sd.card()->syncDevice();
|
||||
sd.cacheClear(); // clear file system's cache to force refresh
|
||||
|
||||
#ifdef LED_BUILTIN
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
#else
|
||||
sd.card()->syncBlocks();
|
||||
#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");
|
||||
}
|
||||
|
||||
uint16_t Adafruit_USBD_I2C::getInterfaceDescriptor(uint8_t itfnum_deprecated, uint8_t* buf, uint16_t bufsize) {
|
||||
uint8_t itfnum = 0;
|
||||
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 Adafruit_USBD_I2C::getInterfaceDescriptor(uint8_t itfnum, uint8_t* buf, uint16_t bufsize) {
|
||||
uint8_t desc[] = { TUD_VENDOR_DESCRIPTOR(itfnum, 0, 0x00, 0x80, 64) };
|
||||
uint16_t const len = sizeof(desc);
|
||||
|
||||
if (buf) {
|
||||
if (bufsize < len) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(buf, desc, len);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,13 +88,11 @@
|
|||
class Adafruit_USBD_I2C : public Adafruit_USBD_Interface {
|
||||
public:
|
||||
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 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:
|
||||
TwoWire* _wire;
|
||||
uint8_t _state;
|
||||
|
|
|
|||
|
|
@ -63,13 +63,6 @@ void setup() {
|
|||
|
||||
// init i2c usb with buffer and size
|
||||
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() {
|
||||
|
|
|
|||
|
|
@ -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