summaryrefslogtreecommitdiff
path: root/nuttx
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2012-04-07 19:38:13 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2012-04-07 19:38:13 +0000
commit45ad2f7a8b237cf58518b874326078659ff90011 (patch)
tree10738af642eec9353c15851c0c46dc7b76cc370a /nuttx
parentd147bb611f61ceaff9a8db9aeebfdf17805f94ef (diff)
downloadnuttx-45ad2f7a8b237cf58518b874326078659ff90011.tar.gz
nuttx-45ad2f7a8b237cf58518b874326078659ff90011.tar.bz2
nuttx-45ad2f7a8b237cf58518b874326078659ff90011.zip
Add partial TxFIFO logic to STM32 OTG FS device driver
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4570 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx')
-rwxr-xr-xnuttx/README.txt77
-rwxr-xr-xnuttx/arch/arm/src/stm32/stm32_otgfsdev.c270
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 */