mirror of
https://github.com/hathach/tinyusb.git
synced 2025-04-18 11:42:25 +00:00
add e15 prefix or walkaround related functions, also minor refactor
This commit is contained in:
parent
0cce42fcc6
commit
19b6cbc616
@ -244,128 +244,133 @@ static void __tusb_irq_path_func(reset_non_control_endpoints)(void)
|
|||||||
|
|
||||||
static void __tusb_irq_path_func(dcd_rp2040_irq)(void)
|
static void __tusb_irq_path_func(dcd_rp2040_irq)(void)
|
||||||
{
|
{
|
||||||
uint32_t const status = usb_hw->ints;
|
uint32_t const status = usb_hw->ints;
|
||||||
uint32_t handled = 0;
|
uint32_t handled = 0;
|
||||||
|
|
||||||
if (status & USB_INTF_DEV_SOF_BITS)
|
if ( status & USB_INTF_DEV_SOF_BITS )
|
||||||
{
|
{
|
||||||
bool keep_sof_alive = false;
|
bool keep_sof_alive = false;
|
||||||
|
|
||||||
handled |= USB_INTF_DEV_SOF_BITS;
|
handled |= USB_INTF_DEV_SOF_BITS;
|
||||||
|
|
||||||
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
||||||
last_sof = time_us_32();
|
// Errata 15 Walkaround for Device Bulk-In endpoint
|
||||||
|
e15_last_sof = time_us_32();
|
||||||
|
|
||||||
for (uint8_t i = 0; i < USB_MAX_ENDPOINTS; i++)
|
for ( uint8_t i = 0; i < USB_MAX_ENDPOINTS; i++ )
|
||||||
|
{
|
||||||
|
struct hw_endpoint * ep = hw_endpoint_get_by_num(i, TUSB_DIR_IN);
|
||||||
|
|
||||||
|
// Active Bulk IN endpoint requires SOF
|
||||||
|
if ( (ep->transfer_type == TUSB_XFER_BULK) && ep->active )
|
||||||
{
|
{
|
||||||
struct hw_endpoint *ep = hw_endpoint_get_by_num(i, TUSB_DIR_IN);
|
keep_sof_alive = true;
|
||||||
|
|
||||||
hw_endpoint_lock_update(ep, 1);
|
hw_endpoint_lock_update(ep, 1);
|
||||||
|
|
||||||
// Bulk IN endpoint in a transfer?
|
|
||||||
if (rp2040_ep_needs_sof(ep) && ep->active) keep_sof_alive = true;
|
|
||||||
|
|
||||||
// Deferred enable?
|
// Deferred enable?
|
||||||
if (ep->pending)
|
if ( ep->pending )
|
||||||
{
|
{
|
||||||
hw_endpoint_start_next_buffer(ep);
|
|
||||||
ep->pending = 0;
|
ep->pending = 0;
|
||||||
|
hw_endpoint_start_next_buffer(ep);
|
||||||
}
|
}
|
||||||
|
|
||||||
hw_endpoint_lock_update(ep, -1);
|
hw_endpoint_lock_update(ep, -1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// disable SOF interrupt if it is used for RESUME in remote wakeup
|
// disable SOF interrupt if it is used for RESUME in remote wakeup
|
||||||
if (!keep_sof_alive && !_sof_enable) usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS;
|
if ( !keep_sof_alive && !_sof_enable ) usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS;
|
||||||
|
|
||||||
dcd_event_sof(0, usb_hw->sof_rd & USB_SOF_RD_BITS, true);
|
dcd_event_sof(0, usb_hw->sof_rd & USB_SOF_RD_BITS, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// xfer events are handled before setup req. So if a transfer completes immediately
|
// xfer events are handled before setup req. So if a transfer completes immediately
|
||||||
// before closing the EP, the events will be delivered in same order.
|
// before closing the EP, the events will be delivered in same order.
|
||||||
if (status & USB_INTS_BUFF_STATUS_BITS)
|
if ( status & USB_INTS_BUFF_STATUS_BITS )
|
||||||
{
|
{
|
||||||
handled |= USB_INTS_BUFF_STATUS_BITS;
|
handled |= USB_INTS_BUFF_STATUS_BITS;
|
||||||
hw_handle_buff_status();
|
hw_handle_buff_status();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status & USB_INTS_SETUP_REQ_BITS)
|
if ( status & USB_INTS_SETUP_REQ_BITS )
|
||||||
{
|
{
|
||||||
handled |= USB_INTS_SETUP_REQ_BITS;
|
handled |= USB_INTS_SETUP_REQ_BITS;
|
||||||
uint8_t const *setup = (uint8_t const *)&usb_dpram->setup_packet;
|
uint8_t const * setup = (uint8_t const*) &usb_dpram->setup_packet;
|
||||||
|
|
||||||
// reset pid to both 1 (data and ack)
|
// reset pid to both 1 (data and ack)
|
||||||
reset_ep0_pid();
|
reset_ep0_pid();
|
||||||
|
|
||||||
// Pass setup packet to tiny usb
|
// Pass setup packet to tiny usb
|
||||||
dcd_event_setup_received(0, setup, true);
|
dcd_event_setup_received(0, setup, true);
|
||||||
usb_hw_clear->sie_status = USB_SIE_STATUS_SETUP_REC_BITS;
|
usb_hw_clear->sie_status = USB_SIE_STATUS_SETUP_REC_BITS;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FORCE_VBUS_DETECT == 0
|
#if FORCE_VBUS_DETECT == 0
|
||||||
// Since we force VBUS detect On, device will always think it is connected and
|
// Since we force VBUS detect On, device will always think it is connected and
|
||||||
// couldn't distinguish between disconnect and suspend
|
// couldn't distinguish between disconnect and suspend
|
||||||
if (status & USB_INTS_DEV_CONN_DIS_BITS)
|
if (status & USB_INTS_DEV_CONN_DIS_BITS)
|
||||||
|
{
|
||||||
|
handled |= USB_INTS_DEV_CONN_DIS_BITS;
|
||||||
|
|
||||||
|
if ( usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS )
|
||||||
{
|
{
|
||||||
handled |= USB_INTS_DEV_CONN_DIS_BITS;
|
// Connected: nothing to do
|
||||||
|
}else
|
||||||
if ( usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS )
|
{
|
||||||
{
|
// Disconnected
|
||||||
// Connected: nothing to do
|
dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, true);
|
||||||
}else
|
|
||||||
{
|
|
||||||
// Disconnected
|
|
||||||
dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
usb_hw_clear->sie_status = USB_SIE_STATUS_CONNECTED_BITS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
usb_hw_clear->sie_status = USB_SIE_STATUS_CONNECTED_BITS;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// SE0 for 2.5 us or more (will last at least 10ms)
|
// SE0 for 2.5 us or more (will last at least 10ms)
|
||||||
if (status & USB_INTS_BUS_RESET_BITS)
|
if ( status & USB_INTS_BUS_RESET_BITS )
|
||||||
{
|
{
|
||||||
pico_trace("BUS RESET\n");
|
pico_trace("BUS RESET\n");
|
||||||
|
|
||||||
handled |= USB_INTS_BUS_RESET_BITS;
|
handled |= USB_INTS_BUS_RESET_BITS;
|
||||||
|
|
||||||
usb_hw->dev_addr_ctrl = 0;
|
usb_hw->dev_addr_ctrl = 0;
|
||||||
reset_non_control_endpoints();
|
reset_non_control_endpoints();
|
||||||
dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
|
dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
|
||||||
usb_hw_clear->sie_status = USB_SIE_STATUS_BUS_RESET_BITS;
|
usb_hw_clear->sie_status = USB_SIE_STATUS_BUS_RESET_BITS;
|
||||||
|
|
||||||
#if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
|
#if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
|
||||||
// Only run enumeration walk-around if pull up is enabled
|
// Only run enumeration walk-around if pull up is enabled
|
||||||
if ( usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS ) rp2040_usb_device_enumeration_fix();
|
if ( usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS ) rp2040_usb_device_enumeration_fix();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note from pico datasheet 4.1.2.6.4 (v1.2)
|
/* Note from pico datasheet 4.1.2.6.4 (v1.2)
|
||||||
* If you enable the suspend interrupt, it is likely you will see a suspend interrupt when
|
* If you enable the suspend interrupt, it is likely you will see a suspend interrupt when
|
||||||
* the device is first connected but the bus is idle. The bus can be idle for a few ms before
|
* the device is first connected but the bus is idle. The bus can be idle for a few ms before
|
||||||
* the host begins sending start of frame packets. You will also see a suspend interrupt
|
* the host begins sending start of frame packets. You will also see a suspend interrupt
|
||||||
* when the device is disconnected if you do not have a VBUS detect circuit connected. This is
|
* when the device is disconnected if you do not have a VBUS detect circuit connected. This is
|
||||||
* because without VBUS detection, it is impossible to tell the difference between
|
* because without VBUS detection, it is impossible to tell the difference between
|
||||||
* being disconnected and suspended.
|
* being disconnected and suspended.
|
||||||
*/
|
*/
|
||||||
if (status & USB_INTS_DEV_SUSPEND_BITS)
|
if ( status & USB_INTS_DEV_SUSPEND_BITS )
|
||||||
{
|
{
|
||||||
handled |= USB_INTS_DEV_SUSPEND_BITS;
|
handled |= USB_INTS_DEV_SUSPEND_BITS;
|
||||||
dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
|
dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
|
||||||
usb_hw_clear->sie_status = USB_SIE_STATUS_SUSPENDED_BITS;
|
usb_hw_clear->sie_status = USB_SIE_STATUS_SUSPENDED_BITS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status & USB_INTS_DEV_RESUME_FROM_HOST_BITS)
|
if ( status & USB_INTS_DEV_RESUME_FROM_HOST_BITS )
|
||||||
{
|
{
|
||||||
handled |= USB_INTS_DEV_RESUME_FROM_HOST_BITS;
|
handled |= USB_INTS_DEV_RESUME_FROM_HOST_BITS;
|
||||||
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
|
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
|
||||||
usb_hw_clear->sie_status = USB_SIE_STATUS_RESUME_BITS;
|
usb_hw_clear->sie_status = USB_SIE_STATUS_RESUME_BITS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status ^ handled)
|
if ( status ^ handled )
|
||||||
{
|
{
|
||||||
panic("Unhandled IRQ 0x%x\n", (uint) (status ^ handled));
|
panic("Unhandled IRQ 0x%x\n", (uint) (status ^ handled));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define USB_INTS_ERROR_BITS ( \
|
#define USB_INTS_ERROR_BITS ( \
|
||||||
|
@ -51,37 +51,41 @@ TU_ATTR_ALWAYS_INLINE static inline bool is_host_mode(void)
|
|||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
||||||
volatile uint32_t last_sof = 0;
|
// Errata 15 Walkaround for Device Bulk-In endpoint to avoid schedule an transfer
|
||||||
|
// within last 20% of an USB frame.
|
||||||
|
|
||||||
bool rp2040_critical_frame_period(struct hw_endpoint *ep)
|
volatile uint32_t e15_last_sof = 0;
|
||||||
|
|
||||||
|
// check if Errata 15 walkround is needed for this endpoint
|
||||||
|
static bool __tusb_irq_path_func(e15_is_bulkin_ep) (struct hw_endpoint *ep)
|
||||||
{
|
{
|
||||||
uint32_t delta;
|
return (!is_host_mode() && tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN &&
|
||||||
|
ep->transfer_type == TUSB_XFER_BULK);
|
||||||
|
}
|
||||||
|
|
||||||
if (usb_hw->main_ctrl & USB_MAIN_CTRL_HOST_NDEVICE_BITS) return false;
|
// check if we need to apply Errata 15 workaround: ie.g
|
||||||
|
// Enpoint is BULK IN and is currently in critical frame period i.e 20% of last usb frame
|
||||||
if (tu_edpt_dir(ep->ep_addr) == TUSB_DIR_OUT ||
|
static bool __tusb_irq_path_func(e15_is_critical_frame_period) (struct hw_endpoint *ep)
|
||||||
ep->transfer_type == TUSB_XFER_INTERRUPT ||
|
{
|
||||||
ep->transfer_type == TUSB_XFER_ISOCHRONOUS)
|
TU_VERIFY(e15_is_bulkin_ep(ep));
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Avoid the last 200us (uframe 6.5-7) of a frame, up to the EOF2 point.
|
/* Avoid the last 200us (uframe 6.5-7) of a frame, up to the EOF2 point.
|
||||||
* The device state machine cannot recover from receiving an incorrect PID
|
* The device state machine cannot recover from receiving an incorrect PID
|
||||||
* when it is expecting an ACK.
|
* when it is expecting an ACK.
|
||||||
*/
|
*/
|
||||||
delta = time_us_32() - last_sof;
|
uint32_t delta = time_us_32() - e15_last_sof;
|
||||||
if (delta < 800 || delta > 998) {
|
if (delta < 800 || delta > 998) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
TU_LOG(3, "Avoiding sof %u now %lu last %lu\n", (usb_hw->sof_rd + 1) & USB_SOF_RD_BITS, now, last_sof);
|
TU_LOG(3, "Avoiding sof %u now %lu last %lu\n", (usb_hw->sof_rd + 1) & USB_SOF_RD_BITS, time_us_32(), e15_last_sof);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rp2040_ep_needs_sof(struct hw_endpoint *ep) {
|
#else
|
||||||
return (tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN &&
|
|
||||||
ep->transfer_type == TUSB_XFER_BULK);
|
#define e15_is_bulkin_ep(x) false
|
||||||
}
|
#define e15_is_critical_frame_period(x) false
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void rp2040_usb_init(void)
|
void rp2040_usb_init(void)
|
||||||
@ -249,17 +253,17 @@ void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t to
|
|||||||
ep->active = true;
|
ep->active = true;
|
||||||
ep->user_buf = buffer;
|
ep->user_buf = buffer;
|
||||||
|
|
||||||
if (rp2040_ep_needs_sof(ep))
|
if ( e15_is_bulkin_ep(ep) )
|
||||||
{
|
{
|
||||||
usb_hw_set->inte = USB_INTS_DEV_SOF_BITS;
|
usb_hw_set->inte = USB_INTS_DEV_SOF_BITS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!rp2040_critical_frame_period(ep))
|
if ( e15_is_critical_frame_period(ep) )
|
||||||
{
|
|
||||||
hw_endpoint_start_next_buffer(ep);
|
|
||||||
} else
|
|
||||||
{
|
{
|
||||||
ep->pending = 1;
|
ep->pending = 1;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
hw_endpoint_start_next_buffer(ep);
|
||||||
}
|
}
|
||||||
|
|
||||||
hw_endpoint_lock_update(ep, -1);
|
hw_endpoint_lock_update(ep, -1);
|
||||||
@ -356,6 +360,7 @@ static void __tusb_irq_path_func(_hw_endpoint_xfer_sync) (struct hw_endpoint *ep
|
|||||||
bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint *ep)
|
bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint *ep)
|
||||||
{
|
{
|
||||||
hw_endpoint_lock_update(ep, 1);
|
hw_endpoint_lock_update(ep, 1);
|
||||||
|
|
||||||
// Part way through a transfer
|
// Part way through a transfer
|
||||||
if (!ep->active)
|
if (!ep->active)
|
||||||
{
|
{
|
||||||
@ -377,10 +382,12 @@ bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint *ep)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(!rp2040_critical_frame_period(ep)) {
|
if ( e15_is_critical_frame_period(ep) )
|
||||||
hw_endpoint_start_next_buffer(ep);
|
{
|
||||||
} else {
|
|
||||||
ep->pending = 1;
|
ep->pending = 1;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
hw_endpoint_start_next_buffer(ep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,14 +93,8 @@ typedef struct hw_endpoint
|
|||||||
|
|
||||||
} hw_endpoint_t;
|
} hw_endpoint_t;
|
||||||
|
|
||||||
#if !TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
||||||
#define rp2040_critical_frame_period(x) false
|
extern volatile uint32_t e15_last_sof;
|
||||||
#define rp2040_ep_needs_sof(x) false
|
|
||||||
#else
|
|
||||||
extern volatile uint32_t last_sof;
|
|
||||||
|
|
||||||
bool rp2040_critical_frame_period(struct hw_endpoint *ep);
|
|
||||||
bool rp2040_ep_needs_sof(struct hw_endpoint *ep);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void rp2040_usb_init(void);
|
void rp2040_usb_init(void);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user