Skip to content

Commit d4c72bf

Browse files
authored
Merge pull request #334 from adafruit/add-max3421e-support
Support max3421e (usb host shield) for nrf52 and samd21/samd51
2 parents 3df9029 + 2ab530d commit d4c72bf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1645
-776
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
/.development
33
.idea
44
platformio.ini
5+
.pio/

examples/DualRole/CDC/serial_host_bridge/.metro_m0_tinyusb.only

Whitespace-only changes.

examples/DualRole/CDC/serial_host_bridge/.metro_m4_tinyusb.only

Whitespace-only changes.

examples/DualRole/CDC/serial_host_bridge/.nrf52840.only

Whitespace-only changes.

examples/DualRole/CDC/serial_host_bridge/serial_host_bridge.ino

Lines changed: 87 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -9,147 +9,142 @@
99
any redistribution
1010
*********************************************************************/
1111

12+
/* This example demonstrates use of both device and host, where
13+
* - Device run on native usb controller (roothub port0)
14+
* - Host depending on MCUs run on either:
15+
* - rp2040: bit-banging 2 GPIOs with the help of Pico-PIO-USB library (roothub port1)
16+
* - samd21/51, nrf52840, esp32: using MAX3421e controller (host shield)
17+
*
18+
* Requirements:
19+
* - For rp2040:
20+
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
21+
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
22+
* - Provide VBus (5v) and GND for peripheral
23+
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
24+
* - For samd21/51, nrf52840, esp32:
25+
* - Additional MAX2341e USB Host shield or featherwing is required
26+
* - SPI instance, CS pin, INT pin are correctly configured in usbh_helper.h
27+
*/
1228

1329
/* This example demonstrates use of Host Serial (CDC). SerialHost (declared below) is
1430
* an object to manage an CDC peripheral connected to our USB Host connector. This example
1531
* will forward all characters from Serial to SerialHost and vice versa.
16-
*
17-
* Note:
18-
* - Device run on native usb controller (controller0)
19-
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
20-
21-
* Requirements:
22-
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
23-
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
24-
* - Provide VBus (5v) and GND for peripheral
25-
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
2632
*/
2733

28-
// pio-usb is required for rp2040 host
29-
#include "pio_usb.h"
30-
31-
// TinyUSB lib
32-
#include "Adafruit_TinyUSB.h"
33-
34-
// Pin D+ for host, D- = D+ + 1
35-
#ifndef PIN_USB_HOST_DP
36-
#define PIN_USB_HOST_DP 16
34+
// nRF52 and ESP32 use freeRTOS, we may need to run USBhost.task() in its own rtos's thread.
35+
// Since USBHost.task() will put loop() into dormant state and prevent followed code from running
36+
// until there is USB host event.
37+
#if defined(ARDUINO_NRF52_ADAFRUIT) || defined(ARDUINO_ARCH_ESP32)
38+
#define USE_FREERTOS
3739
#endif
3840

39-
// Pin for enabling Host VBUS. comment out if not used
40-
#ifndef PIN_5V_EN
41-
#define PIN_5V_EN 18
42-
#endif
43-
44-
#ifndef PIN_5V_EN_STATE
45-
#define PIN_5V_EN_STATE 1
46-
#endif
47-
48-
// USB Host object
49-
Adafruit_USBH_Host USBHost;
41+
// USBHost is defined in usbh_helper.h
42+
#include "usbh_helper.h"
5043

5144
// CDC Host object
52-
Adafruit_USBH_CDC SerialHost;
53-
54-
//--------------------------------------------------------------------+
55-
// Setup and Loop on Core0
56-
//--------------------------------------------------------------------+
45+
Adafruit_USBH_CDC SerialHost;
5746

58-
void setup() {
59-
Serial.begin(115200);
60-
// while ( !Serial ) delay(10); // wait for native usb
61-
62-
Serial.println("TinyUSB Host Serial Echo Example");
63-
}
64-
65-
void loop()
66-
{
47+
// forward Seral <-> SerialHost
48+
void forward_serial(void) {
6749
uint8_t buf[64];
6850

6951
// Serial -> SerialHost
7052
if (Serial.available()) {
7153
size_t count = Serial.read(buf, sizeof(buf));
72-
if ( SerialHost && SerialHost.connected() ) {
54+
if (SerialHost && SerialHost.connected()) {
7355
SerialHost.write(buf, count);
7456
SerialHost.flush();
7557
}
7658
}
7759

7860
// SerialHost -> Serial
79-
if ( SerialHost.connected() && SerialHost.available() ) {
61+
if (SerialHost.connected() && SerialHost.available()) {
8062
size_t count = SerialHost.read(buf, sizeof(buf));
8163
Serial.write(buf, count);
64+
Serial.flush();
8265
}
8366
}
8467

68+
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
8569
//--------------------------------------------------------------------+
86-
// Setup and Loop on Core1
70+
// Using Host shield MAX3421E controller
8771
//--------------------------------------------------------------------+
8872

89-
void setup1() {
90-
// while ( !Serial ) delay(10); // wait for native usb
91-
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
92-
93-
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
94-
uint32_t cpu_hz = clock_get_hz(clk_sys);
95-
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
96-
while ( !Serial ) {
97-
delay(10); // wait for native usb
98-
}
99-
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
100-
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
101-
while(1) {
102-
delay(1);
103-
}
73+
#ifdef USE_FREERTOS
74+
void usbhost_rtos_task(void *param) {
75+
(void) param;
76+
while (1) {
77+
USBHost.task();
10478
}
79+
}
10580

106-
#ifdef PIN_5V_EN
107-
pinMode(PIN_5V_EN, OUTPUT);
81+
void create_usbhost_rtos_task(void) {
82+
const uint32_t usbh_stack_size = 200;
83+
xTaskCreate(usbhost_rtos_task, "usbh", usbh_stack_size, NULL, TASK_PRIO_HIGH, NULL);
84+
}
85+
#endif
10886

109-
// power off first
110-
digitalWrite(PIN_5V_EN, 1-PIN_5V_EN_STATE);
111-
delay(1);
87+
void setup() {
88+
Serial.begin(115200);
89+
90+
// init host stack on controller (rhport) 1
91+
USBHost.begin(1);
11292

113-
// power on
114-
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
115-
delay(10);
93+
// Initialize SerialHost
94+
SerialHost.begin(115200);
95+
96+
#ifdef USE_FREERTOS
97+
create_usbhost_rtos_task();
11698
#endif
11799

118-
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
119-
pio_cfg.pin_dp = PIN_USB_HOST_DP;
120-
121-
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
122-
// For pico-w, PIO is also used to communicate with cyw43
123-
// Therefore we need to alternate the pio-usb configuration
124-
// details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46
125-
pio_cfg.sm_tx = 3;
126-
pio_cfg.sm_rx = 2;
127-
pio_cfg.sm_eop = 3;
128-
pio_cfg.pio_rx_num = 0;
129-
pio_cfg.pio_tx_num = 1;
130-
pio_cfg.tx_ch = 9;
100+
// while ( !Serial ) delay(10); // wait for native usb
101+
Serial.println("TinyUSB Host Serial Echo Example");
102+
}
103+
104+
void loop() {
105+
#ifndef USE_FREERTOS
106+
USBHost.task();
131107
#endif
132108

133-
USBHost.configure_pio_usb(1, &pio_cfg);
109+
forward_serial();
110+
}
111+
112+
#elif defined(ARDUINO_ARCH_RP2040)
113+
//--------------------------------------------------------------------+
114+
// For RP2040 use both core0 for device stack, core1 for host stack
115+
//--------------------------------------------------------------------+
116+
117+
//------------- Core0 -------------//
118+
void setup() {
119+
Serial.begin(115200);
120+
// while ( !Serial ) delay(10); // wait for native usb
121+
Serial.println("TinyUSB Host Serial Echo Example");
122+
}
123+
124+
void loop() {
125+
forward_serial();
126+
}
127+
128+
//------------- Core1 -------------//
129+
void setup1() {
130+
// configure pio-usb: defined in usbh_helper.h
131+
rp2040_configure_pio_usb();
134132

135133
// run host stack on controller (rhport) 1
136134
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
137135
// host bit-banging processing works done in core1 to free up core0 for other works
138136
USBHost.begin(1);
139137

138+
// Initialize SerialHost
140139
SerialHost.begin(115200);
141140
}
142141

143-
void loop1()
144-
{
142+
void loop1() {
145143
USBHost.task();
146-
147-
// periodically flush SerialHost if connected
148-
if ( SerialHost && SerialHost.connected() ) {
149-
SerialHost.flush();
150-
}
151144
}
152145

146+
#endif
147+
153148
//--------------------------------------------------------------------+
154149
// TinyUSB Host callbacks
155150
//--------------------------------------------------------------------+
@@ -169,4 +164,4 @@ void tuh_cdc_umount_cb(uint8_t idx) {
169164
Serial.println("SerialHost is disconnected");
170165
}
171166

172-
}
167+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2023 Ha Thach (tinyusb.org)
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*
24+
* This file is part of the TinyUSB stack.
25+
*/
26+
27+
#ifndef USBH_HELPER_H
28+
#define USBH_HELPER_H
29+
30+
#ifdef ARDUINO_ARCH_RP2040
31+
// pio-usb is required for rp2040 host
32+
#include "pio_usb.h"
33+
34+
// Pin D+ for host, D- = D+ + 1
35+
#ifndef PIN_USB_HOST_DP
36+
#define PIN_USB_HOST_DP 16
37+
#endif
38+
39+
// Pin for enabling Host VBUS. comment out if not used
40+
#ifndef PIN_5V_EN
41+
#define PIN_5V_EN 18
42+
#endif
43+
44+
#ifndef PIN_5V_EN_STATE
45+
#define PIN_5V_EN_STATE 1
46+
#endif
47+
#endif // ARDUINO_ARCH_RP2040
48+
49+
#include "Adafruit_TinyUSB.h"
50+
51+
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
52+
#include "SPI.h"
53+
// USB Host using MAX3421E: SPI, CS, INT
54+
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
55+
#else
56+
Adafruit_USBH_Host USBHost;
57+
#endif
58+
59+
#ifdef ARDUINO_ARCH_RP2040
60+
static void rp2040_configure_pio_usb(void) {
61+
//while ( !Serial ) delay(10); // wait for native usb
62+
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
63+
64+
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
65+
uint32_t cpu_hz = clock_get_hz(clk_sys);
66+
if (cpu_hz != 120000000UL && cpu_hz != 240000000UL) {
67+
while (!Serial) {
68+
delay(10); // wait for native usb
69+
}
70+
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
71+
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
72+
while (1) {
73+
delay(1);
74+
}
75+
}
76+
77+
#ifdef PIN_5V_EN
78+
pinMode(PIN_5V_EN, OUTPUT);
79+
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
80+
#endif
81+
82+
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
83+
pio_cfg.pin_dp = PIN_USB_HOST_DP;
84+
85+
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
86+
// For pico-w, PIO is also used to communicate with cyw43
87+
// Therefore we need to alternate the pio-usb configuration
88+
// details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46
89+
pio_cfg.sm_tx = 3;
90+
pio_cfg.sm_rx = 2;
91+
pio_cfg.sm_eop = 3;
92+
pio_cfg.pio_rx_num = 0;
93+
pio_cfg.pio_tx_num = 1;
94+
pio_cfg.tx_ch = 9;
95+
#endif
96+
97+
USBHost.configure_pio_usb(1, &pio_cfg);
98+
}
99+
#endif
100+
101+
#endif

examples/DualRole/HID/hid_device_report/.metro_m0_tinyusb.only

Whitespace-only changes.

examples/DualRole/HID/hid_device_report/.metro_m4_tinyusb.only

Whitespace-only changes.

examples/DualRole/HID/hid_device_report/.nrf52840.only

Whitespace-only changes.

0 commit comments

Comments
 (0)