Skip to content

Commit 023db26

Browse files
authored
Merge pull request #260 from adafruit/rp2040-host
Add more rp2040 host examples
2 parents 0386ab6 + 0317c06 commit 023db26

File tree

12 files changed

+403
-5
lines changed

12 files changed

+403
-5
lines changed
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
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 both device and host, where
14+
* - Device run on native usb controller (controller0)
15+
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
16+
*
17+
* Example sketch receive keyboard report from host interface (from e.g consumer keyboard)
18+
* and remap it to another key and send it via device interface (to PC). For simplicity,
19+
* this example only toggle shift key to the report, effectively remap:
20+
* - all character key <-> upper case
21+
* - number <-> its symbol (with shift)
22+
*
23+
* Requirements:
24+
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
25+
* - 2 consecutive GPIOs: D+ is defined by HOST_PIN_DP (gpio20), D- = D+ +1 (gpio21)
26+
* - Provide VBus (5v) and GND for peripheral
27+
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
28+
*/
29+
30+
// pio-usb is required for rp2040 host
31+
#include "pio_usb.h"
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+
// Language ID: English
42+
#define LANGUAGE_ID 0x0409
43+
44+
// USB Host object
45+
Adafruit_USBH_Host USBHost;
46+
47+
// HID report descriptor using TinyUSB's template
48+
// Single Report (no ID) descriptor
49+
uint8_t const desc_hid_report[] =
50+
{
51+
TUD_HID_REPORT_DESC_KEYBOARD()
52+
};
53+
54+
// USB HID object. For ESP32 these values cannot be changed after this declaration
55+
// desc report, desc len, protocol, interval, use out endpoint
56+
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_KEYBOARD, 2, false);
57+
58+
//--------------------------------------------------------------------+
59+
// Setup and Loop on Core0
60+
//--------------------------------------------------------------------+
61+
62+
void setup()
63+
{
64+
Serial.begin(115200);
65+
usb_hid.begin();
66+
67+
//while ( !Serial ) delay(10); // wait for native usb
68+
69+
Serial.println("TinyUSB Host HID Remap Example");
70+
}
71+
72+
void loop()
73+
{
74+
75+
}
76+
77+
//--------------------------------------------------------------------+
78+
// Setup and Loop on Core1
79+
//--------------------------------------------------------------------+
80+
81+
void setup1() {
82+
//while ( !Serial ) delay(10); // wait for native usb
83+
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
84+
85+
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
86+
uint32_t cpu_hz = clock_get_hz(clk_sys);
87+
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
88+
while ( !Serial ) delay(10); // wait for native usb
89+
Serial.printf("Error: CPU Clock = %u, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
90+
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n", cpu_hz);
91+
while(1) delay(1);
92+
}
93+
94+
#ifdef HOST_PIN_VBUS_EN
95+
pinMode(HOST_PIN_VBUS_EN, OUTPUT);
96+
digitalWrite(HOST_PIN_VBUS_EN, HOST_PIN_VBUS_EN_STATE);
97+
#endif
98+
99+
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
100+
pio_cfg.pin_dp = HOST_PIN_DP;
101+
USBHost.configure_pio_usb(1, &pio_cfg);
102+
103+
// run host stack on controller (rhport) 1
104+
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
105+
// host bit-banging processing works done in core1 to free up core0 for other works
106+
USBHost.begin(1);
107+
}
108+
109+
void loop1()
110+
{
111+
USBHost.task();
112+
}
113+
114+
// Invoked when device with hid interface is mounted
115+
// Report descriptor is also available for use.
116+
// tuh_hid_parse_report_descriptor() can be used to parse common/simple enough
117+
// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE,
118+
// it will be skipped therefore report_desc = NULL, desc_len = 0
119+
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
120+
(void)desc_report;
121+
(void)desc_len;
122+
uint16_t vid, pid;
123+
tuh_vid_pid_get(dev_addr, &vid, &pid);
124+
125+
Serial.printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
126+
Serial.printf("VID = %04x, PID = %04x\r\n", vid, pid);
127+
128+
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
129+
if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD) {
130+
Serial.printf("HID Keyboard\r\n", vid, pid);
131+
if (!tuh_hid_receive_report(dev_addr, instance)) {
132+
Serial.printf("Error: cannot request to receive report\r\n");
133+
}
134+
}
135+
}
136+
137+
// Invoked when device with hid interface is un-mounted
138+
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
139+
Serial.printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
140+
}
141+
142+
void remap_key(hid_keyboard_report_t const* original_report, hid_keyboard_report_t* remapped_report)
143+
{
144+
memcpy(remapped_report, original_report, sizeof(hid_keyboard_report_t));
145+
146+
// only remap if not empty report i.e key released
147+
for(uint8_t i=0; i<6; i++) {
148+
if (remapped_report->keycode[i] != 0) {
149+
// Note: we ignore right shift here
150+
remapped_report->modifier ^= KEYBOARD_MODIFIER_LEFTSHIFT;
151+
break;
152+
}
153+
}
154+
}
155+
156+
// Invoked when received report from device via interrupt endpoint
157+
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) {
158+
if ( len != 8 ) {
159+
Serial.printf("report len = %u NOT 8, probably something wrong !!\r\n", len);
160+
}else {
161+
hid_keyboard_report_t remapped_report;
162+
remap_key((hid_keyboard_report_t const*) report, &remapped_report);
163+
164+
// send remapped report to PC
165+
// NOTE: for better performance you should save/queue remapped report instead of
166+
// blocking wait for usb_hid ready here
167+
while ( !usb_hid.ready() ) {
168+
yield();
169+
}
170+
171+
usb_hid.sendReport(0, &remapped_report, sizeof(hid_keyboard_report_t));
172+
}
173+
174+
// continue to request to receive report
175+
if (!tuh_hid_receive_report(dev_addr, instance)) {
176+
Serial.printf("Error: cannot request to receive report\r\n");
177+
}
178+
}

examples/DualRole/MassStorage/msc_data_logger/.feather_rp2040_tinyusb.test.only

Whitespace-only changes.
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
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 both device and host, where
14+
* - Device run on native usb controller (controller0)
15+
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
16+
*
17+
* Example will log CPU temperature periodically (ms,value) to USB thumbdrive
18+
*
19+
* Requirements:
20+
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
21+
* - 2 consecutive GPIOs: D+ is defined by HOST_PIN_DP (gpio20), D- = D+ +1 (gpio21)
22+
* - Provide VBus (5v) and GND for peripheral
23+
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
24+
*/
25+
26+
// pio-usb is required for rp2040 host
27+
#include "pio_usb.h"
28+
29+
// SdFat is required for using Adafruit_USBH_MSC_SdFatDevice
30+
#include "SdFat.h"
31+
32+
// TinyUSB lib
33+
#include "Adafruit_TinyUSB.h"
34+
35+
// Pin D+ for host, D- = D+ + 1
36+
#define HOST_PIN_DP 20
37+
38+
// Pin for enabling Host VBUS. comment out if not used
39+
#define HOST_PIN_VBUS_EN 22
40+
#define HOST_PIN_VBUS_EN_STATE 1
41+
42+
43+
#define LOG_FILE "cpu_temp.csv"
44+
#define LOG_INTERVAL 5000
45+
46+
// USB Host object
47+
Adafruit_USBH_Host USBHost;
48+
49+
// USB Host MSC Block Device object which implemented API for use with SdFat
50+
Adafruit_USBH_MSC_BlockDevice msc_block_dev;
51+
52+
// file system object from SdFat
53+
FatVolume fatfs;
54+
File32 f_log;
55+
56+
// if file system is successfully mounted on usb block device
57+
volatile bool is_mounted = false;
58+
59+
//--------------------------------------------------------------------+
60+
// Setup and Loop on Core0
61+
//--------------------------------------------------------------------+
62+
63+
void setup()
64+
{
65+
pinMode(LED_BUILTIN, OUTPUT);
66+
67+
Serial.begin(115200);
68+
//while ( !Serial ) delay(10); // wait for native usb
69+
70+
Serial.println("TinyUSB Host MassStorage Data Logger Example");
71+
}
72+
73+
void loop()
74+
{
75+
if (!is_mounted) {
76+
// nothing to do
77+
delay(1000);
78+
return;
79+
}
80+
81+
// Turn on LED when start writing
82+
digitalWrite(LED_BUILTIN, HIGH);
83+
84+
f_log = fatfs.open(LOG_FILE, O_WRITE | O_APPEND | O_CREAT);
85+
86+
if (!f_log) {
87+
Serial.println("Cannot create file: " LOG_FILE);
88+
}else {
89+
float cpu_temp = analogReadTemp();
90+
uint32_t ms = millis();
91+
92+
Serial.printf("%u,%.02f\r\n", millis(), cpu_temp);
93+
f_log.printf("%u,%.02f\r\n", millis(), cpu_temp);
94+
95+
f_log.close();
96+
}
97+
98+
delay(LOG_INTERVAL);
99+
}
100+
101+
//--------------------------------------------------------------------+
102+
// Setup and Loop on Core1
103+
//--------------------------------------------------------------------+
104+
105+
void setup1() {
106+
//while ( !Serial ) delay(10); // wait for native usb
107+
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
108+
109+
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
110+
uint32_t cpu_hz = clock_get_hz(clk_sys);
111+
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
112+
while ( !Serial ) {
113+
delay(10); // wait for native usb
114+
}
115+
Serial.printf("Error: CPU Clock = %u, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
116+
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n", cpu_hz);
117+
while(1) {
118+
delay(1);
119+
}
120+
}
121+
122+
#ifdef HOST_PIN_VBUS_EN
123+
pinMode(HOST_PIN_VBUS_EN, OUTPUT);
124+
digitalWrite(HOST_PIN_VBUS_EN, HOST_PIN_VBUS_EN_STATE);
125+
#endif
126+
127+
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
128+
pio_cfg.pin_dp = HOST_PIN_DP;
129+
USBHost.configure_pio_usb(1, &pio_cfg);
130+
131+
// run host stack on controller (rhport) 1
132+
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
133+
// host bit-banging processing works done in core1 to free up core0 for other works
134+
USBHost.begin(1);
135+
}
136+
137+
void loop1()
138+
{
139+
USBHost.task();
140+
Serial.flush();
141+
}
142+
143+
//--------------------------------------------------------------------+
144+
// TinyUSB Host callbacks
145+
//--------------------------------------------------------------------+
146+
147+
// Invoked when device is mounted (configured)
148+
void tuh_mount_cb (uint8_t daddr)
149+
{
150+
(void) daddr;
151+
}
152+
153+
/// Invoked when device is unmounted (bus reset/unplugged)
154+
void tuh_umount_cb(uint8_t daddr)
155+
{
156+
(void) daddr;
157+
}
158+
159+
// Invoked when a device with MassStorage interface is mounted
160+
void tuh_msc_mount_cb(uint8_t dev_addr)
161+
{
162+
// Initialize block device with MSC device address
163+
msc_block_dev.begin(dev_addr);
164+
165+
// For simplicity this example only support LUN 0
166+
msc_block_dev.setActiveLUN(0);
167+
168+
msc_block_dev.setWriteCompleteCallback(write_complete_callback);
169+
170+
is_mounted = fatfs.begin(&msc_block_dev);
171+
172+
if (is_mounted) {
173+
fatfs.ls(&Serial, LS_SIZE);
174+
}else {
175+
Serial.println("Failed to mount mass storage device. Make sure it is formatted as FAT");
176+
}
177+
}
178+
179+
// Invoked when a device with MassStorage interface is unmounted
180+
void tuh_msc_umount_cb(uint8_t dev_addr)
181+
{
182+
(void) dev_addr;
183+
184+
// unmount file system
185+
is_mounted = false;
186+
fatfs.end();
187+
188+
// end block device
189+
msc_block_dev.end();
190+
}
191+
192+
193+
bool write_complete_callback(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data)
194+
{
195+
(void) dev_addr;
196+
(void) cb_data;
197+
198+
// turn off LED after write is complete
199+
// Note this only marks the usb transfer is complete, device can take longer to actual
200+
// write data to physical flash
201+
digitalWrite(LED_BUILTIN, LOW);
202+
203+
return true;
204+
}
205+

examples/DualRole/MassStorage/msc_file_explorer/.feather_rp2040_tinyusb.test.only

Whitespace-only changes.

examples/DualRole/msc_file_explorer/msc_file_explorer.ino renamed to examples/DualRole/MassStorage/msc_file_explorer/msc_file_explorer.ino

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,10 @@ bool is_mounted = false;
5555

5656
void setup()
5757
{
58-
Serial1.begin(115200);
59-
6058
Serial.begin(115200);
6159
//while ( !Serial ) delay(10); // wait for native usb
6260

63-
Serial.println("TinyUSB Dual Device Info Example");
61+
Serial.println("TinyUSB Host Mass Storage File Explorer Example");
6462
}
6563

6664
void loop()

0 commit comments

Comments
 (0)