Merged in david_s5/nuttx/master_usb_fix (pull request #125)

BugFix:Lost first word from FIFO
This commit is contained in:
Gregory Nutt 2016-08-25 11:40:50 -06:00
commit 1c115adfb8
2 changed files with 218 additions and 194 deletions

View File

@ -1,10 +1,11 @@
/****************************************************************************************************
* arch/arm/src/stm32/chip/stm32fxxxxx_otgfs.h
*
* Copyright (C) 2012, 2014-2015 Gregory Nutt. All rights reserved.
* Copyright (C) 2012, 2014-2016 Gregory Nutt. All rights reserved.
* Copyright (C) 2016 Omni Hoverboards Inc. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
* Authors: Gregory Nutt <gnutt@nuttx.org>
* Paul Alexander Patience <paul-a.patience@polymtl.ca>
* David Sidrane <david_s5@nscdg.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -470,44 +471,38 @@
/* Core interrupt and Interrupt mask registers */
#define OTGFS_GINTSTS_CMOD (1 << 0) /* Bit 0: Current mode of operation */
#define OTGFS_GINTSTS_CMOD (1 << 0) /* Bit 0: ro Current mode of operation */
# define OTGFS_GINTSTS_DEVMODE (0)
# define OTGFS_GINTSTS_HOSTMODE (OTGFS_GINTSTS_CMOD)
#define OTGFS_GINT_MMIS (1 << 1) /* Bit 1: Mode mismatch interrupt */
#define OTGFS_GINT_OTG (1 << 2) /* Bit 2: OTG interrupt */
#define OTGFS_GINT_SOF (1 << 3) /* Bit 3: Start of frame */
#define OTGFS_GINT_RXFLVL (1 << 4) /* Bit 4: RxFIFO non-empty */
#define OTGFS_GINT_NPTXFE (1 << 5) /* Bit 5: Non-periodic TxFIFO empty */
#define OTGFS_GINT_GINAKEFF (1 << 6) /* Bit 6: Global IN non-periodic NAK effective */
#define OTGFS_GINT_MMIS (1 << 1) /* Bit 1: rc_w1 Mode mismatch interrupt */
#define OTGFS_GINT_OTG (1 << 2) /* Bit 2: ro OTG interrupt */
#define OTGFS_GINT_SOF (1 << 3) /* Bit 3: rc_w1 Start of frame */
#define OTGFS_GINT_RXFLVL (1 << 4) /* Bit 4: ro RxFIFO non-empty */
#define OTGFS_GINT_NPTXFE (1 << 5) /* Bit 5: ro Non-periodic TxFIFO empty */
#define OTGFS_GINT_GINAKEFF (1 << 6) /* Bit 6: ro Global IN non-periodic NAK effective */
#define OTGFS_GINT_GONAKEFF (1 << 7) /* Bit 7: Global OUT NAK effective */
/* Bits 8-9: Reserved, must be kept at reset value */
#define OTGFS_GINT_ESUSP (1 << 10) /* Bit 10: Early suspend */
#define OTGFS_GINT_USBSUSP (1 << 11) /* Bit 11: USB suspend */
#define OTGFS_GINT_USBRST (1 << 12) /* Bit 12: USB reset */
#define OTGFS_GINT_ENUMDNE (1 << 13) /* Bit 13: Enumeration done */
#define OTGFS_GINT_ISOODRP (1 << 14) /* Bit 14: Isochronous OUT packet dropped interrupt */
#define OTGFS_GINT_EOPF (1 << 15) /* Bit 15: End of periodic frame interrupt */
/* Bits 16 Reserved, must be kept at reset value */
#define OTGFS_GINTMSK_EPMISM (1 << 17) /* Bit 17: Endpoint mismatch interrupt mask */
#define OTGFS_GINT_IEP (1 << 18) /* Bit 18: IN endpoint interrupt */
#define OTGFS_GINT_OEP (1 << 19) /* Bit 19: OUT endpoint interrupt */
#define OTGFS_GINT_IISOIXFR (1 << 20) /* Bit 20: Incomplete isochronous IN transfer */
#define OTGFS_GINT_IISOOXFR (1 << 21) /* Bit 21: Incomplete isochronous OUT transfer (device) */
#define OTGFS_GINT_IPXFR (1 << 21) /* Bit 21: Incomplete periodic transfer (host) */
/* Bit 22: Reserved, must be kept at reset value */
#if defined(CONFIG_STM32_STM32F446) || defined(CONFIG_STM32_STM32F469)
# define OTGFS_GINT_RSTDET (1 << 23) /* Bit 23: Reset detected interrupt */
#endif
#define OTGFS_GINT_HPRT (1 << 24) /* Bit 24: Host port interrupt */
#define OTGFS_GINT_HC (1 << 25) /* Bit 25: Host channels interrupt */
#define OTGFS_GINT_PTXFE (1 << 26) /* Bit 26: Periodic TxFIFO empty */
#if defined(CONFIG_STM32_STM32F446) || defined(CONFIG_STM32_STM32F469)
# define OTGFS_GINT_LPMINT (1 << 27) /* Bit 27: LPM interrupt */
#endif
#define OTGFS_GINT_CIDSCHG (1 << 28) /* Bit 28: Connector ID status change */
#define OTGFS_GINT_DISC (1 << 29) /* Bit 29: Disconnect detected interrupt */
#define OTGFS_GINT_SRQ (1 << 30) /* Bit 30: Session request/new session detected interrupt */
#define OTGFS_GINT_WKUP (1 << 31) /* Bit 31: Resume/remote wakeup detected interrupt */
#define OTGFS_GINT_RES89 (3 << 8) /* Bits 8-9: Reserved, must be kept at reset value */
#define OTGFS_GINT_ESUSP (1 << 10) /* Bit 10: rc_w1 Early suspend */
#define OTGFS_GINT_USBSUSP (1 << 11) /* Bit 11: rc_w1 USB suspend */
#define OTGFS_GINT_USBRST (1 << 12) /* Bit 12: rc_w1 USB reset */
#define OTGFS_GINT_ENUMDNE (1 << 13) /* Bit 13: rc_w1 Enumeration done */
#define OTGFS_GINT_ISOODRP (1 << 14) /* Bit 14: rc_w1 Isochronous OUT packet dropped interrupt */
#define OTGFS_GINT_EOPF (1 << 15) /* Bit 15: rc_w1 End of periodic frame interrupt */
#define OTGFS_GINT_RES16 (1 << 16) /* Bits 16 Reserved, must be kept at reset value */
#define OTGFS_GINTMSK_EPMISM (1 << 17) /* Bit 17: Reserved in GINT rw Endpoint mismatch interrupt mask */
#define OTGFS_GINT_IEP (1 << 18) /* Bit 18: ro IN endpoint interrupt */
#define OTGFS_GINT_OEP (1 << 19) /* Bit 19: ro OUT endpoint interrupt */
#define OTGFS_GINT_IISOIXFR (1 << 20) /* Bit 20: rc_w1Incomplete isochronous IN transfer */
#define OTGFS_GINT_IISOOXFR (1 << 21) /* Bit 21: rc_w1 Incomplete isochronous OUT transfer */
#define OTGFS_GINT_RES2223 (3 << 22) /* Bits 22-23: Reserved, must be kept at reset value */
#define OTGFS_GINT_HPRT (1 << 24) /* Bit 24: ro Host port interrupt */
#define OTGFS_GINT_HC (1 << 25) /* Bit 25: ro Host channels interrupt */
#define OTGFS_GINT_PTXFE (1 << 26) /* Bit 26: ro Periodic TxFIFO empty */
#define OTGFS_GINT_RES27 (1 << 27) /* Bit 27 Reserved, must be kept at reset value */
#define OTGFS_GINT_CIDSCHG (1 << 28) /* Bit 28: rc_w1 Connector ID status change */
#define OTGFS_GINT_DISC (1 << 29) /* Bit 29: rc_w1 Disconnect detected interrupt */
#define OTGFS_GINT_SRQ (1 << 30) /* Bit 30: rc_w1 Session request/new session detected interrupt */
#define OTGFS_GINT_WKUP (1 << 31) /* Bit 31: rc_w1 Resume/remote wakeup detected interrupt */
/* Receive status debug read/OTG status read and pop registers (host mode) */

View File

@ -1,8 +1,9 @@
/****************************************************************************
* arch/arm/src/stm32/stm32_otgfsdev.c
*
* Copyright (C) 2012-2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
* Copyright (C) 2012-2016 Gregory Nutt. All rights reserved.
* Authors: Gregory Nutt <gnutt@nuttx.org>
* David Sidrane <david_s5@nscdg.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -111,7 +112,8 @@
# define CONFIG_USBDEV_EP3_TXFIFO_SIZE 192
#endif
#if (CONFIG_USBDEV_RXFIFO_SIZE + CONFIG_USBDEV_EP0_TXFIFO_SIZE + \
#if (CONFIG_USBDEV_RXFIFO_SIZE + \
CONFIG_USBDEV_EP0_TXFIFO_SIZE + CONFIG_USBDEV_EP1_TXFIFO_SIZE + \
CONFIG_USBDEV_EP2_TXFIFO_SIZE + CONFIG_USBDEV_EP3_TXFIFO_SIZE) > 1280
# error "FIFO allocations exceed FIFO memory size"
#endif
@ -151,6 +153,27 @@
# error "CONFIG_USBDEV_EP3_TXFIFO_SIZE is out of range"
#endif
#define OTGFS_GINT_RESERVED (OTGFS_GINT_RES89 | \
(OTGFS_GINT_RES16 | OTGFS_GINTMSK_EPMISM) \
|OTGFS_GINT_RES2223 | \
OTGFS_GINT_RES27)
#define OTGFS_GINT_RC_W1 (OTGFS_GINT_MMIS | \
OTGFS_GINT_SOF | \
OTGFS_GINT_ESUSP | \
OTGFS_GINT_USBSUSP | \
OTGFS_GINT_USBRST | \
OTGFS_GINT_ENUMDNE | \
OTGFS_GINT_ISOODRP | \
OTGFS_GINT_EOPF | \
OTGFS_GINT_IISOIXFR | \
OTGFS_GINT_IISOOXFR | \
OTGFS_GINT_CIDSCHG | \
OTGFS_GINT_DISC | \
OTGFS_GINT_SRQ | \
OTGFS_GINT_SOF | \
OTGFS_GINT_WKUP)
/* Debug ***********************************************************************/
/* Trace error codes */
@ -3119,9 +3142,8 @@ static inline void stm32_rxinterrupt(FAR struct stm32_usbdev_s *priv)
/* Disable the Rx status queue level interrupt */
regval = stm32_getreg(STM32_OTGFS_GINTMSK);
regval &= ~OTGFS_GINT_RXFLVL;
stm32_putreg(regval, STM32_OTGFS_GINTMSK);
while(0 != (stm32_getreg(STM32_OTGFS_GINTSTS) & OTGFS_GINT_RXFLVL))
{
/* Get the status from the top of the FIFO */
@ -3131,6 +3153,11 @@ static inline void stm32_rxinterrupt(FAR struct stm32_usbdev_s *priv)
epphy = (regval & OTGFS_GRXSTSD_EPNUM_MASK) >> OTGFS_GRXSTSD_EPNUM_SHIFT;
/* Workaround for bad values read from the STM32_OTGFS_GRXSTSP register
* happens regval is 0xb4e48168 or 0xa80c9367 or 267E781c
* All of which provide out of range indexes for epout[epphy]
*/
if (epphy < STM32_NENDPOINTS)
{
privep = &priv->epout[epphy];
@ -3197,6 +3224,22 @@ static inline void stm32_rxinterrupt(FAR struct stm32_usbdev_s *priv)
case OTGFS_GRXSTSD_PKTSTS_SETUPDONE:
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_SETUPDONE), epphy);
/* Now that the Setup Phase is complete if it was an OUT enable
* the endpoint
* (Doing this here prevents the loss of the first FIFO word)
*/
if (priv->ep0state == EP0STATE_SETUP_OUT)
{
/* Clear NAKSTS so that we can receive the data */
regval = stm32_getreg(STM32_OTGFS_DOEPCTL0);
regval |= OTGFS_DOEPCTL0_CNAK;
stm32_putreg(regval, STM32_OTGFS_DOEPCTL0);
}
}
break;
@ -3232,12 +3275,6 @@ static inline void stm32_rxinterrupt(FAR struct stm32_usbdev_s *priv)
datlen = GETUINT16(priv->ctrlreq.len);
if (USB_REQ_ISOUT(priv->ctrlreq.type) && datlen > 0)
{
/* Clear NAKSTS so that we can receive the data */
regval = stm32_getreg(STM32_OTGFS_DOEPCTL0);
regval |= OTGFS_DOEPCTL0_CNAK;
stm32_putreg(regval, STM32_OTGFS_DOEPCTL0);
/* Wait for the data phase. */
priv->ep0state = EP0STATE_SETUP_OUT;
@ -3261,12 +3298,7 @@ static inline void stm32_rxinterrupt(FAR struct stm32_usbdev_s *priv)
break;
}
}
/* Enable the Rx Status Queue Level interrupt */
regval = stm32_getreg(STM32_OTGFS_GINTMSK);
regval |= OTGFS_GINT_RXFLVL;
stm32_putreg(regval, STM32_OTGFS_GINTMSK);
}
}
/****************************************************************************
@ -3289,7 +3321,7 @@ static inline void stm32_enuminterrupt(FAR struct stm32_usbdev_s *priv)
regval = stm32_getreg(STM32_OTGFS_GUSBCFG);
regval &= ~OTGFS_GUSBCFG_TRDT_MASK;
regval |= OTGFS_GUSBCFG_TRDT(5);
regval |= OTGFS_GUSBCFG_TRDT(6);
stm32_putreg(regval, STM32_OTGFS_GUSBCFG);
}
@ -3508,6 +3540,7 @@ static int stm32_usbinterrupt(int irq, FAR void *context)
FAR struct stm32_usbdev_s *priv = &g_otgfsdev;
uint32_t regval;
uint32_t reserved;
usbtrace(TRACE_INTENTRY(STM32_TRACEINTID_USB), 0);
@ -3519,14 +3552,21 @@ static int stm32_usbinterrupt(int irq, FAR void *context)
* some interrupts (like RXFLVL) will generate additional interrupting
* events.
*/
for (; ; )
{
/* Get the set of pending, un-masked interrupts */
regval = stm32_getreg(STM32_OTGFS_GINTSTS);
reserved = (regval & OTGFS_GINT_RESERVED);
regval &= stm32_getreg(STM32_OTGFS_GINTMSK);
/* With out modifying the reserved bits, acknowledge all
* **Writable** pending irqs we will service below
*/
stm32_putreg(((regval | reserved) & OTGFS_GINT_RC_W1), STM32_OTGFS_GINTSTS);
/* Break out of the loop when there are no further pending (and
* unmasked) interrupts to be processes.
*/
@ -3545,7 +3585,6 @@ static int stm32_usbinterrupt(int irq, FAR void *context)
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPOUT), (uint16_t)regval);
stm32_epout_interrupt(priv);
stm32_putreg(OTGFS_GINT_OEP, STM32_OTGFS_GINTSTS);
}
/* IN endpoint interrupt. The core sets this bit to indicate that
@ -3556,7 +3595,6 @@ static int stm32_usbinterrupt(int irq, FAR void *context)
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_EPIN), (uint16_t)regval);
stm32_epin_interrupt(priv);
stm32_putreg(OTGFS_GINT_IEP, STM32_OTGFS_GINTSTS);
}
/* Host/device mode mismatch error interrupt */
@ -3565,7 +3603,6 @@ static int stm32_usbinterrupt(int irq, FAR void *context)
if ((regval & OTGFS_GINT_MMIS) != 0)
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_MISMATCH), (uint16_t)regval);
stm32_putreg(OTGFS_GINT_MMIS, STM32_OTGFS_GINTSTS);
}
#endif
@ -3575,7 +3612,6 @@ static int stm32_usbinterrupt(int irq, FAR void *context)
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_WAKEUP), (uint16_t)regval);
stm32_resumeinterrupt(priv);
stm32_putreg(OTGFS_GINT_WKUP, STM32_OTGFS_GINTSTS);
}
/* USB suspend interrupt */
@ -3584,7 +3620,6 @@ static int stm32_usbinterrupt(int irq, FAR void *context)
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_SUSPEND), (uint16_t)regval);
stm32_suspendinterrupt(priv);
stm32_putreg(OTGFS_GINT_USBSUSP, STM32_OTGFS_GINTSTS);
}
/* Start of frame interrupt */
@ -3593,7 +3628,6 @@ static int stm32_usbinterrupt(int irq, FAR void *context)
if ((regval & OTGFS_GINT_SOF) != 0)
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_SOF), (uint16_t)regval);
stm32_putreg(OTGFS_GINT_SOF, STM32_OTGFS_GINTSTS);
}
#endif
@ -3605,7 +3639,6 @@ static int stm32_usbinterrupt(int irq, FAR void *context)
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_RXFIFO), (uint16_t)regval);
stm32_rxinterrupt(priv);
stm32_putreg(OTGFS_GINT_RXFLVL, STM32_OTGFS_GINTSTS);
}
/* USB reset interrupt */
@ -3618,7 +3651,6 @@ static int stm32_usbinterrupt(int irq, FAR void *context)
stm32_usbreset(priv);
usbtrace(TRACE_INTEXIT(STM32_TRACEINTID_USB), 0);
stm32_putreg(OTGFS_GINT_USBRST, STM32_OTGFS_GINTSTS);
return OK;
}
@ -3628,7 +3660,6 @@ static int stm32_usbinterrupt(int irq, FAR void *context)
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_ENUMDNE), (uint16_t)regval);
stm32_enuminterrupt(priv);
stm32_putreg(OTGFS_GINT_ENUMDNE, STM32_OTGFS_GINTSTS);
}
/* Incomplete isochronous IN transfer interrupt. When the core finds
@ -3642,7 +3673,6 @@ static int stm32_usbinterrupt(int irq, FAR void *context)
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_IISOIXFR), (uint16_t)regval);
stm32_isocininterrupt(priv);
stm32_putreg(OTGFS_GINT_IISOIXFR, STM32_OTGFS_GINTSTS);
}
/* Incomplete isochronous OUT transfer. For isochronous OUT
@ -3659,7 +3689,6 @@ static int stm32_usbinterrupt(int irq, FAR void *context)
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_IISOOXFR), (uint16_t)regval);
stm32_isocoutinterrupt(priv);
stm32_putreg(OTGFS_GINT_IISOOXFR, STM32_OTGFS_GINTSTS);
}
#endif
@ -3670,7 +3699,6 @@ static int stm32_usbinterrupt(int irq, FAR void *context)
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_SRQ), (uint16_t)regval);
stm32_sessioninterrupt(priv);
stm32_putreg(OTGFS_GINT_SRQ, STM32_OTGFS_GINTSTS);
}
/* OTG interrupt */
@ -3679,7 +3707,6 @@ static int stm32_usbinterrupt(int irq, FAR void *context)
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_OTG), (uint16_t)regval);
stm32_otginterrupt(priv);
stm32_putreg(OTGFS_GINT_OTG, STM32_OTGFS_GINTSTS);
}
#endif
}
@ -5338,7 +5365,9 @@ static void stm32_hwinitialize(FAR struct stm32_usbdev_s *priv)
/* Clear any pending interrupts */
stm32_putreg(0xbfffffff, STM32_OTGFS_GINTSTS);
regval = stm32_getreg(STM32_OTGFS_GINTSTS);
regval &= OTGFS_GINT_RESERVED;
stm32_putreg(regval | OTGFS_GINT_RC_W1, STM32_OTGFS_GINTSTS);
/* Enable the interrupts in the INTMSK */