From 80224770316966e4339d414c60aea6a5020caa16 Mon Sep 17 00:00:00 2001 From: Reimu NotMoe Date: Fri, 27 Dec 2024 00:36:31 +0800 Subject: dcd_pic: add readme --- src/portable/microchip/pic/README.md | 51 ++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/portable/microchip/pic/README.md (limited to 'src/portable') diff --git a/src/portable/microchip/pic/README.md b/src/portable/microchip/pic/README.md new file mode 100644 index 000000000..7ba6a4a96 --- /dev/null +++ b/src/portable/microchip/pic/README.md @@ -0,0 +1,51 @@ +# Microchip PIC Chipidea FS Driver + +This driver adds support for Microchip PIC microcontrollers with full-speed Chipidea USB peripheral to the TinyUSB stack. It supports the following families: + +- PIC32MX (untested) +- PIC32MM +- PIC32MK (untested) +- PIC24FJ +- PIC24EP (untested) +- dsPIC33EP (untested) + +Currently only the device mode is supported. + + +## Important Notes + +### Handling of shared VBUS & GPIO pin + +Some PICs have the USB VBUS pin bonded with a GPIO pin in the chip package. This driver does **NOT** handle the potential conflict between the VBUS and GPIO functionalities. + +Developers must ensure that the GPIO pin is tristated when the VBUS pin is managed by the USB peripheral in order to prevent damaging the chip. + +This design choice allows developers the flexibility to use the GPIO functionality for controlling VBUS in device mode if desired. + + +## TODO + +### Handle USB remote wakeup timing correctly + +The Chipidea FS IP doesn't handle the RESUME signal automatically and it must be managed in software. It needs to be asserted for exactly 10ms, and this is impossible to do without per-device support due to BSP differences. For now, a simple for-based loop is used. + +### 8-bit PIC support + +The 8-bit PICs also uses the Chipidea FS IP. Technically it's possible to support them as well. + +Possible difficulties: +- Memory size constraints (1KB/8KB ballpark) +- A third BDT layout (now we have two) +- Different compiler-specific directives +- Compiler bugs if you use SDCC + + +## Author +[ReimuNotMoe](https://github.com/ReimuNotMoe) at SudoMaker, Ltd. + + +## Credits + +This driver is based on: +- Microchip's USB driver (usb_device.c) +- TinyUSB's NXP KHCI driver (dcd_khci.c) -- cgit v1.3.1 From 99e6b32a7da695f16a2fed93c59bfa0d5a1952dc Mon Sep 17 00:00:00 2001 From: Reimu NotMoe Date: Fri, 27 Dec 2024 00:36:42 +0800 Subject: dcd_pic: change license header and credit people accordingly --- src/portable/microchip/pic/dcd_pic.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/portable') diff --git a/src/portable/microchip/pic/dcd_pic.c b/src/portable/microchip/pic/dcd_pic.c index d40c4794a..461c65259 100644 --- a/src/portable/microchip/pic/dcd_pic.c +++ b/src/portable/microchip/pic/dcd_pic.c @@ -1,8 +1,11 @@ /* * The MIT License (MIT) * - * Copyright (c) 2020 Koji Kitayama - * Copyright (c) 2022 Reimu NotMoe + * Copyright (c) 2022-2024 SudoMaker, Ltd. + * Author: Mike Yang (Reimu NotMoe) + * + * Based on usb_device.c - Copyright (c) 2015 Microchip Technology Inc. + * Based on dcd_khci.c - Copyright (c) 2020 Koji Kitayama * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal -- cgit v1.3.1 From 8907a817a2a782423bf8d6db2136147b6e334225 Mon Sep 17 00:00:00 2001 From: Reimu NotMoe Date: Fri, 27 Dec 2024 00:50:32 +0800 Subject: dcd_pic: handle bus resume correctly --- src/portable/microchip/pic/dcd_pic.c | 58 ++++++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 9 deletions(-) (limited to 'src/portable') diff --git a/src/portable/microchip/pic/dcd_pic.c b/src/portable/microchip/pic/dcd_pic.c index 461c65259..0dac18523 100644 --- a/src/portable/microchip/pic/dcd_pic.c +++ b/src/portable/microchip/pic/dcd_pic.c @@ -741,8 +741,11 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) //--------------------------------------------------------------------+ void dcd_int_handler(uint8_t rhport) { - uint32_t is = U1IR; - uint32_t msk = U1IE; + uint32_t is, msk; + + // Part 1 - "USB interrupts" + is = U1IR; + msk = U1IE; U1IR = is & ~msk; is &= msk; @@ -750,7 +753,7 @@ void dcd_int_handler(uint8_t rhport) if (is & _U1IR_UERRIF_MASK) { uint32_t es = U1EIR; U1EIR = es; - U1IR = is; /* discard any pending events */ + U1IR = is; /* discard any pending events */ } if (is & _U1IR_URSTIF_MASK) { @@ -761,29 +764,66 @@ void dcd_int_handler(uint8_t rhport) if (is & _U1IR_IDLEIF_MASK) { // Note Host usually has extra delay after bus reset (without SOF), which could falsely // detected as Sleep event. Though usbd has debouncing logic so we are good + + /* + * NOTE: Do not clear U1OTGIRbits.ACTVIF here! + * Reason: + * ACTVIF is only generated once an IDLEIF has been generated. + * This is a 1:1 ratio interrupt generation. + * For every IDLEIF, there will be only one ACTVIF regardless of + * the number of subsequent bus transitions. + * + * If the ACTIF is cleared here, a problem could occur when: + * [ IDLE ][bus activity -> + * <--- 3 ms -----> ^ + * ^ ACTVIF=1 + * IDLEIF=1 + * # # # # (#=Program polling flags) + * ^ + * This polling loop will see both + * IDLEIF=1 and ACTVIF=1. + * However, the program services IDLEIF first + * because ACTIVIE=0. + * If this routine clears the only ACTIVIF, + * then it can never get out of the suspend + * mode. + */ + U1OTGIESET = _U1OTGIE_ACTVIE_MASK; U1IR = _U1IR_IDLEIF_MASK; process_bus_sleep(rhport); } - if (is & _U1IR_RESUMEIF_MASK) { - U1IR = _U1IR_RESUMEIF_MASK; - process_bus_resume(rhport); - } - if (is & _U1IR_SOFIF_MASK) { U1IR = _U1IR_SOFIF_MASK; dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true); } if (is & _U1IR_STALLIF_MASK) { - U1IR = _U1IR_STALLIF_MASK; process_stall(rhport); + U1IR = _U1IR_STALLIF_MASK; } if (is & _U1IR_TRNIF_MASK) { process_tokdne(rhport); } + // Part 2 - "USB OTG interrupts" + is = U1OTGIR; + msk = U1OTGIE; + + U1OTGIR = is & ~msk; + is &= msk; + + if (is & _U1OTGIR_ACTVIF_MASK) { +#if TU_PIC_INT_SIZE == 4 + U1OTGIECLR = _U1OTGIE_ACTVIE_MASK; +#else + U1OTGIE &= ~_U1OTGIE_ACTVIE_MASK; +#endif + U1OTGIR = _U1OTGIR_ACTVIF_MASK; + process_bus_resume(rhport); + } + intr_clear(rhport); } -- cgit v1.3.1 From f409472998cfba4f6be0534912c1afd48e0d6816 Mon Sep 17 00:00:00 2001 From: Reimu NotMoe Date: Fri, 27 Dec 2024 00:57:22 +0800 Subject: dcd_pic: handle remote wakeup more correctly --- src/portable/microchip/pic/dcd_pic.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'src/portable') diff --git a/src/portable/microchip/pic/dcd_pic.c b/src/portable/microchip/pic/dcd_pic.c index 0dac18523..9ffeb0811 100644 --- a/src/portable/microchip/pic/dcd_pic.c +++ b/src/portable/microchip/pic/dcd_pic.c @@ -532,8 +532,25 @@ void dcd_remote_wakeup(uint8_t rhport) #else U1CONbits.RESUME = 1; #endif - unsigned cnt = 25000000 / 1000; + + // FIXME: Assert RESUME signal correctly, requires device-specific handling + // For now we use a hardcoded cycle-based delay which attempts to delay 10ms + // at the most common CPU frequencies. On PIC32s we assume the loop body + // takes 3 cycles. On 16-bit PICs we assume the XC16 compiler is in use and + // use its `__delay_ms' function. + +#if CFG_TUSB_MCU == OPT_MCU_PIC32MM + uint32_t cnt = 24000000 / 1000 / 3; + while (cnt--) asm volatile("nop"); +#elif CFG_TUSB_MCU == OPT_MCU_PIC32MX + uint32_t cnt = 40000000 / 1000 / 3; while (cnt--) asm volatile("nop"); +#elif CFG_TUSB_MCU == OPT_MCU_PIC32MK + uint32_t cnt = 120000000 / 1000 / 3; + while (cnt--) asm volatile("nop"); +#else + __delay_ms(10); +#endif #if TU_PIC_INT_SIZE == 4 U1CONCLR = _U1CON_RESUME_MASK; -- cgit v1.3.1 From 0192b2a9b0a8a7a300326c27ebd59f15cb34790e Mon Sep 17 00:00:00 2001 From: Reimu NotMoe Date: Fri, 27 Dec 2024 00:59:45 +0800 Subject: dcd_pic: implement dcd_deinit() --- src/portable/microchip/pic/dcd_pic.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src/portable') diff --git a/src/portable/microchip/pic/dcd_pic.c b/src/portable/microchip/pic/dcd_pic.c index 9ffeb0811..04c54059f 100644 --- a/src/portable/microchip/pic/dcd_pic.c +++ b/src/portable/microchip/pic/dcd_pic.c @@ -508,6 +508,19 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { return true; } +bool dcd_deinit(uint8_t rhport) +{ + U1CON = 0; + U1IE = 0; + U1OTGIE = 0; +#if TU_PIC_INT_SIZE == 4 + U1PWRCCLR = _U1PWRC_USUSPEND_MASK | _U1PWRC_USBPWR_MASK; +#else + U1PWRC &= ~(_U1PWRC_USUSPEND_MASK | _U1PWRC_USBPWR_MASK); +#endif + return true; +} + void dcd_int_enable(uint8_t rhport) { intr_enable(rhport); -- cgit v1.3.1 From 6e1140683140eb7bb80dfae0d207a920dec6d12c Mon Sep 17 00:00:00 2001 From: Reimu NotMoe Date: Fri, 27 Dec 2024 01:02:10 +0800 Subject: dcd_pic: handle EP0 timeout/stall correctly --- src/portable/microchip/pic/dcd_pic.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'src/portable') diff --git a/src/portable/microchip/pic/dcd_pic.c b/src/portable/microchip/pic/dcd_pic.c index 04c54059f..4e0bd735e 100644 --- a/src/portable/microchip/pic/dcd_pic.c +++ b/src/portable/microchip/pic/dcd_pic.c @@ -316,12 +316,23 @@ static void prepare_next_setup_packet(uint8_t rhport) { const unsigned out_odd = _dcd.endpoint[0][0].odd; const unsigned in_odd = _dcd.endpoint[0][1].odd; - TU_ASSERT(0 == _dcd.bdt[0][0][out_odd].own, ); + + // Abandon any previous control transfers that might have been using EP0. + // Ordinarily, nothing actually needs abandoning, since the previous control + // transfer would have completed successfully prior to the host sending the + // next SETUP packet. However, in a timeout error case, or after an EP0 + // STALL event, one or more UOWN bits might still be set. If so, we should + // clear the UOWN bits, so the EP0 IN/OUT endpoints are in a known inactive + // state, ready for re-arming by the `dcd_edpt_xfer' function that will be + // called next. _dcd.bdt[0][0][out_odd].data = 0; + _dcd.bdt[0][0][out_odd].own = 0; _dcd.bdt[0][0][out_odd ^ 1].data = 1; _dcd.bdt[0][1][in_odd].data = 1; + _dcd.bdt[0][1][in_odd].own = 0; _dcd.bdt[0][1][in_odd ^ 1].data = 0; + _dcd.bdt[0][1][in_odd ^ 1].own = 0; dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_OUT), _dcd.setup_packet, sizeof(_dcd.setup_packet)); } -- cgit v1.3.1 From a4169114ec6acb07cf8e26a1718e61c0c7af69fa Mon Sep 17 00:00:00 2001 From: Reimu NotMoe Date: Fri, 27 Dec 2024 01:04:29 +0800 Subject: dcd_pic: let the user manage shared GPIO/VBUS pin --- src/portable/microchip/pic/dcd_pic.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/portable') diff --git a/src/portable/microchip/pic/dcd_pic.c b/src/portable/microchip/pic/dcd_pic.c index 4e0bd735e..a4fa0e840 100644 --- a/src/portable/microchip/pic/dcd_pic.c +++ b/src/portable/microchip/pic/dcd_pic.c @@ -489,10 +489,6 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { intr_disable(rhport); intr_clear(rhport); -#if CFG_TUSB_MCU == OPT_MCU_PIC32MM - TRISBbits.TRISB6 = 1; -#endif - tu_memclr(&_dcd, sizeof(_dcd)); #if TU_PIC_INT_SIZE == 4 -- cgit v1.3.1 From 655092d568720188a3a34b9376a7ebcf274dab79 Mon Sep 17 00:00:00 2001 From: Reimu NotMoe Date: Fri, 27 Dec 2024 04:17:26 +0800 Subject: dcd_pic: check USBBUSY bit on PIC32s --- src/portable/microchip/pic/dcd_pic.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/portable') diff --git a/src/portable/microchip/pic/dcd_pic.c b/src/portable/microchip/pic/dcd_pic.c index a4fa0e840..b4a698199 100644 --- a/src/portable/microchip/pic/dcd_pic.c +++ b/src/portable/microchip/pic/dcd_pic.c @@ -492,6 +492,9 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { tu_memclr(&_dcd, sizeof(_dcd)); #if TU_PIC_INT_SIZE == 4 + // The USBBUSY bit is present on PIC32s and we're required to check it + // prior to powering on the USB peripheral (see DS61126F page 27) + while (U1PWRCbits.USBBUSY); U1PWRCSET = _U1PWRC_USBPWR_MASK; #else U1PWRCbits.USBPWR = 1; -- cgit v1.3.1 From b91d5ebb4509d02d108e249197884913698aac1c Mon Sep 17 00:00:00 2001 From: pschatzmann Date: Sat, 4 Jan 2025 22:20:46 +0100 Subject: rp2040 correct dcd_edpt_iso_activate --- src/portable/raspberrypi/rp2040/dcd_rp2040.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/portable') diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c index af08b549d..b91dd38d5 100644 --- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c @@ -496,6 +496,12 @@ bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) { (void) rhport; const uint8_t ep_addr = ep_desc->bEndpointAddress; + + // init w/o allocate + const uint16_t mps = ep_desc->wMaxPacketSize; + uint16_t size = (uint16_t)tu_div_ceil(mps, 64) * 64u; + hw_endpoint_init(ep_addr, size, TUSB_XFER_ISOCHRONOUS); + // Fill in endpoint control register with buffer offset struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr); TU_ASSERT(ep->hw_data_buf != NULL); // must be inited and buffer allocated -- cgit v1.3.1 From f7fa4d0edb2eccfe494d1499a6fc4ef3e039309b Mon Sep 17 00:00:00 2001 From: Jannis Konrad Date: Wed, 5 Feb 2025 17:35:02 +0100 Subject: ch32v3 fs: signal bus speed --- src/portable/wch/dcd_ch32_usbfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/portable') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 4e8e25a00..d7674b5a3 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -192,7 +192,8 @@ void dcd_int_handler(uint8_t rhport) { data.xfer[0][TUSB_DIR_OUT].max_size = 64; data.xfer[0][TUSB_DIR_IN].max_size = 64; - dcd_event_bus_signal(rhport, DCD_EVENT_BUS_RESET, true); + //dcd_event_bus_reset(rhport, (USBOTG_FS->BASE_CTRL & USBFS_CTRL_LOW_SPEED) ? 1 : 0, true); + dcd_event_bus_reset(rhport, (USBOTG_FS->UDEV_CTRL & USBFS_UDEV_CTRL_LOW_SPEED) ? 1 : 0, true); USBOTG_FS->DEV_ADDR = 0x00; EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; -- cgit v1.3.1 From 169d2d7a1fd120d8d0267eaf0a7dcc5e47059100 Mon Sep 17 00:00:00 2001 From: Jannis Konrad Date: Thu, 6 Feb 2025 08:50:25 +0100 Subject: use speed enum --- src/portable/wch/dcd_ch32_usbfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/portable') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index d7674b5a3..c248ba14e 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -192,8 +192,8 @@ void dcd_int_handler(uint8_t rhport) { data.xfer[0][TUSB_DIR_OUT].max_size = 64; data.xfer[0][TUSB_DIR_IN].max_size = 64; - //dcd_event_bus_reset(rhport, (USBOTG_FS->BASE_CTRL & USBFS_CTRL_LOW_SPEED) ? 1 : 0, true); - dcd_event_bus_reset(rhport, (USBOTG_FS->UDEV_CTRL & USBFS_UDEV_CTRL_LOW_SPEED) ? 1 : 0, true); + //dcd_event_bus_reset(rhport, (USBOTG_FS->BASE_CTRL & USBFS_CTRL_LOW_SPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL, true); + dcd_event_bus_reset(rhport, (USBOTG_FS->UDEV_CTRL & USBFS_UDEV_CTRL_LOW_SPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL, true); USBOTG_FS->DEV_ADDR = 0x00; EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; -- cgit v1.3.1 From 93ff3daa116471e41615b85cd7d466cc48bc2148 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 28 Feb 2025 16:41:51 +0700 Subject: fix(hcd_rp2040) assert/panic endpoint already active: when a device reset while having on-going control transfer --- src/portable/raspberrypi/rp2040/hcd_rp2040.c | 48 +++++++++++++++------------- src/portable/raspberrypi/rp2040/rp2040_usb.c | 2 +- 2 files changed, 27 insertions(+), 23 deletions(-) (limited to 'src/portable') diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c index 2c0a3fd49..478c6e789 100644 --- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c @@ -459,28 +459,33 @@ tusb_speed_t hcd_port_speed_get(uint8_t rhport) } // Close all opened endpoint belong to this device -void hcd_device_close(uint8_t rhport, uint8_t dev_addr) -{ +void hcd_device_close(uint8_t rhport, uint8_t dev_addr) { pico_trace("hcd_device_close %d\n", dev_addr); (void) rhport; - if (dev_addr == 0) return; - - for (size_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++) - { - hw_endpoint_t* ep = &ep_pool[i]; + // reset epx if it is currently active with unplugged device + if (epx.configured && epx.active && epx.dev_addr == dev_addr) { + epx.configured = false; + *epx.endpoint_control = 0; + *epx.buffer_control = 0; + hw_endpoint_reset_transfer(&epx); + } - if (ep->dev_addr == dev_addr && ep->configured) - { - // in case it is an interrupt endpoint, disable it - usb_hw_clear->int_ep_ctrl = (1 << (ep->interrupt_num + 1)); - usb_hw->int_ep_addr_ctrl[ep->interrupt_num] = 0; - - // unconfigure the endpoint - ep->configured = false; - *ep->endpoint_control = 0; - *ep->buffer_control = 0; - hw_endpoint_reset_transfer(ep); + // dev0 only has ep0 + if (dev_addr != 0) { + for (size_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++) { + hw_endpoint_t *ep = &ep_pool[i]; + if (ep->dev_addr == dev_addr && ep->configured) { + // in case it is an interrupt endpoint, disable it + usb_hw_clear->int_ep_ctrl = (1 << (ep->interrupt_num + 1)); + usb_hw->int_ep_addr_ctrl[ep->interrupt_num] = 0; + + // unconfigure the endpoint + ep->configured = false; + *ep->endpoint_control = 0; + *ep->buffer_control = 0; + hw_endpoint_reset_transfer(ep); + } } } } @@ -557,7 +562,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * } // If a normal transfer (non-interrupt) then initiate using - // sie ctrl registers. Otherwise interrupt ep registers should + // sie ctrl registers. Otherwise, interrupt ep registers should // already be configured if ( ep == &epx ) { @@ -597,13 +602,12 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet (void) rhport; // Copy data into setup packet buffer - for ( uint8_t i = 0; i < 8; i++ ) - { + for (uint8_t i = 0; i < 8; i++) { usbh_dpram->setup_packet[i] = setup_packet[i]; } // Configure EP0 struct with setup info for the trans complete - struct hw_endpoint * ep = _hw_endpoint_allocate(0); + struct hw_endpoint * ep = _hw_endpoint_allocate( (uint8_t) TUSB_XFER_CONTROL); TU_ASSERT(ep); // EPX should be inactive diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c index 43f48da39..9d0bd762d 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.c +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c @@ -110,7 +110,7 @@ void __tusb_irq_path_func(_hw_endpoint_buffer_control_update32)(struct hw_endpoi *ep->buffer_control = value & ~USB_BUF_CTRL_AVAIL; // 4.1.2.5.1 Con-current access: 12 cycles (should be good for 48*12Mhz = 576Mhz) after write to buffer control // Don't need delay in host mode as host is in charge - if ( !is_host_mode()) { + if (!is_host_mode()) { busy_wait_at_least_cycles(12); } } -- cgit v1.3.1 From 102c1991d0abcfba9275830c48706ac34d7734d5 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 5 Mar 2025 22:26:28 +0700 Subject: rp2040: abort transfer if active in iso_activate() add hw_endpoint_abort_xfer() --- src/portable/raspberrypi/rp2040/dcd_rp2040.c | 59 ++++++++++++++++------------ 1 file changed, 33 insertions(+), 26 deletions(-) (limited to 'src/portable') diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c index b91dd38d5..358ce84bc 100644 --- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c @@ -148,6 +148,32 @@ static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t* buffer, uint16_t total_by hw_endpoint_xfer_start(ep, buffer, total_bytes); } +static void hw_endpoint_abort_xfer(struct hw_endpoint* ep) { + // Abort any pending transfer + // Due to Errata RP2040-E2: ABORT flag is only applicable for B2 and later (unusable for B0, B1). + // Which means we are not guaranteed to safely abort pending transfer on B0 and B1. + const uint8_t dir = tu_edpt_dir(ep->ep_addr); + const uint8_t epnum = tu_edpt_number(ep->ep_addr); + const uint32_t abort_mask = TU_BIT((epnum << 1) | (dir ? 0 : 1)); + if (rp2040_chip_version() >= 2) { + usb_hw_set->abort = abort_mask; + while ((usb_hw->abort_done & abort_mask) != abort_mask) {} + } + + uint32_t buf_ctrl = USB_BUF_CTRL_SEL; // reset to buffer 0 + if (ep->next_pid) { + buf_ctrl |= USB_BUF_CTRL_DATA1_PID; + } + + _hw_endpoint_buffer_control_set_value32(ep, buf_ctrl); + hw_endpoint_reset_transfer(ep); + + if (rp2040_chip_version() >= 2) { + usb_hw_clear->abort_done = abort_mask; + usb_hw_clear->abort = abort_mask; + } +} + static void __tusb_irq_path_func(hw_handle_buff_status)(void) { uint32_t remaining_buffers = usb_hw->buf_status; pico_trace("buf_status = 0x%08lx\r\n", remaining_buffers); @@ -178,25 +204,10 @@ TU_ATTR_ALWAYS_INLINE static inline void reset_ep0(void) { // setup transfer. Also clear a stall in case for (uint8_t dir = 0; dir < 2; dir++) { struct hw_endpoint* ep = hw_endpoint_get_by_num(0, dir); + ep->next_pid = 1u; if (ep->active) { - // Abort any pending transfer from a prior control transfer per USB specs - // Due to Errata RP2040-E2: ABORT flag is only applicable for B2 and later (unusable for B0, B1). - // Which means we are not guaranteed to safely abort pending transfer on B0 and B1. - uint32_t const abort_mask = (dir ? USB_EP_ABORT_EP0_IN_BITS : USB_EP_ABORT_EP0_OUT_BITS); - if (rp2040_chip_version() >= 2) { - usb_hw_set->abort = abort_mask; - while ((usb_hw->abort_done & abort_mask) != abort_mask) {} - } - - _hw_endpoint_buffer_control_set_value32(ep, USB_BUF_CTRL_DATA1_PID | USB_BUF_CTRL_SEL); - hw_endpoint_reset_transfer(ep); - - if (rp2040_chip_version() >= 2) { - usb_hw_clear->abort_done = abort_mask; - usb_hw_clear->abort = abort_mask; - } + hw_endpoint_abort_xfer(ep); // Abort any pending transfer per USB specs } - ep->next_pid = 1u; } } @@ -495,18 +506,14 @@ bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet // New API: Configure and enable an ISO endpoint according to descriptor bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) { (void) rhport; - const uint8_t ep_addr = ep_desc->bEndpointAddress; + struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_desc->bEndpointAddress); + TU_ASSERT(ep->hw_data_buf != NULL); // must be inited and allocated previously - // init w/o allocate - const uint16_t mps = ep_desc->wMaxPacketSize; - uint16_t size = (uint16_t)tu_div_ceil(mps, 64) * 64u; - hw_endpoint_init(ep_addr, size, TUSB_XFER_ISOCHRONOUS); + if (ep->active) { + hw_endpoint_abort_xfer(ep); // abort any pending transfer + } - // Fill in endpoint control register with buffer offset - struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr); - TU_ASSERT(ep->hw_data_buf != NULL); // must be inited and buffer allocated ep->wMaxPacketSize = ep_desc->wMaxPacketSize; - hw_endpoint_enable(ep); return true; } -- cgit v1.3.1 From 65e44e0a51272f9d75719d90955f19209dbf1ea2 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 6 Mar 2025 22:46:21 +0700 Subject: fix(dwc2) host driver conflict with max3421e --- examples/host/bare_api/src/tusb_config.h | 3 ++- examples/host/cdc_msc_hid/src/tusb_config.h | 3 ++- examples/host/cdc_msc_hid_freertos/src/tusb_config.h | 3 ++- examples/host/device_info/src/tusb_config.h | 3 ++- examples/host/hid_controller/src/tusb_config.h | 3 ++- examples/host/msc_file_explorer/src/tusb_config.h | 3 ++- src/portable/synopsys/dwc2/hcd_dwc2.c | 2 +- 7 files changed, 13 insertions(+), 7 deletions(-) (limited to 'src/portable') diff --git a/examples/host/bare_api/src/tusb_config.h b/examples/host/bare_api/src/tusb_config.h index fab233be0..a03675c5f 100644 --- a/examples/host/bare_api/src/tusb_config.h +++ b/examples/host/bare_api/src/tusb_config.h @@ -69,9 +69,10 @@ // Enable Host stack #define CFG_TUH_ENABLED 1 +// #define CFG_TUH_MAX3421 1 // use max3421 as host controller + #if CFG_TUSB_MCU == OPT_MCU_RP2040 // #define CFG_TUH_RPI_PIO_USB 1 // use pio-usb as host controller - // #define CFG_TUH_MAX3421 1 // use max3421 as host controller // host roothub port is 1 if using either pio-usb or max3421 #if (defined(CFG_TUH_RPI_PIO_USB) && CFG_TUH_RPI_PIO_USB) || (defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421) diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index a59a0ffb9..cc8d6e5c4 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -69,9 +69,10 @@ // Enable Host stack #define CFG_TUH_ENABLED 1 +// #define CFG_TUH_MAX3421 1 // use max3421 as host controller + #if CFG_TUSB_MCU == OPT_MCU_RP2040 // #define CFG_TUH_RPI_PIO_USB 1 // use pio-usb as host controller - // #define CFG_TUH_MAX3421 1 // use max3421 as host controller // host roothub port is 1 if using either pio-usb or max3421 #if (defined(CFG_TUH_RPI_PIO_USB) && CFG_TUH_RPI_PIO_USB) || (defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421) diff --git a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h index 02de4197b..682265f59 100644 --- a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h +++ b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h @@ -74,9 +74,10 @@ // Enable Host stack #define CFG_TUH_ENABLED 1 +// #define CFG_TUH_MAX3421 1 // use max3421 as host controller + #if CFG_TUSB_MCU == OPT_MCU_RP2040 // #define CFG_TUH_RPI_PIO_USB 1 // use pio-usb as host controller - // #define CFG_TUH_MAX3421 1 // use max3421 as host controller // host roothub port is 1 if using either pio-usb or max3421 #if (defined(CFG_TUH_RPI_PIO_USB) && CFG_TUH_RPI_PIO_USB) || (defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421) diff --git a/examples/host/device_info/src/tusb_config.h b/examples/host/device_info/src/tusb_config.h index 5190b5b1f..db02a97db 100644 --- a/examples/host/device_info/src/tusb_config.h +++ b/examples/host/device_info/src/tusb_config.h @@ -74,9 +74,10 @@ // Enable Host stack #define CFG_TUH_ENABLED 1 +// #define CFG_TUH_MAX3421 1 // use max3421 as host controller + #if CFG_TUSB_MCU == OPT_MCU_RP2040 // #define CFG_TUH_RPI_PIO_USB 1 // use pio-usb as host controller - // #define CFG_TUH_MAX3421 1 // use max3421 as host controller // host roothub port is 1 if using either pio-usb or max3421 #if (defined(CFG_TUH_RPI_PIO_USB) && CFG_TUH_RPI_PIO_USB) || (defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421) diff --git a/examples/host/hid_controller/src/tusb_config.h b/examples/host/hid_controller/src/tusb_config.h index 3ac591d8f..351fe0178 100644 --- a/examples/host/hid_controller/src/tusb_config.h +++ b/examples/host/hid_controller/src/tusb_config.h @@ -69,9 +69,10 @@ // Enable Host stack #define CFG_TUH_ENABLED 1 +// #define CFG_TUH_MAX3421 1 // use max3421 as host controller + #if CFG_TUSB_MCU == OPT_MCU_RP2040 // #define CFG_TUH_RPI_PIO_USB 1 // use pio-usb as host controller - // #define CFG_TUH_MAX3421 1 // use max3421 as host controller // host roothub port is 1 if using either pio-usb or max3421 #if (defined(CFG_TUH_RPI_PIO_USB) && CFG_TUH_RPI_PIO_USB) || (defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421) diff --git a/examples/host/msc_file_explorer/src/tusb_config.h b/examples/host/msc_file_explorer/src/tusb_config.h index c798b4383..c1829c300 100644 --- a/examples/host/msc_file_explorer/src/tusb_config.h +++ b/examples/host/msc_file_explorer/src/tusb_config.h @@ -69,9 +69,10 @@ // Enable Host stack #define CFG_TUH_ENABLED 1 +// #define CFG_TUH_MAX3421 1 // use max3421 as host controller + #if CFG_TUSB_MCU == OPT_MCU_RP2040 // #define CFG_TUH_RPI_PIO_USB 1 // use pio-usb as host controller - // #define CFG_TUH_MAX3421 1 // use max3421 as host controller // host roothub port is 1 if using either pio-usb or max3421 #if (defined(CFG_TUH_RPI_PIO_USB) && CFG_TUH_RPI_PIO_USB) || (defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421) diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index ebbb6200a..b13479b02 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -26,7 +26,7 @@ #include "tusb_option.h" -#if CFG_TUH_ENABLED && defined(TUP_USBIP_DWC2) +#if CFG_TUH_ENABLED && defined(TUP_USBIP_DWC2) && !CFG_TUH_MAX3421 #if !(CFG_TUH_DWC2_SLAVE_ENABLE || CFG_TUH_DWC2_DMA_ENABLE) #error DWC2 require either CFG_TUH_DWC2_SLAVE_ENABLE or CFG_TUH_DWC2_DMA_ENABLE to be enabled -- cgit v1.3.1 From 585bcbfcdd5e24e25dd8d42b51446824b8143602 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sun, 16 Mar 2025 00:07:15 +0100 Subject: Fix 2 IAR warnings. Signed-off-by: HiFiPhile --- src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/portable') diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c index 7d5cfb5b0..7c637ce0c 100644 --- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c +++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c @@ -297,7 +297,7 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { dcd_reg->EPLISTSTART = (uint32_t) _dcd.ep; dcd_reg->DATABUFSTART = tu_align((uint32_t) &_dcd, TU_BIT(22)); // 22-bit alignment - dcd_reg->INTSTAT |= dcd_reg->INTSTAT; // clear all pending interrupt + dcd_reg->INTSTAT = dcd_reg->INTSTAT; // clear all pending interrupt dcd_reg->INTEN = INT_DEVICE_STATUS_MASK; dcd_reg->DEVCMDSTAT |= DEVCMDSTAT_DEVICE_ENABLE_MASK | DEVCMDSTAT_DEVICE_CONNECT_MASK | DEVCMDSTAT_RESET_CHANGE_MASK | DEVCMDSTAT_CONNECT_CHANGE_MASK | DEVCMDSTAT_SUSPEND_CHANGE_MASK; @@ -563,7 +563,8 @@ void dcd_int_handler(uint8_t rhport) uint32_t const cmd_stat = dcd_reg->DEVCMDSTAT; - uint32_t int_status = dcd_reg->INTSTAT & dcd_reg->INTEN; + uint32_t int_status = dcd_reg->INTSTAT; + int_status &= dcd_reg->INTEN; dcd_reg->INTSTAT = int_status; // Acknowledge handled interrupt if (int_status == 0) return; -- cgit v1.3.1