Skip to content

Commit c2bcda8

Browse files
authored
Merge pull request #1412 from hathach/pio-host
PIO USB support
2 parents d23c9b7 + e0e9426 commit c2bcda8

File tree

37 files changed

+781
-262
lines changed

37 files changed

+781
-262
lines changed

.github/workflows/build_arm.yml

+1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ jobs:
8282
run: |
8383
git clone --depth 1 -b develop https://github.com/raspberrypi/pico-sdk ~/pico-sdk
8484
echo >> $GITHUB_ENV PICO_SDK_PATH=~/pico-sdk
85+
git submodule update --init hw/mcu/raspberry_pi/Pico-PIO-USB
8586
8687
- name: Set Toolchain URL
8788
run: echo >> $GITHUB_ENV TOOLCHAIN_URL=https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/releases/download/v10.2.1-1.1/xpack-arm-none-eabi-gcc-10.2.1-1.1-linux-x64.tar.gz

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -146,3 +146,6 @@
146146
[submodule "hw/mcu/allwinner"]
147147
path = hw/mcu/allwinner
148148
url = https://github.com/hathach/allwinner_driver.git
149+
[submodule "hw/mcu/raspberry_pi/Pico-PIO-USB"]
150+
path = hw/mcu/raspberry_pi/Pico-PIO-USB
151+
url = https://github.com/sekigon-gonnoc/Pico-PIO-USB.git

examples/device/hid_boot_interface/src/tusb_config.h

+4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@
3939
#error CFG_TUSB_MCU must be defined
4040
#endif
4141

42+
// Use raspberry pio-usb for device
43+
// #define CFG_TUD_RPI_PIO_USB 1
44+
// #define BOARD_DEVICE_RHPORT_NUM 1
45+
4246
// RHPort number used for device can be defined by board.mk, default to port 0
4347
#ifndef BOARD_DEVICE_RHPORT_NUM
4448
#define BOARD_DEVICE_RHPORT_NUM 0

examples/host/hid_to_cdc/CMakeLists.txt renamed to examples/dual/host_hid_to_device_cdc/CMakeLists.txt

+3-1
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,6 @@ target_include_directories(${PROJECT} PUBLIC
2525

2626
# Configure compilation flags and libraries for the example... see the corresponding function
2727
# in hw/bsp/FAMILY/family.cmake for details.
28-
family_configure_device_example(${PROJECT})
28+
family_configure_device_example(${PROJECT})
29+
family_configure_host_example(${PROJECT})
30+
family_configure_pico_pio_usb_example(${PROJECT})
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
board:mimxrt1060_evk
22
board:mimxrt1064_evk
3+
mcu:RP2040

examples/host/hid_to_cdc/src/main.c renamed to examples/dual/host_hid_to_device_cdc/src/main.c

+98-117
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,8 @@
2323
*
2424
*/
2525

26-
// This example runs both host and device concurrently. The USB host looks for
27-
// any HID device with reports that are 8 bytes long and then assumes they are
28-
// keyboard reports. It translates the keypresses of the reports to ASCII and
29-
// transmits it over CDC to the device's host.
26+
// This example runs both host and device concurrently. The USB host receive
27+
// reports from HID device and print it out over USB Device CDC interface.
3028

3129
#include <stdlib.h>
3230
#include <stdio.h>
@@ -73,28 +71,28 @@ enum {
7371
static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
7472

7573
void led_blinking_task(void);
76-
void cdc_task(void);
7774

7875
/*------------- MAIN -------------*/
7976
int main(void)
8077
{
8178
board_init();
79+
80+
printf("TinyUSB Host HID <-> Device CDC Example\r\n");
81+
8282
tusb_init();
8383

8484
while (1)
8585
{
8686
tud_task(); // tinyusb device task
8787
tuh_task(); // tinyusb host task
8888
led_blinking_task();
89-
90-
cdc_task();
9189
}
9290

9391
return 0;
9492
}
9593

9694
//--------------------------------------------------------------------+
97-
// Device callbacks
95+
// Device CDC
9896
//--------------------------------------------------------------------+
9997

10098
// Invoked when device is mounted
@@ -124,8 +122,20 @@ void tud_resume_cb(void)
124122
blink_interval_ms = BLINK_MOUNTED;
125123
}
126124

125+
// Invoked when CDC interface received data from host
126+
void tud_cdc_rx_cb(uint8_t itf)
127+
{
128+
(void) itf;
129+
130+
char buf[64];
131+
uint32_t count = tud_cdc_read(buf, sizeof(buf));
132+
133+
// TODO control LED on keyboard of host stack
134+
(void) count;
135+
}
136+
127137
//--------------------------------------------------------------------+
128-
// Host callbacks
138+
// Host HID
129139
//--------------------------------------------------------------------+
130140

131141
// Invoked when device with hid interface is mounted
@@ -137,169 +147,140 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
137147
{
138148
(void)desc_report;
139149
(void)desc_len;
150+
151+
// Interface protocol (hid_interface_protocol_enum_t)
152+
const char* protocol_str[] = { "None", "Keyboard", "Mouse" };
153+
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
154+
140155
uint16_t vid, pid;
141156
tuh_vid_pid_get(dev_addr, &vid, &pid);
142157

143-
printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
144-
printf("VID = %04x, PID = %04x\r\n", vid, pid);
158+
char tempbuf[256];
159+
int count = sprintf(tempbuf, "[%04x:%04x][%u] HID Interface%u, Protocol = %s\r\n", vid, pid, dev_addr, instance, protocol_str[itf_protocol]);
160+
161+
tud_cdc_write(tempbuf, count);
162+
tud_cdc_write_flush();
145163

146-
// Receive any report and treat it like a keyboard.
164+
// Receive report from boot keyboard & mouse only
147165
// tuh_hid_report_received_cb() will be invoked when report is available
148-
if ( !tuh_hid_receive_report(dev_addr, instance) )
166+
if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD || itf_protocol == HID_ITF_PROTOCOL_MOUSE)
149167
{
150-
printf("Error: cannot request to receive report\r\n");
168+
if ( !tuh_hid_receive_report(dev_addr, instance) )
169+
{
170+
tud_cdc_write_str("Error: cannot request report\r\n");
171+
}
151172
}
152173
}
153174

154175
// Invoked when device with hid interface is un-mounted
155176
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
156177
{
157-
printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
178+
char tempbuf[256];
179+
int count = sprintf(tempbuf, "[%u] HID Interface%u is unmounted\r\n", dev_addr, instance);
180+
tud_cdc_write(tempbuf, count);
181+
tud_cdc_write_flush();
158182
}
159183

160-
// keycodes from last report to check if key is holding or newly pressed
161-
uint8_t last_keycodes[6] = {0};
162-
163184
// look up new key in previous keys
164-
static inline bool key_in_last_report(const uint8_t key_arr[6], uint8_t keycode)
185+
static inline bool find_key_in_report(hid_keyboard_report_t const *report, uint8_t keycode)
165186
{
166187
for(uint8_t i=0; i<6; i++)
167188
{
168-
if (key_arr[i] == keycode) return true;
189+
if (report->keycode[i] == keycode) return true;
169190
}
170191

171192
return false;
172193
}
173194

174-
// Invoked when received report from device via interrupt endpoint
175-
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
176-
{
177-
if (len != 8)
178-
{
179-
char ch_num;
180-
181-
tud_cdc_write_str("incorrect report len: ");
182-
183-
if ( len > 10 )
184-
{
185-
ch_num = '0' + (len / 10);
186-
tud_cdc_write(&ch_num, 1);
187-
len = len % 10;
188-
}
189-
190-
ch_num = '0' + len;
191-
tud_cdc_write(&ch_num, 1);
192-
193-
tud_cdc_write_str("\r\n");
194-
tud_cdc_write_flush();
195195

196-
// Don't request a new report for a wrong sized endpoint.
197-
return;
198-
}
199-
200-
uint8_t const modifiers = report[0];
196+
// convert hid keycode to ascii and print via usb device CDC (ignore non-printable)
197+
static void process_kbd_report(uint8_t dev_addr, hid_keyboard_report_t const *report)
198+
{
199+
(void) dev_addr;
200+
static hid_keyboard_report_t prev_report = { 0, 0, {0} }; // previous report to check key released
201201
bool flush = false;
202202

203-
for (int i = 2; i < 8; i++)
203+
for(uint8_t i=0; i<6; i++)
204204
{
205-
uint8_t keycode = report[i];
206-
207-
if (keycode)
205+
uint8_t keycode = report->keycode[i];
206+
if ( keycode )
208207
{
209-
if ( key_in_last_report(last_keycodes, keycode) )
208+
if ( find_key_in_report(&prev_report, keycode) )
210209
{
211210
// exist in previous report means the current key is holding
212-
// do nothing
213211
}else
214212
{
215213
// not existed in previous report means the current key is pressed
216-
// Only print keycodes 0 - 128.
217-
if (keycode < 128)
214+
215+
// remap the key code for Colemak layout
216+
#ifdef KEYBOARD_COLEMAK
217+
uint8_t colemak_key_code = colemak[keycode];
218+
if (colemak_key_code != 0) keycode = colemak_key_code;
219+
#endif
220+
221+
bool const is_shift = report->modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT);
222+
uint8_t ch = keycode2ascii[keycode][is_shift ? 1 : 0];
223+
224+
if (ch)
218225
{
219-
// remap the key code for Colemak layout so @tannewt can type.
220-
#ifdef KEYBOARD_COLEMAK
221-
uint8_t colemak_key_code = colemak[keycode];
222-
if (colemak_key_code != 0) keycode = colemak_key_code;
223-
#endif
224-
225-
bool const is_shift = modifiers & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT);
226-
char c = keycode2ascii[keycode][is_shift ? 1 : 0];
227-
if (c)
228-
{
229-
if (c == '\n') tud_cdc_write("\r", 1);
230-
tud_cdc_write(&c, 1);
231-
flush = true;
232-
}
226+
if (ch == '\n') tud_cdc_write("\r", 1);
227+
tud_cdc_write(&ch, 1);
228+
flush = true;
233229
}
234230
}
235231
}
232+
// TODO example skips key released
236233
}
237234

238235
if (flush) tud_cdc_write_flush();
239236

240-
// save current report
241-
memcpy(last_keycodes, report+2, 6);
242-
243-
// continue to request to receive report
244-
if ( !tuh_hid_receive_report(dev_addr, instance) )
245-
{
246-
printf("Error: cannot request to receive report\r\n");
247-
}
237+
prev_report = *report;
248238
}
249239

240+
// send mouse report to usb device CDC
241+
static void process_mouse_report(uint8_t dev_addr, hid_mouse_report_t const * report)
242+
{
243+
//------------- button state -------------//
244+
//uint8_t button_changed_mask = report->buttons ^ prev_report.buttons;
245+
char l = report->buttons & MOUSE_BUTTON_LEFT ? 'L' : '-';
246+
char m = report->buttons & MOUSE_BUTTON_MIDDLE ? 'M' : '-';
247+
char r = report->buttons & MOUSE_BUTTON_RIGHT ? 'R' : '-';
250248

249+
char tempbuf[32];
250+
int count = sprintf(tempbuf, "[%u] %c%c%c %d %d %d\r\n", dev_addr, l, m, r, report->x, report->y, report->wheel);
251251

252-
//--------------------------------------------------------------------+
253-
// USB CDC
254-
//--------------------------------------------------------------------+
255-
void cdc_task(void)
256-
{
257-
// connected() check for DTR bit
258-
// Most but not all terminal client set this when making connection
259-
// if ( tud_cdc_connected() )
260-
{
261-
// connected and there are data available
262-
if ( tud_cdc_available() )
263-
{
264-
// read datas
265-
char buf[64];
266-
uint32_t count = tud_cdc_read(buf, sizeof(buf));
267-
(void) count;
268-
269-
// Echo back
270-
// Note: Skip echo by commenting out write() and write_flush()
271-
// for throughput test e.g
272-
// $ dd if=/dev/zero of=/dev/ttyACM0 count=10000
273-
tud_cdc_write(buf, count);
274-
tud_cdc_write_flush();
275-
}
276-
}
252+
tud_cdc_write(tempbuf, count);
253+
tud_cdc_write_flush();
277254
}
278255

279-
// Invoked when cdc when line state changed e.g connected/disconnected
280-
void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
256+
// Invoked when received report from device via interrupt endpoint
257+
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
281258
{
282-
(void) itf;
283-
(void) rts;
259+
(void) len;
260+
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
284261

285-
// TODO set some indicator
286-
if ( dtr )
262+
switch(itf_protocol)
287263
{
288-
// Terminal connected
289-
}else
290-
{
291-
// Terminal disconnected
264+
case HID_ITF_PROTOCOL_KEYBOARD:
265+
process_kbd_report(dev_addr, (hid_keyboard_report_t const*) report );
266+
break;
267+
268+
case HID_ITF_PROTOCOL_MOUSE:
269+
process_mouse_report(dev_addr, (hid_mouse_report_t const*) report );
270+
break;
271+
272+
default: break;
292273
}
293-
}
294274

295-
// Invoked when CDC interface received data from host
296-
void tud_cdc_rx_cb(uint8_t itf)
297-
{
298-
(void) itf;
275+
// continue to request to receive report
276+
if ( !tuh_hid_receive_report(dev_addr, instance) )
277+
{
278+
tud_cdc_write_str("Error: cannot request report\r\n");
279+
}
299280
}
300281

301282
//--------------------------------------------------------------------+
302-
// BLINKING TASK
283+
// Blinking Task
303284
//--------------------------------------------------------------------+
304285
void led_blinking_task(void)
305286
{

examples/host/hid_to_cdc/src/tusb_config.h renamed to examples/dual/host_hid_to_device_cdc/src/tusb_config.h

+3-9
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@
4949
#define BOARD_HOST_RHPORT_NUM 1
5050
#endif
5151

52+
// Use raspberry pio-usb for host
53+
#define CFG_TUH_RPI_PIO_USB 1
54+
5255
// RHPort max operational speed can defined by board.mk
5356
// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed
5457
#ifndef BOARD_DEVICE_RHPORT_SPEED
@@ -124,10 +127,6 @@
124127

125128
//------------- CLASS -------------//
126129
#define CFG_TUD_CDC 1
127-
#define CFG_TUD_MSC 0
128-
#define CFG_TUD_HID 0
129-
#define CFG_TUD_MIDI 0
130-
#define CFG_TUD_VENDOR 0
131130

132131
// CDC FIFO size of TX and RX
133132
#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
@@ -144,14 +143,9 @@
144143
#define CFG_TUH_ENUMERATION_BUFSIZE 256
145144

146145
#define CFG_TUH_HUB 1
147-
#define CFG_TUH_CDC 0
148-
#define CFG_TUH_MSC 0
149-
#define CFG_TUH_VENDOR 0
150-
151146
// max device support (excluding hub device)
152147
#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1) // hub typically has 4 ports
153148

154-
//------------- HID -------------//
155149
#define CFG_TUH_HID 4
156150
#define CFG_TUH_HID_EPIN_BUFSIZE 64
157151
#define CFG_TUH_HID_EPOUT_BUFSIZE 64

examples/host/hid_to_cdc/src/usb_descriptors.c renamed to examples/dual/host_hid_to_device_cdc/src/usb_descriptors.c

-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ enum
8181
{
8282
ITF_NUM_CDC = 0,
8383
ITF_NUM_CDC_DATA,
84-
ITF_NUM_MSC,
8584
ITF_NUM_TOTAL
8685
};
8786

0 commit comments

Comments
 (0)