Skip to content

Commit 3a2e592

Browse files
authored
Merge pull request #225 from adafruit/host-cdc
Add Host cdc support
2 parents ddde366 + 8a101fe commit 3a2e592

File tree

6 files changed

+348
-0
lines changed

6 files changed

+348
-0
lines changed

examples/DualRole/serial_host_bridge/.feather_rp2040_tinyusb.test.only

Whitespace-only changes.
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*********************************************************************
2+
Adafruit invests time and resources providing this open source code,
3+
please support Adafruit and open-source hardware by purchasing
4+
products from Adafruit!
5+
6+
MIT license, check LICENSE for more information
7+
Copyright (c) 2019 Ha Thach for Adafruit Industries
8+
All text above, and the splash screen below must be included in
9+
any redistribution
10+
*********************************************************************/
11+
12+
13+
/* This example demonstrates use of Host Serial (CDC). SerialHost (declared below) is
14+
* an object to manage an CDC peripheral connected to our USB Host connector. This example
15+
* 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 HOST_PIN_DP (gpio20), D- = D+ +1 (gpio21)
24+
* - Provide VBus (5v) and GND for peripheral
25+
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
26+
*/
27+
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+
#define HOST_PIN_DP 20
36+
37+
// Pin for enabling Host VBUS. comment out if not used
38+
#define HOST_PIN_VBUS_EN 22
39+
#define HOST_PIN_VBUS_EN_STATE 1
40+
41+
// USB Host object
42+
Adafruit_USBH_Host USBHost;
43+
44+
// CDC Host object
45+
Adafruit_USBH_CDC SerialHost;
46+
47+
//--------------------------------------------------------------------+
48+
// Setup and Loop on Core0
49+
//--------------------------------------------------------------------+
50+
51+
void setup() {
52+
Serial1.begin(115200);
53+
54+
Serial.begin(115200);
55+
while ( !Serial ) delay(10); // wait for native usb
56+
57+
Serial.println("TinyUSB Host Serial Echo Example");
58+
}
59+
60+
void loop()
61+
{
62+
uint8_t buf[64];
63+
64+
// Serial -> SerialHost
65+
if (Serial.available()) {
66+
size_t count = Serial.read(buf, sizeof(buf));
67+
if ( SerialHost && SerialHost.connected() ) {
68+
SerialHost.write(buf, count);
69+
SerialHost.flush();
70+
}
71+
}
72+
73+
// SerialHost -> Serial
74+
if ( SerialHost.connected() && SerialHost.available() ) {
75+
size_t count = SerialHost.read(buf, sizeof(buf));
76+
Serial.write(buf, count);
77+
}
78+
}
79+
80+
//--------------------------------------------------------------------+
81+
// Setup and Loop on Core1
82+
//--------------------------------------------------------------------+
83+
84+
void setup1() {
85+
while ( !Serial ) delay(10); // wait for native usb
86+
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
87+
88+
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
89+
uint32_t cpu_hz = clock_get_hz(clk_sys);
90+
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
91+
while ( !Serial ) {
92+
delay(10); // wait for native usb
93+
}
94+
Serial.printf("Error: CPU Clock = %u, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
95+
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n", cpu_hz);
96+
while(1) {
97+
delay(1);
98+
}
99+
}
100+
101+
#ifdef HOST_PIN_VBUS_EN
102+
pinMode(HOST_PIN_VBUS_EN, OUTPUT);
103+
104+
// power off first
105+
digitalWrite(HOST_PIN_VBUS_EN, 1-HOST_PIN_VBUS_EN_STATE);
106+
delay(1);
107+
108+
// power on
109+
digitalWrite(HOST_PIN_VBUS_EN, HOST_PIN_VBUS_EN_STATE);
110+
delay(10);
111+
#endif
112+
113+
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
114+
pio_cfg.pin_dp = HOST_PIN_DP;
115+
USBHost.configure_pio_usb(1, &pio_cfg);
116+
117+
// run host stack on controller (rhport) 1
118+
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
119+
// host bit-banging processing works done in core1 to free up core0 for other works
120+
USBHost.begin(1);
121+
}
122+
123+
void loop1()
124+
{
125+
USBHost.task();
126+
127+
// periodically flush SerialHost if connected
128+
if ( SerialHost && SerialHost.connected() ) {
129+
SerialHost.flush();
130+
}
131+
}
132+
133+
//--------------------------------------------------------------------+
134+
// TinyUSB Host callbacks
135+
//--------------------------------------------------------------------+
136+
137+
// Invoked when a device with CDC interface is mounted
138+
// idx is index of cdc interface in the internal pool.
139+
void tuh_cdc_mount_cb(uint8_t idx) {
140+
// bind SerialHost object to this interface index
141+
SerialHost.begin(idx);
142+
143+
Serial.println("SerialHost is connected to a new CDC device");
144+
}
145+
146+
// Invoked when a device with CDC interface is unmounted
147+
void tuh_cdc_umount_cb(uint8_t idx) {
148+
if (idx == SerialHost.getIndex()) {
149+
// unbind SerialHost if this interface is unmounted
150+
SerialHost.end();
151+
152+
Serial.println("SerialHost is disconnected");
153+
}
154+
}

src/Adafruit_TinyUSB.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,23 @@
3737
#if TUSB_OPT_DEVICE_ENABLED
3838

3939
#include "arduino/Adafruit_USBD_Device.h"
40+
4041
#if CFG_TUD_CDC
4142
#include "arduino/Adafruit_USBD_CDC.h"
4243
#endif
4344

4445
#if CFG_TUD_HID
4546
#include "arduino/hid/Adafruit_USBD_HID.h"
4647
#endif
48+
4749
#if CFG_TUD_MIDI
4850
#include "arduino/midi/Adafruit_USBD_MIDI.h"
4951
#endif
52+
5053
#if CFG_TUD_MSC
5154
#include "arduino/msc/Adafruit_USBD_MSC.h"
5255
#endif
56+
5357
#if CFG_TUD_VENDOR
5458
#include "arduino/webusb/Adafruit_USBD_WebUSB.h"
5559
#endif
@@ -64,6 +68,11 @@ void TinyUSB_Device_Init(uint8_t rhport);
6468
#if CFG_TUH_ENABLED
6569

6670
#include "arduino/Adafruit_USBH_Host.h"
71+
72+
#if CFG_TUH_CDC
73+
#include "arduino/cdc/Adafruit_USBH_CDC.h"
74+
#endif
75+
6776
#if CFG_TUH_MSC
6877
#include "arduino/msc/Adafruit_USBH_MSC.h"
6978
#endif

src/arduino/cdc/Adafruit_USBH_CDC.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2022 Ha Thach (tinyusb.org) for Adafruit Industries
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+
25+
#include "tusb_option.h"
26+
27+
#if CFG_TUH_ENABLED && CFG_TUH_MSC
28+
29+
#include "tusb.h"
30+
31+
#include "Adafruit_USBH_CDC.h"
32+
33+
Adafruit_USBH_CDC::Adafruit_USBH_CDC(void) { _idx = TUSB_INDEX_INVALID; }
34+
35+
void Adafruit_USBH_CDC::begin(uint8_t idx) { _idx = idx; }
36+
37+
void Adafruit_USBH_CDC::end(void) { _idx = TUSB_INDEX_INVALID; }
38+
39+
bool Adafruit_USBH_CDC::connected(void) {
40+
return (_idx != TUSB_INDEX_INVALID) && tuh_cdc_connected(_idx);
41+
}
42+
43+
bool Adafruit_USBH_CDC::mounted(void) {
44+
return (_idx != TUSB_INDEX_INVALID) && tuh_cdc_mounted(_idx);
45+
}
46+
47+
int Adafruit_USBH_CDC::available(void) {
48+
return (int)tuh_cdc_read_available(_idx);
49+
}
50+
51+
int Adafruit_USBH_CDC::peek(void) {
52+
// TODO support later
53+
return -1;
54+
}
55+
56+
int Adafruit_USBH_CDC::read(void) {
57+
uint8_t ch;
58+
return read(&ch, 1) ? (int)ch : -1;
59+
}
60+
61+
size_t Adafruit_USBH_CDC::read(uint8_t *buffer, size_t size) {
62+
return tuh_cdc_read(_idx, buffer, size);
63+
}
64+
65+
void Adafruit_USBH_CDC::flush(void) { (void)tuh_cdc_write_flush(_idx); }
66+
67+
size_t Adafruit_USBH_CDC::write(uint8_t ch) { return write(&ch, 1); }
68+
69+
size_t Adafruit_USBH_CDC::write(const uint8_t *buffer, size_t size) {
70+
size_t remain = size;
71+
while (remain && tuh_cdc_mounted(_idx)) {
72+
size_t wrcount = tuh_cdc_write(_idx, buffer, remain);
73+
remain -= wrcount;
74+
buffer += wrcount;
75+
76+
// Write FIFO is full, run host task while wait for space become available
77+
if (remain) {
78+
tuh_task();
79+
}
80+
}
81+
82+
return size - remain;
83+
84+
return tuh_cdc_write(_idx, buffer, size);
85+
}
86+
87+
int Adafruit_USBH_CDC::availableForWrite(void) {
88+
return (int)tuh_cdc_write_available(_idx);
89+
}
90+
91+
#endif

src/arduino/cdc/Adafruit_USBH_CDC.h

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2022 Ha Thach (tinyusb.org) for Adafruit Industries
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+
25+
#ifndef ADAFRUIT_USBH_CDC_H_
26+
#define ADAFRUIT_USBH_CDC_H_
27+
28+
#include "Stream.h"
29+
30+
class Adafruit_USBH_CDC : public Stream {
31+
public:
32+
Adafruit_USBH_CDC(void);
33+
34+
// Init/Bind to an specific cdc interface
35+
void begin(uint8_t idx = 0);
36+
37+
// unbind cdc interface
38+
void end(void);
39+
40+
// Get index of cdc interface
41+
uint8_t getIndex(void) { return _idx; }
42+
43+
// If cdc is mounted
44+
bool mounted(void);
45+
operator bool() { return mounted(); }
46+
47+
// if cdc's DTR is asserted
48+
bool connected(void);
49+
50+
//------------- Stream API -------------//
51+
virtual int available(void);
52+
virtual int peek(void);
53+
54+
virtual int read(void);
55+
size_t read(uint8_t *buffer, size_t size);
56+
57+
virtual void flush(void);
58+
virtual size_t write(uint8_t ch);
59+
60+
virtual size_t write(const uint8_t *buffer, size_t size);
61+
size_t write(const char *buffer, size_t size) {
62+
return write((const uint8_t *)buffer, size);
63+
}
64+
65+
virtual int availableForWrite(void);
66+
using Print::write; // pull in write(str) from Print
67+
68+
private:
69+
uint8_t _idx; // TinyUSB CDC Interface Index
70+
};
71+
72+
#endif

src/arduino/ports/rp2040/tusb_config_rp2040.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,16 +97,38 @@ extern int serial1_printf(const char *__restrict __format, ...);
9797
// Size of buffer to hold descriptors and other data used for enumeration
9898
#define CFG_TUH_ENUMERATION_BUFSIZE 256
9999

100+
// Number of hub devices
100101
#define CFG_TUH_HUB 1
102+
101103
// max device support (excluding hub device)
102104
#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1) // hub typically has 4 ports
103105

104106
// Enable tuh_edpt_xfer() API
105107
//#define CFG_TUH_API_EDPT_XFER 1
106108

109+
// Number of mass storage
107110
#define CFG_TUH_MSC 1
111+
112+
// Number of HIDs
108113
#define CFG_TUH_HID 4
109114

115+
// Number of CDC interfaces
116+
#define CFG_TUH_CDC 1
117+
118+
// RX & TX fifo size
119+
#define CFG_TUH_CDC_RX_BUFSIZE 128
120+
#define CFG_TUH_CDC_TX_BUFSIZE 128
121+
122+
// Set Line Control state on enumeration/mounted:
123+
// DTR ( bit 0), RTS (bit 1)
124+
#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03
125+
126+
// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t
127+
// bit rate = 115200, 1 stop bit, no parity, 8 bit data width
128+
// This need https://github.com/sekigon-gonnoc/Pico-PIO-USB/pull/58 to be merged
129+
// first #define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200,
130+
// CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }
131+
110132
#ifdef __cplusplus
111133
}
112134
#endif

0 commit comments

Comments
 (0)