Skip to content

Commit

Permalink
Merge pull request #334 from adafruit/add-max3421e-support
Browse files Browse the repository at this point in the history
Support max3421e (usb host shield) for nrf52 and samd21/samd51
  • Loading branch information
hathach authored Sep 18, 2023
2 parents 3df9029 + 2ab530d commit d4c72bf
Show file tree
Hide file tree
Showing 52 changed files with 1,645 additions and 776 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
/.development
.idea
platformio.ini
.pio/
Empty file.
Empty file.
Empty file.
179 changes: 87 additions & 92 deletions examples/DualRole/CDC/serial_host_bridge/serial_host_bridge.ino
Original file line number Diff line number Diff line change
Expand Up @@ -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
//--------------------------------------------------------------------+
Expand All @@ -169,4 +164,4 @@ void tuh_cdc_umount_cb(uint8_t idx) {
Serial.println("SerialHost is disconnected");
}

}
}
101 changes: 101 additions & 0 deletions examples/DualRole/CDC/serial_host_bridge/usbh_helper.h
Original file line number Diff line number Diff line change
@@ -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
Empty file.
Empty file.
Empty file.
Loading

0 comments on commit d4c72bf

Please sign in to comment.