diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2009-06-07 15:48:01 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2009-06-07 15:48:01 +0000 |
commit | 14d0a961ecf430c882eae8d7c7d66ba420c13403 (patch) | |
tree | 47435a2e441745acfa63f5262cd85fb5b8c3f7c4 /nuttx | |
parent | 99a001eab90e0b2058b969545396018239f1ee2b (diff) | |
download | px4-nuttx-14d0a961ecf430c882eae8d7c7d66ba420c13403.tar.gz px4-nuttx-14d0a961ecf430c882eae8d7c7d66ba420c13403.tar.bz2 px4-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
Diffstat (limited to 'nuttx')
-rw-r--r-- | nuttx/ChangeLog | 7 | ||||
-rw-r--r-- | nuttx/Documentation/NuttX.html | 21 | ||||
-rw-r--r-- | nuttx/arch/arm/src/str71x/str71x_serial.c | 205 | ||||
-rw-r--r-- | nuttx/sched/wd_cancel.c | 6 |
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 <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> 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 |