From 2660af5d87275e08d6b535908a64d17ea63682f3 Mon Sep 17 00:00:00 2001 From: sakumisu <1203593632@qq.com> Date: Thu, 14 Mar 2024 19:31:52 +0800 Subject: [PATCH] add timer to control interrupt transfer --- class/hub/usbh_hub.c | 21 +++++++++++++++---- common/usb_hc.h | 1 + common/usb_osal.h | 12 +++++++++++ core/usbh_core.h | 4 ++++ osal/usb_osal_freertos.c | 45 ++++++++++++++++++++++++++++++++++++++++ osal/usb_osal_rtthread.c | 31 +++++++++++++++++++++++++++ 6 files changed, 110 insertions(+), 4 deletions(-) diff --git a/class/hub/usbh_hub.c b/class/hub/usbh_hub.c index f638a34..cf2b1ab 100644 --- a/class/hub/usbh_hub.c +++ b/class/hub/usbh_hub.c @@ -304,11 +304,21 @@ static void hub_int_complete_callback(void *arg, int nbytes) if (nbytes > 0) { usbh_hub_thread_wakeup(hub); } else if (nbytes == -USB_ERR_NAK) { - usbh_submit_urb(&hub->intin_urb); + /* Restart timer to submit urb again */ + USB_LOG_DBG("Restart timer\r\n"); + usb_osal_timer_start(hub->int_timer); } else { } } +static void hub_int_timeout(void *arg) +{ + struct usbh_hub *hub = (struct usbh_hub *)arg; + + usbh_int_urb_fill(&hub->intin_urb, hub->parent, hub->intin, hub->int_buffer, 1, 0, hub_int_complete_callback, hub); + usbh_submit_urb(&hub->intin_urb); +} + static int usbh_hub_connect(struct usbh_hubport *hport, uint8_t intf) { struct usb_endpoint_descriptor *ep_desc; @@ -384,8 +394,9 @@ static int usbh_hub_connect(struct usbh_hubport *hport, uint8_t intf) USB_LOG_INFO("Register HUB Class:%s\r\n", hport->config.intf[intf].devname); hub->int_buffer = g_hub_intbuf[hub->bus->busid][hub->index - 1]; - usbh_int_urb_fill(&hub->intin_urb, hub->parent, hub->intin, hub->int_buffer, 1, 0, hub_int_complete_callback, hub); - usbh_submit_urb(&hub->intin_urb); + + hub->int_timer = usb_osal_timer_create("hubint_tim", USBH_GET_URB_INTERVAL(hub->intin->bInterval, hport->speed), hub_int_timeout, hub, 0); + usb_osal_timer_start(hub->int_timer); return 0; } @@ -401,6 +412,8 @@ static int usbh_hub_disconnect(struct usbh_hubport *hport, uint8_t intf) usbh_kill_urb(&hub->intin_urb); } + usb_osal_timer_delete(hub->int_timer); + for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) { child = &hub->child[port]; usbh_hubport_release(child); @@ -616,7 +629,7 @@ static void usbh_hub_events(struct usbh_hub *hub) /* Start next hub int transfer */ if (!hub->is_roothub && hub->connected) { - usbh_submit_urb(&hub->intin_urb); + usb_osal_timer_start(hub->int_timer); } } diff --git a/common/usb_hc.h b/common/usb_hc.h index 364a909..adfddbe 100644 --- a/common/usb_hc.h +++ b/common/usb_hc.h @@ -38,6 +38,7 @@ struct usbh_urb { struct usbh_hubport *hport; struct usb_endpoint_descriptor *ep; uint8_t data_toggle; + uint8_t interval; struct usb_setup_packet *setup; uint8_t *transfer_buffer; uint32_t transfer_buffer_length; diff --git a/common/usb_osal.h b/common/usb_osal.h index 0ae658f..738efaa 100644 --- a/common/usb_osal.h +++ b/common/usb_osal.h @@ -8,6 +8,7 @@ #include #include +#include #define USB_OSAL_WAITING_FOREVER (0xFFFFFFFFU) @@ -16,6 +17,12 @@ typedef void *usb_osal_sem_t; typedef void *usb_osal_mutex_t; typedef void *usb_osal_mq_t; typedef void (*usb_thread_entry_t)(void *argument); +typedef void (*usb_timer_handler_t)(void *argument); +struct usb_osal_timer { + usb_timer_handler_t handler; + void *argument; + void *timer; +}; /* * Task with smaller priority value indicates higher task priority @@ -39,6 +46,11 @@ void usb_osal_mq_delete(usb_osal_mq_t mq); int usb_osal_mq_send(usb_osal_mq_t mq, uintptr_t addr); int usb_osal_mq_recv(usb_osal_mq_t mq, uintptr_t *addr, uint32_t timeout); +struct usb_osal_timer *usb_osal_timer_create(const char *name, uint32_t timeout_ms, usb_timer_handler_t handler, void *argument, bool is_period); +void usb_osal_timer_delete(struct usb_osal_timer *timer); +void usb_osal_timer_start(struct usb_osal_timer *timer); +void usb_osal_timer_stop(struct usb_osal_timer *timer); + size_t usb_osal_enter_critical_section(void); void usb_osal_leave_critical_section(size_t flag); diff --git a/core/usbh_core.h b/core/usbh_core.h index ef59650..d5cfc38 100644 --- a/core/usbh_core.h +++ b/core/usbh_core.h @@ -43,6 +43,8 @@ extern "C" { #define CLASS_INFO_DEFINE __attribute__((section("usbh_class_info"))) __USED __ALIGNED(1) #endif +#define USBH_GET_URB_INTERVAL(interval, speed) (speed < USB_SPEED_HIGH ? interval: (1 << (interval - 1))) + #define USBH_EP_INIT(ep, ep_desc) \ do { \ ep = ep_desc; \ @@ -128,6 +130,7 @@ struct usbh_hub { struct usb_endpoint_descriptor *intin; struct usbh_urb intin_urb; uint8_t *int_buffer; + struct usb_osal_timer *int_timer; }; struct usbh_devaddr_map { @@ -214,6 +217,7 @@ static inline void usbh_int_urb_fill(struct usbh_urb *urb, urb->timeout = timeout; urb->complete = complete; urb->arg = arg; + urb->interval = USBH_GET_URB_INTERVAL(ep->bInterval, hport->speed); } extern struct usbh_bus g_usbhost_bus[]; diff --git a/osal/usb_osal_freertos.c b/osal/usb_osal_freertos.c index 69c210a..e536ff1 100644 --- a/osal/usb_osal_freertos.c +++ b/osal/usb_osal_freertos.c @@ -116,6 +116,51 @@ int usb_osal_mq_recv(usb_osal_mq_t mq, uintptr_t *addr, uint32_t timeout) } } +static void __usb_timeout(TimerHandle_t *handle) +{ + struct usb_osal_timer *timer = (struct usb_osal_timer *)pvTimerGetTimerID((TimerHandle_t)handle); + + timer->handler(timer->argument); +} + +struct usb_osal_timer *usb_osal_timer_create(const char *name, uint32_t timeout_ms, usb_timer_handler_t handler, void *argument, bool is_period) +{ + struct usb_osal_timer *timer; + + timer = pvPortMalloc(sizeof(struct usb_osal_timer)); + + if (timer == NULL) { + return NULL; + } + memset(timer, 0, sizeof(struct usb_osal_timer)); + + timer->handler = handler; + timer->argument = argument; + + timer->timer = (void *)xTimerCreate("usb_tim", pdMS_TO_TICKS(timeout_ms), is_period, timer, (TimerCallbackFunction_t)__usb_timeout); + if (timer->timer == NULL) { + return NULL; + } + return timer; +} + +void usb_osal_timer_delete(struct usb_osal_timer *timer) +{ + xTimerStop(timer->timer, 0); + xTimerDelete(timer->timer, 0); + vPortFree(timer); +} + +void usb_osal_timer_start(struct usb_osal_timer *timer) +{ + xTimerStart(timer->timer, 0); +} + +void usb_osal_timer_stop(struct usb_osal_timer *timer) +{ + xTimerStop(timer->timer, 0); +} + size_t usb_osal_enter_critical_section(void) { taskDISABLE_INTERRUPTS(); diff --git a/osal/usb_osal_rtthread.c b/osal/usb_osal_rtthread.c index 890f048..18b66a4 100644 --- a/osal/usb_osal_rtthread.c +++ b/osal/usb_osal_rtthread.c @@ -122,6 +122,37 @@ int usb_osal_mq_recv(usb_osal_mq_t mq, uintptr_t *addr, uint32_t timeout) return (int)ret; } +struct usb_osal_timer *usb_osal_timer_create(const char *name, uint32_t timeout_ms, usb_timer_handler_t handler, void *argument, bool is_period) +{ + struct usb_osal_timer *timer; + + timer = rt_malloc(sizeof(struct usb_osal_timer)); + memset(timer, 0, sizeof(struct usb_osal_timer)); + + timer->timer = (void *)rt_timer_create("usb_tim", handler, argument, timeout_ms, is_period ? (RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER) : (RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER)); + if (timer->timer == NULL) { + return NULL; + } + return timer; +} + +void usb_osal_timer_delete(struct usb_osal_timer *timer) +{ + rt_timer_stop(timer->timer); + rt_timer_delete(timer->timer); + rt_free(timer); +} + +void usb_osal_timer_start(struct usb_osal_timer *timer) +{ + rt_timer_start(timer->timer); +} + +void usb_osal_timer_stop(struct usb_osal_timer *timer) +{ + rt_timer_stop(timer->timer); +} + size_t usb_osal_enter_critical_section(void) { return rt_hw_interrupt_disable();