diff options
-rwxr-xr-x | nuttx/README.txt | 77 | ||||
-rwxr-xr-x | nuttx/arch/arm/src/stm32/stm32_otgfsdev.c | 270 |
2 files changed, 267 insertions, 80 deletions
diff --git a/nuttx/README.txt b/nuttx/README.txt index 47e50a870..523bcc782 100755 --- a/nuttx/README.txt +++ b/nuttx/README.txt @@ -8,6 +8,8 @@ README - Installation Directories with Spaces in the Path - Notes about Header Files o Configuring NuttX + - Instantiating "Canned" Configurations + - NuttX Configuration Tool o Toolchains - Cross-Development Toolchains - NuttX Buildroot Toolchain @@ -25,6 +27,7 @@ INSTALLATION ^^^^^^^^^^^^ Installing Cygwin +----------------- NuttX may be installed and built on a Linux system or on a Windows system if Cygwin is installed. Installing Cygwin on your Windows PC @@ -56,7 +59,8 @@ Installing Cygwin fast nor reliable). The rest of these instructions assume that you are at a bash command line prompt in either Linux or in Cygwin shell. -Download and Unpack: +Download and Unpack +------------------- Download and unpack the NuttX tarball. If you are reading this, then you have probably already done that. After unpacking, you will end @@ -65,7 +69,8 @@ Download and Unpack: match the various instructions in the documentation and some scripts in the source tree. -Semi-Optional apps/ Package: +Semi-Optional apps/ Package +--------------------------- All NuttX libraries and example code used to be in included within the NuttX source tree. As of NuttX-6.0, this application code was @@ -98,7 +103,8 @@ Semi-Optional apps/ Package: can be changed by editing your NuttX configuration file, but that is another story). -Installation Directories with Spaces in the Path: +Installation Directories with Spaces in the Path +------------------------------------------------ The nuttx build directory should reside in a path that contains no spaces in any higher level directory name. For example, under @@ -114,7 +120,8 @@ Installation Directories with Spaces in the Path: Then I install NuttX in /home/nuttx and always build from /home/nuttx/nuttx. -Notes about Header Files: +Notes about Header Files +------------------------ Other C-Library Header Files. @@ -167,6 +174,9 @@ Notes about Header Files: CONFIGURING NUTTX ^^^^^^^^^^^^^^^^^ +Instantiating "Canned" Configurations +------------------------------------- + "Canned" NuttX configuration files are retained in: configs/<board-name>/<config-dir> @@ -206,10 +216,54 @@ easier. It is used as follows: cd ${TOPDIR}/tools ./configure.sh <board-name>/<config-dir> + +NuttX Configuration Tool +------------------------ + + An automated tool is under development to support re-configuration + of NuttX. This tool, however, is not yet quite ready for general + usage. + + This automated tool is based on the kconfig-frontends application + available at http://ymorin.is-a-geek.org/projects/kconfig-frontends + (A snapshot of this tool is also available at ../misc/tools). This + application provides a tool called 'mconf' that is used by the NuttX + top-level Makefile. The following make target is provided: + + make menuconfig + + This make target will bring up NuttX configuration menus. The + 'menuconfig' target depends on two things: + + 1. The Kconfig configuration data files that appear in almost all + NuttX directories. These data files are the part that is still + under development (patches are welcome!). The Kconfig files + contain configuration information for the configuration settings + relevant to the directory in which the Kconfig file resides. + + NOTE: For a description of the syntax of this configuration file, + see ../misc/tools/kconfig-language.txt. + + 2. The 'mconf' tool. 'mconf' is part of the kconfig-frontends + package. You can download that package from the website + http://ymorin.is-a-geek.org/projects/kconfig-frontends or you + can use the snapshot in ../misc/tools. + + Building may be as simple as 'configure; make; make install' + but there may be some build complexities, especially if you + are building under Cygwin. See the more detailed build + instructions at ../misc/tools/README.txt + + The 'make install' step will, by default, install the 'mconf' + tool at /usr/local/bin/mconf. Where ever you choose to + install 'mconf', make certain that your PATH variable includes + a path to that installation directory. + TOOLCHAINS ^^^^^^^^^^ Cross-Development Toolchains +---------------------------- In order to build NuttX for your board, you will have to obtain a cross- compiler to generate code for your target CPU. For each board, @@ -223,6 +277,7 @@ Cross-Development Toolchains is optional but can save a lot of confusion in the future. NuttX Buildroot Toolchain +------------------------- For many configurations, a DIY set of tools is available for NuttX. These tools can be downloaded from the NuttX SourceForge file repository. After @@ -236,6 +291,15 @@ NuttX Buildroot Toolchain This toolchain is available for both the Linux and Cygwin development environments. + Advantages: (1) NuttX header files are built into the tool chain, + and (2) related support tools like NXFLAT tools and the ROMFS + genromfs tools can be built into your toolchain. + + Disadvantages: This tool chain is not was well supported as some other + toolchains. GNU tools are not my priority and so the buildroot tools + often get behind. For example, the is still no EABI support in the + NuttX buildroot toolchain for ARM. + SHELLS ^^^^^^ @@ -270,6 +334,7 @@ BUILDING NUTTX ^^^^^^^^^^^^^^ Building +-------- NuttX builds in-place in the source tree. You do not need to create any special build directories. Assuming that your Make.defs is setup @@ -286,6 +351,7 @@ Building to see if that applies to your target. Re-building +----------- Re-building is normally simple -- just type make again. @@ -309,6 +375,7 @@ Re-building then make NuttX. Build Targets +------------- Below is a summary of the build targets available in the top-level NuttX Makefile: @@ -386,6 +453,7 @@ CYGWIN BUILD PROBLEMS ^^^^^^^^^^^^^^^^^^^^^ Strange Path Problems +--------------------- If you see strange behavior when building under Cygwin then you may have a problem with your PATH variable. For example, if you see failures to @@ -410,6 +478,7 @@ The solution is either: $ export PATH=/usr/local/bin:/usr/bin:/bin:$PATH Window Native Toolchain Issues +------------------------------ There are many popular Windows native toolchains that may be used with NuttX. Examples include CodeSourcery (for Windows), devkitARM, and several vendor- diff --git a/nuttx/arch/arm/src/stm32/stm32_otgfsdev.c b/nuttx/arch/arm/src/stm32/stm32_otgfsdev.c index 19bd3f17b..8e6bb3888 100755 --- a/nuttx/arch/arm/src/stm32/stm32_otgfsdev.c +++ b/nuttx/arch/arm/src/stm32/stm32_otgfsdev.c @@ -375,16 +375,19 @@ static bool stm32_addlast(FAR struct stm32_ep_s *privep, /* Special endpoint 0 data transfer logic */ static inline void stm32_ep0xfer(uint8_t epphy, FAR uint8_t *data, uint32_t nbytes); -static void stm32_ep0read(FAR uint8_t *dest, uint16_t len); -static void stm32_ep0configsetup(FAR struct stm32_usbdev_s *priv) +static void stm32_ep0configsetup(FAR struct stm32_usbdev_s *priv); -/* IN request handling */ +/* IN request and TxFIFO handling */ +static void stm32_epwritefifo(FAR struct stm32_ep_s *privep, + FAR uint8_t *buf, int nbytes); static int stm32_wrrequest(FAR struct stm32_usbdev_s *priv, FAR struct stm32_ep_s *privep); -/* OUT request handling */ +/* OUT request and RxFIFO handling */ +static void stm32_epreadfifo(FAR struct stm32_ep_s *privep, + FAR uint8_t *dest, uint16_t len); static void stm32_epoutcomplete(FAR struct stm32_usbdev_s *priv, FAR struct stm32_ep_s *privep); static inline void stm32_epoutreceive(FAR struct stm32_ep_s *privep, int bcnt); @@ -426,6 +429,7 @@ static inline void stm32_epoutinterrupt(FAR struct stm32_usbdev_s *priv); static inline void stm32_runtestmode(FAR struct stm32_usbdev_s *priv); static inline void stm32_epin(FAR struct stm32_usbdev_s *priv, uint8_t epno); +static inline void stm32_txfifoempty(FAR struct stm32_usbdev_s *priv, int epno); static inline void stm32_epininterrupt(FAR struct stm32_usbdev_s *priv); /* Other second level interrupt processing */ @@ -692,61 +696,64 @@ static inline void stm32_ep0xfer(uint8_t epphy, uint8_t *buf, uint32_t nbytes) } /******************************************************************************* - * Name: stm32_ep0read + * Name: stm32_ep0configsetup * * Description: - * Read a Setup packet from the DTD. + * Setup to receive a SETUP packet. * *******************************************************************************/ -static void stm32_ep0read(FAR uint8_t *dest, uint16_t len) +static void stm32_ep0configsetup(FAR struct stm32_usbdev_s *priv) { - uint32_t regaddr; - int i; + uint32_t regval; - /* Get the address of the EP0 FIFO */ + regval = (USB_SIZEOF_CTRLREQ * 3 << OTGFS_DOEPTSIZ0_XFRSIZ_SHIFT) || + (OTGFS_DOEPTSIZ0_PKTCNT) || + (3 << OTGFS_DOEPTSIZ0_STUPCNT_SHIFT); + stm32_putreg(regval, STM32_OTGFS_DOEPTSIZ0); +} - regaddr = STM32_OTGFS_DFIFO_DEP(0); +/**************************************************************************** + * Name: stm32_epwritefifo + * + * Description: + * Send data to the endpoint's TxFIFO. + * + ****************************************************************************/ - /* Read 32-bits and write 4 x 8-bits at time (to avoid unaligned accesses) */ +static void stm32_epwritefifo(FAR struct stm32_ep_s *privep, + FAR uint8_t *buf, int nbytes) +{ + uint32_t regaddr; + uint32_t regval; + int nwords; + int i; - for (i = 0; i < len; i += 4) - { - union - { - uint32_t w; - uint8_t b[4]; - } data; + /* Convert the number of bytes to words */ - /* Read 1 x 32-bits of EP0 packet data */ + nwords = (nbytes + 3) >> 2; - data.w = stm32_getreg(regaddr); + /* Get the TxFIFO for this endpoint (same as the endpoint number) */ - /* Write 4 x 8-bits of EP0 packet data */ + regaddr = STM32_OTGFS_DFIFO_DEP(privep->epphy); - *dest++ = data.b[0]; - *dest++ = data.b[1]; - *dest++ = data.b[2]; - *dest++ = data.b[3]; - } -} + /* Then transfer each word to the TxFIFO */ -/******************************************************************************* - * Name: stm32_ep0configsetup - * - * Description: - * Setup to receive a SETUP packet. - * - *******************************************************************************/ + for (i = 0; i < nwords; i++) + { + /* Read four bytes from the source buffer (to avoid unaligned accesses) + * and pack these into one 32-bit word (little endian). + */ -static void stm32_ep0configsetup(FAR struct stm32_usbdev_s *priv) -{ - uint32_t regval; + regval = (uint32_t)*buf++; + regval |= ((uint32_t)*buf++) << 8; + regval |= ((uint32_t)*buf++) << 16; + regval |= ((uint32_t)*buf++) << 24; - regval = (USB_SIZEOF_CTRLREQ * 3 << OTGFS_DOEPTSIZ0_XFRSIZ_SHIFT) || - (OTGFS_DOEPTSIZ0_PKTCNT) || - (3 << OTGFS_DOEPTSIZ0_STUPCNT_SHIFT); - stm32_putreg(regval, STM32_OTGFS_DOEPTSIZ0); + /* Then write the packed data to the TxFIFO */ + + stm32_putreg(regval, regaddr); + } } /**************************************************************************** @@ -757,16 +764,20 @@ static void stm32_ep0configsetup(FAR struct stm32_usbdev_s *priv) * ****************************************************************************/ -static int stm32_wrrequest(struct stm32_usbdev_s *priv, struct stm32_ep_s *privep) +static int stm32_wrrequest(FAR struct stm32_usbdev_s *priv, + FAR struct stm32_ep_s *privep) { struct stm32_req_s *privreq; + uint32_t regaddr; + uint32_t regval; uint8_t *buf; uint8_t epno; int nbytes; + int nwords; int bytesleft; - /* We get here when an IN endpoint interrupt occurs. So now we know that - * there is no TX transfer in progress. + /* We get here when an IN endpoint or Tx FIFO empty interrupt occurs. So + * now we know that there is no TX transfer in progress. */ privep->active = false; @@ -789,57 +800,102 @@ static int stm32_wrrequest(struct stm32_usbdev_s *priv, struct stm32_ep_s *prive ullvdbg("epno=%d req=%p: len=%d xfrd=%d nullpkt=%d\n", epno, privreq, privreq->req.len, privreq->req.xfrd, privep->zlp); - /* Get the number of bytes left to be sent in the packet */ + /* Loop while there are still bytes to be transferred (or a zero-length- + * packet, ZLP, to be sent). The loop will also be terminated if there + * is insufficient space remaining in the TxFIFO to send a complete + * packet. + */ - bytesleft = privreq->req.len - privreq->req.xfrd; - nbytes = bytesleft; + while (privreq->req.xfrd < privreq->req.len || privep->zlp) + { + /* Get the number of bytes left to be sent in the request */ - /* Send the next packet */ + bytesleft = privreq->req.len - privreq->req.xfrd; + nbytes = bytesleft; - if (nbytes > 0) - { - /* Either send the maxpacketsize or all of the remaining data in - * the request. + /* Limit the size of the transfer to one full packet and handle + * zero-length packets (ZLPs). */ - privep->zlp = 0; - if (nbytes >= privep->ep.maxpacket) + if (nbytes > 0) { - nbytes = privep->ep.maxpacket; - - /* Handle the case where this packet is exactly the - * maxpacketsize. Do we need to send a zero-length packet - * in this case? + /* Either send the maxpacketsize or all of the remaining data in + * the request. */ - if (bytesleft == privep->ep.maxpacket && - (privreq->req.flags & USBDEV_REQFLAGS_NULLPKT) != 0) + privep->zlp = 0; + if (nbytes >= privep->ep.maxpacket) { - privep->zlp = 1; + nbytes = privep->ep.maxpacket; + + /* Handle the case where this packet is exactly the + * maxpacketsize. Do we need to send a zero-length packet + * in this case? + */ + + if (bytesleft == privep->ep.maxpacket && + (privreq->req.flags & USBDEV_REQFLAGS_NULLPKT) != 0) + { +#warning "How, exactly, do I need to handle zero-length packets?" + privep->zlp = 1; + } } } - } - /* Send the packet (might be a null packet nbytes == 0) */ + /* Get the transfer size in 32-bit words */ - buf = privreq->req.buf + privreq->req.xfrd; - stm32_epwrite(priv, privep, buf, nbytes); - privep->active = true; + nwords = (nbytes + 3) >> 2; - /* Update for the next data IN interrupt */ + /* Get the number of 32-bit words available in the TxFIFO. The + * DXTFSTS indicates the amount of free space available in the + * endpoint TxFIFO. Values are in terms of 32-bit words: + * + * 0: Endpoint TxFIFO is full + * 1: 1 word available + * 2: 2 words available + * n: n words available + */ + + regaddr = STM32_OTGFS_DTXFSTS(privep->epphy); + regval = stm32_getreg(regaddr); + + /* And terminate the loop if there is insufficient space in the TxFIFO + * hold the entire packet. + */ + + if ((regval & OTGFS_DTXFSTS_MASK) < nwords) + { + /* The TxFIFO is full */ + + break; + } + + /* Transfer data to the TxFIFO */ + + buf = privreq->req.buf + privreq->req.xfrd; + stm32_epwritefifo(privep, buf, nbytes); + + /* If it was not before, the OUT endpoint is now actively transferring + * data. + */ + + privep->active = true; - privreq->req.xfrd += nbytes; - bytesleft = privreq->req.len - privreq->req.xfrd; + /* Update for the next time through the loop */ + + privreq->req.xfrd += nbytes; + } /* If all of the bytes were sent (including any final null packet) * then we are finished with the transfer */ - if (bytesleft == 0 && !privep->zlp) + if (privreq->req.xfrd >= privreq->req.len && !privep->zlp) { usbtrace(TRACE_COMPLETE(USB_EPNO(privep->ep.eplog)), privreq->req.xfrd); - privep->zlp = 0; stm32_reqcomplete(privep, OK); + + privep->zlp = 0; privep->active = false; } @@ -847,6 +903,47 @@ static int stm32_wrrequest(struct stm32_usbdev_s *priv, struct stm32_ep_s *prive } /******************************************************************************* + * Name: stm32_epreadfifo + * + * Description: + * Read packet from the EP0 RxFIFO. + * + *******************************************************************************/ + +static void stm32_epreadfifo(FAR struct stm32_ep_s *privep, + FAR uint8_t *dest, uint16_t len) +{ + uint32_t regaddr; + int i; + + /* Get the address of the endpoint FIFO */ + + regaddr = STM32_OTGFS_DFIFO_DEP(privep->epphy); + + /* Read 32-bits and write 4 x 8-bits at time (to avoid unaligned accesses) */ + + for (i = 0; i < len; i += 4) + { + union + { + uint32_t w; + uint8_t b[4]; + } data; + + /* Read 1 x 32-bits of EP0 packet data */ + + data.w = stm32_getreg(regaddr); + + /* Write 4 x 8-bits of EP0 packet data */ + + *dest++ = data.b[0]; + *dest++ = data.b[1]; + *dest++ = data.b[2]; + *dest++ = data.b[3]; + } +} + +/******************************************************************************* * Name: stm32_epoutcomplete * * Description: @@ -943,7 +1040,7 @@ static inline void stm32_epoutreceive(FAR struct stm32_ep_s *privep, int bcnt) /* Transfer the data from the RxFIFO to the request's data buffer */ - stm32_ep0read(dest, readlen); + stm32_epreadfifo(privep, dest, readlen); /* Update the number of bytes transferred */ @@ -973,7 +1070,7 @@ static void stm32_epoutsetup(FAR struct stm32_usbdev_s *priv, * just return, leaving the newly received request in the request queue. */ - if (!priv->active) + if (!privep->active) { /* Loop until a valid request is found (or the request queue is empty). * The loop is only need to look at the request queue again is an invalid @@ -2173,6 +2270,26 @@ static inline void stm32_epin(FAR struct stm32_usbdev_s *priv, uint8_t epno) } } +/**************************************************************************** + * Name: stm32_txfifoempty + * + * Description: + * TxFIFO empty interrupt handling + * + ****************************************************************************/ + +static inline void stm32_txfifoempty(FAR struct stm32_usbdev_s *priv, int epno) +{ + FAR struct stm32_ep_s *privep = &priv->epin[epno]; + + /* Continue processing the write request queue. This may mean sending + * more dat from the exisiting request or terminating the current requests + * and (perhaps) starting the IN transfer from the next write request. + */ + + stm32_wrrequest(priv, privep); +} + /******************************************************************************* * Name: stm32_epininterrupt * @@ -2482,7 +2599,8 @@ static inline void stm32_rxinterrupt(FAR struct stm32_usbdev_s *priv) * last SETUP packet will be processed. */ - stm32_ep0read((FAR uint8_t*)&priv->ctrlreq, USB_SIZEOF_CTRLREQ); + stm32_epreadfifo(&priv->epout[EP0], (FAR uint8_t*)&priv->ctrlreq, + USB_SIZEOF_CTRLREQ); /* The SETUP data has been processed */ |