diff --git a/.gitignore b/.gitignore index b10336bf..68e95fce 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /.development .idea platformio.ini +.pio/ diff --git a/examples/DualRole/CDC/serial_host_bridge/.metro_m0_tinyusb.only b/examples/DualRole/CDC/serial_host_bridge/.metro_m0_tinyusb.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/CDC/serial_host_bridge/.metro_m4_tinyusb.only b/examples/DualRole/CDC/serial_host_bridge/.metro_m4_tinyusb.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/CDC/serial_host_bridge/.nrf52840.only b/examples/DualRole/CDC/serial_host_bridge/.nrf52840.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/CDC/serial_host_bridge/serial_host_bridge.ino b/examples/DualRole/CDC/serial_host_bridge/serial_host_bridge.ino index 42464a9c..c797db43 100644 --- a/examples/DualRole/CDC/serial_host_bridge/serial_host_bridge.ino +++ b/examples/DualRole/CDC/serial_host_bridge/serial_host_bridge.ino @@ -9,147 +9,142 @@ 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_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" */ -// 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_USB_HOST_DP -#define PIN_USB_HOST_DP 16 +// 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 -// 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 - -// USB Host object -Adafruit_USBH_Host USBHost; +// USBHost is defined in usbh_helper.h +#include "usbh_helper.h" // CDC Host object -Adafruit_USBH_CDC SerialHost; - -//--------------------------------------------------------------------+ -// Setup and Loop on Core0 -//--------------------------------------------------------------------+ +Adafruit_USBH_CDC SerialHost; -void setup() { - Serial.begin(115200); - // while ( !Serial ) delay(10); // wait for native usb - - Serial.println("TinyUSB Host Serial Echo Example"); -} - -void loop() -{ +// forward Seral <-> SerialHost +void forward_serial(void) { 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 //--------------------------------------------------------------------+ -// Setup and Loop on Core1 +// Using Host shield MAX3421E controller //--------------------------------------------------------------------+ -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 USE_FREERTOS +void usbhost_rtos_task(void *param) { + (void) param; + while (1) { + USBHost.task(); } +} -#ifdef PIN_5V_EN - pinMode(PIN_5V_EN, OUTPUT); +void create_usbhost_rtos_task(void) { + const uint32_t usbh_stack_size = 200; + xTaskCreate(usbhost_rtos_task, "usbh", usbh_stack_size, NULL, TASK_PRIO_HIGH, NULL); +} +#endif - // power off first - digitalWrite(PIN_5V_EN, 1-PIN_5V_EN_STATE); - delay(1); +void setup() { + Serial.begin(115200); + + // init host stack on controller (rhport) 1 + USBHost.begin(1); - // power on - digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE); - delay(10); + // Initialize SerialHost + SerialHost.begin(115200); + +#ifdef USE_FREERTOS + create_usbhost_rtos_task(); #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; +// while ( !Serial ) delay(10); // wait for native usb + Serial.println("TinyUSB Host Serial Echo Example"); +} + +void loop() { +#ifndef USE_FREERTOS + USBHost.task(); #endif - USBHost.configure_pio_usb(1, &pio_cfg); + 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(); // 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(); - - // periodically flush SerialHost if connected - if ( SerialHost && SerialHost.connected() ) { - SerialHost.flush(); - } } +#endif + //--------------------------------------------------------------------+ // TinyUSB Host callbacks //--------------------------------------------------------------------+ @@ -169,4 +164,4 @@ void tuh_cdc_umount_cb(uint8_t idx) { Serial.println("SerialHost is disconnected"); } -} \ No newline at end of file +} diff --git a/examples/DualRole/CDC/serial_host_bridge/usbh_helper.h b/examples/DualRole/CDC/serial_host_bridge/usbh_helper.h new file mode 100644 index 00000000..1a77a1fc --- /dev/null +++ b/examples/DualRole/CDC/serial_host_bridge/usbh_helper.h @@ -0,0 +1,101 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#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 + #include "SPI.h" + // USB Host using MAX3421E: SPI, CS, INT + Adafruit_USBH_Host USBHost(&SPI, 10, 9); +#else + Adafruit_USBH_Host USBHost; +#endif + +#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 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_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 diff --git a/examples/DualRole/HID/hid_device_report/.metro_m0_tinyusb.only b/examples/DualRole/HID/hid_device_report/.metro_m0_tinyusb.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/HID/hid_device_report/.metro_m4_tinyusb.only b/examples/DualRole/HID/hid_device_report/.metro_m4_tinyusb.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/HID/hid_device_report/.nrf52840.only b/examples/DualRole/HID/hid_device_report/.nrf52840.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/HID/hid_device_report/hid_device_report.ino b/examples/DualRole/HID/hid_device_report/hid_device_report.ino index 0b7bc1dc..2abe49ab 100644 --- a/examples/DualRole/HID/hid_device_report/hid_device_report.ino +++ b/examples/DualRole/HID/hid_device_report/hid_device_report.ino @@ -11,95 +11,64 @@ /* 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) + * - 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: - * - [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 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 */ -// pio-usb is required for rp2040 host -#include "pio_usb.h" -#include "Adafruit_TinyUSB.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 - -// Language ID: English -#define LANGUAGE_ID 0x0409 - -// USB Host object -Adafruit_USBH_Host USBHost; +// USBHost is defined in usbh_helper.h +#include "usbh_helper.h" +#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 //--------------------------------------------------------------------+ -// Setup and Loop on Core0 +// Using Host shield MAX3421E controller //--------------------------------------------------------------------+ - -void setup() -{ +void setup() { Serial.begin(115200); - while ( !Serial ) delay(10); // wait for native usb - Serial.println("TinyUSB Dual Device Info Example"); + // 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() -{ +void loop() { + USBHost.task(); Serial.flush(); } +#elif defined(ARDUINO_ARCH_RP2040) //--------------------------------------------------------------------+ -// Setup and Loop on Core1 +// For RP2040 use both core0 for device stack, core1 for host stack //--------------------------------------------------------------------+ -void setup1() { +//------------- Core0 -------------// +void setup() { + Serial.begin(115200); //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_5V_EN - pinMode(PIN_5V_EN, OUTPUT); - digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE); -#endif + Serial.println("TinyUSB Dual: HID Device Report Example"); +} - 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 +void loop() { + Serial.flush(); +} - USBHost.configure_pio_usb(1, &pio_cfg); +//------------- 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 @@ -107,11 +76,12 @@ void setup1() { USBHost.begin(1); } -void loop1() -{ +void loop1() { USBHost.task(); } +#endif + extern "C" { // Invoked when device with hid interface is mounted diff --git a/examples/DualRole/HID/hid_device_report/usbh_helper.h b/examples/DualRole/HID/hid_device_report/usbh_helper.h new file mode 100644 index 00000000..1a77a1fc --- /dev/null +++ b/examples/DualRole/HID/hid_device_report/usbh_helper.h @@ -0,0 +1,101 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#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 + #include "SPI.h" + // USB Host using MAX3421E: SPI, CS, INT + Adafruit_USBH_Host USBHost(&SPI, 10, 9); +#else + Adafruit_USBH_Host USBHost; +#endif + +#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 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_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 diff --git a/examples/DualRole/HID/hid_mouse_log_filter/.metro_m0_tinyusb.only b/examples/DualRole/HID/hid_mouse_log_filter/.metro_m0_tinyusb.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/HID/hid_mouse_log_filter/.metro_m4_tinyusb.only b/examples/DualRole/HID/hid_mouse_log_filter/.metro_m4_tinyusb.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/HID/hid_mouse_log_filter/.nrf52840.only b/examples/DualRole/HID/hid_mouse_log_filter/.nrf52840.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/HID/hid_mouse_log_filter/hid_mouse_log_filter.ino b/examples/DualRole/HID/hid_mouse_log_filter/hid_mouse_log_filter.ino index 10ac3c69..6e5956dd 100644 --- a/examples/DualRole/HID/hid_mouse_log_filter/hid_mouse_log_filter.ino +++ b/examples/DualRole/HID/hid_mouse_log_filter/hid_mouse_log_filter.ino @@ -10,123 +10,85 @@ 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) + * - 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) * - * Example sketch receive mouse report from host interface (from e.g consumer mouse) + * 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). - * - * 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" */ -// pio-usb is required for rp2040 host -#include "pio_usb.h" -#include "Adafruit_TinyUSB.h" -#include - -// 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 - -// Language ID: English -#define LANGUAGE_ID 0x0409 - -// USB Host object -Adafruit_USBH_Host USBHost; +// 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() +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_MOUSE, 2, false); -/* Adjustable parameters for the log_filter() method. Adjust for each user (would be ideal to have this - * adjustable w/o recompiling - */ +/* 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 -//--------------------------------------------------------------------+ -// Setup and Loop on Core0 -//--------------------------------------------------------------------+ - -void setup() -{ +void setup() { Serial.begin(115200); usb_hid.begin(); +#ifndef ARDUINO_ARCH_RP2040 + // 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"); } -void loop() -{ +#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 +//--------------------------------------------------------------------+ +// Using Host shield MAX3421E controller +//--------------------------------------------------------------------+ +void loop() { + USBHost.task(); Serial.flush(); } +#elif defined(ARDUINO_ARCH_RP2040) //--------------------------------------------------------------------+ -// Setup and Loop on Core1 +// For RP2040 use both core0 for device stack, core1 for host stack //--------------------------------------------------------------------+ -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_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 +void loop() { + Serial.flush(); +} - USBHost.configure_pio_usb(1, &pio_cfg); +//------------- 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 @@ -134,12 +96,15 @@ void setup1() { USBHost.begin(1); } -void loop1() -{ +void loop1() { USBHost.task(); } +#endif +//--------------------------------------------------------------------+ +// TinyUSB Host callbacks +//--------------------------------------------------------------------+ extern "C" { @@ -192,18 +157,12 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons * 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 - { +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; } } @@ -211,7 +170,7 @@ int8_t log_filter(int8_t val) /* * Adjust HID report by applying log_filter */ -void filter_report(hid_mouse_report_t const* report) { +void filter_report(hid_mouse_report_t const *report) { int8_t old_x = report->x; int8_t old_y = report->y; @@ -222,5 +181,5 @@ void filter_report(hid_mouse_report_t const* report) { //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)); - + } diff --git a/examples/DualRole/HID/hid_mouse_log_filter/usbh_helper.h b/examples/DualRole/HID/hid_mouse_log_filter/usbh_helper.h new file mode 100644 index 00000000..1a77a1fc --- /dev/null +++ b/examples/DualRole/HID/hid_mouse_log_filter/usbh_helper.h @@ -0,0 +1,101 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#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 + #include "SPI.h" + // USB Host using MAX3421E: SPI, CS, INT + Adafruit_USBH_Host USBHost(&SPI, 10, 9); +#else + Adafruit_USBH_Host USBHost; +#endif + +#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 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_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 diff --git a/examples/DualRole/HID/hid_mouse_tremor_filter/.metro_m0_tinyusb.only b/examples/DualRole/HID/hid_mouse_tremor_filter/.metro_m0_tinyusb.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/HID/hid_mouse_tremor_filter/.metro_m4_tinyusb.only b/examples/DualRole/HID/hid_mouse_tremor_filter/.metro_m4_tinyusb.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/HID/hid_mouse_tremor_filter/.nrf52840.only b/examples/DualRole/HID/hid_mouse_tremor_filter/.nrf52840.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/HID/hid_mouse_tremor_filter/hid_mouse_tremor_filter.ino b/examples/DualRole/HID/hid_mouse_tremor_filter/hid_mouse_tremor_filter.ino index 9145fd37..cbe1c79d 100644 --- a/examples/DualRole/HID/hid_mouse_tremor_filter/hid_mouse_tremor_filter.ino +++ b/examples/DualRole/HID/hid_mouse_tremor_filter/hid_mouse_tremor_filter.ino @@ -9,51 +9,35 @@ 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) - * - * 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". + * - 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: - * - [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" + * - 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 */ -// pio-usb is required for rp2040 host -#include "pio_usb.h" -#include "Adafruit_TinyUSB.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 - -// Language ID: English -#define LANGUAGE_ID 0x0409 +/* 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". + */ -// USB Host object -Adafruit_USBH_Host USBHost; +// 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() +uint8_t const desc_hid_report[] = { + TUD_HID_REPORT_DESC_MOUSE() }; // USB HID object. For ESP32 these values cannot be changed after this declaration @@ -73,67 +57,49 @@ typedef struct { 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); -//--------------------------------------------------------------------+ -// Setup and Loop on Core0 -//--------------------------------------------------------------------+ +void filter_report(hid_mouse_report_t const *report); -void setup() -{ + +void setup() { Serial.begin(115200); usb_hid.begin(); coeffs[0] = butterworth_lowpass(CUTOFF_FREQUENCY, SAMPLING_FREQUENCY); coeffs[1] = butterworth_lowpass(CUTOFF_FREQUENCY, SAMPLING_FREQUENCY); +#ifndef ARDUINO_ARCH_RP2040 + // 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"); } -void loop() -{ + +#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 +//--------------------------------------------------------------------+ +// Using Host shield MAX3421E controller +//--------------------------------------------------------------------+ +void loop() { + USBHost.task(); Serial.flush(); } +#elif defined(ARDUINO_ARCH_RP2040) //--------------------------------------------------------------------+ -// Setup and Loop on Core1 +// For RP2040 use both core0 for device stack, core1 for host stack //--------------------------------------------------------------------+ +void loop() { + Serial.flush(); +} +//------------- 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_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); + // 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 @@ -141,12 +107,15 @@ void setup1() { USBHost.begin(1); } -void loop1() -{ +void loop1() { USBHost.task(); } +#endif +//--------------------------------------------------------------------+ +// TinyUSB Host callbacks +//--------------------------------------------------------------------+ extern "C" { @@ -214,14 +183,15 @@ butterworth_coeffs_t butterworth_lowpass(float cutoff_frequency, float sampling_ } 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); + 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) { +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 }; diff --git a/examples/DualRole/HID/hid_mouse_tremor_filter/usbh_helper.h b/examples/DualRole/HID/hid_mouse_tremor_filter/usbh_helper.h new file mode 100644 index 00000000..1a77a1fc --- /dev/null +++ b/examples/DualRole/HID/hid_mouse_tremor_filter/usbh_helper.h @@ -0,0 +1,101 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#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 + #include "SPI.h" + // USB Host using MAX3421E: SPI, CS, INT + Adafruit_USBH_Host USBHost(&SPI, 10, 9); +#else + Adafruit_USBH_Host USBHost; +#endif + +#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 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_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 diff --git a/examples/DualRole/HID/hid_remapper/.metro_m0_tinyusb.only b/examples/DualRole/HID/hid_remapper/.metro_m0_tinyusb.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/HID/hid_remapper/.metro_m4_tinyusb.only b/examples/DualRole/HID/hid_remapper/.metro_m4_tinyusb.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/HID/hid_remapper/.nrf52840.only b/examples/DualRole/HID/hid_remapper/.nrf52840.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/HID/hid_remapper/hid_remapper.ino b/examples/DualRole/HID/hid_remapper/hid_remapper.ino index b23e3303..a3231546 100644 --- a/examples/DualRole/HID/hid_remapper/hid_remapper.ino +++ b/examples/DualRole/HID/hid_remapper/hid_remapper.ino @@ -9,116 +9,79 @@ 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) + * - 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) * - * Example sketch receive keyboard report from host interface (from e.g consumer keyboard) + * 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) * 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_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" */ -// pio-usb is required for rp2040 host -#include "pio_usb.h" -#include "Adafruit_TinyUSB.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 - -// Language ID: English -#define LANGUAGE_ID 0x0409 - -// USB Host object -Adafruit_USBH_Host USBHost; +// 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_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(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_KEYBOARD, 2, false); -//--------------------------------------------------------------------+ -// Setup and Loop on Core0 -//--------------------------------------------------------------------+ -void setup() -{ +void setup() { Serial.begin(115200); usb_hid.begin(); - //while ( !Serial ) delay(10); // wait for native usb +#ifndef ARDUINO_ARCH_RP2040 + // 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"); } -void loop() -{ - +#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 +//--------------------------------------------------------------------+ +// Using Host shield MAX3421E controller +//--------------------------------------------------------------------+ +void loop() { + USBHost.task(); } +#elif defined(ARDUINO_ARCH_RP2040) //--------------------------------------------------------------------+ -// Setup and Loop on Core1 +// For RP2040 use both core0 for device stack, core1 for host stack //--------------------------------------------------------------------+ -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_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 +void loop() { + // nothing to do +} - USBHost.configure_pio_usb(1, &pio_cfg); +//------------- 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 @@ -126,10 +89,16 @@ 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. @@ -137,8 +106,8 @@ void loop1() // 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); @@ -159,12 +128,11 @@ 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; @@ -175,16 +143,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(); } @@ -196,3 +164,5 @@ 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"); } } + +} diff --git a/examples/DualRole/HID/hid_remapper/usbh_helper.h b/examples/DualRole/HID/hid_remapper/usbh_helper.h new file mode 100644 index 00000000..1a77a1fc --- /dev/null +++ b/examples/DualRole/HID/hid_remapper/usbh_helper.h @@ -0,0 +1,101 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#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 + #include "SPI.h" + // USB Host using MAX3421E: SPI, CS, INT + Adafruit_USBH_Host USBHost(&SPI, 10, 9); +#else + Adafruit_USBH_Host USBHost; +#endif + +#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 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_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 diff --git a/examples/DualRole/MassStorage/msc_data_logger/.metro_m0_tinyusb.only b/examples/DualRole/MassStorage/msc_data_logger/.metro_m0_tinyusb.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/MassStorage/msc_data_logger/.metro_m4_tinyusb.only b/examples/DualRole/MassStorage/msc_data_logger/.metro_m4_tinyusb.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/MassStorage/msc_data_logger/.nrf52840.only b/examples/DualRole/MassStorage/msc_data_logger/.nrf52840.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/MassStorage/msc_data_logger/msc_data_logger.ino b/examples/DualRole/MassStorage/msc_data_logger/msc_data_logger.ino index 031a2391..b21195e7 100644 --- a/examples/DualRole/MassStorage/msc_data_logger/msc_data_logger.ino +++ b/examples/DualRole/MassStorage/msc_data_logger/msc_data_logger.ino @@ -11,47 +11,43 @@ /* 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 will log CPU temperature periodically (ms,value) to USB thumbdrive + * - 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: - * - [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 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 */ -// pio-usb is required for rp2040 host -#include "pio_usb.h" - -// SdFat is required for using Adafruit_USBH_MSC_SdFatDevice -#include "SdFat.h" - -// TinyUSB lib -#include "Adafruit_TinyUSB.h" +/* Example sketch read analog pin (default A0) and log it to LOG_FILE on the msc device + * every LOG_INTERVAL ms. */ -// Pin D+ for host, D- = D+ + 1 -#ifndef PIN_USB_HOST_DP -#define PIN_USB_HOST_DP 16 +// 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 -// 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 +// SdFat is required for using Adafruit_USBH_MSC_SdFatDevice +#include "SdFat.h" +// USBHost is defined in usbh_helper.h +#include "usbh_helper.h" #define LOG_FILE "cpu_temp.csv" #define LOG_INTERVAL 5000 -// USB Host object -Adafruit_USBH_Host USBHost; +// Analog pin for reading +const int analogPin = A0; // USB Host MSC Block Device object which implemented API for use with SdFat Adafruit_USBH_MSC_BlockDevice msc_block_dev; @@ -63,25 +59,16 @@ File32 f_log; // if file system is successfully mounted on usb block device volatile bool is_mounted = false; -//--------------------------------------------------------------------+ -// 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() -{ +void data_log(void) { if (!is_mounted) { // nothing to do - delay(1000); + return; + } + + static uint32_t last_ms = 0; + uint32_t ms = millis(); + + if ( ms - last_ms < LOG_INTERVAL ) { return; } @@ -92,61 +79,75 @@ void loop() if (!f_log) { Serial.println("Cannot create file: " LOG_FILE); - }else { - float cpu_temp = analogReadTemp(); - uint32_t ms = millis(); + } else { + int value = analogRead(analogPin); - Serial.printf("%u,%.02f\r\n", millis(), cpu_temp); - f_log.printf("%u,%.02f\r\n", millis(), cpu_temp); + Serial.printf("%u,%d\r\n", ms, value); + f_log.printf("%u,%d\r\n", ms, value); f_log.close(); } - delay(LOG_INTERVAL); + last_ms = ms; + Serial.flush(); } -//--------------------------------------------------------------------+ -// 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 USE_FREERTOS +void usbhost_rtos_task(void *param) { + (void) param; + while (1) { + USBHost.task(); } +} + +void create_usbhost_rtos_task(void) { + const uint32_t usbh_stack_size = 400; + xTaskCreate(usbhost_rtos_task, "usbh", usbh_stack_size, NULL, TASK_PRIO_HIGH, NULL); +} +#endif + +void setup() { + Serial.begin(115200); + + pinMode(LED_BUILTIN, OUTPUT); -#ifdef PIN_5V_EN - pinMode(PIN_5V_EN, OUTPUT); - digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE); +#ifndef ARDUINO_ARCH_RP2040 + // init host stack on controller (rhport) 1 + // For rp2040: this is called in core1's setup1() + USBHost.begin(1); +#endif + +#ifdef USE_FREERTOS + create_usbhost_rtos_task(); #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; +// 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 +//--------------------------------------------------------------------+ +void loop() { +#ifndef USE_FREERTOS + USBHost.task(); #endif + data_log(); +} - USBHost.configure_pio_usb(1, &pio_cfg); +#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(); // run host stack on controller (rhport) 1 // Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the @@ -154,51 +155,59 @@ 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; -// Invoked when device is mounted (configured) -void tuh_mount_cb (uint8_t daddr) + // 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; +} + +extern "C" { + +// Invoked when device is mounted (configured) +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 @@ -209,17 +218,4 @@ 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; } - diff --git a/examples/DualRole/MassStorage/msc_data_logger/usbh_helper.h b/examples/DualRole/MassStorage/msc_data_logger/usbh_helper.h new file mode 100644 index 00000000..1a77a1fc --- /dev/null +++ b/examples/DualRole/MassStorage/msc_data_logger/usbh_helper.h @@ -0,0 +1,101 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#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 + #include "SPI.h" + // USB Host using MAX3421E: SPI, CS, INT + Adafruit_USBH_Host USBHost(&SPI, 10, 9); +#else + Adafruit_USBH_Host USBHost; +#endif + +#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 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_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 diff --git a/examples/DualRole/MassStorage/msc_file_explorer/.metro_m0_tinyusb.only b/examples/DualRole/MassStorage/msc_file_explorer/.metro_m0_tinyusb.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/MassStorage/msc_file_explorer/.metro_m4_tinyusb.only b/examples/DualRole/MassStorage/msc_file_explorer/.metro_m4_tinyusb.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/MassStorage/msc_file_explorer/.nrf52840.only b/examples/DualRole/MassStorage/msc_file_explorer/.nrf52840.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/MassStorage/msc_file_explorer/msc_file_explorer.ino b/examples/DualRole/MassStorage/msc_file_explorer/msc_file_explorer.ino index a857e817..a9968d23 100644 --- a/examples/DualRole/MassStorage/msc_file_explorer/msc_file_explorer.ino +++ b/examples/DualRole/MassStorage/msc_file_explorer/msc_file_explorer.ino @@ -9,43 +9,28 @@ 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) + * - 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: - * - [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 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 */ -// pio-usb is required for rp2040 host -#include "pio_usb.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_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 - -// USB Host object -Adafruit_USBH_Host USBHost; +// USBHost is defined in usbh_helper.h +#include "usbh_helper.h" // USB Host MSC Block Device object which implemented API for use with SdFat Adafruit_USBH_MSC_BlockDevice msc_block_dev; @@ -56,64 +41,40 @@ FatVolume fatfs; // if file system is successfully mounted on usb block device bool is_mounted = false; -//--------------------------------------------------------------------+ -// Setup and Loop on Core0 -//--------------------------------------------------------------------+ - -void setup() -{ +void setup() { Serial.begin(115200); - //while ( !Serial ) delay(10); // wait for native usb +#ifndef ARDUINO_ARCH_RP2040 + // 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"); } -void loop() -{ + +#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 +//--------------------------------------------------------------------+ +// Using Host shield MAX3421E controller +//--------------------------------------------------------------------+ +void loop() { + USBHost.task(); + Serial.flush(); } +#elif defined(ARDUINO_ARCH_RP2040) //--------------------------------------------------------------------+ -// Setup and Loop on Core1 +// For RP2040 use both core0 for device stack, core1 for host stack //--------------------------------------------------------------------+ +void loop() { +} +//------------- 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_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); + // 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 @@ -121,30 +82,32 @@ 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) -{ +void tuh_msc_mount_cb(uint8_t dev_addr) { + Serial.printf("Device attached, address = %d\r\n", dev_addr); + // Initialize block device with MSC device address msc_block_dev.begin(dev_addr); @@ -159,9 +122,8 @@ 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) -{ - (void) dev_addr; +void tuh_msc_umount_cb(uint8_t dev_addr) { + Serial.printf("Device removed, address = %d\r\n", dev_addr); // unmount file system is_mounted = false; @@ -171,3 +133,4 @@ void tuh_msc_umount_cb(uint8_t dev_addr) msc_block_dev.end(); } +} \ No newline at end of file diff --git a/examples/DualRole/MassStorage/msc_file_explorer/usbh_helper.h b/examples/DualRole/MassStorage/msc_file_explorer/usbh_helper.h new file mode 100644 index 00000000..1a77a1fc --- /dev/null +++ b/examples/DualRole/MassStorage/msc_file_explorer/usbh_helper.h @@ -0,0 +1,101 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#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 + #include "SPI.h" + // USB Host using MAX3421E: SPI, CS, INT + Adafruit_USBH_Host USBHost(&SPI, 10, 9); +#else + Adafruit_USBH_Host USBHost; +#endif + +#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 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_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 diff --git a/examples/DualRole/Simple/device_info/.metro_m0_tinyusb.only b/examples/DualRole/Simple/device_info/.metro_m0_tinyusb.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/Simple/device_info/.metro_m4_tinyusb.only b/examples/DualRole/Simple/device_info/.metro_m4_tinyusb.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/Simple/device_info/.nrf52840.only b/examples/DualRole/Simple/device_info/.nrf52840.only new file mode 100644 index 00000000..e69de29b diff --git a/examples/DualRole/Simple/device_info/device_info.ino b/examples/DualRole/Simple/device_info/device_info.ino index d15c2df2..c13d8dc8 100644 --- a/examples/DualRole/Simple/device_info/device_info.ino +++ b/examples/DualRole/Simple/device_info/device_info.ino @@ -11,16 +11,23 @@ /* 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) + * - 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: - * - [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" - * - * RP2040 host stack will get device descriptors of attached devices and print it out via + * - 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: @@ -41,30 +48,12 @@ * */ -// pio-usb is required for rp2040 host -#include "pio_usb.h" -#include "Adafruit_TinyUSB.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 +// USBHost is defined in usbh_helper.h +#include "usbh_helper.h" // Language ID: English #define LANGUAGE_ID 0x0409 -// USB Host object -Adafruit_USBH_Host USBHost; - typedef struct { tusb_desc_device_t desc_device; uint16_t manufacturer[32]; @@ -76,65 +65,43 @@ typedef struct { // CFG_TUH_DEVICE_MAX is defined by tusb_config header dev_info_t dev_info[CFG_TUH_DEVICE_MAX] = { 0 }; -//--------------------------------------------------------------------+ -// 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 +#ifndef ARDUINO_ARCH_RP2040 + // 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) //--------------------------------------------------------------------+ -// Setup and Loop on Core1 +// For RP2040 use both core0 for device stack, core1 for host stack //--------------------------------------------------------------------+ -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_5V_EN - pinMode(PIN_5V_EN, OUTPUT); - digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE); -#endif +//------------- Core0 -------------// +void loop() { - 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); +//------------- 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 @@ -142,27 +109,29 @@ void setup1() { USBHost.begin(1); } -void loop1() -{ +void loop1() { USBHost.task(); + Serial.flush(); } +#endif //--------------------------------------------------------------------+ // TinyUSB Host callbacks //--------------------------------------------------------------------+ -void print_device_descriptor(tuh_xfer_t* xfer); +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++ ) { + 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 ) { + 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); + (char *) dev->manufacturer, (char *) dev->product); no_device = false; } @@ -174,11 +143,10 @@ void print_lsusb(void) { } // Invoked when device is mounted (configured) -void tuh_mount_cb (uint8_t daddr) -{ +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_info_t *dev = &dev_info[daddr - 1]; dev->mounted = true; // Get Device Descriptor @@ -186,27 +154,24 @@ void tuh_mount_cb (uint8_t daddr) } /// Invoked when device is unmounted (bus reset/unplugged) -void tuh_umount_cb(uint8_t daddr) -{ +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_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 ) - { +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; + 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"); @@ -223,23 +188,26 @@ void print_device_descriptor(tuh_xfer_t* xfer) // 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)) ) { + 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((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))) { + 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((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))) { + 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((char *) dev->serial); } Serial.printf("\r\n"); @@ -255,7 +223,7 @@ void print_device_descriptor(tuh_xfer_t* xfer) 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; + (void) utf8_len; // Get the UTF-16 length out of the data itself. for (size_t i = 0; i < utf16_len; i++) { @@ -263,13 +231,13 @@ static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, ui if (chr < 0x80) { *utf8++ = chr & 0xff; } else if (chr < 0x800) { - *utf8++ = (uint8_t)(0xC0 | (chr >> 6 & 0x1F)); - *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F)); + *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)); + *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. } @@ -297,6 +265,5 @@ void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len) { 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'; + ((uint8_t *) temp_buf)[utf8_len] = '\0'; } - diff --git a/examples/DualRole/Simple/device_info/usbh_helper.h b/examples/DualRole/Simple/device_info/usbh_helper.h new file mode 100644 index 00000000..1a77a1fc --- /dev/null +++ b/examples/DualRole/Simple/device_info/usbh_helper.h @@ -0,0 +1,101 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#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 + #include "SPI.h" + // USB Host using MAX3421E: SPI, CS, INT + Adafruit_USBH_Host USBHost(&SPI, 10, 9); +#else + Adafruit_USBH_Host USBHost; +#endif + +#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 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_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 diff --git a/examples/MassStorage/msc_ramdisk/msc_ramdisk.ino b/examples/MassStorage/msc_ramdisk/msc_ramdisk.ino index 53183fb3..26d2a153 100644 --- a/examples/MassStorage/msc_ramdisk/msc_ramdisk.ino +++ b/examples/MassStorage/msc_ramdisk/msc_ramdisk.ino @@ -35,8 +35,7 @@ Adafruit_USBD_MSC usb_msc; // the setup function runs once when you press reset or power the board -void setup() -{ +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 diff --git a/src/arduino/Adafruit_TinyUSB_API.cpp b/src/arduino/Adafruit_TinyUSB_API.cpp index 15cca0d0..b0afda8a 100644 --- a/src/arduino/Adafruit_TinyUSB_API.cpp +++ b/src/arduino/Adafruit_TinyUSB_API.cpp @@ -57,20 +57,34 @@ void TinyUSB_Device_FlushCDC(void) { // Debug log with Serial1 #if CFG_TUSB_DEBUG && defined(CFG_TUSB_DEBUG_PRINTF) +// #define USE_SEGGER_RTT + +#ifdef USE_SEGGER_RTT +#include "SEGGER_RTT/RTT/SEGGER_RTT.h" +#endif + __attribute__((used)) int CFG_TUSB_DEBUG_PRINTF(const char *__restrict format, ...) { +#ifndef USE_SEGGER_RTT static bool ser1_inited = false; if (!ser1_inited) { ser1_inited = true; Serial1.begin(115200); } +#endif char buf[256]; int len; va_list ap; va_start(ap, format); len = vsnprintf(buf, sizeof(buf), format, ap); + +#ifdef USE_SEGGER_RTT + SEGGER_RTT_Write(0, buf, len); +#else Serial1.write(buf); +#endif + va_end(ap); return len; } diff --git a/src/arduino/Adafruit_USBH_Host.cpp b/src/arduino/Adafruit_USBH_Host.cpp index 1add7a75..d5bdab6c 100644 --- a/src/arduino/Adafruit_USBH_Host.cpp +++ b/src/arduino/Adafruit_USBH_Host.cpp @@ -29,7 +29,24 @@ #include "Adafruit_TinyUSB_API.h" #include "Adafruit_USBH_Host.h" -Adafruit_USBH_Host::Adafruit_USBH_Host(void) {} +#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 +static void max3421_isr(void); +#endif + +Adafruit_USBH_Host *Adafruit_USBH_Host::_instance = NULL; + +Adafruit_USBH_Host::Adafruit_USBH_Host(void) { + Adafruit_USBH_Host::_instance = this; + _spi = NULL; + _cs = _intr = -1; +} + +Adafruit_USBH_Host::Adafruit_USBH_Host(SPIClass *spi, int8_t cs, int8_t intr) { + Adafruit_USBH_Host::_instance = this; + _spi = spi; + _cs = cs; + _intr = intr; +} bool Adafruit_USBH_Host::configure(uint8_t rhport, uint32_t cfg_id, const void *cfg_param) { @@ -43,7 +60,26 @@ bool Adafruit_USBH_Host::configure_pio_usb(uint8_t rhport, } #endif -bool Adafruit_USBH_Host::begin(uint8_t rhport) { return tuh_init(rhport); } +bool Adafruit_USBH_Host::begin(uint8_t rhport) { +#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 + if (_spi == NULL || _intr < 0 || _cs < 0) { + return false; + } + + // CS pin + pinMode(_cs, OUTPUT); + digitalWrite(_cs, HIGH); + + // SPI init + SPI.begin(); + + // Interrupt pin + pinMode(_intr, INPUT_PULLUP); + attachInterrupt(_intr, max3421_isr, FALLING); +#endif + + return tuh_init(rhport); +} void Adafruit_USBH_Host::task(void) { tuh_task(); } @@ -76,4 +112,103 @@ TU_ATTR_WEAK void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, (void)report; (void)len; } + +//--------------------------------------------------------------------+ +// USB Host using MAX3421E +//--------------------------------------------------------------------+ +#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 + +static void max3421_isr(void) { tuh_int_handler(1); } + +extern "C" { + +void tuh_max3421_spi_cs_api(uint8_t rhport, bool active) { + (void)rhport; + if (!Adafruit_USBH_Host::_instance) { + return; + } + + digitalWrite(Adafruit_USBH_Host::_instance->_cs, active ? LOW : HIGH); +} + +bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const *tx_buf, + size_t tx_len, uint8_t *rx_buf, size_t rx_len) { + (void)rhport; + + if (!Adafruit_USBH_Host::_instance) { + return false; + } + Adafruit_USBH_Host *host = Adafruit_USBH_Host::_instance; + + // MAX3421e max clock is 26MHz + // Depending on mcu ports, it may need to be clipped down +#ifdef ARDUINO_ARCH_SAMD + // SAMD 21/51 can only work reliably at 12MHz + uint32_t const max_clock = 12000000ul; +#else + uint32_t const max_clock = 26000000ul; +#endif + + SPISettings config(max_clock, MSBFIRST, SPI_MODE0); + host->_spi->beginTransaction(config); + + size_t count = 0; + while (count < tx_len || count < rx_len) { + uint8_t data = 0x00; + + if (count < tx_len) { + data = tx_buf[count]; + } + + data = host->_spi->transfer(data); + + if (count < rx_len) { + rx_buf[count] = data; + } + + count++; + } + + host->_spi->endTransaction(); + return true; +} + +void tuh_max3421_int_api(uint8_t rhport, bool enabled) { + (void)rhport; + + if (!Adafruit_USBH_Host::_instance) { + return; + } + +#ifdef ARDUINO_ARCH_SAMD +#ifdef __SAMD51__ + Adafruit_USBH_Host *host = Adafruit_USBH_Host::_instance; + const IRQn_Type irq = + (IRQn_Type)(EIC_0_IRQn + g_APinDescription[host->_intr].ulExtInt); + + if (enabled) { + NVIC_EnableIRQ(irq); + } else { + NVIC_DisableIRQ(irq); + } +#else + if (enabled) { + NVIC_EnableIRQ(EIC_IRQn); + } else { + NVIC_DisableIRQ(EIC_IRQn); + } +#endif + +#elif defined(ARDUINO_NRF52_ADAFRUIT) + if (enabled) { + NVIC_EnableIRQ(GPIOTE_IRQn); + } else { + NVIC_DisableIRQ(GPIOTE_IRQn); + } + +#endif +} +} +#endif + #endif diff --git a/src/arduino/Adafruit_USBH_Host.h b/src/arduino/Adafruit_USBH_Host.h index 3752b952..1a625aef 100644 --- a/src/arduino/Adafruit_USBH_Host.h +++ b/src/arduino/Adafruit_USBH_Host.h @@ -27,16 +27,32 @@ #include "Adafruit_USBD_Interface.h" #include "tusb.h" +#include #ifdef ARDUINO_ARCH_ESP32 #include "esp32-hal-tinyusb.h" #endif +extern "C" { +void tuh_max3421_spi_cs_api(uint8_t rhport, bool active); +bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const *tx_buf, + size_t tx_len, uint8_t *rx_buf, size_t rx_len); +void tuh_max3421_int_api(uint8_t rhport, bool enabled); +} + class Adafruit_USBH_Host { private: + SPIClass *_spi; + int8_t _cs; + int8_t _intr; + public: + // default constructor Adafruit_USBH_Host(void); + // constructor for using MAX3421E (host shield) + Adafruit_USBH_Host(SPIClass *spi, int8_t cs, int8_t intr); + bool configure(uint8_t rhport, uint32_t cfg_id, const void *cfg_param); #ifdef ARDUINO_ARCH_RP2040 @@ -46,6 +62,9 @@ class Adafruit_USBH_Host { bool begin(uint8_t rhport); void task(void); + //------------- internal usage -------------// + static Adafruit_USBH_Host *_instance; + private: // uint16_t const *descrip`tor_string_cb(uint8_t index, uint16_t langid); // @@ -53,14 +72,12 @@ class Adafruit_USBH_Host { // friend uint8_t const *tud_descriptor_configuration_cb(uint8_t index); // friend uint16_t const *tud_descriptor_string_cb(uint8_t index, // uint16_t langid); -}; -// extern Adafruit_USBH_Host TinyUSBHost; -// -//// USBHost has a high chance to conflict with other usb stack -//// only define if supported BSP -// #ifdef USE_TINYUSB -// #define USBHost TinyUSBHost -// #endif + friend void tuh_max3421_spi_cs_api(uint8_t rhport, bool active); + friend bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const *tx_buf, + size_t tx_len, uint8_t *rx_buf, + size_t rx_len); + friend void tuh_max3421_int_api(uint8_t rhport, bool enabled); +}; -#endif /* ADAFRUIT_USBH_HOST_H_ */ +#endif diff --git a/src/arduino/msc/Adafruit_USBH_MSC.cpp b/src/arduino/msc/Adafruit_USBH_MSC.cpp index 9cec5e81..250f1057 100644 --- a/src/arduino/msc/Adafruit_USBH_MSC.cpp +++ b/src/arduino/msc/Adafruit_USBH_MSC.cpp @@ -59,7 +59,9 @@ bool Adafruit_USBH_MSC_BlockDevice::isBusy(void) { return _busy; } bool Adafruit_USBH_MSC_BlockDevice::wait_for_io(void) { while (_busy) { - tuh_task(); + if (tuh_task_event_ready()) { + tuh_task(); + } } return true; diff --git a/src/arduino/ports/nrf/Adafruit_TinyUSB_nrf.cpp b/src/arduino/ports/nrf/Adafruit_TinyUSB_nrf.cpp index 46069e5e..fe8798a2 100644 --- a/src/arduino/ports/nrf/Adafruit_TinyUSB_nrf.cpp +++ b/src/arduino/ports/nrf/Adafruit_TinyUSB_nrf.cpp @@ -68,13 +68,15 @@ static void usb_device_task(void *param) { // 2 is highest for application NVIC_SetPriority(USBD_IRQn, 2); - tusb_init(); + // init device on rhport0 + tud_init(0); usb_hardware_init(); // RTOS forever loop while (1) { tud_task(); + TinyUSB_Device_FlushCDC(); } } diff --git a/src/arduino/ports/nrf/tusb_config_nrf.h b/src/arduino/ports/nrf/tusb_config_nrf.h index 7b9e5711..7aa94266 100644 --- a/src/arduino/ports/nrf/tusb_config_nrf.h +++ b/src/arduino/ports/nrf/tusb_config_nrf.h @@ -34,12 +34,6 @@ extern "C" { //-------------------------------------------------------------------- #define CFG_TUSB_MCU OPT_MCU_NRF5X -#ifdef USE_TINYUSB -#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE -#else -#define CFG_TUSB_RHPORT0_MODE OPT_MODE_NONE -#endif - #define CFG_TUSB_OS OPT_OS_FREERTOS #define CFG_TUSB_MEM_SECTION #define CFG_TUSB_MEM_ALIGN __attribute__((aligned(4))) @@ -48,6 +42,22 @@ extern "C" { #define CFG_TUSB_DEBUG 0 #endif +// For selectively disable device log (when > CFG_TUSB_DEBUG) +// #define CFG_TUD_LOG_LEVEL 3 + +#ifdef USE_TINYUSB +// Enable device stack +#define CFG_TUD_ENABLED 1 + +// Enable host stack with MAX3421E (host shield) +#define CFG_TUH_ENABLED 1 +#define CFG_TUH_MAX3421 1 + +#else +#define CFG_TUD_ENABLED 0 +#define CFG_TUH_ENABLED 0 +#endif + //-------------------------------------------------------------------- // DEVICE CONFIGURATION //-------------------------------------------------------------------- @@ -79,10 +89,54 @@ extern "C" { #ifndef CFG_TUD_VENDOR_RX_BUFSIZE #define CFG_TUD_VENDOR_RX_BUFSIZE 64 #endif + #ifndef CFG_TUD_VENDOR_TX_BUFSIZE #define CFG_TUD_VENDOR_TX_BUFSIZE 64 #endif +//-------------------------------------------------------------------- +// Host Configuration +//-------------------------------------------------------------------- + +// Size of buffer to hold descriptors and other data used for enumeration +#define CFG_TUH_ENUMERATION_BUFSIZE 256 + +// Number of hub devices +#define CFG_TUH_HUB 1 + +// max device support (excluding hub device): 1 hub typically has 4 ports +#define CFG_TUH_DEVICE_MAX (3 * CFG_TUH_HUB + 1) + +// Enable tuh_edpt_xfer() API +// #define CFG_TUH_API_EDPT_XFER 1 + +// Number of mass storage +#define CFG_TUH_MSC 1 + +// Number of HIDs +// typical keyboard + mouse device can have 3,4 HID interfaces +#define CFG_TUH_HID (3 * CFG_TUH_DEVICE_MAX) + +// Number of CDC interfaces +// FTDI and CP210x are not part of CDC class, only to re-use CDC driver API +#define CFG_TUH_CDC 1 +#define CFG_TUH_CDC_FTDI 1 +#define CFG_TUH_CDC_CP210X 1 + +// RX & TX fifo size +#define CFG_TUH_CDC_RX_BUFSIZE 64 +#define CFG_TUH_CDC_TX_BUFSIZE 64 + +// Set Line Control state on enumeration/mounted: +// DTR ( bit 0), RTS (bit 1) +#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03 + +// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t +// bit rate = 115200, 1 stop bit, no parity, 8 bit data width +// This need Pico-PIO-USB at least 0.5.1 +#define CFG_TUH_CDC_LINE_CODING_ON_ENUM \ + { 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } + #ifdef __cplusplus } #endif diff --git a/src/arduino/ports/rp2040/tusb_config_rp2040.h b/src/arduino/ports/rp2040/tusb_config_rp2040.h index 42a00a78..e94d5db3 100644 --- a/src/arduino/ports/rp2040/tusb_config_rp2040.h +++ b/src/arduino/ports/rp2040/tusb_config_rp2040.h @@ -52,6 +52,9 @@ extern "C" { #define CFG_TUSB_DEBUG 0 #endif +// For selectively disable device log (when > CFG_TUSB_DEBUG) +// #define CFG_TUD_LOG_LEVEL 3 + #define CFG_TUSB_MEM_SECTION #define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4) diff --git a/src/arduino/ports/samd/Adafruit_TinyUSB_samd.cpp b/src/arduino/ports/samd/Adafruit_TinyUSB_samd.cpp index a2a890f7..e5aee7bb 100644 --- a/src/arduino/ports/samd/Adafruit_TinyUSB_samd.cpp +++ b/src/arduino/ports/samd/Adafruit_TinyUSB_samd.cpp @@ -112,11 +112,8 @@ void TinyUSB_Port_InitDevice(uint8_t rhport) { NVIC_SetPriority((IRQn_Type)USB_IRQn, 0UL); #endif -#if CFG_TUSB_DEBUG - Serial1.begin(115200); -#endif - - tusb_init(); + // Init port 0 as device + tud_init(0); } void TinyUSB_Port_EnterDFU(void) { diff --git a/src/arduino/ports/samd/tusb_config_samd.h b/src/arduino/ports/samd/tusb_config_samd.h index f001eb02..1a28b63b 100644 --- a/src/arduino/ports/samd/tusb_config_samd.h +++ b/src/arduino/ports/samd/tusb_config_samd.h @@ -38,21 +38,25 @@ extern "C" { #define CFG_TUSB_MCU OPT_MCU_SAMD21 #endif -#ifdef USE_TINYUSB -#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE -#else -#define CFG_TUSB_RHPORT0_MODE OPT_MODE_NONE -#endif - #define CFG_TUSB_OS OPT_OS_NONE #ifndef CFG_TUSB_DEBUG #define CFG_TUSB_DEBUG 0 #endif +// For selectively disable device log (when > CFG_TUSB_DEBUG) +// #define CFG_TUD_LOG_LEVEL 3 + #define CFG_TUSB_MEM_SECTION #define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4) +// Enable device stack +#define CFG_TUD_ENABLED 1 + +// Enable host stack with MAX3421E (host shield) +#define CFG_TUH_ENABLED 1 +#define CFG_TUH_MAX3421 1 + //-------------------------------------------------------------------- // DEVICE CONFIGURATION //-------------------------------------------------------------------- @@ -84,6 +88,49 @@ extern "C" { #define CFG_TUD_VENDOR_RX_BUFSIZE 64 #define CFG_TUD_VENDOR_TX_BUFSIZE 64 +//-------------------------------------------------------------------- +// Host Configuration +//-------------------------------------------------------------------- + +// Size of buffer to hold descriptors and other data used for enumeration +#define CFG_TUH_ENUMERATION_BUFSIZE 256 + +// Number of hub devices +#define CFG_TUH_HUB 1 + +// max device support (excluding hub device): 1 hub typically has 4 ports +#define CFG_TUH_DEVICE_MAX (3 * CFG_TUH_HUB + 1) + +// Enable tuh_edpt_xfer() API +// #define CFG_TUH_API_EDPT_XFER 1 + +// Number of mass storage +#define CFG_TUH_MSC 1 + +// Number of HIDs +// typical keyboard + mouse device can have 3,4 HID interfaces +#define CFG_TUH_HID (3 * CFG_TUH_DEVICE_MAX) + +// Number of CDC interfaces +// FTDI and CP210x are not part of CDC class, only to re-use CDC driver API +#define CFG_TUH_CDC 1 +#define CFG_TUH_CDC_FTDI 1 +#define CFG_TUH_CDC_CP210X 1 + +// RX & TX fifo size +#define CFG_TUH_CDC_RX_BUFSIZE 64 +#define CFG_TUH_CDC_TX_BUFSIZE 64 + +// Set Line Control state on enumeration/mounted: +// DTR ( bit 0), RTS (bit 1) +#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03 + +// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t +// bit rate = 115200, 1 stop bit, no parity, 8 bit data width +// This need Pico-PIO-USB at least 0.5.1 +#define CFG_TUH_CDC_LINE_CODING_ON_ENUM \ + { 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } + #ifdef __cplusplus } #endif diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index d6f9c8b2..b879ab56 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -263,7 +263,7 @@ static void fifo_read(uint8_t rhport, uint8_t * buffer, uint16_t len, bool in_is max3421_spi_lock(rhport, in_isr); - tuh_max3421_spi_xfer_api(rhport, ®, 1, &hirq, 0); + tuh_max3421_spi_xfer_api(rhport, ®, 1, &hirq, 1); _hcd_data.hirq = hirq; tuh_max3421_spi_xfer_api(rhport, NULL, 0, buffer, len); @@ -428,8 +428,8 @@ bool hcd_init(uint8_t rhport) { reg_write(rhport, PINCTL_ADDR, PINCTL_FDUPSPI, false); // V1 is 0x01, V2 is 0x12, V3 is 0x13 - // uint8_t const revision = reg_read(rhport, REVISION_ADDR, false); - // TU_LOG2_HEX(revision); +// uint8_t const revision = reg_read(rhport, REVISION_ADDR, false); +// TU_LOG2_HEX(revision); // reset reg_write(rhport, USBCTL_ADDR, USBCTL_CHIPRES, false);