diff --git a/.github/workflows/build_arm.yml b/.github/workflows/build_arm.yml index 133671f8..5a796a49 100644 --- a/.github/workflows/build_arm.yml +++ b/.github/workflows/build_arm.yml @@ -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 diff --git a/.gitmodules b/.gitmodules index 21bbf08c..044ac24e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -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 diff --git a/examples/device/hid_boot_interface/src/tusb_config.h b/examples/device/hid_boot_interface/src/tusb_config.h index 1c8fa40b..8bc85b72 100644 --- a/examples/device/hid_boot_interface/src/tusb_config.h +++ b/examples/device/hid_boot_interface/src/tusb_config.h @@ -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 diff --git a/examples/host/hid_to_cdc/CMakeLists.txt b/examples/dual/host_hid_to_device_cdc/CMakeLists.txt similarity index 86% rename from examples/host/hid_to_cdc/CMakeLists.txt rename to examples/dual/host_hid_to_device_cdc/CMakeLists.txt index abc4d91d..24ebfdec 100644 --- a/examples/host/hid_to_cdc/CMakeLists.txt +++ b/examples/dual/host_hid_to_device_cdc/CMakeLists.txt @@ -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}) \ No newline at end of file +family_configure_device_example(${PROJECT}) +family_configure_host_example(${PROJECT}) +family_configure_pico_pio_usb_example(${PROJECT}) diff --git a/examples/host/hid_to_cdc/Makefile b/examples/dual/host_hid_to_device_cdc/Makefile similarity index 100% rename from examples/host/hid_to_cdc/Makefile rename to examples/dual/host_hid_to_device_cdc/Makefile diff --git a/examples/host/hid_to_cdc/only.txt b/examples/dual/host_hid_to_device_cdc/only.txt similarity index 79% rename from examples/host/hid_to_cdc/only.txt rename to examples/dual/host_hid_to_device_cdc/only.txt index 78d94e3c..6ee8e3fd 100644 --- a/examples/host/hid_to_cdc/only.txt +++ b/examples/dual/host_hid_to_device_cdc/only.txt @@ -1,2 +1,3 @@ board:mimxrt1060_evk board:mimxrt1064_evk +mcu:RP2040 diff --git a/examples/host/hid_to_cdc/src/main.c b/examples/dual/host_hid_to_device_cdc/src/main.c similarity index 61% rename from examples/host/hid_to_cdc/src/main.c rename to examples/dual/host_hid_to_device_cdc/src/main.c index cdf5d264..62ecb2c3 100644 --- a/examples/host/hid_to_cdc/src/main.c +++ b/examples/dual/host_hid_to_device_cdc/src/main.c @@ -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 #include @@ -73,12 +71,14 @@ 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) @@ -86,15 +86,13 @@ int main(void) 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 @@ -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 @@ -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]); - // Receive any report and treat it like a keyboard. + tud_cdc_write(tempbuf, count); + tud_cdc_write_flush(); + + // 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) + +// 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) { - 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]; + (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 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; - } + // 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) + { + 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); + 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); + + tud_cdc_write(tempbuf, count); + tud_cdc_write_flush(); +} + +// 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) len; + uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance); + + switch(itf_protocol) + { + 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; + } // continue to request to receive report if ( !tuh_hid_receive_report(dev_addr, instance) ) { - printf("Error: cannot request to receive report\r\n"); + tud_cdc_write_str("Error: cannot request report\r\n"); } } - - //--------------------------------------------------------------------+ -// 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(); - } - } -} - -// Invoked when cdc when line state changed e.g connected/disconnected -void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) -{ - (void) itf; - (void) rts; - - // TODO set some indicator - if ( dtr ) - { - // Terminal connected - }else - { - // Terminal disconnected - } -} - -// Invoked when CDC interface received data from host -void tud_cdc_rx_cb(uint8_t itf) -{ - (void) itf; -} - -//--------------------------------------------------------------------+ -// BLINKING TASK +// Blinking Task //--------------------------------------------------------------------+ void led_blinking_task(void) { diff --git a/examples/host/hid_to_cdc/src/tusb_config.h b/examples/dual/host_hid_to_device_cdc/src/tusb_config.h similarity index 95% rename from examples/host/hid_to_cdc/src/tusb_config.h rename to examples/dual/host_hid_to_device_cdc/src/tusb_config.h index 9a35ffc3..0fa4899a 100644 --- a/examples/host/hid_to_cdc/src/tusb_config.h +++ b/examples/dual/host_hid_to_device_cdc/src/tusb_config.h @@ -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 @@ -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) @@ -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 diff --git a/examples/host/hid_to_cdc/src/usb_descriptors.c b/examples/dual/host_hid_to_device_cdc/src/usb_descriptors.c similarity index 99% rename from examples/host/hid_to_cdc/src/usb_descriptors.c rename to examples/dual/host_hid_to_device_cdc/src/usb_descriptors.c index 7dd73937..e55899f6 100644 --- a/examples/host/hid_to_cdc/src/usb_descriptors.c +++ b/examples/dual/host_hid_to_device_cdc/src/usb_descriptors.c @@ -81,7 +81,6 @@ enum { ITF_NUM_CDC = 0, ITF_NUM_CDC_DATA, - ITF_NUM_MSC, ITF_NUM_TOTAL }; diff --git a/examples/host/bare_api/CMakeLists.txt b/examples/host/bare_api/CMakeLists.txt index bff281a8..607ef22e 100644 --- a/examples/host/bare_api/CMakeLists.txt +++ b/examples/host/bare_api/CMakeLists.txt @@ -24,4 +24,7 @@ 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_host_example(${PROJECT}) \ No newline at end of file +family_configure_host_example(${PROJECT}) + +# For rp2040, un-comment to enable pico-pio-usb +# family_configure_pico_pio_usb_example(${PROJECT}) diff --git a/examples/host/cdc_msc_hid/CMakeLists.txt b/examples/host/cdc_msc_hid/CMakeLists.txt index 0a99bc3a..214e9f2e 100644 --- a/examples/host/cdc_msc_hid/CMakeLists.txt +++ b/examples/host/cdc_msc_hid/CMakeLists.txt @@ -26,4 +26,7 @@ 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_host_example(${PROJECT}) \ No newline at end of file +family_configure_host_example(${PROJECT}) + +# For rp2040, un-comment to enable pico-pio-usb +# family_configure_pico_pio_usb_example(${PROJECT}) diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index bc6c68e5..e9e68cf5 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -39,8 +39,15 @@ #error CFG_TUSB_MCU must be defined #endif +// Use raspberry pio-usb for host +// #define CFG_TUH_RPI_PIO_USB 1 +// #define CFG_TUH_RPI_PIO_USB 1 + #if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX #define CFG_TUSB_RHPORT0_MODE (OPT_MODE_HOST | OPT_MODE_HIGH_SPEED) +#elif defined(CFG_TUH_RPI_PIO_USB) && CFG_TUH_RPI_PIO_USB + // rp2040: port0 is native, port 1 for PIO-USB + #define CFG_TUSB_RHPORT1_MODE OPT_MODE_HOST #else #define CFG_TUSB_RHPORT0_MODE OPT_MODE_HOST #endif diff --git a/examples/host/hid_controller/CMakeLists.txt b/examples/host/hid_controller/CMakeLists.txt index aaf8bc34..6227e079 100644 --- a/examples/host/hid_controller/CMakeLists.txt +++ b/examples/host/hid_controller/CMakeLists.txt @@ -25,4 +25,7 @@ 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_host_example(${PROJECT}) \ No newline at end of file +family_configure_host_example(${PROJECT}) + +# For rp2040, un-comment to enable pico-pio-usb +# family_configure_pico_pio_usb_example(${PROJECT}) diff --git a/examples/rules.mk b/examples/rules.mk index 97f6956f..538dffbc 100644 --- a/examples/rules.mk +++ b/examples/rules.mk @@ -199,7 +199,7 @@ flash-xfel: $(BUILD)/$(PROJECT)-sunxi.bin PYOCD_OPTION ?= flash-pyocd: $(BUILD)/$(PROJECT).hex pyocd flash -t $(PYOCD_TARGET) $(PYOCD_OPTION) $< - pyocd reset -t $(PYOCD_TARGET) + #pyocd reset -t $(PYOCD_TARGET) # Flash using openocd OPENOCD_OPTION ?= diff --git a/hw/bsp/rp2040/family.c b/hw/bsp/rp2040/family.c index fa63dadf..dcf38b6e 100644 --- a/hw/bsp/rp2040/family.c +++ b/hw/bsp/rp2040/family.c @@ -127,6 +127,9 @@ void board_init(void) #ifndef BUTTON_BOOTSEL #endif + // Set the system clock to a multiple of 120mhz for bitbanging USB with pico-usb + set_sys_clock_khz(120000, true); + #if defined(UART_DEV) && defined(LIB_PICO_STDIO_UART) bi_decl(bi_2pins_with_func(UART_TX_PIN, UART_TX_PIN, GPIO_FUNC_UART)); uart_inst = uart_get_instance(UART_DEV); diff --git a/hw/bsp/rp2040/family.cmake b/hw/bsp/rp2040/family.cmake index e832c075..17ae3de9 100644 --- a/hw/bsp/rp2040/family.cmake +++ b/hw/bsp/rp2040/family.cmake @@ -23,9 +23,11 @@ if (NOT TARGET _rp2040_family_inclusion_marker) set(PICO_TINYUSB_PATH ${TOP}) endif() + #------------------------------------ # Base config for both device and host; wrapped by SDK's tinyusb_common + #------------------------------------ add_library(tinyusb_common_base INTERFACE) - + target_sources(tinyusb_common_base INTERFACE ${TOP}/src/tusb.c ${TOP}/src/common/tusb_fifo.c @@ -56,11 +58,44 @@ if (NOT TARGET _rp2040_family_inclusion_marker) CFG_TUSB_DEBUG=${TINYUSB_DEBUG_LEVEL} ) + #------------------------------------ + # PIO USB for both host and device + #------------------------------------ + add_library(pico_pio_usb INTERFACE) + + if (NOT DEFINED PICO_PIO_USB_PATH) + set(PICO_PIO_USB_PATH "${TOP}/hw/mcu/raspberry_pi/Pico-PIO-USB") + endif() + + target_sources(pico_pio_usb INTERFACE + ${PICO_PIO_USB_PATH}/src/pio_usb.c + ${PICO_PIO_USB_PATH}/src/pio_usb_host.c + ${PICO_PIO_USB_PATH}/src/pio_usb_device.c + ${PICO_PIO_USB_PATH}/src/usb_crc.c + ) + + target_include_directories(pico_pio_usb INTERFACE + ${PICO_PIO_USB_PATH}/src + ) + + target_link_libraries(pico_pio_usb INTERFACE + hardware_dma + hardware_pio + pico_multicore + ) + + target_compile_definitions(pico_pio_usb INTERFACE + PIO_USB_USE_TINYUSB + ) + + #------------------------------------ # Base config for device mode; wrapped by SDK's tinyusb_device + #------------------------------------ add_library(tinyusb_device_base INTERFACE) target_sources(tinyusb_device_base INTERFACE ${TOP}/src/portable/raspberrypi/rp2040/dcd_rp2040.c ${TOP}/src/portable/raspberrypi/rp2040/rp2040_usb.c + ${TOP}/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c ${TOP}/src/device/usbd.c ${TOP}/src/device/usbd_control.c ${TOP}/src/class/audio/audio_device.c @@ -77,11 +112,14 @@ if (NOT TARGET _rp2040_family_inclusion_marker) ${TOP}/src/class/video/video_device.c ) + #------------------------------------ # Base config for host mode; wrapped by SDK's tinyusb_host + #------------------------------------ add_library(tinyusb_host_base INTERFACE) target_sources(tinyusb_host_base INTERFACE ${TOP}/src/portable/raspberrypi/rp2040/hcd_rp2040.c ${TOP}/src/portable/raspberrypi/rp2040/rp2040_usb.c + ${TOP}/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c ${TOP}/src/host/usbh.c ${TOP}/src/host/hub.c ${TOP}/src/class/cdc/cdc_host.c @@ -90,12 +128,14 @@ if (NOT TARGET _rp2040_family_inclusion_marker) ${TOP}/src/class/vendor/vendor_host.c ) - # Sometimes have to do host specific actions in mostly - # common functions + # Sometimes have to do host specific actions in mostly common functions target_compile_definitions(tinyusb_host_base INTERFACE RP2040_USB_HOST_MODE=1 ) + #------------------------------------ + # BSP & Additions + #------------------------------------ add_library(tinyusb_bsp INTERFACE) target_sources(tinyusb_bsp INTERFACE ${TOP}/hw/bsp/rp2040/family.c @@ -129,6 +169,10 @@ if (NOT TARGET _rp2040_family_inclusion_marker) ) endif() + #------------------------------------ + # Functions + #------------------------------------ + function(family_configure_target TARGET) pico_add_extra_outputs(${TARGET}) pico_enable_stdio_uart(${TARGET} 1) @@ -145,6 +189,13 @@ if (NOT TARGET _rp2040_family_inclusion_marker) target_link_libraries(${TARGET} PUBLIC pico_stdlib tinyusb_host) endfunction() + function(family_configure_pico_pio_usb_example TARGET) + family_configure_target(${TARGET}) + target_link_libraries(${TARGET} PUBLIC pico_stdlib pico_pio_usb) + pico_generate_pio_header(tinyusb_common_base ${PICO_PIO_USB_PATH}/src/usb_tx.pio) + pico_generate_pio_header(tinyusb_common_base ${PICO_PIO_USB_PATH}/src/usb_rx.pio) + endfunction() + function(family_initialize_project PROJECT DIR) # call the original version of this function from family_common.cmake _family_initialize_project(${PROJECT} ${DIR}) diff --git a/hw/mcu/raspberry_pi/Pico-PIO-USB b/hw/mcu/raspberry_pi/Pico-PIO-USB new file mode 160000 index 00000000..2a9fefd6 --- /dev/null +++ b/hw/mcu/raspberry_pi/Pico-PIO-USB @@ -0,0 +1 @@ +Subproject commit 2a9fefd6ccf42e5d8570ae83fdc54c9c875ebdd1 diff --git a/lib/Pico-PIO-USB b/lib/Pico-PIO-USB new file mode 160000 index 00000000..53ec0916 --- /dev/null +++ b/lib/Pico-PIO-USB @@ -0,0 +1 @@ +Subproject commit 53ec09168c5a3cd30d8dcb577fa97dc328d769d4 diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index ce3d1598..2573f5a6 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -329,7 +329,7 @@ bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass); - TU_LOG2("HID opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr); + TU_LOG2("[%u] HID opening Interface %u\r\n", dev_addr, desc_itf->bInterfaceNumber); // len = interface + hid + n*endpoints uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t); diff --git a/src/common/tusb_debug.h b/src/common/tusb_debug.h index 647e8a8d..ac5bee6e 100644 --- a/src/common/tusb_debug.h +++ b/src/common/tusb_debug.h @@ -57,7 +57,7 @@ void tu_print_mem(void const *buf, uint32_t count, uint8_t indent); #define tu_printf printf #endif -static inline void tu_print_var(uint8_t const* buf, uint32_t bufsize) +static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize) { for(uint32_t i=0; i= 2 #define TU_LOG2 TU_LOG1 #define TU_LOG2_MEM TU_LOG1_MEM + #define TU_LOG2_ARR TU_LOG1_ARR #define TU_LOG2_VAR TU_LOG1_VAR #define TU_LOG2_INT TU_LOG1_INT #define TU_LOG2_HEX TU_LOG1_HEX @@ -91,6 +94,7 @@ static inline void tu_print_var(uint8_t const* buf, uint32_t bufsize) #if CFG_TUSB_DEBUG >= 3 #define TU_LOG3 TU_LOG1 #define TU_LOG3_MEM TU_LOG1_MEM + #define TU_LOG3_ARR TU_LOG1_ARR #define TU_LOG3_VAR TU_LOG1_VAR #define TU_LOG3_INT TU_LOG1_INT #define TU_LOG3_HEX TU_LOG1_HEX diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 8eb4ad47..c1cf2a81 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -228,6 +228,8 @@ #elif TU_CHECK_MCU(OPT_MCU_RP2040) #define TUP_DCD_ENDPOINT_MAX 16 + #define TU_ATTR_FAST_FUNC __attribute__((section(".time_critical.tinyusb"))) + //------------- Silabs -------------// #elif TU_CHECK_MCU(OPT_MCU_EFM32GG) #define TUP_USBIP_DWC2 @@ -282,4 +284,9 @@ #define TUP_RHPORT_HIGHSPEED 0x00 #endif +// fast function, normally mean placing function in SRAM +#ifndef TU_ATTR_FAST_FUNC + #define TU_ATTR_FAST_FUNC +#endif + #endif diff --git a/src/device/dcd.h b/src/device/dcd.h index 8efbc90e..bc68c9be 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -174,16 +174,40 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr); extern void dcd_event_handler(dcd_event_t const * event, bool in_isr); // helper to send bus signal event -extern void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr); +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr) +{ + dcd_event_t event = { .rhport = rhport, .event_id = eid }; + dcd_event_handler(&event, in_isr); +} // helper to send bus reset event -extern void dcd_event_bus_reset (uint8_t rhport, tusb_speed_t speed, bool in_isr); +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_bus_reset (uint8_t rhport, tusb_speed_t speed, bool in_isr) +{ + dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_BUS_RESET }; + event.bus_reset.speed = speed; + dcd_event_handler(&event, in_isr); +} // helper to send setup received -extern void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr); +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr) +{ + dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SETUP_RECEIVED }; + memcpy(&event.setup_received, setup, 8); + + dcd_event_handler(&event, in_isr); +} // helper to send transfer complete event -extern void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr); +TU_ATTR_ALWAYS_INLINE static inline void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr) +{ + dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_XFER_COMPLETE }; + + event.xfer_complete.ep_addr = ep_addr; + event.xfer_complete.len = xferred_bytes; + event.xfer_complete.result = result; + + dcd_event_handler(&event, in_isr); +} #ifdef __cplusplus } diff --git a/src/device/usbd.c b/src/device/usbd.c index 167a053e..1dd1a352 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -1071,7 +1071,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const //--------------------------------------------------------------------+ // DCD Event Handler //--------------------------------------------------------------------+ -void dcd_event_handler(dcd_event_t const * event, bool in_isr) +TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const * event, bool in_isr) { switch (event->event_id) { @@ -1121,38 +1121,6 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr) } } -void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr) -{ - dcd_event_t event = { .rhport = rhport, .event_id = eid }; - dcd_event_handler(&event, in_isr); -} - -void dcd_event_bus_reset (uint8_t rhport, tusb_speed_t speed, bool in_isr) -{ - dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_BUS_RESET }; - event.bus_reset.speed = speed; - dcd_event_handler(&event, in_isr); -} - -void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr) -{ - dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SETUP_RECEIVED }; - memcpy(&event.setup_received, setup, 8); - - dcd_event_handler(&event, in_isr); -} - -void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr) -{ - dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_XFER_COMPLETE }; - - event.xfer_complete.ep_addr = ep_addr; - event.xfer_complete.len = xferred_bytes; - event.xfer_complete.result = result; - - dcd_event_handler(&event, in_isr); -} - //--------------------------------------------------------------------+ // USBD API For Class Driver //--------------------------------------------------------------------+ diff --git a/src/device/usbd.h b/src/device/usbd.h index 58396261..964cfb99 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -55,7 +55,7 @@ void tud_task (void) tud_task_ext(UINT32_MAX, false); } -// Check if there is pending events need proccessing by tud_task() +// Check if there is pending events need processing by tud_task() bool tud_task_event_ready(void); // Interrupt handler, name alias to DCD diff --git a/src/host/hcd.h b/src/host/hcd.h index c40bea64..036394c7 100644 --- a/src/host/hcd.h +++ b/src/host/hcd.h @@ -144,9 +144,16 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr); // Endpoints API //--------------------------------------------------------------------+ -bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]); +// Open an endpoint bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc); + +// Submit a transfer, when complete hcd_event_xfer_complete() must be invoked bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen); + +// Submit a special transfer to send 8-byte Setup Packet, when complete hcd_event_xfer_complete() must be invoked +bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]); + +// clear stall, data toggle is also reset to DATA0 bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr); //--------------------------------------------------------------------+ @@ -164,13 +171,49 @@ extern void hcd_devtree_get_info(uint8_t dev_addr, hcd_devtree_info_t* devtree_i extern void hcd_event_handler(hcd_event_t const* event, bool in_isr); // Helper to send device attach event -extern void hcd_event_device_attach(uint8_t rhport, bool in_isr); +TU_ATTR_ALWAYS_INLINE static inline +void hcd_event_device_attach(uint8_t rhport, bool in_isr) +{ + hcd_event_t event; + event.rhport = rhport; + event.event_id = HCD_EVENT_DEVICE_ATTACH; + event.connection.hub_addr = 0; + event.connection.hub_port = 0; + hcd_event_handler(&event, in_isr); +} // Helper to send device removal event -extern void hcd_event_device_remove(uint8_t rhport, bool in_isr); +TU_ATTR_ALWAYS_INLINE static inline +void hcd_event_device_remove(uint8_t rhport, bool in_isr) +{ + hcd_event_t event; + event.rhport = rhport; + event.event_id = HCD_EVENT_DEVICE_REMOVE; + event.connection.hub_addr = 0; + event.connection.hub_port = 0; + + hcd_event_handler(&event, in_isr); +} // Helper to send USB transfer event -extern void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred_bytes, xfer_result_t result, bool in_isr); +TU_ATTR_ALWAYS_INLINE static inline +void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred_bytes, xfer_result_t result, bool in_isr) +{ + hcd_event_t event = + { + .rhport = 0, // TODO correct rhport + .event_id = HCD_EVENT_XFER_COMPLETE, + .dev_addr = dev_addr, + .xfer_complete = + { + .ep_addr = ep_addr, + .result = result, + .len = xferred_bytes + } + }; + + hcd_event_handler(&event, in_isr); +} #ifdef __cplusplus } diff --git a/src/host/usbh.c b/src/host/usbh.c index 80d17614..e0e41a8d 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -410,7 +410,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) case HCD_EVENT_DEVICE_ATTACH: // TODO due to the shared _usbh_ctrl_buf, we must complete enumerating // one device before enumerating another one. - TU_LOG2("USBH DEVICE ATTACH\r\n"); + TU_LOG2("[%u:] USBH DEVICE ATTACH\r\n", event.rhport); enum_new_device(&event); break; @@ -550,12 +550,12 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) const uint8_t rhport = usbh_get_rhport(daddr); TU_LOG2("[%u:%u] %s: ", rhport, daddr, xfer->setup->bRequest <= TUSB_REQ_SYNCH_FRAME ? tu_str_std_request[xfer->setup->bRequest] : "Unknown Request"); - TU_LOG2_VAR(&xfer->setup); + TU_LOG2_VAR(xfer->setup); TU_LOG2("\r\n"); if (xfer->complete_cb) { - TU_ASSERT( hcd_setup_send(rhport, daddr, (uint8_t*) &_ctrl_xfer.request) ); + TU_ASSERT( hcd_setup_send(rhport, daddr, (uint8_t const*) &_ctrl_xfer.request) ); }else { // blocking if complete callback is not provided @@ -630,7 +630,7 @@ static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result if (XFER_RESULT_SUCCESS != result) { - TU_LOG2("[%u:%u] Control %s\r\n", rhport, dev_addr, result == XFER_RESULT_STALLED ? "STALLED" : "FAILED"); + TU_LOG1("[%u:%u] Control %s\r\n", rhport, dev_addr, result == XFER_RESULT_STALLED ? "STALLED" : "FAILED"); // terminate transfer if any stage failed _xfer_complete(dev_addr, result); @@ -643,12 +643,13 @@ static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result { // DATA stage: initial data toggle is always 1 _set_control_xfer_stage(CONTROL_STAGE_DATA); - return hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, request->bmRequestType_bit.direction), _ctrl_xfer.buffer, request->wLength); + TU_ASSERT( hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, request->bmRequestType_bit.direction), _ctrl_xfer.buffer, request->wLength) ); + return true; } __attribute__((fallthrough)); case CONTROL_STAGE_DATA: - if (xferred_bytes) + if (request->wLength) { TU_LOG2("[%u:%u] Control data:\r\n", rhport, dev_addr); TU_LOG2_MEM(_ctrl_xfer.buffer, xferred_bytes, 2); @@ -658,7 +659,7 @@ static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result // ACK stage: toggle is always 1 _set_control_xfer_stage(CONTROL_STAGE_ACK); - hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, 1-request->bmRequestType_bit.direction), NULL, 0); + TU_ASSERT( hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, 1-request->bmRequestType_bit.direction), NULL, 0) ); break; case CONTROL_STAGE_ACK: @@ -798,7 +799,7 @@ bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * b static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size) { - TU_LOG2("Open EP0 with Size = %u (addr = %u)\r\n", max_packet_size, dev_addr); + TU_LOG2("[%u:%u] Open EP0 with Size = %u\r\n", usbh_get_rhport(dev_addr), dev_addr, max_packet_size); tusb_desc_endpoint_t ep0_desc = { @@ -854,7 +855,7 @@ void hcd_devtree_get_info(uint8_t dev_addr, hcd_devtree_info_t* devtree_info) } } -void hcd_event_handler(hcd_event_t const* event, bool in_isr) +TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr) { switch (event->event_id) { @@ -864,52 +865,6 @@ void hcd_event_handler(hcd_event_t const* event, bool in_isr) } } -void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred_bytes, xfer_result_t result, bool in_isr) -{ - hcd_event_t event = - { - .rhport = 0, // TODO correct rhport - .event_id = HCD_EVENT_XFER_COMPLETE, - .dev_addr = dev_addr, - .xfer_complete = - { - .ep_addr = ep_addr, - .result = result, - .len = xferred_bytes - } - }; - - hcd_event_handler(&event, in_isr); -} - -void hcd_event_device_attach(uint8_t rhport, bool in_isr) -{ - hcd_event_t event = - { - .rhport = rhport, - .event_id = HCD_EVENT_DEVICE_ATTACH - }; - - event.connection.hub_addr = 0; - event.connection.hub_port = 0; - - hcd_event_handler(&event, in_isr); -} - -void hcd_event_device_remove(uint8_t hostid, bool in_isr) -{ - hcd_event_t event = - { - .rhport = hostid, - .event_id = HCD_EVENT_DEVICE_REMOVE - }; - - event.connection.hub_addr = 0; - event.connection.hub_port = 0; - - hcd_event_handler(&event, in_isr); -} - //--------------------------------------------------------------------+ // Descriptors Async //--------------------------------------------------------------------+ @@ -1184,7 +1139,7 @@ enum { //ENUM_HUB_GET_STATUS_1, ENUM_HUB_CLEAR_RESET_1, ENUM_ADDR0_DEVICE_DESC, - ENUM_RESET_2, // 2nd reset before set address + ENUM_RESET_2, // 2nd reset before set address (not used) ENUM_HUB_GET_STATUS_2, ENUM_HUB_CLEAR_RESET_2, ENUM_SET_ADDR, @@ -1272,15 +1227,17 @@ static void process_enumeration(tuh_xfer_t* xfer) } break; +#if 0 case ENUM_RESET_2: + // XXX note used by now, but may be needed for some devices !? // Reset device again before Set Address - TU_LOG2("Port reset \r\n"); + TU_LOG2("Port reset2 \r\n"); if (_dev0.hub_addr == 0) { // connected directly to roothub hcd_port_reset( _dev0.rhport ); osal_task_delay(RESET_DELAY); - + hcd_port_reset_end(_dev0.rhport); // TODO: fall through to SET ADDRESS, refactor later } #if CFG_TUH_HUB @@ -1292,6 +1249,7 @@ static void process_enumeration(tuh_xfer_t* xfer) } #endif __attribute__((fallthrough)); +#endif case ENUM_SET_ADDR: enum_request_set_addr(); @@ -1305,7 +1263,7 @@ static void process_enumeration(tuh_xfer_t* xfer) TU_ASSERT(new_dev, ); new_dev->addressed = 1; - // TODO close device 0, may not be needed + // Close device 0 hcd_device_close(_dev0.rhport, 0); // open control pipe for new address @@ -1396,7 +1354,9 @@ static bool enum_new_device(hcd_event_t* event) { // connected/disconnected directly with roothub // wait until device is stable TODO non blocking + hcd_port_reset(_dev0.rhport); osal_task_delay(RESET_DELAY); + hcd_port_reset_end( _dev0.rhport); // device unplugged while delaying if ( !hcd_port_connect_status(_dev0.rhport) ) return true; diff --git a/src/portable/ehci/ehci.c b/src/portable/ehci/ehci.c index 665f2380..76ba2a92 100644 --- a/src/portable/ehci/ehci.c +++ b/src/portable/ehci/ehci.c @@ -163,15 +163,15 @@ void hcd_port_reset(uint8_t rhport) regs->portsc = portsc; } -#if 0 void hcd_port_reset_end(uint8_t rhport) { (void) rhport; +#if 0 ehci_registers_t* regs = ehci_data.regs; regs->portsc_bm.port_reset = 0; -} #endif +} bool hcd_port_connect_status(uint8_t rhport) { diff --git a/src/portable/mentor/musb/hcd_musb.c b/src/portable/mentor/musb/hcd_musb.c index 3bfd65b4..85e18e3a 100644 --- a/src/portable/mentor/musb/hcd_musb.c +++ b/src/portable/mentor/musb/hcd_musb.c @@ -617,6 +617,11 @@ void hcd_port_reset(uint8_t rhport) _hcd.need_reset = false; } +void hcd_port_reset_end(uint8_t rhport) +{ + (void) rhport; +} + tusb_speed_t hcd_port_speed_get(uint8_t rhport) { (void)rhport; diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index e0938224..3e523ebc 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -216,6 +216,11 @@ void hcd_port_reset(uint8_t hostid) OHCI_REG->rhport_status[0] = RHPORT_PORT_RESET_STATUS_MASK; } +void hcd_port_reset_end(uint8_t rhport) +{ + (void) rhport; +} + bool hcd_port_connect_status(uint8_t hostid) { (void) hostid; diff --git a/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c new file mode 100644 index 00000000..1bc5594d --- /dev/null +++ b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c @@ -0,0 +1,210 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2018, hathach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && CFG_TUD_RPI_PIO_USB + +#include "pico.h" +#include "pio_usb.h" +#include "pio_usb_ll.h" + +#include "device/dcd.h" + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM DECLARATION +//--------------------------------------------------------------------+ + +#define RHPORT_OFFSET 1 +#define RHPORT_PIO(_x) ((_x)-RHPORT_OFFSET) + +//------------- -------------// +static usb_device_t *usb_device = NULL; +static usb_descriptor_buffers_t desc; + +/*------------------------------------------------------------------*/ +/* Device API + *------------------------------------------------------------------*/ + +// Initialize controller to device mode +void dcd_init (uint8_t rhport) +{ + (void) rhport; + + static pio_usb_configuration_t config = PIO_USB_DEFAULT_CONFIG; + usb_device = pio_usb_device_init(&config, &desc); +} + +// Enable device interrupt +void dcd_int_enable (uint8_t rhport) +{ + (void) rhport; +} + +// Disable device interrupt +void dcd_int_disable (uint8_t rhport) +{ + (void) rhport; +} + +// Receive Set Address request, mcu port must also include status IN response +void dcd_set_address (uint8_t rhport, uint8_t dev_addr) +{ + // must be called before queuing status + pio_usb_device_set_address(dev_addr); + dcd_edpt_xfer(rhport, 0x80, NULL, 0); +} + +// Wake up host +void dcd_remote_wakeup (uint8_t rhport) +{ + (void) rhport; +} + +// Connect by enabling internal pull-up resistor on D+/D- +void dcd_connect(uint8_t rhport) +{ + (void) rhport; +} + +// Disconnect by disabling internal pull-up resistor on D+/D- +void dcd_disconnect(uint8_t rhport) +{ + (void) rhport; +} + +//--------------------------------------------------------------------+ +// Endpoint API +//--------------------------------------------------------------------+ + +// Configure endpoint's registers according to descriptor +bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) +{ + (void) rhport; + return pio_usb_device_endpoint_open((uint8_t const*) desc_ep); +} + +void dcd_edpt_close_all (uint8_t rhport) +{ + (void) rhport; +} + +// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack +bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +{ + (void) rhport; + endpoint_t *ep = pio_usb_device_get_endpoint_by_address(ep_addr); + return pio_usb_ll_transfer_start(ep, buffer, total_bytes); +} + +// Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack - optional, however, must be listed in usbd.c +//bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +//{ +// (void) rhport; +// (void) ep_addr; +// (void) ff; +// (void) total_bytes; +// return false; +//} + +// Stall endpoint +void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + endpoint_t *ep = pio_usb_device_get_endpoint_by_address(ep_addr); + ep->has_transfer = false; + ep->stalled = true; +} + +// clear stall, data toggle is also reset to DATA0 +void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + endpoint_t *ep = pio_usb_device_get_endpoint_by_address(ep_addr); + ep->data_id = 0; + ep->stalled = false; +} + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +static void __no_inline_not_in_flash_func(handle_endpoint_irq)(uint8_t tu_rhport, xfer_result_t result, volatile uint32_t* ep_reg) +{ + const uint32_t ep_all = *ep_reg; + + for(uint8_t ep_idx = 0; ep_idx < PIO_USB_EP_POOL_CNT; ep_idx++) + { + uint32_t const mask = (1u << ep_idx); + + if (ep_all & mask) + { + endpoint_t* ep = PIO_USB_ENDPOINT(ep_idx); + dcd_event_xfer_complete(tu_rhport, ep->ep_num, ep->actual_len, result, true); + } + } + + // clear all + (*ep_reg) &= ~ep_all; +} + +// IRQ Handler +void __no_inline_not_in_flash_func(pio_usb_device_irq_handler)(uint8_t root_id) +{ + uint8_t const tu_rhport = root_id + 1; + root_port_t* rport = PIO_USB_ROOT_PORT(root_id); + uint32_t const ints = rport->ints; + + if (ints & PIO_USB_INTS_RESET_END_BITS) + { + dcd_event_bus_reset(tu_rhport, TUSB_SPEED_FULL, true); + } + + if (ints & PIO_USB_INTS_SETUP_REQ_BITS) + { + dcd_event_setup_received(tu_rhport, rport->setup_packet, true); + } + + if ( ints & PIO_USB_INTS_ENDPOINT_COMPLETE_BITS ) + { + handle_endpoint_irq(tu_rhport, XFER_RESULT_SUCCESS, &rport->ep_complete); + } + + if ( ints & PIO_USB_INTS_ENDPOINT_STALLED_BITS ) + { + handle_endpoint_irq(tu_rhport, XFER_RESULT_STALLED, &rport->ep_stalled); + } + + if ( ints & PIO_USB_INTS_ENDPOINT_ERROR_BITS ) + { + handle_endpoint_irq(tu_rhport, XFER_RESULT_FAILED, &rport->ep_error); + } + + // clear all + rport->ints &= ~ints; +} + +#endif diff --git a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c new file mode 100644 index 00000000..1b2d2933 --- /dev/null +++ b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c @@ -0,0 +1,217 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if CFG_TUH_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && CFG_TUH_RPI_PIO_USB + +#include "pico.h" +#include "pio_usb.h" +#include "pio_usb_ll.h" + +//--------------------------------------------------------------------+ +// INCLUDE +//--------------------------------------------------------------------+ +#include "osal/osal.h" + +#include "host/hcd.h" +#include "host/usbh.h" + +#define RHPORT_OFFSET 1 +#define RHPORT_PIO(_x) ((_x)-RHPORT_OFFSET) + +static pio_usb_configuration_t pio_host_config = PIO_USB_DEFAULT_CONFIG; + +//--------------------------------------------------------------------+ +// HCD API +//--------------------------------------------------------------------+ +bool hcd_init(uint8_t rhport) +{ + (void) rhport; + + // To run USB SOF interrupt in core1, call this init in core1 + pio_usb_host_init(&pio_host_config); + + return true; +} + +void hcd_port_reset(uint8_t rhport) +{ + uint8_t const pio_rhport = RHPORT_PIO(rhport); + pio_usb_host_port_reset_start(pio_rhport); +} + +void hcd_port_reset_end(uint8_t rhport) +{ + uint8_t const pio_rhport = RHPORT_PIO(rhport); + pio_usb_host_port_reset_end(pio_rhport); +} + +bool hcd_port_connect_status(uint8_t rhport) +{ + uint8_t const pio_rhport = RHPORT_PIO(rhport); + + root_port_t *root = PIO_USB_ROOT_PORT(pio_rhport); + port_pin_status_t line_state = pio_usb_bus_get_line_state(root); + + return line_state != PORT_PIN_SE0; +} + +tusb_speed_t hcd_port_speed_get(uint8_t rhport) +{ + // TODO determine link speed + uint8_t const pio_rhport = RHPORT_PIO(rhport); + return PIO_USB_ROOT_PORT(pio_rhport)->is_fullspeed ? TUSB_SPEED_FULL : TUSB_SPEED_LOW; +} + +// Close all opened endpoint belong to this device +void hcd_device_close(uint8_t rhport, uint8_t dev_addr) +{ + uint8_t const pio_rhport = RHPORT_PIO(rhport); + pio_usb_host_close_device(pio_rhport, dev_addr); +} + +uint32_t hcd_frame_number(uint8_t rhport) +{ + (void) rhport; + return 0; +} + +void hcd_int_enable(uint8_t rhport) +{ + (void) rhport; +} + +void hcd_int_disable(uint8_t rhport) +{ + (void) rhport; +} + +//--------------------------------------------------------------------+ +// Endpoint API +//--------------------------------------------------------------------+ + +bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep) +{ + hcd_devtree_info_t dev_tree; + hcd_devtree_get_info(dev_addr, &dev_tree); + bool const need_pre = (dev_tree.hub_addr && dev_tree.speed == TUSB_SPEED_LOW); + + uint8_t const pio_rhport = RHPORT_PIO(rhport); + return pio_usb_host_endpoint_open(pio_rhport, dev_addr, (uint8_t const*) desc_ep, need_pre); +} + +bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) +{ + uint8_t const pio_rhport = RHPORT_PIO(rhport); + return pio_usb_host_endpoint_transfer(pio_rhport, dev_addr, ep_addr, buffer, buflen); +} + +bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) +{ + uint8_t const pio_rhport = RHPORT_PIO(rhport); + return pio_usb_host_send_setup(pio_rhport, dev_addr, setup_packet); +} + +//bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr) +//{ +// // EPX is shared, so multiple device addresses and endpoint addresses share that +// // so if any transfer is active on epx, we are busy. Interrupt endpoints have their own +// // EPX so ep->active will only be busy if there is a pending transfer on that interrupt endpoint +// // on that device +// pico_trace("hcd_edpt_busy dev addr %d ep_addr 0x%x\n", dev_addr, ep_addr); +// struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr); +// assert(ep); +// bool busy = ep->active; +// pico_trace("busy == %d\n", busy); +// return busy; +//} + +bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr) +{ + (void) dev_addr; + (void) ep_addr; + + return true; +} + +static void __no_inline_not_in_flash_func(handle_endpoint_irq)(root_port_t* rport, xfer_result_t result, volatile uint32_t* ep_reg) +{ + (void) rport; + const uint32_t ep_all = *ep_reg; + + for(uint8_t ep_idx = 0; ep_idx < PIO_USB_EP_POOL_CNT; ep_idx++) + { + uint32_t const mask = (1u << ep_idx); + + if (ep_all & mask) + { + endpoint_t* ep = PIO_USB_ENDPOINT(ep_idx); + hcd_event_xfer_complete(ep->dev_addr, ep->ep_num, ep->actual_len, result, true); + } + } + + // clear all + (*ep_reg) &= ~ep_all; +} + +// IRQ Handler +void __no_inline_not_in_flash_func(pio_usb_host_irq_handler)(uint8_t root_id) +{ + uint8_t const tu_rhport = root_id + 1; + root_port_t* rport = PIO_USB_ROOT_PORT(root_id); + uint32_t const ints = rport->ints; + + if ( ints & PIO_USB_INTS_CONNECT_BITS ) + { + hcd_event_device_attach(tu_rhport, true); + } + + if ( ints & PIO_USB_INTS_DISCONNECT_BITS ) + { + hcd_event_device_remove(tu_rhport, true); + } + + if ( ints & PIO_USB_INTS_ENDPOINT_COMPLETE_BITS ) + { + handle_endpoint_irq(rport, XFER_RESULT_SUCCESS, &rport->ep_complete); + } + + if ( ints & PIO_USB_INTS_ENDPOINT_STALLED_BITS ) + { + handle_endpoint_irq(rport, XFER_RESULT_STALLED, &rport->ep_stalled); + } + + if ( ints & PIO_USB_INTS_ENDPOINT_ERROR_BITS ) + { + handle_endpoint_irq(rport, XFER_RESULT_FAILED, &rport->ep_error); + } + + // clear all + rport->ints &= ~ints; +} + +#endif diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c index 91582279..2d77ad4f 100644 --- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c @@ -26,7 +26,7 @@ #include "tusb_option.h" -#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_RP2040 +#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && !CFG_TUD_RPI_PIO_USB #include "pico.h" #include "rp2040_usb.h" diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c index 234bea20..5164035a 100644 --- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c @@ -27,7 +27,7 @@ #include "tusb_option.h" -#if CFG_TUH_ENABLED && CFG_TUSB_MCU == OPT_MCU_RP2040 +#if CFG_TUH_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && !CFG_TUH_RPI_PIO_USB #include "pico.h" #include "rp2040_usb.h" @@ -40,7 +40,8 @@ #include "host/hcd.h" #include "host/usbh.h" -#define ROOT_PORT 0 +// port 0 is native USB port, other is counted as software PIO +#define RHPORT_NATIVE 0 //--------------------------------------------------------------------+ // Low level rp2040 controller functions @@ -185,11 +186,11 @@ static void hcd_rp2040_irq(void) if (dev_speed()) { - hcd_event_device_attach(ROOT_PORT, true); + hcd_event_device_attach(RHPORT_NATIVE, true); } else { - hcd_event_device_remove(ROOT_PORT, true); + hcd_event_device_remove(RHPORT_NATIVE, true); } // Clear speed change interrupt @@ -388,6 +389,11 @@ void hcd_port_reset(uint8_t rhport) // TODO: Nothing to do here yet. Perhaps need to reset some state? } +void hcd_port_reset_end(uint8_t rhport) +{ + (void) rhport; +} + bool hcd_port_connect_status(uint8_t rhport) { pico_trace("hcd_port_connect_status\n"); diff --git a/src/portable/renesas/usba/hcd_usba.c b/src/portable/renesas/usba/hcd_usba.c index ebb68234..5246ecb9 100644 --- a/src/portable/renesas/usba/hcd_usba.c +++ b/src/portable/renesas/usba/hcd_usba.c @@ -620,6 +620,11 @@ void hcd_port_reset(uint8_t rhport) _hcd.need_reset = false; } +void hcd_port_reset_end(uint8_t rhport) +{ + (void) rhport; +} + tusb_speed_t hcd_port_speed_get(uint8_t rhport) { (void)rhport; diff --git a/src/tusb_option.h b/src/tusb_option.h index 9cacedd4..0c914bc4 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -239,7 +239,7 @@ #define TUH_OPT_RHPORT -1 #endif -#define CFG_TUH_ENABLED ( TUH_RHPORT_MODE & OPT_MODE_HOST ) +#define CFG_TUH_ENABLED (TUH_RHPORT_MODE & OPT_MODE_HOST) // For backward compatible #define TUSB_OPT_DEVICE_ENABLED CFG_TUD_ENABLED @@ -258,7 +258,7 @@ //--------------------------------------------------------------------+ -// COMMON OPTIONS +// Common Options (Default) //--------------------------------------------------------------------+ // Debug enable to print out error message @@ -289,7 +289,7 @@ #define TUSB_OPT_MUTEX (CFG_TUSB_OS != OPT_OS_NONE) //-------------------------------------------------------------------- -// DEVICE OPTIONS +// Device Options (Default) //-------------------------------------------------------------------- #ifndef CFG_TUD_ENDPOINT0_SIZE @@ -354,7 +354,7 @@ #endif //-------------------------------------------------------------------- -// HOST OPTIONS +// Host Options (Default) //-------------------------------------------------------------------- #if CFG_TUH_ENABLED #ifndef CFG_TUH_DEVICE_MAX @@ -396,6 +396,16 @@ #define CFG_TUH_API_EDPT_XFER 0 #endif +// Enable PIO-USB software host controller +#ifndef CFG_TUH_RPI_PIO_USB +#define CFG_TUH_RPI_PIO_USB 0 +#endif + +#ifndef CFG_TUD_RPI_PIO_USB +#define CFG_TUD_RPI_PIO_USB 0 +#endif + + //------------------------------------------------------------------ // Configuration Validation //------------------------------------------------------------------ diff --git a/tools/build_board.py b/tools/build_board.py index b2a80c68..4d895329 100644 --- a/tools/build_board.py +++ b/tools/build_board.py @@ -28,12 +28,11 @@ def filter_with_input(mylist): # If examples are not specified in arguments, build all all_examples = [] -for entry in os.scandir("examples/device"): - if entry.is_dir(): - all_examples.append("device/" + entry.name) -for entry in os.scandir("examples/host"): - if entry.is_dir(): - all_examples.append("host/" + entry.name) +for dir1 in os.scandir("examples"): + if dir1.is_dir(): + for entry in os.scandir(dir1.path): + if entry.is_dir(): + all_examples.append(dir1.name + '/' + entry.name) filter_with_input(all_examples) all_examples.sort() diff --git a/tools/build_family.py b/tools/build_family.py index 4094d07d..095ca4ff 100644 --- a/tools/build_family.py +++ b/tools/build_family.py @@ -28,12 +28,11 @@ def filter_with_input(mylist): # If examples are not specified in arguments, build all all_examples = [] -for entry in os.scandir("examples/device"): - if entry.is_dir(): - all_examples.append("device/" + entry.name) -for entry in os.scandir("examples/host"): - if entry.is_dir(): - all_examples.append("host/" + entry.name) +for dir1 in os.scandir("examples"): + if dir1.is_dir(): + for entry in os.scandir(dir1.path): + if entry.is_dir(): + all_examples.append(dir1.name + '/' + entry.name) filter_with_input(all_examples) all_examples.sort()