summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2009-06-07 15:48:01 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2009-06-07 15:48:01 +0000
commit14d0a961ecf430c882eae8d7c7d66ba420c13403 (patch)
tree47435a2e441745acfa63f5262cd85fb5b8c3f7c4
parent99a001eab90e0b2058b969545396018239f1ee2b (diff)
downloadnuttx-14d0a961ecf430c882eae8d7c7d66ba420c13403.tar.gz
nuttx-14d0a961ecf430c882eae8d7c7d66ba420c13403.tar.bz2
nuttx-14d0a961ecf430c882eae8d7c7d66ba420c13403.zip
Drastic measures to work around missed interrupts -- must be a better way
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1860 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r--nuttx/ChangeLog7
-rw-r--r--nuttx/Documentation/NuttX.html21
-rw-r--r--nuttx/arch/arm/src/str71x/str71x_serial.c205
-rw-r--r--nuttx/sched/wd_cancel.c6
4 files changed, 189 insertions, 50 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index 66205c86b..65d20a20e 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -758,7 +758,10 @@
* arch/arm/src/str71x: Serial output is now correct and timer interrupts are
working. The test at configs/olimex-strp711/ostest passes. This means that
the basic STR-P711 port is complete.
- * configs/olimex-strp711/nsh: Add a NuttShell (NSH) configuration for the
- STR-P711.
+ * configs/olimex-strp711/nsh: Add and verifed a NuttShell (NSH) configuration
+ for the STR-P711.
+ * arch/arm/str71x/str71x_serial.c: The STR711 interrupt driven serial driver
+ finally works after some extradinary measures to handle missed interrupts.
+ NSH is fully functional on the Olimex STR-P711 board.
diff --git a/nuttx/Documentation/NuttX.html b/nuttx/Documentation/NuttX.html
index bd9aced78..13ff8a373 100644
--- a/nuttx/Documentation/NuttX.html
+++ b/nuttx/Documentation/NuttX.html
@@ -8,7 +8,7 @@
<tr align="center" bgcolor="#e4e4e4">
<td>
<h1><big><font color="#3c34ec"><i>NuttX RTOS</i></font></big></h1>
- <p>Last Updated: June 05, 2009</p>
+ <p>Last Updated: June 07, 2009</p>
</td>
</tr>
</table>
@@ -781,7 +781,8 @@
This port boots and passes the OS test (examples/ostest).
The port is complete and verified. As of NuttX 0.3.17, the port includes:
timer interrupts, serial console, USB driver, and SPI-based MMC/SD card
- support. A verified NuttShell (NSH) configuration is also available.
+ support. A verified NuttShell <a href="NuttShell.html">(NSH)</a>
+ configuration is also available.
</p>
</td>
</tr>
@@ -800,10 +801,11 @@
</p>
<p>
<b>STATUS:</b>
- Integration is complete on the basic port (boot logic, system time, serial console),
- The board boots and passes the OS test with console output visible on UART0.
- Additional drivers are needed: SPI, USB, to name two. It should not take too much
- more effort to get this port up and running.
+ Integration is complete on the basic port (boot logic, system time, serial console).
+ Two configurations have been verified: (1) The board boots and passes the OS test
+ with console output visible on UART0, and the NuttShell <a href="NuttShell.html">(NSH)</a>
+ is fully functional with interrupt driven serial console. An SPI driver is available
+ but untested. Additional features are needed: USB driver, MMC/SD support, to name two.
</p>
</td>
</tr>
@@ -1425,8 +1427,11 @@ nuttx-0.4.8 2009-xx-xx Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
* arch/arm/src/str71x: Serial output is now correct and timer interrupts are
working. The test at configs/olimex-strp711/ostest passes. This means that
the basic STR-P711 port is complete.
- * configs/olimex-strp711/nsh: Add a NuttShell (NSH) configuration for the
- STR-P711.
+ * configs/olimex-strp711/nsh: Add and verifed a NuttShell (NSH) configuration
+ for the STR-P711.
+ * arch/arm/str71x/str71x_serial.c: The STR711 interrupt driven serial driver
+ finally works after some extradinary measures to handle missed interrupts.
+ NSH is fully functional on the Olimex STR-P711 board.
pascal-0.1.3 2009-xx-xx Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
diff --git a/nuttx/arch/arm/src/str71x/str71x_serial.c b/nuttx/arch/arm/src/str71x/str71x_serial.c
index 58e2ebac2..74ccd3a27 100644
--- a/nuttx/arch/arm/src/str71x/str71x_serial.c
+++ b/nuttx/arch/arm/src/str71x/str71x_serial.c
@@ -42,7 +42,9 @@
#include <unistd.h>
#include <semaphore.h>
#include <string.h>
+#include <time.h>
#include <errno.h>
+#include <wdog.h>
#include <debug.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
@@ -195,6 +197,11 @@
# warning "No CONFIG_UARTn_SERIAL_CONSOLE Setting"
#endif
+/* I am problems with lost UART interrupts. Could this just be my hardware? */
+
+#define CONFIG_UART_LOSTTXINTPROTECTION 1
+#define LOSTINT_TIMEOUT (100/CLK_TCK)
+
/* Select RX interrupt enable bits. There are two models: (1) We interrupt
* when each character is received. Or, (2) we interrupt when either the Rx
* FIFO is half full, OR a timeout occurs with data in the RX FIFO. The
@@ -229,12 +236,34 @@ struct up_dev_s
ubyte parity; /* 0=none, 1=odd, 2=even */
ubyte bits; /* Number of bits (7 or 8) */
boolean stopbits2; /* TRUE: Configure with 2 stop bits instead of 1 */
+#ifdef CONFIG_UART_LOSTTXINTPROTECTION
+ boolean wdrunning; /* TRUE: The watchdog is running */
+ WDOG_ID wdog; /* Watchdog to catch missed UART interrupts */
+#endif
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
+/* Internal Helpers */
+
+static inline uint16 up_serialin(struct up_dev_s *priv, int offset);
+static inline void up_serialout(struct up_dev_s *priv, int offset, uint16 value);
+static inline void up_disableuartint(struct up_dev_s *priv, uint16 *ier);
+static inline void up_restoreuartint(struct up_dev_s *priv, uint16 ier);
+#ifdef HAVE_CONSOLE
+static inline void up_waittxnotfull(struct up_dev_s *priv);
+#endif
+#ifdef CONFIG_UART_LOSTTXINTPROTECTION
+static void up_lostint(int argc, uint32 arg1, ...);
+static int up_intinternal(struct uart_dev_s *dev);
+#else
+static inline int up_intinternal(struct uart_dev_s *dev);
+#endif
+
+/* Serial Driver Methods */
+
static int up_setup(struct uart_dev_s *dev);
static void up_shutdown(struct uart_dev_s *dev);
static int up_attach(struct uart_dev_s *dev);
@@ -266,7 +295,7 @@ struct uart_ops_s g_uart_ops =
.send = up_send,
.txint = up_txint,
.txready = up_txready,
- .txempty = up_txempty,
+ .txempty = up_txempty,
};
/* I/O buffers */
@@ -480,6 +509,35 @@ static inline void up_waittxnotfull(struct up_dev_s *priv)
#endif
/****************************************************************************
+ * Name: up_lostint
+ *
+ * Description:
+ * Check for lost interrupts
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_UART_LOSTTXINTPROTECTION
+static void up_lostint(int argc, uint32 arg1, ...)
+{
+ struct uart_dev_s *dev = (struct uart_dev_s*)arg1;
+ struct up_dev_s *priv;
+
+ /* Check if we missed any interrupt conditions */
+
+ DEBUGASSERT(argc == 1 && dev && dev->priv);
+ (void)up_intinternal(dev);
+
+ /* Re-start a watchdog to catch more missed interrupts */
+
+ priv = (struct up_dev_s*)dev->priv;
+ if (priv->wdrunning)
+ {
+ wd_start(priv->wdog, LOSTINT_TIMEOUT, up_lostint, 1, (void*)dev);
+ }
+}
+#endif
+
+/****************************************************************************
* Name: up_setup
*
* Description:
@@ -559,6 +617,11 @@ static int up_setup(struct uart_dev_s *dev)
/* Set up the IER */
priv->ier = up_serialin(priv, STR71X_UART_IER_OFFSET);
+
+ /* Set up a watchdog to catch missed UART interrupts */
+#ifdef CONFIG_UART_LOSTTXINTPROTECTION
+ priv->wdog = wd_create();
+#endif
#endif
return OK;
}
@@ -576,6 +639,9 @@ static void up_shutdown(struct uart_dev_s *dev)
{
struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
up_disableuartint(priv, NULL);
+#ifdef CONFIG_UART_LOSTTXINTPROTECTION
+ wd_delete(priv->wdog);
+#endif
}
/****************************************************************************
@@ -646,45 +712,18 @@ static void up_detach(struct uart_dev_s *dev)
*
****************************************************************************/
-static int up_interrupt(int irq, void *context)
+#ifdef CONFIG_UART_LOSTTXINTPROTECTION
+static int up_intinternal(struct uart_dev_s *dev)
+#else
+static inline int up_intinternal(struct uart_dev_s *dev)
+#endif
{
- struct uart_dev_s *dev = NULL;
- struct up_dev_s *priv;
- int passes;
- boolean handled;
+ struct up_dev_s *priv;
+ int passes;
+ boolean handled;
-#ifdef CONFIG_STR71X_UART0
- if (g_uart0priv.irq == irq)
- {
- dev = &g_uart0port;
- }
- else
-#endif
-#ifdef CONFIG_STR71X_UART1
- if (g_uart1priv.irq == irq)
- {
- dev = &g_uart1port;
- }
- else
-#endif
-#ifdef CONFIG_STR71X_UART2
- if (g_uart2priv.irq == irq)
- {
- dev = &g_uart2port;
- }
- else
-#endif
-#ifdef CONFIG_STR71X_UART3
- if (g_uart3priv.irq == irq)
- {
- dev = &g_uart3port;
- }
- else
-#endif
- {
- PANIC(OSERR_INTERNAL);
- }
priv = (struct up_dev_s*)dev->priv;
+ DEBUGASSERT(priv && dev);
/* Loop until there are no characters to be transferred or,
* until we have been looping for a long time.
@@ -724,6 +763,44 @@ static int up_interrupt(int irq, void *context)
return OK;
}
+static int up_interrupt(int irq, void *context)
+{
+ struct uart_dev_s *dev = NULL;
+
+#ifdef CONFIG_STR71X_UART0
+ if (g_uart0priv.irq == irq)
+ {
+ dev = &g_uart0port;
+ }
+ else
+#endif
+#ifdef CONFIG_STR71X_UART1
+ if (g_uart1priv.irq == irq)
+ {
+ dev = &g_uart1port;
+ }
+ else
+#endif
+#ifdef CONFIG_STR71X_UART2
+ if (g_uart2priv.irq == irq)
+ {
+ dev = &g_uart2port;
+ }
+ else
+#endif
+#ifdef CONFIG_STR71X_UART3
+ if (g_uart3priv.irq == irq)
+ {
+ dev = &g_uart3port;
+ }
+ else
+#endif
+ {
+ PANIC(OSERR_INTERNAL);
+ }
+ return up_intinternal(dev);
+}
+
/****************************************************************************
* Name: up_ioctl
*
@@ -848,19 +925,73 @@ static void up_send(struct uart_dev_s *dev, int ch)
static void up_txint(struct uart_dev_s *dev, boolean enable)
{
+#ifdef CONFIG_UART_LOSTTXINTPROTECTION
struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
+ irqstate_t flags;
+
+ flags = irqsave();
if (enable)
{
/* Set to receive an interrupt when the TX fifo is half emptied */
+
#ifndef CONFIG_SUPPRESS_SERIAL_INTS
priv->ier |= STR71X_UARTSR_THE;
+ up_serialout(priv, STR71X_UART_IER_OFFSET, priv->ier);
+
+
+ /* Start a watchdog to catch missed UART Tx interrupts (Need to do
+ * this before calling uart_xmitchars() because that function
+ * could recurse and disable Tx interrupts before returning.
+ */
+
+ wd_start(priv->wdog, LOSTINT_TIMEOUT, up_lostint, 1, (void*)dev);
+ priv->wdrunning = TRUE;
+
+ /* The serial driver wants an interrupt here, but will not get get
+ * one unless we "prime the pump."
+ */
+
+ uart_xmitchars(dev);
#endif
}
else
{
+ /* Stop the watchdog if it is running */
+
+ if (priv->wdrunning)
+ {
+ wd_cancel(priv->wdog);
+ priv->wdrunning = FALSE;
+ }
+
+ /* Disable the TX interrupt */
+
+ priv->ier &= ~STR71X_UARTSR_THE;
+ up_serialout(priv, STR71X_UART_IER_OFFSET, priv->ier);
+
+ }
+ irqrestore(flags);
+
+#else /* CONFIG_UART_LOSTTXINTPROTECTION */
+
+ struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
+ if (enable)
+ {
+ /* Set to receive an interrupt when the TX fifo is half emptied */
+
+#ifndef CONFIG_SUPPRESS_SERIAL_INTS
+ priv->ier |= STR71X_UARTSR_THE;
+#endif
+ }
+ else
+ {
+ /* Disable the TX interrupt */
+
priv->ier &= ~STR71X_UARTSR_THE;
}
up_serialout(priv, STR71X_UART_IER_OFFSET, priv->ier);
+
+#endif /* CONFIG_UART_LOSTTXINTPROTECTION */
}
/****************************************************************************
diff --git a/nuttx/sched/wd_cancel.c b/nuttx/sched/wd_cancel.c
index 0a22edd5d..9bdeafcf8 100644
--- a/nuttx/sched/wd_cancel.c
+++ b/nuttx/sched/wd_cancel.c
@@ -1,7 +1,7 @@
/****************************************************************************
* wd_cancel.c
*
- * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* Redistribution and use in source and binary forms, with or without
@@ -98,9 +98,9 @@ STATUS wd_cancel (WDOG_ID wdid)
saved_state = irqsave();
- /* Make sure that the the watchdog is still active */
+ /* Make sure that the watchdog is initialed (non-NULL) and is still active */
- if (wdid->active)
+ if (wdid && wdid->active)
{
/* Search the g_wdactivelist for the target FCB. We can't use sq_rem
* to do this because there are additional operations that need to be