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+
7787void 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
87104void 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() {
97118void 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
104124void 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 -------------//
124129void 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
178142void loop1 () {
179- host_loop ();
143+ USBHost. task ();
180144}
181145
182146#endif
0 commit comments