From 64319d5b4fada128a541d5b38cd6f6372fcb4988 Mon Sep 17 00:00:00 2001 From: patacongo Date: Tue, 28 Aug 2012 23:36:58 +0000 Subject: [PATCH] I think the STM32 UST OTG FS host driver is finally finished git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@5065 7fd9a85b-ad96-42d3-883c-3090e2eb8679 --- nuttx/ChangeLog | 2 + nuttx/arch/arm/src/stm32/stm32_otgfshost.c | 84 +++++++++++++--------- 2 files changed, 54 insertions(+), 32 deletions(-) diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index c3c81108e..62b05931d 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -3211,3 +3211,5 @@ is now required to enabled strerror(). Add an option CONFIG_LIBC_STRERROR_SHORT that can be used to output shortened strings by strerror(). + * arch/arm/src/stm32/stm32_usbotghost.c: Finally... the USB OTG FS + appears to handle NAKing correctly is complete. diff --git a/nuttx/arch/arm/src/stm32/stm32_otgfshost.c b/nuttx/arch/arm/src/stm32/stm32_otgfshost.c index 684904925..ab5ef23ec 100644 --- a/nuttx/arch/arm/src/stm32/stm32_otgfshost.c +++ b/nuttx/arch/arm/src/stm32/stm32_otgfshost.c @@ -809,7 +809,7 @@ static void stm32_chan_halt(FAR struct stm32_usbhost_s *priv, int chidx, uint32_t eptype; unsigned int avail; - /* Save the recon for the halt. We need this in the channel halt interrrupt + /* Save the reason for the halt. We need this in the channel halt interrrupt * handling logic to know what to do next. */ @@ -1474,6 +1474,9 @@ static int stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, FAR uint8_t *buffer, size_t buflen) { FAR struct stm32_chan_s *chan; + uint16_t start; + uint16_t elapsed; + size_t xfrlen; int ret = OK; /* Loop until the transfer completes (i.e., buflen is decremented to zero) @@ -1481,22 +1484,19 @@ static int stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, */ chan = &priv->chan[chidx]; - chan->buffer = buffer; - chan->buflen = buflen; + start = stm32_getframe(); - /* There is a bug in the code at present. With debug OFF, this driver - * overruns the typical FLASH device and there are many problems with - * NAKS. Sticking a big delay here allows the device (FLASH drive) to - * catch up but sacrifices driver performance. - */ - -#if !defined(CONFIG_DEBUG_VERBOSE) || !defined(CONFIG_DEBUG_USB) -#warning "REVISIT this delay" - usleep(50*1000); -#endif - - while (chan->buflen > 0) + while (buflen > 0) { + /* Transfer one packet at a time. The hardware is capable of queueing + * multiple OUT packets, but I just haven't figured out how to handle + * the case where a single OUT packet in the group is NAKed. + */ + + xfrlen = MIN(chan->maxpacket, buflen); + chan->buffer = buffer; + chan->buflen = xfrlen; + /* Set up for the wait BEFORE starting the transfer */ ret = stm32_chan_waitsetup(priv, chan); @@ -1556,30 +1556,50 @@ static int stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, ret = stm32_chan_wait(priv, chan); - /* EAGAIN indicates that the device NAKed the transfer and we need - * do try again. NAK retries are not yet supported for OUT transfers - * so any unsuccessful response will cause us to abort the OUT - * transfer. - */ + /* Handle transfer failures */ if (ret != OK) { udbg("Transfer failed: %d\n", ret); - break; + + /* Check for a special case: If (1) the transfer was NAKed and (2) + * no Tx FIFO empty or Rx FIFO not-empty event occurred, then we + * should be able to just flush the Rx and Tx FIFOs and try again. + * We can detect this latter case becasue the then the transfer + * buffer pointer and buffer size will be unaltered. + */ + + elapsed = stm32_getframe() - start; + if (ret != -EAGAIN || /* Not a NAK condition OR */ + elapsed >= STM32_DATANAK_DELAY || /* Timeout has elapsed OR */ + chan->buflen != xfrlen) /* Data has been partially transferred */ + { + /* Break out and return the error */ + + break; + } + + /* Is this flush really necessary? What does the hardware do with the + * data in the FIFO when the NAK occurs? Does it discard it? + */ + + stm32_flush_txfifos(OTGFS_GRSTCTL_TXFNUM_HALL); + + /* Get the device a little time to catch up. Then retry the transfer + * using the same buffer pointer length. + */ + + usleep(20*1000); + } + else + { + /* Successfully transferred. Update the buffer pointer and length */ + + buffer += xfrlen; + buflen -= xfrlen; } } - /* There is a bug in the code at present. With debug OFF, this driver - * overruns the typical FLASH device and there are many problems with - * NAKS. Sticking a big delay here allows the device (FLASH drive) to - * catch up but sacrifices driver performance. - */ - -#if !defined(CONFIG_DEBUG_VERBOSE) || !defined(CONFIG_DEBUG_USB) -#warning "REVISIT this delay" - usleep(50*1000); -#endif - return ret; }