Skip to content

Commit 9496e0b

Browse files
authored
Merge pull request #175 from adafruit/rp2040-pio-usb-host
Add rp2040 pio usb host
2 parents 9c03087 + 093234c commit 9496e0b

File tree

10 files changed

+402
-19
lines changed

10 files changed

+402
-19
lines changed

.github/workflows/githubci.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,24 @@ jobs:
2525

2626
steps:
2727
- name: Setup Python
28-
uses: actions/setup-python@v1
28+
uses: actions/setup-python@v3
2929
with:
3030
python-version: '3.x'
3131

3232
- name: Checkout code
33-
uses: actions/checkout@v2
33+
uses: actions/checkout@v3
3434

3535
- name: Checkout adafruit/ci-arduino
36-
uses: actions/checkout@v2
36+
uses: actions/checkout@v3
3737
with:
3838
repository: adafruit/ci-arduino
3939
path: ci
4040

4141
- name: pre-install
4242
run: bash ci/actions_install.sh
4343

44-
#- name: Install Libraries for building examples
45-
# run: arduino-cli lib install "Adafruit SPIFlash" "MIDI Library" "Adafruit seesaw Library" "Adafruit NeoPixel" "SdFat - Adafruit Fork" "SD" "Adafruit Circuit Playground" "Adafruit InternalFlash"
44+
- name: Install Libraries for building examples
45+
run: arduino-cli lib install "Adafruit SPIFlash" "MIDI Library" "Adafruit seesaw Library" "Adafruit NeoPixel" "SdFat - Adafruit Fork" "SD" "Adafruit Circuit Playground" "Adafruit InternalFlash" "Pico PIO USB"
4646

4747
- name: test platforms
4848
run: python3 ci/build_platform.py ${{ matrix.arduino-platform }}
@@ -52,15 +52,15 @@ jobs:
5252
needs: build
5353
steps:
5454
- name: Setup Python
55-
uses: actions/setup-python@v1
55+
uses: actions/setup-python@v3
5656
with:
5757
python-version: '3.x'
5858

5959
- name: Checkout code
60-
uses: actions/checkout@v2
60+
uses: actions/checkout@v3
6161

6262
- name: Checkout adafruit/ci-arduino
63-
uses: actions/checkout@v2
63+
uses: actions/checkout@v3
6464
with:
6565
repository: adafruit/ci-arduino
6666
path: ci

examples/DualRole/device_info_rp2040/.feather_rp2040_tinyusb.test.only

Whitespace-only changes.
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
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+
// pio-usb is required for rp2040 host
13+
#include "pio_usb.h"
14+
#define HOST_PIN_DP 2 // Pin used as D+ for host, D- = D+ + 1
15+
16+
#include "Adafruit_TinyUSB.h"
17+
18+
#define LANGUAGE_ID 0x0409 // English
19+
20+
// USB Host object
21+
Adafruit_USBH_Host USBHost;
22+
23+
// holding device descriptor
24+
tusb_desc_device_t desc_device;
25+
26+
// the setup function runs once when you press reset or power the board
27+
void setup()
28+
{
29+
Serial1.begin(115200);
30+
31+
Serial.begin(115200);
32+
//while ( !Serial ) delay(10); // wait for native usb
33+
34+
Serial.println("TinyUSB Dual Device Info Example");
35+
}
36+
37+
void loop()
38+
{
39+
}
40+
41+
// core1's setup
42+
void setup1() {
43+
//while ( !Serial ) delay(10); // wait for native usb
44+
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
45+
46+
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
47+
uint32_t cpu_hz = clock_get_hz(clk_sys);
48+
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
49+
while ( !Serial ) delay(10); // wait for native usb
50+
Serial.printf("Error: CPU Clock = %u, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
51+
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n", cpu_hz);
52+
while(1) delay(1);
53+
}
54+
55+
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
56+
pio_cfg.pin_dp = HOST_PIN_DP;
57+
USBHost.configure_pio_usb(1, &pio_cfg);
58+
59+
// run host stack on controller (rhport) 1
60+
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
61+
// host bit-banging processing works done in core1 to free up core0 for other works
62+
USBHost.begin(1);
63+
}
64+
65+
// core1's loop
66+
void loop1()
67+
{
68+
USBHost.task();
69+
}
70+
71+
//--------------------------------------------------------------------+
72+
// TinyUSB Host callbacks
73+
//--------------------------------------------------------------------+
74+
75+
// Invoked when device is mounted (configured)
76+
void tuh_mount_cb (uint8_t daddr)
77+
{
78+
Serial.printf("Device attached, address = %d\r\n", daddr);
79+
80+
// Get Device Descriptor
81+
tuh_descriptor_get_device(daddr, &desc_device, 18, print_device_descriptor, 0);
82+
}
83+
84+
/// Invoked when device is unmounted (bus reset/unplugged)
85+
void tuh_umount_cb(uint8_t daddr)
86+
{
87+
Serial.printf("Device removed, address = %d\r\n", daddr);
88+
}
89+
90+
void print_device_descriptor(tuh_xfer_t* xfer)
91+
{
92+
if ( XFER_RESULT_SUCCESS != xfer->result )
93+
{
94+
Serial.printf("Failed to get device descriptor\r\n");
95+
return;
96+
}
97+
98+
uint8_t const daddr = xfer->daddr;
99+
100+
Serial.printf("Device %u: ID %04x:%04x\r\n", daddr, desc_device.idVendor, desc_device.idProduct);
101+
Serial.printf("Device Descriptor:\r\n");
102+
Serial.printf(" bLength %u\r\n" , desc_device.bLength);
103+
Serial.printf(" bDescriptorType %u\r\n" , desc_device.bDescriptorType);
104+
Serial.printf(" bcdUSB %04x\r\n" , desc_device.bcdUSB);
105+
Serial.printf(" bDeviceClass %u\r\n" , desc_device.bDeviceClass);
106+
Serial.printf(" bDeviceSubClass %u\r\n" , desc_device.bDeviceSubClass);
107+
Serial.printf(" bDeviceProtocol %u\r\n" , desc_device.bDeviceProtocol);
108+
Serial.printf(" bMaxPacketSize0 %u\r\n" , desc_device.bMaxPacketSize0);
109+
Serial.printf(" idVendor 0x%04x\r\n" , desc_device.idVendor);
110+
Serial.printf(" idProduct 0x%04x\r\n" , desc_device.idProduct);
111+
Serial.printf(" bcdDevice %04x\r\n" , desc_device.bcdDevice);
112+
113+
// Get String descriptor using Sync API
114+
uint16_t temp_buf[128];
115+
116+
Serial.printf(" iManufacturer %u " , desc_device.iManufacturer);
117+
if (XFER_RESULT_SUCCESS == tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)) )
118+
{
119+
print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
120+
}
121+
Serial.printf("\r\n");
122+
123+
Serial.printf(" iProduct %u " , desc_device.iProduct);
124+
if (XFER_RESULT_SUCCESS == tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)))
125+
{
126+
print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
127+
}
128+
Serial.printf("\r\n");
129+
130+
Serial.printf(" iSerialNumber %u " , desc_device.iSerialNumber);
131+
if (XFER_RESULT_SUCCESS == tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)))
132+
{
133+
print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
134+
}
135+
Serial.printf("\r\n");
136+
137+
Serial.printf(" bNumConfigurations %u\r\n" , desc_device.bNumConfigurations);
138+
}
139+
140+
//--------------------------------------------------------------------+
141+
// String Descriptor Helper
142+
//--------------------------------------------------------------------+
143+
144+
static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) {
145+
// TODO: Check for runover.
146+
(void)utf8_len;
147+
// Get the UTF-16 length out of the data itself.
148+
149+
for (size_t i = 0; i < utf16_len; i++) {
150+
uint16_t chr = utf16[i];
151+
if (chr < 0x80) {
152+
*utf8++ = chr & 0xff;
153+
} else if (chr < 0x800) {
154+
*utf8++ = (uint8_t)(0xC0 | (chr >> 6 & 0x1F));
155+
*utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
156+
} else {
157+
// TODO: Verify surrogate.
158+
*utf8++ = (uint8_t)(0xE0 | (chr >> 12 & 0x0F));
159+
*utf8++ = (uint8_t)(0x80 | (chr >> 6 & 0x3F));
160+
*utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
161+
}
162+
// TODO: Handle UTF-16 code points that take two entries.
163+
}
164+
}
165+
166+
// Count how many bytes a utf-16-le encoded string will take in utf-8.
167+
static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
168+
size_t total_bytes = 0;
169+
for (size_t i = 0; i < len; i++) {
170+
uint16_t chr = buf[i];
171+
if (chr < 0x80) {
172+
total_bytes += 1;
173+
} else if (chr < 0x800) {
174+
total_bytes += 2;
175+
} else {
176+
total_bytes += 3;
177+
}
178+
// TODO: Handle UTF-16 code points that take two entries.
179+
}
180+
return total_bytes;
181+
}
182+
183+
static void print_utf16(uint16_t *temp_buf, size_t buf_len) {
184+
size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
185+
size_t utf8_len = _count_utf8_bytes(temp_buf + 1, utf16_len);
186+
187+
_convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, sizeof(uint16_t) * buf_len);
188+
((uint8_t*) temp_buf)[utf8_len] = '\0';
189+
190+
Serial.printf((char*)temp_buf);
191+
}
192+

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ category=Communication
88
url=https://github.com/adafruit/Adafruit_TinyUSB_Arduino
99
architectures=*
1010
includes=Adafruit_TinyUSB.h
11-
depends=Adafruit SPIFlash, MIDI Library, Adafruit seesaw Library, Adafruit NeoPixel, SdFat - Adafruit Fork, SD, Adafruit Circuit Playground, Adafruit InternalFlash
11+
depends=Adafruit SPIFlash, MIDI Library, SdFat - Adafruit Fork

src/Adafruit_TinyUSB.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@
3333

3434
#include "tusb_option.h"
3535

36+
// Device
3637
#if TUSB_OPT_DEVICE_ENABLED
3738

38-
3939
#include "arduino/Adafruit_USBD_Device.h"
4040
#if CFG_TUD_CDC
4141
#include "arduino/Adafruit_USBD_CDC.h"
@@ -60,4 +60,11 @@ void TinyUSB_Device_Init(uint8_t rhport);
6060

6161
#endif
6262

63+
// Host
64+
#if CFG_TUH_ENABLED
65+
66+
#include "arduino/Adafruit_USBH_Host.h"
67+
68+
#endif
69+
6370
#endif /* ADAFRUIT_TINYUSB_H_ */

src/arduino/Adafruit_USBH_Host.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2022, Ha Thach (tinyusb.org) for Adafruit
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
28+
29+
#include "Adafruit_TinyUSB_API.h"
30+
#include "Adafruit_USBH_Host.h"
31+
32+
Adafruit_USBH_Host::Adafruit_USBH_Host(void) {}
33+
34+
bool Adafruit_USBH_Host::configure(uint8_t rhport, uint32_t cfg_id,
35+
const void *cfg_param) {
36+
return tuh_configure(rhport, cfg_id, cfg_param);
37+
}
38+
39+
#ifdef ARDUINO_ARCH_RP2040
40+
bool Adafruit_USBH_Host::configure_pio_usb(uint8_t rhport,
41+
const void *cfg_param) {
42+
return configure(rhport, TUH_CFGID_RPI_PIO_USB_CONFIGURATION, cfg_param);
43+
}
44+
#endif
45+
46+
bool Adafruit_USBH_Host::begin(uint8_t rhport) { return tuh_init(rhport); }
47+
48+
void Adafruit_USBH_Host::task(void) { tuh_task(); }
49+
50+
// Invoked when device with hid interface is mounted
51+
// Report descriptor is also available for use.
52+
// tuh_hid_parse_report_descriptor() can be used to parse common/simple enough
53+
// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE,
54+
// it will be skipped therefore report_desc = NULL, desc_len = 0
55+
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance,
56+
uint8_t const *desc_report, uint16_t desc_len) {
57+
(void)dev_addr;
58+
(void)instance;
59+
(void)desc_report;
60+
(void)desc_len;
61+
}
62+
63+
// Invoked when device with hid interface is un-mounted
64+
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
65+
(void)dev_addr;
66+
(void)instance;
67+
}
68+
69+
// Invoked when received report from device via interrupt endpoint
70+
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance,
71+
uint8_t const *report, uint16_t len) {
72+
(void)dev_addr;
73+
(void)instance;
74+
(void)report;
75+
(void)len;
76+
}
77+
#endif

0 commit comments

Comments
 (0)