diff --git a/ChangeLog b/ChangeLog index 71534b470d..3705363b24 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2796,5 +2796,7 @@ keyboard data in multi-user mode. * graphics/nxconsole/nxcon_kdbind.c: Fixed unmatched sem_wait and sem_post. Fix some conditional compilation that included a few too many lines of code. + * drivers/input/stmpe11_tsc.c and stmpe11.h: Add a timeout to catch missed + pen up events. Now the STM3240G-EVAL touchscreen works very smoothly. diff --git a/TODO b/TODO index 33f29d2dc7..b756914208 100644 --- a/TODO +++ b/TODO @@ -17,7 +17,7 @@ nuttx/ (3) USB (drivers/usbdev, drivers/usbhost) (8) Libraries (lib/) (10) File system/Generic drivers (fs/, drivers/) - (4) Graphics subystem (graphics/) + (5) Graphics subystem (graphics/) (1) Pascal add-on (pcode/) (1) Documentation (Documentation/) (7) Build system / Toolchains @@ -757,6 +757,8 @@ o File system / Generic drivers (fs/, drivers/) o Graphics subystem (graphics/) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + See also the NxWidgets TODO list file for related issues. + Title: UNTESTED GRAPHICS APIS Description: Testing of all APIs is not complete. See http://nuttx.sourceforge.net/NXGraphicsSubsystem.html#testcoverage @@ -781,7 +783,7 @@ o Graphics subystem (graphics/) Priority: Low Title: AUTO-RAISE DISABLED - Descption: Auto-raise is currently disabled in NX multi-server mode. The + Description: Auto-raise is currently disabled in NX multi-server mode. The reason is complex: - Most touchscreen controls send touch data a high rates - In multi-server mode, touch events get queued in a message @@ -795,6 +797,18 @@ o Graphics subystem (graphics/) Status: Open Priority: Medium low + Title: IMPROVED NXCONSOLE FONT CACHING + Description: Now each NxConsole instance has its own private font cache + whose size is determined by CONFIG_NXCONSOLE_MXCHARS. If there + are multiple NxConsole instances using the same font, each will + have a separate font cache. This is inefficient and wasteful + of memory: Each NxConsole instance should share a common font + cache. + Status: Open + Priority: Medium. Not important for day-to-day testing but would be + a critical improvement if NxConsole were to be used in a + product. + o Pascal Add-On (pcode/) ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/drivers/input/stmpe11.h b/drivers/input/stmpe11.h index b637ec6441..05917fc37a 100644 --- a/drivers/input/stmpe11.h +++ b/drivers/input/stmpe11.h @@ -46,8 +46,10 @@ #include +#include #include +#include #include #include @@ -92,6 +94,10 @@ #define STMPE11_FLAGS_ADC_INITIALIZED (1 << 2) /* 1: The ADC block has been initialized */ #define STMPE11_FLAGS_TS_INITIALIZED (1 << 3) /* 1: The TS block has been initialized */ +/* Timeout to detect missing pen up events */ + +#define STMPE11_PENUP_TICKS ((100 + (MSEC_PER_TICK-1)) / MSEC_PER_TICK) + /******************************************************************************************** * Public Types ********************************************************************************************/ @@ -137,6 +143,7 @@ struct stmpe11_dev_s uint8_t inuse; /* SMTPE11 pins in use */ uint8_t flags; /* See SMTPE11_FLAGS_* definitions */ + struct work_s work; /* Supports the interrupt handling "bottom half" */ /* Fields that may be disabled to save size if touchscreen support is not used. */ @@ -153,7 +160,8 @@ struct stmpe11_dev_s uint16_t threshy; /* Thresholded Y value */ sem_t waitsem; /* Used to wait for the availability of data */ - struct work_s work; /* Supports the interrupt handling "bottom half" */ + struct work_s timeout; /* Supports tiemeout work */ + WDOG_ID wdog; /* Timeout to detect missing pen down events */ struct stmpe11_sample_s sample; /* Last sampled touch point data */ /* The following is a list if poll structures of threads waiting for diff --git a/drivers/input/stmpe11_base.c b/drivers/input/stmpe11_base.c index 546f1d9016..8e29006103 100644 --- a/drivers/input/stmpe11_base.c +++ b/drivers/input/stmpe11_base.c @@ -183,16 +183,23 @@ static int stmpe11_interrupt(int irq, FAR void *context) config->enable(config, false); - /* Transfer processing to the worker thread. Since STMPE11 interrupts are - * disabled while the work is pending, no special action should be required - * to protected the work queue. + /* Check if interrupt work is already queue. If it is already busy, then + * we already have interrupt processing in the pipeline and we need to do + * nothing more. */ - DEBUGASSERT(work_available(&priv->work)); - ret = work_queue(&priv->work, stmpe11_worker, priv, 0); - if (ret != 0) + if (work_available(&priv->work)) { - illdbg("Failed to queue work: %d\n", ret); + /* Yes.. Transfer processing to the worker thread. Since STMPE11 + * interrupts are disabled while the work is pending, no special + * action should be required to protect the work queue. + */ + + ret = work_queue(&priv->work, stmpe11_worker, priv, 0); + if (ret != 0) + { + illdbg("Failed to queue work: %d\n", ret); + } } /* Clear any pending interrupts and return success */ diff --git a/drivers/input/stmpe11_tsc.c b/drivers/input/stmpe11_tsc.c index ca6d92ce03..03ede7302c 100644 --- a/drivers/input/stmpe11_tsc.c +++ b/drivers/input/stmpe11_tsc.c @@ -315,7 +315,7 @@ static inline int stmpe11_waitsample(FAR struct stmpe11_dev_s *priv, * the failure now. */ - idbg("sem_wait failed: %d\n", errval); + idbg("ERROR: sem_wait failed: %d\n", errval); DEBUGASSERT(errval == EINTR); #endif ret = -EINTR; @@ -677,7 +677,7 @@ static int stmpe11_poll(FAR struct file *filep, FAR struct pollfd *fds, if ((fds->events & POLLIN) == 0) { - idbg("Missing POLLIN: revents: %08x\n", fds->revents); + idbg("ERROR: Missing POLLIN: revents: %08x\n", fds->revents); ret = -EDEADLK; goto errout; } @@ -702,7 +702,7 @@ static int stmpe11_poll(FAR struct file *filep, FAR struct pollfd *fds, if (i >= CONFIG_STMPE11_NPOLLWAITERS) { - idbg("No availabled slot found: %d\n", i); + idbg("ERROR: No availabled slot found: %d\n", i); fds->priv = NULL; ret = -EBUSY; goto errout; @@ -734,6 +734,64 @@ errout: } #endif +/**************************************************************************** + * Name: stmpe11_timeoutworker + * + * Description: + * A timer has expired without receiving a pen up event. Check again. + * + ****************************************************************************/ + +static void stmpe11_timeoutworker(FAR void *arg) +{ + FAR struct stmpe11_dev_s *priv = (FAR struct stmpe11_dev_s *)arg; + + DEBUGASSERT(priv); + + /* Treat the timeout just like an interrupt occurred */ + + stmpe11_tscworker(priv, stmpe11_getreg8(priv, STMPE11_INT_STA)); +} + +/**************************************************************************** + * Name: stmpe11_timeout + * + * Description: + * A timer has expired without receiving a pen up event. Schedule work + * to check again. + * + ****************************************************************************/ + +static void stmpe11_timeout(int argc, uint32_t arg1, ...) +{ + FAR struct stmpe11_dev_s *priv = (FAR struct stmpe11_dev_s *)((uintptr_t)arg1); + int ret; + + /* Are we still stuck in the pen down state? */ + + if (priv->sample.contact == CONTACT_MOVE || + priv->sample.contact == CONTACT_MOVE) + { + /* Yes... is the worker thread available? If not, then apparently + * we have work already pending? + */ + + if (work_available(&priv->timeout)) + { + /* Yes.. Transfer processing to the worker thread. Since STMPE11 + * interrupts are disabled while the work is pending, no special + * action should be required to protect the work queue. + */ + + ret = work_queue(&priv->timeout, stmpe11_timeoutworker, priv, 0); + if (ret != 0) + { + illdbg("Failed to queue work: %d\n", ret); + } + } + } +} + /**************************************************************************** * Name: stmpe11_tscinitialize * @@ -849,7 +907,7 @@ int stmpe11_register(STMPE11_HANDLE handle, int minor) if (ret < 0) { int errval = errno; - idbg("sem_wait failed: %d\n", errval); + idbg("ERROR: sem_wait failed: %d\n", errval); return -errval; } @@ -857,25 +915,35 @@ int stmpe11_register(STMPE11_HANDLE handle, int minor) if ((priv->inuse & TSC_PIN_SET) != 0) { - idbg("TSC pins is already in-use: %02x\n", priv->inuse); + idbg("ERROR: TSC pins is already in-use: %02x\n", priv->inuse); sem_post(&priv->exclsem); return -EBUSY; } - /* Initialize the TS structure to their default values */ + /* Initialize the TS structure fields to their default values */ priv->minor = minor; priv->penchange = false; priv->threshx = 0; priv->threshy = 0; + /* Create a timer for catching missed pen up conditions */ + + priv->wdog = wd_create(); + if (!priv->wdog) + { + idbg("ERROR: Failed to create a watchdog\n", errno); + sem_post(&priv->exclsem); + return -ENOSPC; + } + /* Register the character driver */ snprintf(devname, DEV_NAMELEN, DEV_FORMAT, minor); ret = register_driver(devname, &g_stmpe11fops, 0666, priv); if (ret < 0) { - idbg("Failed to register driver %s: %d\n", devname, ret); + idbg("ERROR: Failed to register driver %s: %d\n", devname, ret); sem_post(&priv->exclsem); return ret; } @@ -913,6 +981,10 @@ void stmpe11_tscworker(FAR struct stmpe11_dev_s *priv, uint8_t intsta) ASSERT(priv != NULL); + /* Cancel the missing pen up timer */ + + (void)wd_cancel(priv->wdog); + /* Get a pointer the callbacks for convenience (and so the code is not so * ugly). */ @@ -1050,9 +1122,20 @@ void stmpe11_tscworker(FAR struct stmpe11_dev_s *priv, uint8_t intsta) stmpe11_notify(priv); - /* Reset and clear all data in the FIFO */ + /* If we think that the pend is still down, the start/re-start the pen up + * timer. + */ ignored: + if (priv->sample.contact == CONTACT_MOVE || + priv->sample.contact == CONTACT_MOVE) + { + (void)wd_start(priv->wdog, STMPE11_PENUP_TICKS, stmpe11_timeout, + 1, (uint32_t)((uintptr_t)priv)); + } + + /* Reset and clear all data in the FIFO */ + stmpe11_putreg8(priv, STMPE11_FIFO_STA, FIFO_STA_FIFO_RESET); stmpe11_putreg8(priv, STMPE11_FIFO_STA, 0); }