diff --git a/arch/arm/src/stm32/stm32_otgfshost.c b/arch/arm/src/stm32/stm32_otgfshost.c index 6d66203dcf..699c5c958c 100644 --- a/arch/arm/src/stm32/stm32_otgfshost.c +++ b/arch/arm/src/stm32/stm32_otgfshost.c @@ -1827,6 +1827,7 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, FAR uint8_t *buffer, size_t buflen) { FAR struct stm32_chan_s *chan; + systime_t start; ssize_t xfrd; int ret; @@ -1841,6 +1842,7 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, chan->xfrd = 0; xfrd = 0; + start = clock_systimer(); while (chan->xfrd < chan->buflen) { /* Set up for the wait BEFORE starting the transfer */ @@ -1865,11 +1867,7 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, ret = stm32_chan_wait(priv, chan); - /* EAGAIN indicates that the device NAKed the transfer. In the case - * of a NAK, we do not retry but rather assume that the transfer is - * commplete and return the data that we have received. Retry could - * be handled in class driver. - */ + /* EAGAIN indicates that the device NAKed the transfer. */ if (ret < 0) { @@ -1889,21 +1887,43 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, } else { - /* No... Break out and return the NAK */ + /* Get the elapsed time. Has the timeout elapsed? + * if not then try again. + */ - return (ssize_t)ret; + systime_t elapsed = clock_systimer() - start; + if (elapsed >= STM32_DATANAK_DELAY) + { + /* Timeout out... break out returning the NAK as + * as a failure. + */ + + return (ssize_t)ret; + } } } + else + { + /* Some unexpected, fatal error occurred. */ - usbhost_trace1(OTGFS_TRACE1_TRNSFRFAILED, ret); + usbhost_trace1(OTGFS_TRACE1_TRNSFRFAILED, ret); - /* Break out and return the error */ + /* Break out and return the error */ - uerr("ERROR: stm32_chan_wait failed: %d\n", ret); - return (ssize_t)ret; + uerr("ERROR: stm32_chan_wait failed: %d\n", ret); + return (ssize_t)ret; + } } + else + { + /* Successfully received another chunk of data... add that to the + * runing total. Then continue reading until we read 'buflen' + * bytes of data or until the the devices NAKs (implying a short + * packet). + */ - xfrd += chan->xfrd; + xfrd += chan->xfrd; + } } return xfrd; diff --git a/arch/arm/src/stm32/stm32_otghshost.c b/arch/arm/src/stm32/stm32_otghshost.c index 2b5411cf04..2a100e7a54 100644 --- a/arch/arm/src/stm32/stm32_otghshost.c +++ b/arch/arm/src/stm32/stm32_otghshost.c @@ -1832,6 +1832,7 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, FAR uint8_t *buffer, size_t buflen) { FAR struct stm32_chan_s *chan; + systime_t start; ssize_t xfrd; int ret; @@ -1846,6 +1847,7 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, chan->xfrd = 0; xfrd = 0; + start = clock_systimer(); while (chan->xfrd < chan->buflen) { /* Set up for the wait BEFORE starting the transfer */ @@ -1870,11 +1872,7 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, ret = stm32_chan_wait(priv, chan); - /* EAGAIN indicates that the device NAKed the transfer. In the case - * of a NAK, we do not retry but rather assume that the transfer is - * commplete and return the data that we have received. Retry could - * be handled in class driver. - */ + /* EAGAIN indicates that the device NAKed the transfer. */ if (ret < 0) { @@ -1894,21 +1892,43 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, } else { - /* No... Break out and return the NAK */ + /* Get the elapsed time. Has the timeout elapsed? + * if not then try again. + */ - return (ssize_t)ret; + systime_t elapsed = clock_systimer() - start; + if (elapsed >= STM32_DATANAK_DELAY) + { + /* Timeout out... break out returning the NAK as + * as a failure. + */ + + return (ssize_t)ret; + } } } + else + { + /* Some unexpected, fatal error occurred. */ - usbhost_trace1(OTGHS_TRACE1_TRNSFRFAILED, ret); + usbhost_trace1(OTGHS_TRACE1_TRNSFRFAILED, ret); - /* Break out and return the error */ + /* Break out and return the error */ - uerr("ERROR: stm32_chan_wait failed: %d\n", ret); - return (ssize_t)ret; + uerr("ERROR: stm32_chan_wait failed: %d\n", ret); + return (ssize_t)ret; + } } + else + { + /* Successfully received another chunk of data... add that to the + * runing total. Then continue reading until we read 'buflen' + * bytes of data or until the the devices NAKs (implying a short + * packet). + */ - xfrd += chan->xfrd; + xfrd += chan->xfrd; + } } return xfrd; diff --git a/arch/arm/src/stm32f7/stm32_otghost.c b/arch/arm/src/stm32f7/stm32_otghost.c index 6cbb0c617f..03a9ca1a1c 100644 --- a/arch/arm/src/stm32f7/stm32_otghost.c +++ b/arch/arm/src/stm32f7/stm32_otghost.c @@ -1826,6 +1826,7 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, FAR uint8_t *buffer, size_t buflen) { FAR struct stm32_chan_s *chan; + systime_t start; ssize_t xfrd; int ret; @@ -1840,6 +1841,7 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, chan->xfrd = 0; xfrd = 0; + start = clock_systimer(); while (chan->xfrd < chan->buflen) { /* Set up for the wait BEFORE starting the transfer */ @@ -1864,11 +1866,7 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, ret = stm32_chan_wait(priv, chan); - /* EAGAIN indicates that the device NAKed the transfer. In the case - * of a NAK, we do not retry but rather assume that the transfer is - * commplete and return the data that we have received. Retry could - * be handled in class driver. - */ + /* EAGAIN indicates that the device NAKed the transfer. */ if (ret < 0) { @@ -1888,21 +1886,43 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, } else { - /* No... Break out and return the NAK */ + /* Get the elapsed time. Has the timeout elapsed? + * if not then try again. + */ - return (ssize_t)ret; + systime_t elapsed = clock_systimer() - start; + if (elapsed >= STM32_DATANAK_DELAY) + { + /* Timeout out... break out returning the NAK as + * as a failure. + */ + + return (ssize_t)ret; + } } } + else + { + /* Some unexpected, fatal error occurred. */ - usbhost_trace1(OTG_TRACE1_TRNSFRFAILED, ret); + usbhost_trace1(OTG_TRACE1_TRNSFRFAILED, ret); - /* Break out and return the error */ + /* Break out and return the error */ - uerr("ERROR: stm32_chan_wait failed: %d\n", ret); - return (ssize_t)ret; + uerr("ERROR: stm32_chan_wait failed: %d\n", ret); + return (ssize_t)ret; + } } + else + { + /* Successfully received another chunk of data... add that to the + * runing total. Then continue reading until we read 'buflen' + * bytes of data or until the the devices NAKs (implying a short + * packet). + */ - xfrd += chan->xfrd; + xfrd += chan->xfrd; + } } return xfrd; diff --git a/arch/arm/src/stm32l4/stm32l4_otgfshost.c b/arch/arm/src/stm32l4/stm32l4_otgfshost.c index d2c41ffd79..7855ea2eeb 100644 --- a/arch/arm/src/stm32l4/stm32l4_otgfshost.c +++ b/arch/arm/src/stm32l4/stm32l4_otgfshost.c @@ -1831,6 +1831,7 @@ static ssize_t stm32l4_in_transfer(FAR struct stm32l4_usbhost_s *priv, size_t buflen) { FAR struct stm32l4_chan_s *chan; + systime_t start; ssize_t xfrd; int ret; @@ -1845,6 +1846,7 @@ static ssize_t stm32l4_in_transfer(FAR struct stm32l4_usbhost_s *priv, chan->xfrd = 0; xfrd = 0; + start = clock_systimer(); while (chan->xfrd < chan->buflen) { /* Set up for the wait BEFORE starting the transfer */ @@ -1869,11 +1871,7 @@ static ssize_t stm32l4_in_transfer(FAR struct stm32l4_usbhost_s *priv, ret = stm32l4_chan_wait(priv, chan); - /* EAGAIN indicates that the device NAKed the transfer. In the case - * of a NAK, we do not retry but rather assume that the transfer is - * commplete and return the data that we have received. Retry could - * be handled in class driver. - */ + /* EAGAIN indicates that the device NAKed the transfer. */ if (ret < 0) { @@ -1893,21 +1891,43 @@ static ssize_t stm32l4_in_transfer(FAR struct stm32l4_usbhost_s *priv, } else { - /* No... Break out and return the NAK */ + /* Get the elapsed time. Has the timeout elapsed? + * if not then try again. + */ - return (ssize_t)ret; + systime_t elapsed = clock_systimer() - start; + if (elapsed >= STM32L4_DATANAK_DELAY) + { + /* Timeout out... break out returning the NAK as + * as a failure. + */ + + return (ssize_t)ret; + } } } + else + { + /* Some unexpected, fatal error occurred. */ - usbhost_trace1(OTGFS_TRACE1_TRNSFRFAILED, ret); + usbhost_trace1(OTGFS_TRACE1_TRNSFRFAILED, ret); - /* Break out and return the error */ + /* Break out and return the error */ - uerr("ERROR: stm32l4_chan_wait failed: %d\n", ret); - return (ssize_t)ret; + uerr("ERROR: stm32l4_chan_wait failed: %d\n", ret); + return (ssize_t)ret; + } } + else + { + /* Successfully received another chunk of data... add that to the + * runing total. Then continue reading until we read 'buflen' + * bytes of data or until the the devices NAKs (implying a short + * packet). + */ - xfrd += chan->xfrd; + xfrd += chan->xfrd; + } } return xfrd; diff --git a/configs/olimex-stm32-p407/README.txt b/configs/olimex-stm32-p407/README.txt index b8c7bc7546..646442a2fa 100644 --- a/configs/olimex-stm32-p407/README.txt +++ b/configs/olimex-stm32-p407/README.txt @@ -339,7 +339,15 @@ must be is one of the following. above under "OTGFS Host". STATUS: I have seen this work with some FLASH sticks but not with - others. This probably needs a little TLC to get 100% reliable. + others. I have not studied the failure case carefully. They seem + to fail because the request is NAKed. That is not a failure, however, + that is normal behavior when the FLASH is not ready. + + There have been other cases like this with the STM32 host drivers: + in the event of NAKs, other drivers retry and wait for the data. The + STM32 does not but returns the NAK failure immediately. My guess is + that there needs to be be some retry logic to the driver 100% + reliable. 2. Kernel Modules / Shared Libraries