Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PIO USB support #1412

Merged
merged 53 commits into from
May 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
1d29817
start to add pio usb (host) support
hathach Mar 1, 2022
df4c614
update pio usb submodule
hathach Mar 1, 2022
d3ed769
clean up
hathach Mar 1, 2022
918f3e9
minor rename
hathach Mar 2, 2022
635fb9d
try to fix ci
hathach Mar 2, 2022
d4d7d35
checkout pio-usb
hathach Mar 2, 2022
fa62d5a
got interrupt endpoint working
hathach Mar 3, 2022
c0195fc
skip pyocd reset after flash
hathach Mar 4, 2022
45052c6
Merge branch 'master' into pio-host
hathach Mar 19, 2022
e2f0aef
make use pio_usb_port_reset_start/end
hathach Mar 30, 2022
e94d11a
implement pio_usb_irq_handler
hathach Mar 31, 2022
75bca96
pio usb control work well including stall response
hathach Apr 1, 2022
e6e3dfe
hid example work well
hathach Apr 1, 2022
db6cba6
rename pio to pio_usb
hathach Apr 1, 2022
c25f835
update to use pio hw endpoint
hathach Apr 1, 2022
f881e77
extracting hw root port
hathach Apr 2, 2022
f6851cf
clean up hcd pio
hathach Apr 2, 2022
7ea75d3
use pio usb host init
hathach Apr 3, 2022
d7d7e61
correct pio usb speed, and close device
hathach Apr 3, 2022
d97c154
add need_pre for pio usb, but not work out well
hathach Apr 4, 2022
d5d4909
proof of concpet that device pio-usb work with host pio-usb
hathach Apr 8, 2022
cc5a472
catch up with pio lib
hathach Apr 14, 2022
05bfc1a
pio device works well
hathach Apr 14, 2022
00a0e3f
update lib pio
hathach Apr 15, 2022
b5a9537
support pio dcd endpiont stall
hathach Apr 15, 2022
a32cb1b
clean up pio driver
hathach Apr 18, 2022
3280390
update lib pio
hathach Apr 20, 2022
98bbb0d
Merge branch 'master' into pio-host
hathach Apr 21, 2022
12debd7
keep up with pio usb
hathach Apr 21, 2022
2f9b9a3
more with pio usb
hathach Apr 22, 2022
26a2527
follow pio usb changes
hathach Apr 25, 2022
4d11c65
improve pio usb endpoint handler
hathach Apr 26, 2022
455bddd
minor clean up
hathach Apr 26, 2022
fd827a8
everything work great
hathach Apr 26, 2022
4a661de
add TU_ATTR_FAST_FUNC for rp2040 __not_in_flash() section
hathach Apr 27, 2022
ae5490e
clean up
hathach Apr 27, 2022
a72d4e2
make hcd_event_handler() fastfunc, and force inline other helper
hathach Apr 27, 2022
85dcb73
more clean up
hathach Apr 28, 2022
608577e
update pio
hathach Apr 29, 2022
0b30a10
configure hid_to_cdc example to build with rp2040 with pio usb as host
hathach Apr 29, 2022
c289438
fix ci build
hathach Apr 29, 2022
79b5ab8
fix incorrect total number of interface
hathach May 6, 2022
26ee622
move pio usb files to src
hathach May 10, 2022
e3b57ce
rename host/hid_to_cdc to dual/host_hid_to_device_cdc
hathach May 10, 2022
993f7b6
include dual examples to ci
hathach May 10, 2022
717a474
move pio-usb init to family_configure_pio_usb_example() to stay compa…
hathach May 10, 2022
35b77a4
cmake lib rename
hathach May 10, 2022
8473ca1
clean up
hathach May 10, 2022
8bd923f
sync with pio usb
hathach May 10, 2022
f09df55
clean up example
hathach May 11, 2022
be2a513
remove pico-usb fork
hathach May 16, 2022
4586d8f
add upstream Pico-PIO-USB
hathach May 16, 2022
e0e9426
print addres of mouse input
hathach May 16, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/build_arm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ jobs:
run: |
git clone --depth 1 -b develop https://github.com/raspberrypi/pico-sdk ~/pico-sdk
echo >> $GITHUB_ENV PICO_SDK_PATH=~/pico-sdk
git submodule update --init hw/mcu/raspberry_pi/Pico-PIO-USB

- name: Set Toolchain URL
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
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,6 @@
[submodule "hw/mcu/allwinner"]
path = hw/mcu/allwinner
url = https://github.com/hathach/allwinner_driver.git
[submodule "hw/mcu/raspberry_pi/Pico-PIO-USB"]
path = hw/mcu/raspberry_pi/Pico-PIO-USB
url = https://github.com/sekigon-gonnoc/Pico-PIO-USB.git
4 changes: 4 additions & 0 deletions examples/device/hid_boot_interface/src/tusb_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
#error CFG_TUSB_MCU must be defined
#endif

// Use raspberry pio-usb for device
// #define CFG_TUD_RPI_PIO_USB 1
// #define BOARD_DEVICE_RHPORT_NUM 1

// RHPort number used for device can be defined by board.mk, default to port 0
#ifndef BOARD_DEVICE_RHPORT_NUM
#define BOARD_DEVICE_RHPORT_NUM 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ target_include_directories(${PROJECT} PUBLIC

# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
family_configure_device_example(${PROJECT})
family_configure_device_example(${PROJECT})
family_configure_host_example(${PROJECT})
family_configure_pico_pio_usb_example(${PROJECT})
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
board:mimxrt1060_evk
board:mimxrt1064_evk
mcu:RP2040
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,8 @@
*
*/

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

#include <stdlib.h>
#include <stdio.h>
Expand Down Expand Up @@ -73,28 +71,28 @@ enum {
static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;

void led_blinking_task(void);
void cdc_task(void);

/*------------- MAIN -------------*/
int main(void)
{
board_init();

printf("TinyUSB Host HID <-> Device CDC Example\r\n");

tusb_init();

while (1)
{
tud_task(); // tinyusb device task
tuh_task(); // tinyusb host task
led_blinking_task();

cdc_task();
}

return 0;
}

//--------------------------------------------------------------------+
// Device callbacks
// Device CDC
//--------------------------------------------------------------------+

// Invoked when device is mounted
Expand Down Expand Up @@ -124,8 +122,20 @@ void tud_resume_cb(void)
blink_interval_ms = BLINK_MOUNTED;
}

// Invoked when CDC interface received data from host
void tud_cdc_rx_cb(uint8_t itf)
{
(void) itf;

char buf[64];
uint32_t count = tud_cdc_read(buf, sizeof(buf));

// TODO control LED on keyboard of host stack
(void) count;
}

//--------------------------------------------------------------------+
// Host callbacks
// Host HID
//--------------------------------------------------------------------+

// Invoked when device with hid interface is mounted
Expand All @@ -137,169 +147,140 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
{
(void)desc_report;
(void)desc_len;

// Interface protocol (hid_interface_protocol_enum_t)
const char* protocol_str[] = { "None", "Keyboard", "Mouse" };
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);

uint16_t vid, pid;
tuh_vid_pid_get(dev_addr, &vid, &pid);

printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
printf("VID = %04x, PID = %04x\r\n", vid, pid);
char tempbuf[256];
int count = sprintf(tempbuf, "[%04x:%04x][%u] HID Interface%u, Protocol = %s\r\n", vid, pid, dev_addr, instance, protocol_str[itf_protocol]);

tud_cdc_write(tempbuf, count);
tud_cdc_write_flush();

// Receive any report and treat it like a keyboard.
// Receive report from boot keyboard & mouse only
// tuh_hid_report_received_cb() will be invoked when report is available
if ( !tuh_hid_receive_report(dev_addr, instance) )
if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD || itf_protocol == HID_ITF_PROTOCOL_MOUSE)
{
printf("Error: cannot request to receive report\r\n");
if ( !tuh_hid_receive_report(dev_addr, instance) )
{
tud_cdc_write_str("Error: cannot request report\r\n");
}
}
}

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

// keycodes from last report to check if key is holding or newly pressed
uint8_t last_keycodes[6] = {0};

// look up new key in previous keys
static inline bool key_in_last_report(const uint8_t key_arr[6], uint8_t keycode)
static inline bool find_key_in_report(hid_keyboard_report_t const *report, uint8_t keycode)
{
for(uint8_t i=0; i<6; i++)
{
if (key_arr[i] == keycode) return true;
if (report->keycode[i] == keycode) return true;
}

return false;
}

// Invoked when received report from device via interrupt endpoint
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
{
if (len != 8)
{
char ch_num;

tud_cdc_write_str("incorrect report len: ");

if ( len > 10 )
{
ch_num = '0' + (len / 10);
tud_cdc_write(&ch_num, 1);
len = len % 10;
}

ch_num = '0' + len;
tud_cdc_write(&ch_num, 1);

tud_cdc_write_str("\r\n");
tud_cdc_write_flush();

// Don't request a new report for a wrong sized endpoint.
return;
}

uint8_t const modifiers = report[0];
// convert hid keycode to ascii and print via usb device CDC (ignore non-printable)
static void process_kbd_report(uint8_t dev_addr, hid_keyboard_report_t const *report)
{
(void) dev_addr;
static hid_keyboard_report_t prev_report = { 0, 0, {0} }; // previous report to check key released
bool flush = false;

for (int i = 2; i < 8; i++)
for(uint8_t i=0; i<6; i++)
{
uint8_t keycode = report[i];

if (keycode)
uint8_t keycode = report->keycode[i];
if ( keycode )
{
if ( key_in_last_report(last_keycodes, keycode) )
if ( find_key_in_report(&prev_report, keycode) )
{
// exist in previous report means the current key is holding
// do nothing
}else
{
// not existed in previous report means the current key is pressed
// Only print keycodes 0 - 128.
if (keycode < 128)

// remap the key code for Colemak layout
#ifdef KEYBOARD_COLEMAK
uint8_t colemak_key_code = colemak[keycode];
if (colemak_key_code != 0) keycode = colemak_key_code;
#endif

bool const is_shift = report->modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT);
uint8_t ch = keycode2ascii[keycode][is_shift ? 1 : 0];

if (ch)
{
// remap the key code for Colemak layout so @tannewt can type.
#ifdef KEYBOARD_COLEMAK
uint8_t colemak_key_code = colemak[keycode];
if (colemak_key_code != 0) keycode = colemak_key_code;
#endif

bool const is_shift = modifiers & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT);
char c = keycode2ascii[keycode][is_shift ? 1 : 0];
if (c)
{
if (c == '\n') tud_cdc_write("\r", 1);
tud_cdc_write(&c, 1);
flush = true;
}
if (ch == '\n') tud_cdc_write("\r", 1);
tud_cdc_write(&ch, 1);
flush = true;
}
}
}
// TODO example skips key released
}

if (flush) tud_cdc_write_flush();

// save current report
memcpy(last_keycodes, report+2, 6);

// continue to request to receive report
if ( !tuh_hid_receive_report(dev_addr, instance) )
{
printf("Error: cannot request to receive report\r\n");
}
prev_report = *report;
}

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

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

//--------------------------------------------------------------------+
// USB CDC
//--------------------------------------------------------------------+
void cdc_task(void)
{
// connected() check for DTR bit
// Most but not all terminal client set this when making connection
// if ( tud_cdc_connected() )
{
// connected and there are data available
if ( tud_cdc_available() )
{
// read datas
char buf[64];
uint32_t count = tud_cdc_read(buf, sizeof(buf));
(void) count;

// Echo back
// Note: Skip echo by commenting out write() and write_flush()
// for throughput test e.g
// $ dd if=/dev/zero of=/dev/ttyACM0 count=10000
tud_cdc_write(buf, count);
tud_cdc_write_flush();
}
}
tud_cdc_write(tempbuf, count);
tud_cdc_write_flush();
}

// Invoked when cdc when line state changed e.g connected/disconnected
void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
// Invoked when received report from device via interrupt endpoint
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
{
(void) itf;
(void) rts;
(void) len;
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);

// TODO set some indicator
if ( dtr )
switch(itf_protocol)
{
// Terminal connected
}else
{
// Terminal disconnected
case HID_ITF_PROTOCOL_KEYBOARD:
process_kbd_report(dev_addr, (hid_keyboard_report_t const*) report );
break;

case HID_ITF_PROTOCOL_MOUSE:
process_mouse_report(dev_addr, (hid_mouse_report_t const*) report );
break;

default: break;
}
}

// Invoked when CDC interface received data from host
void tud_cdc_rx_cb(uint8_t itf)
{
(void) itf;
// continue to request to receive report
if ( !tuh_hid_receive_report(dev_addr, instance) )
{
tud_cdc_write_str("Error: cannot request report\r\n");
}
}

//--------------------------------------------------------------------+
// BLINKING TASK
// Blinking Task
//--------------------------------------------------------------------+
void led_blinking_task(void)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@
#define BOARD_HOST_RHPORT_NUM 1
#endif

// Use raspberry pio-usb for host
#define CFG_TUH_RPI_PIO_USB 1

// RHPort max operational speed can defined by board.mk
// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed
#ifndef BOARD_DEVICE_RHPORT_SPEED
Expand Down Expand Up @@ -124,10 +127,6 @@

//------------- CLASS -------------//
#define CFG_TUD_CDC 1
#define CFG_TUD_MSC 0
#define CFG_TUD_HID 0
#define CFG_TUD_MIDI 0
#define CFG_TUD_VENDOR 0

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

#define CFG_TUH_HUB 1
#define CFG_TUH_CDC 0
#define CFG_TUH_MSC 0
#define CFG_TUH_VENDOR 0

// max device support (excluding hub device)
#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1) // hub typically has 4 ports

//------------- HID -------------//
#define CFG_TUH_HID 4
#define CFG_TUH_HID_EPIN_BUFSIZE 64
#define CFG_TUH_HID_EPOUT_BUFSIZE 64
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ enum
{
ITF_NUM_CDC = 0,
ITF_NUM_CDC_DATA,
ITF_NUM_MSC,
ITF_NUM_TOTAL
};

Expand Down
Loading