From e4a35d1cc7c4bf9fd907d437407ff7080ea4e6a4 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Wed, 12 Jul 2023 00:59:55 +0300 Subject: [PATCH 1/3] sn32: fix host remote wakeup Previously a device which attempted to wake a sleeping host would not be notified about the resumed operation and thus stay suspended for ever. This is due to the fact that only a host initiated wakeup would trigger a interrupt. As a workaround we use the SOF interrupt which is enabled for a short amount of time to detect the resume of the bus and wakeup the device. --- os/hal/ports/SN32/LLD/SN32F2xx/USB/hal_usb_lld.c | 15 +++++++++++++-- os/hal/ports/SN32/LLD/SN32F2xx/USB/hal_usb_lld.h | 3 +++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/os/hal/ports/SN32/LLD/SN32F2xx/USB/hal_usb_lld.c b/os/hal/ports/SN32/LLD/SN32F2xx/USB/hal_usb_lld.c index d9e2a7d386..84572910d8 100644 --- a/os/hal/ports/SN32/LLD/SN32F2xx/USB/hal_usb_lld.c +++ b/os/hal/ports/SN32/LLD/SN32F2xx/USB/hal_usb_lld.c @@ -292,7 +292,15 @@ static void usb_lld_serve_interrupt(USBDriver *usbp) { ///////////////////////////////////////////////// /* Device Status Interrupt (SOF) */ ///////////////////////////////////////////////// - if ((iwIntFlag & mskUSB_SOF) && (SN32_USB->INTEN & mskUSB_SOF_IE)) { + if (iwIntFlag & mskUSB_SOF) { + /* SOF interrupt was used to detect resume of the USB bus after issuing a + * remote wake up of the host, therefore we disable it again. */ + if (usbp->config->sof_cb == NULL) { + SN32_USB->INTEN &= ~mskUSB_SOF_IE; + } + if (usbp->state == USB_SUSPENDED) { + _usb_wakeup(usbp); + } /* SOF */ _usb_isr_invoke_sof_cb(usbp); SN32_USB->INSTSC = (mskUSB_SOF); @@ -504,7 +512,10 @@ void usb_lld_reset(USBDriver *usbp) { usb_lld_init_endpoint(usbp, 0); /* Enable other interrupts.*/ - SN32_USB->INTEN |= (mskUSB_IE|mskEPnACK_EN|mskBUSWK_IE|mskUSB_SOF_IE); + SN32_USB->INTEN |= (mskUSB_IE|mskEPnACK_EN|mskBUSWK_IE); + if (usbp->config->sof_cb != NULL) { + SN32_USB->INTEN |= mskUSB_SOF_IE; + } //SN32_USB->INTEN |= (mskEP1_NAK_EN|mskEP2_NAK_EN|mskEP3_NAK_EN|mskEP4_NAK_EN); #if (USB_ENDPOINTS_NUMBER > 4) //SN32_USB->INTEN |= (mskEP5_NAK_EN|mskEP6_NAK_EN); diff --git a/os/hal/ports/SN32/LLD/SN32F2xx/USB/hal_usb_lld.h b/os/hal/ports/SN32/LLD/SN32F2xx/USB/hal_usb_lld.h index a114f1237e..5226c8f923 100644 --- a/os/hal/ports/SN32/LLD/SN32F2xx/USB/hal_usb_lld.h +++ b/os/hal/ports/SN32/LLD/SN32F2xx/USB/hal_usb_lld.h @@ -390,6 +390,9 @@ struct USBDriver { #define usb_lld_wakeup_host(usbp) \ do { \ SN32_USB->SGCTL = (mskBUS_DRVEN|mskBUS_K_STATE); \ + /* remote wakeup doesn't trigger the wakeup interrupt, therefore \ + * we use the SOF interrupt to detect resume of the bus. */ \ + SN32_USB->INTEN |= mskUSB_SOF_IE; \ osalThreadSleepMilliseconds(SN32_USB_HOST_WAKEUP_DURATION); \ SN32_USB->SGCTL &= ~mskBUS_DRVEN; \ } while (false) From e9a4a512c0281b02bdd4bbd0a725155f1e144297 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Wed, 12 Jul 2023 10:57:02 +0300 Subject: [PATCH 2/3] sn32: usb: only activate interrupts on lld start --- .../ports/SN32/LLD/SN32F2xx/USB/hal_usb_lld.c | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/os/hal/ports/SN32/LLD/SN32F2xx/USB/hal_usb_lld.c b/os/hal/ports/SN32/LLD/SN32F2xx/USB/hal_usb_lld.c index 84572910d8..9f3a960f0f 100644 --- a/os/hal/ports/SN32/LLD/SN32F2xx/USB/hal_usb_lld.c +++ b/os/hal/ports/SN32/LLD/SN32F2xx/USB/hal_usb_lld.c @@ -466,6 +466,16 @@ void usb_lld_start(USBDriver *usbp) { #endif /* SN32_USB_USE_USB1 == TRUE */ /* Reset procedure enforced on driver start.*/ usb_lld_reset(usbp); + + /* Enable other interrupts.*/ + SN32_USB->INTEN |= (mskUSB_IE|mskEPnACK_EN|mskBUSWK_IE); + if (usbp->config->sof_cb != NULL) { + SN32_USB->INTEN |= mskUSB_SOF_IE; + } + //SN32_USB->INTEN |= (mskEP1_NAK_EN|mskEP2_NAK_EN|mskEP3_NAK_EN|mskEP4_NAK_EN); +#if (USB_ENDPOINTS_NUMBER > 4) + //SN32_USB->INTEN |= (mskEP5_NAK_EN|mskEP6_NAK_EN); +#endif /* (USB_ENDPOINTS_NUMBER > 4) */ } } @@ -510,17 +520,6 @@ void usb_lld_reset(USBDriver *usbp) { /* EP0 initialization.*/ usbp->epc[0] = &ep0config; usb_lld_init_endpoint(usbp, 0); - - /* Enable other interrupts.*/ - SN32_USB->INTEN |= (mskUSB_IE|mskEPnACK_EN|mskBUSWK_IE); - if (usbp->config->sof_cb != NULL) { - SN32_USB->INTEN |= mskUSB_SOF_IE; - } - //SN32_USB->INTEN |= (mskEP1_NAK_EN|mskEP2_NAK_EN|mskEP3_NAK_EN|mskEP4_NAK_EN); -#if (USB_ENDPOINTS_NUMBER > 4) - //SN32_USB->INTEN |= (mskEP5_NAK_EN|mskEP6_NAK_EN); -#endif /* (USB_ENDPOINTS_NUMBER > 4) */ - } /** From 5ded9de940910b1c17895fb2935597fc80da2922 Mon Sep 17 00:00:00 2001 From: Dimitris Mantzouranis Date: Wed, 19 Jul 2023 17:00:04 +0300 Subject: [PATCH 3/3] sn32: usb: do NOT clear interrupt status until handled Leftover Sonix reference code cleanup. Sometimes when there is traffic on more than 1 ep's packets would be dropped before they could be handled. Clearing the status flags after handling them takes care of it. --- os/hal/ports/SN32/LLD/SN32F2xx/USB/hal_usb_lld.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/os/hal/ports/SN32/LLD/SN32F2xx/USB/hal_usb_lld.c b/os/hal/ports/SN32/LLD/SN32F2xx/USB/hal_usb_lld.c index 9f3a960f0f..cb6f91c7f1 100644 --- a/os/hal/ports/SN32/LLD/SN32F2xx/USB/hal_usb_lld.c +++ b/os/hal/ports/SN32/LLD/SN32F2xx/USB/hal_usb_lld.c @@ -208,10 +208,8 @@ static void sn32_usb_write_fifo(usbep_t ep, const uint8_t *buf, size_t sz, bool static void usb_lld_serve_interrupt(USBDriver *usbp) { uint32_t iwIntFlag; - /* Get Interrupt Status and clear immediately. */ + /* Get Interrupt Status */ iwIntFlag = SN32_USB->INSTS; - /* Keep only PRESETUP & ERR_SETUP flags. */ - SN32_USB->INSTSC = ~(mskEP0_PRESETUP | mskERR_SETUP); if (iwIntFlag == 0) { //@20160902 add for EMC protection