diff --git a/arch/arm/src/stm32/stm32_usbdev.c b/arch/arm/src/stm32/stm32_usbdev.c index 992063f1aa..3995e6071b 100644 --- a/arch/arm/src/stm32/stm32_usbdev.c +++ b/arch/arm/src/stm32/stm32_usbdev.c @@ -93,9 +93,9 @@ # undef CONFIG_STM32_USBDEV_REGDEBUG #endif -/* Initial interrupt mask */ +/* Initial interrupt mask: Reset + Suspend + Correct Transfer */ -#define STM32_CNTR_SETUP (USB_CNTR_RESETM|USB_CNTR_SUSPM|USB_CNTR_WKUPM|USB_CNTR_CTRM) +#define STM32_CNTR_SETUP (USB_CNTR_RESETM|USB_CNTR_SUSPM|USB_CNTR_CTRM) /* Endpoint identifiers. The STM32 supports up to 16 mono-directional or 8 * bidirectional endpoints. However, when you take into account PMA buffer @@ -373,6 +373,8 @@ static inline uint16 stm32_geteprxstatus(ubyte epno); static uint16 stm32_eptxstalled(ubyte epno); static uint16 stm32_eprxstalled(ubyte epno); +static void stm32_setimask(struct stm32_usbdev_s *priv, uint16 setbits, + uint16 clrbits); static void stm32_suspend(struct stm32_usbdev_s *priv); static void stm32_initresume(struct stm32_usbdev_s *priv); static void stm32_esofpoll(struct stm32_usbdev_s *priv) ; @@ -1890,7 +1892,7 @@ static void stm32_lptransfer(struct stm32_usbdev_s *priv) uint16 epval; uint16 istr; - /* Etay in loop while pending ints */ + /* Stay in loop while LP interrupts are pending */ while (((istr = stm32_getreg(STM32_USB_ISTR)) & USB_ISTR_CTR) != 0) { @@ -2041,8 +2043,9 @@ static int stm32_hpinterrupt(int irq, void *context) * for isochronous and double-buffer bulk transfers. */ - usbtrace(TRACE_INTENTRY(STM32_TRACEINTID_HPINTERRUPT), irq); - while (((istr = stm32_getreg(STM32_USB_ISTR)) & USB_ISTR_CTR) != 0) + istr = stm32_getreg(STM32_USB_ISTR); + usbtrace(TRACE_INTENTRY(STM32_TRACEINTID_HPINTERRUPT), istr); + while ((istr & USB_ISTR_CTR) != 0) { stm32_putreg((uint16)~USB_ISTR_CTR, STM32_USB_ISTR); @@ -2090,6 +2093,10 @@ static int stm32_hpinterrupt(int irq, void *context) privep->txbusy = 0; stm32_wrrequest(priv, privep); } + + /* Fetch the status again for the next time through the loop */ + + istr = stm32_getreg(STM32_USB_ISTR); } usbtrace(TRACE_INTEXIT(STM32_TRACEINTID_HPINTERRUPT), 0); @@ -2110,7 +2117,7 @@ static int stm32_lpinterrupt(int irq, void *context) struct stm32_usbdev_s *priv = &g_usbdev; uint16 istr = stm32_getreg(STM32_USB_ISTR); - usbtrace(TRACE_INTENTRY(STM32_TRACEINTID_LPINTERRUPT), irq); + usbtrace(TRACE_INTENTRY(STM32_TRACEINTID_LPINTERRUPT), istr); /* Handle Reset interrupts. When this event occurs, the peripheral is left * in the same conditions it is left by the system reset (but with the @@ -2124,10 +2131,12 @@ static int stm32_lpinterrupt(int irq, void *context) stm32_putreg(~USB_ISTR_RESET, STM32_USB_ISTR); usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_RESET), 0); - /* Restore our power-up state and exit now. */ + /* Restore our power-up state and exit now because istr is no longer + * valid. + */ stm32_reset(priv); - return OK; + goto exit_lpinterrupt; } /* Handle Wakeup interrupts. This interrupt is only enable while the USB is @@ -2161,12 +2170,12 @@ static int stm32_lpinterrupt(int irq, void *context) if ((istr & USB_ISTR_SUSP & priv->imask) != 0) { + usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_SUSP), 0); stm32_suspend(priv); /* Clear of the ISTR bit must be done after setting of USB_CNTR_FSUSP */ stm32_putreg(~USB_ISTR_SUSP, STM32_USB_ISTR); - usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_SUSP), 0); } if ((istr & USB_ISTR_ESOF & priv->imask) != 0) @@ -2187,10 +2196,35 @@ static int stm32_lpinterrupt(int irq, void *context) stm32_lptransfer(priv); } +exit_lpinterrupt: usbtrace(TRACE_INTEXIT(STM32_TRACEINTID_LPINTERRUPT), 0); return OK; } +/**************************************************************************** + * Name: stm32_setimask + ****************************************************************************/ + +static void +stm32_setimask(struct stm32_usbdev_s *priv, uint16 setbits, uint16 clrbits) +{ + uint16 regval; + + /* Adjust the interrupt mask bits in the shadow copy first */ + + priv->imask &= ~clrbits; + priv->imask |= setbits; + + /* Then make the interrupt mask bits in the CNTR register match the shadow + * register (Hmmm... who is shadowing whom?) + */ + + regval = stm32_getreg(STM32_USB_CNTR); + regval &= ~USB_CNTR_ALLINTS; + regval |= priv->imask; + stm32_putreg(regval, STM32_USB_CNTR); +} + /**************************************************************************** * Name: stm32_suspend ****************************************************************************/ @@ -2199,17 +2233,12 @@ static void stm32_suspend(struct stm32_usbdev_s *priv) { uint16 regval; - /* Disable ESOF polling, disable the SUSP interrupt, and - * enable the WKUP interrupt. + /* Disable ESOF polling, disable the SUSP interrupt, and enable the WKUP + * interrupt. Clear any pending WKUP interrupt. */ - priv->imask &= ~(USB_CNTR_ESOFM|USB_CNTR_SUSPM); - priv->imask |= USB_CNTR_WKUPM; - stm32_putreg(priv->imask, STM32_USB_CNTR); - - /* Clear any pending interrupts that we just enabled */ - - stm32_putreg(~USB_CNTR_WKUPM, STM32_USB_ISTR); + stm32_setimask(priv, USB_CNTR_WKUPM, USB_CNTR_ESOFM|USB_CNTR_SUSPM); + stm32_putreg(~USB_ISTR_WKUP, STM32_USB_ISTR); /* Enter suspend mode */ @@ -2288,17 +2317,12 @@ static void stm32_esofpoll(struct stm32_usbdev_s *priv) stm32_putreg(regval, STM32_USB_CNTR); priv->rsmstate = RSMSTATE_IDLE; - /* Disable ESOF polling, disable the SUSP interrupt, and - * enable the WKUP interrupt. + /* Disable ESOF polling, disable the SUSP interrupt, and enable + * the WKUP interrupt. Clear any pending WKUP interrupt. */ - priv->imask &= ~(USB_CNTR_ESOFM|USB_CNTR_SUSPM); - priv->imask |= USB_CNTR_WKUPM; - stm32_putreg(priv->imask, STM32_USB_CNTR); - - /* Clear any pending interrupts that we just enabled */ - - stm32_putreg(~USB_CNTR_WKUPM, STM32_USB_ISTR); + stm32_setimask(priv, USB_CNTR_WKUPM, USB_CNTR_ESOFM|USB_CNTR_SUSPM); + stm32_putreg(~USB_ISTR_WKUP, STM32_USB_ISTR); } break; @@ -3000,16 +3024,12 @@ static int stm32_wakeup(struct usbdev_s *dev) /* Disable the SUSP interrupt (until we are fully resumed), disable * the WKUP interrupt (we are already waking up), and enable the - * ESOF interrupt that will drive the resume operations. + * ESOF interrupt that will drive the resume operations. Clear any + * pending ESOF interrupt. */ - priv->imask &= ~(USB_CNTR_WKUPM|USB_CNTR_SUSPM); - priv->imask |= USB_CNTR_ESOFM; - stm32_putreg(priv->imask, STM32_USB_CNTR); - - /* Clear any pending interrupts that we just enabled */ - - stm32_putreg(~USB_CNTR_ESOFM, STM32_USB_ISTR); + stm32_setimask(priv, USB_CNTR_ESOFM, USB_CNTR_WKUPM|USB_CNTR_SUSPM); + stm32_putreg(~USB_ISTR_ESOF, STM32_USB_ISTR); irqrestore(flags); return OK; } @@ -3087,7 +3107,7 @@ static void stm32_reset(struct stm32_usbdev_s *priv) /* Set the interrrupt priority */ up_prioritize_irq(STM32_IRQ_USBHPCANTX, CONFIG_USB_PRI); - up_prioritize_irq( STM32_IRQ_USBLPCANRX0, CONFIG_USB_PRI); + up_prioritize_irq(STM32_IRQ_USBLPCANRX0, CONFIG_USB_PRI); } /**************************************************************************** @@ -3096,17 +3116,18 @@ static void stm32_reset(struct stm32_usbdev_s *priv) static void stm32_hwreset(struct stm32_usbdev_s *priv) { - /* Enable pull-up to connect the device */ + /* Put the USB controller into reset */ - stm32_usbpullup(&priv->usbdev, TRUE); stm32_putreg(USB_CNTR_FRES, STM32_USB_CNTR); - + + /* Disable interrupts (and perhaps take the USB controller out of reset) */ + priv->imask = 0; stm32_putreg(priv->imask, STM32_USB_CNTR); /* Clear pending interrupts */ - stm32_putreg(0, STM32_USB_ISTR); + stm32_putreg((uint16)~USB_ISTR_ALLINTS, STM32_USB_ISTR); /* Set the STM32 BTABLE address */ @@ -3128,8 +3149,7 @@ static void stm32_hwreset(struct stm32_usbdev_s *priv) /* Enable interrupts at the USB controllr */ - priv->imask = STM32_CNTR_SETUP; - stm32_putreg(priv->imask, STM32_USB_CNTR); + stm32_setimask(priv, STM32_CNTR_SETUP, (USB_CNTR_ALLINTS & ~STM32_CNTR_SETUP)); } /**************************************************************************** @@ -3164,6 +3184,10 @@ void up_usbinitialize(void) stm32_putreg(USB_CNTR_FRES|USB_CNTR_PDWN, STM32_USB_CNTR); + /* Disconnect the device / disable the pull-up */ + + stm32_usbpullup(&priv->usbdev, FALSE); + /* Initialize the device state structure. NOTE: many fields * have the initial value of zero and, hence, are not explicitly * initialized here. @@ -3275,7 +3299,7 @@ void up_usbuninitialize(void) /* Clear pending interrupts */ - stm32_putreg(0, STM32_USB_ISTR); + stm32_putreg(~USB_ISTR_ALLINTS, STM32_USB_ISTR); /* Disconnect the device / disable the pull-up */ @@ -3346,6 +3370,10 @@ int usbdev_register(struct usbdevclass_driver_s *driver) up_prioritize_irq(STM32_IRQ_USBHPCANTX, CONFIG_USB_PRI); up_prioritize_irq(STM32_IRQ_USBLPCANRX0, CONFIG_USB_PRI); + + /* Enable pull-up to connect the device */ + + stm32_usbpullup(&priv->usbdev, TRUE); } return ret; } diff --git a/arch/arm/src/stm32/stm32_usbdev.h b/arch/arm/src/stm32/stm32_usbdev.h index e40c254909..af39ad8aef 100644 --- a/arch/arm/src/stm32/stm32_usbdev.h +++ b/arch/arm/src/stm32/stm32_usbdev.h @@ -161,9 +161,12 @@ #define USB_CNTR_SUSPM (1 << 11) /* Bit 11: Suspend mode Interrupt Mask */ #define USB_CNTR_WKUPM (1 << 12) /* Bit 12: Wakeup Interrupt Mask */ #define USB_CNTR_ERRM (1 << 13) /* Bit 13: Error Interrupt Mask */ -#define USB_CNTR_DMAOVRN (1 << 14) /* Bit 14: Packet Memory Area Over / Underrun Interrupt Mask */ +#define USB_CNTR_DMAOVRNM (1 << 14) /* Bit 14: Packet Memory Area Over / Underrun Interrupt Mask */ #define USB_CNTR_CTRM (1 << 15) /* Bit 15: Correct Transfer Interrupt Mask */ +#define USB_CNTR_ALLINTS (USB_CNTR_ESOFM|USB_CNTR_SOFM|USB_CNTR_RESETM|USB_CNTR_SUSPM|\ + USB_CNTR_WKUPM|USB_CNTR_ERRM|USB_CNTR_DMAOVRNM|USB_CNTR_CTRM) + /* USB interrupt status register */ #define USB_ISTR_EPID_SHIFT (0) /* Bits 3-0: Endpoint Identifier */ @@ -178,6 +181,9 @@ #define USB_ISTR_DMAOVRN (1 << 14) /* Bit 14: Packet Memory Area Over / Underrun */ #define USB_ISTR_CTR (1 << 15) /* Bit 15: Correct Transfer */ +#define USB_ISTR_ALLINTS (USB_ISTR_ESOF|USB_ISTR_SOF|USB_ISTR_RESET|USB_ISTR_SUSP|\ + USB_ISTR_WKUP|USB_ISTR_ERR|USB_ISTR_DMAOVRN|USB_ISTR_CTR) + /* USB frame number register */ #define USB_FNR_FN_SHIFT (0) /* Bits 10-0: Frame Number */