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
This commit is contained in:
parent
2b29f8dfc8
commit
eba07de989
@ -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.
|
||||
|
||||
|
||||
|
@ -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 <spudmonkey@racsa.co.cr>
|
||||
* 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 <spudmonkey@racsa.co.cr>
|
||||
|
||||
|
@ -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 */
|
||||
@ -479,6 +508,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
|
||||
*
|
||||
@ -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 */
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user