Skip to content

Commit fe9ae96

Browse files
committed
update all dual examples to support max3421e tested with samd21 and nrf52840
1 parent 1752f57 commit fe9ae96

32 files changed

+1207
-742
lines changed

examples/DualRole/CDC/serial_host_bridge/serial_host_bridge.ino

Lines changed: 72 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -9,83 +9,104 @@
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-
#ifdef ARDUINO_ARCH_RP2040
29-
// pio-usb is required for rp2040 host
30-
#include "pio_usb.h"
31-
32-
// Pin D+ for host, D- = D+ + 1
33-
#ifndef PIN_USB_HOST_DP
34-
#define PIN_USB_HOST_DP 16
35-
#endif
36-
37-
// Pin for enabling Host VBUS. comment out if not used
38-
#ifndef PIN_5V_EN
39-
#define PIN_5V_EN 18
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
4039
#endif
4140

42-
#ifndef PIN_5V_EN_STATE
43-
#define PIN_5V_EN_STATE 1
44-
#endif
45-
#endif
46-
47-
#include "Adafruit_TinyUSB.h"
48-
49-
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
50-
#include "SPI.h"
51-
// USB Host using MAX3421E: SPI, CS, INT
52-
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
53-
#else
54-
Adafruit_USBH_Host USBHost;
55-
#endif
41+
// USBHost is defined in usbh_helper.h
42+
#include "usbh_helper.h"
5643

5744
// CDC Host object
58-
Adafruit_USBH_CDC SerialHost;
59-
45+
Adafruit_USBH_CDC SerialHost;
6046

61-
void host_loop()
62-
{
63-
USBHost.task();
47+
// forward Seral <-> SerialHost
48+
void forward_serial(void) {
49+
uint8_t buf[64];
6450

65-
// periodically flush SerialHost if connected
66-
if ( SerialHost && SerialHost.connected() ) {
67-
SerialHost.flush();
51+
// Serial -> SerialHost
52+
if (Serial.available()) {
53+
size_t count = Serial.read(buf, sizeof(buf));
54+
if (SerialHost && SerialHost.connected()) {
55+
SerialHost.write(buf, count);
56+
SerialHost.flush();
57+
}
6858
}
6959

70-
Serial.flush();
60+
// SerialHost -> Serial
61+
if (SerialHost.connected() && SerialHost.available()) {
62+
size_t count = SerialHost.read(buf, sizeof(buf));
63+
Serial.write(buf, count);
64+
Serial.flush();
65+
}
7166
}
7267

7368
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
7469
//--------------------------------------------------------------------+
7570
// Using Host shield MAX3421E controller
7671
//--------------------------------------------------------------------+
72+
73+
#ifdef USE_FREERTOS
74+
void usbhost_rtos_task(void *param) {
75+
(void) param;
76+
while (1) {
77+
USBHost.task();
78+
}
79+
}
80+
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
86+
7787
void setup() {
7888
Serial.begin(115200);
7989

8090
// init host stack on controller (rhport) 1
8191
USBHost.begin(1);
8292

93+
// Initialize SerialHost
94+
SerialHost.begin(115200);
95+
96+
#ifdef USE_FREERTOS
97+
create_usbhost_rtos_task();
98+
#endif
99+
83100
// while ( !Serial ) delay(10); // wait for native usb
84101
Serial.println("TinyUSB Host Serial Echo Example");
85102
}
86103

87104
void loop() {
88-
host_loop();
105+
#ifndef USE_FREERTOS
106+
USBHost.task();
107+
#endif
108+
109+
forward_serial();
89110
}
90111

91112
#elif defined(ARDUINO_ARCH_RP2040)
@@ -97,86 +118,29 @@ void loop() {
97118
void setup() {
98119
Serial.begin(115200);
99120
// while ( !Serial ) delay(10); // wait for native usb
100-
101121
Serial.println("TinyUSB Host Serial Echo Example");
102122
}
103123

104124
void loop() {
105-
uint8_t buf[64];
106-
107-
// Serial -> SerialHost
108-
if (Serial.available()) {
109-
size_t count = Serial.read(buf, sizeof(buf));
110-
if ( SerialHost && SerialHost.connected() ) {
111-
SerialHost.write(buf, count);
112-
SerialHost.flush();
113-
}
114-
}
115-
116-
// SerialHost -> Serial
117-
if ( SerialHost.connected() && SerialHost.available() ) {
118-
size_t count = SerialHost.read(buf, sizeof(buf));
119-
Serial.write(buf, count);
120-
}
125+
forward_serial();
121126
}
122127

123128
//------------- Core1 -------------//
124129
void setup1() {
125-
// while ( !Serial ) delay(10); // wait for native usb
126-
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
127-
128-
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
129-
uint32_t cpu_hz = clock_get_hz(clk_sys);
130-
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
131-
while ( !Serial ) {
132-
delay(10); // wait for native usb
133-
}
134-
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
135-
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
136-
while(1) {
137-
delay(1);
138-
}
139-
}
140-
141-
#ifdef PIN_5V_EN
142-
pinMode(PIN_5V_EN, OUTPUT);
143-
144-
// power off first
145-
digitalWrite(PIN_5V_EN, 1-PIN_5V_EN_STATE);
146-
delay(1);
147-
148-
// power on
149-
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
150-
delay(10);
151-
#endif
152-
153-
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
154-
pio_cfg.pin_dp = PIN_USB_HOST_DP;
155-
156-
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
157-
// For pico-w, PIO is also used to communicate with cyw43
158-
// Therefore we need to alternate the pio-usb configuration
159-
// details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46
160-
pio_cfg.sm_tx = 3;
161-
pio_cfg.sm_rx = 2;
162-
pio_cfg.sm_eop = 3;
163-
pio_cfg.pio_rx_num = 0;
164-
pio_cfg.pio_tx_num = 1;
165-
pio_cfg.tx_ch = 9;
166-
#endif
167-
168-
USBHost.configure_pio_usb(1, &pio_cfg);
130+
// configure pio-usb: defined in usbh_helper.h
131+
rp2040_configure_pio_usb();
169132

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

138+
// Initialize SerialHost
175139
SerialHost.begin(115200);
176140
}
177141

178142
void loop1() {
179-
host_loop();
143+
USBHost.task();
180144
}
181145

182146
#endif
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

0 commit comments

Comments
 (0)