drivers/ft5x06.c: Add additional configuration options: Optimize if multi-touch capability is not used. Add options to swap X/Y and thresholding to reduce the rate of false alarm reports (with no motion).

This commit is contained in:
Gregory Nutt 2017-12-18 10:31:49 -06:00
parent a0004173d4
commit 4a5e18a6db
4 changed files with 183 additions and 12 deletions

View File

@ -67,10 +67,7 @@ STATUS
2017-12-18: Added an option to the FT5x06 driver to support a timer- 2017-12-18: Added an option to the FT5x06 driver to support a timer-
based poll instead of interrupts. This is very inefficient in that it based poll instead of interrupts. This is very inefficient in that it
will introduce delays in touchscreen response and will consume more CPU will introduce delays in touchscreen response and will consume more CPU
bandwidth. bandwidth. The driver appears to be functional.
The FT5x06 driver is not, however, functional. It is generating hard
faults.
Configurations Configurations
============== ==============
@ -178,8 +175,23 @@ Configurations
Touch panel I2C address: 0x38 Touch panel I2C address: 0x38
4. The touchscreen test program at apps/examples/touchscreen is also 4. The touchscreen test program at apps/examples/touchscreen is also
included in this configuration. As of this writing, touchscreen included in this configuration.
is not yet functional, however.
nsh> tc 5
tc_main: nsamples: 2
tc_main: Initializing external touchscreen device
tc_main: Opening /dev/input0
Sample :
npoints : 1
Point 1 :
id : 0
flags : 1a
x : 230
y : 84
h : 0
w : 0
pressure : 0
etc.
nsh: nsh:

View File

@ -18,6 +18,7 @@ CONFIG_FAT_LFN=y
CONFIG_FS_FAT=y CONFIG_FS_FAT=y
CONFIG_FS_PROCFS=y CONFIG_FS_PROCFS=y
CONFIG_FT5X06_POLLMODE=y CONFIG_FT5X06_POLLMODE=y
CONFIG_FT5X06_SINGLEPOINT=y
CONFIG_GRAPHICS_PDCURSES=y CONFIG_GRAPHICS_PDCURSES=y
CONFIG_I2CTOOL_MAXBUS=9 CONFIG_I2CTOOL_MAXBUS=9
CONFIG_INPUT_FT5X06=y CONFIG_INPUT_FT5X06=y

View File

@ -78,7 +78,7 @@ config INPUT_FT5336
if INPUT_FT5X06 if INPUT_FT5X06
config FT5X06_POLLMODE config FT5X06_POLLMODE
bool " FT5336/FT5x06 polled mode" bool "Polled mode"
default n default n
---help--- ---help---
Run the FT5x06 in a non-interrupt driven polled mode. Events will Run the FT5x06 in a non-interrupt driven polled mode. Events will
@ -88,6 +88,40 @@ config FT5X06_POLLMODE
in detecting touch related events and (2) it will consume a in detecting touch related events and (2) it will consume a
significant amount of CPU time to perform the polling. significant amount of CPU time to perform the polling.
config FT5X06_SWAPXY
bool "Swap X/Y"
default n
---help---
Reverse the meaning of X and Y to handle different LCD orientations.
config FT5X06_SINGLEPOINT
bool "Single point"
default n
---help---
Do no report multi-touch events
if FT5X06_SINGLEPOINT
config FT5X06_THRESHX
int "X threshold"
default 12
---help---
New touch positions will only be reported when the X or Y data changes by these
thresholds. This trades reduced data rates for some loss in dragging accuracy. For
12-bit values the raw ranges are 0-4095. So for example, if your display is
320x240, then THRESHX=13 and THRESHY=17 would correspond to one pixel. Default: 12
config FT5X06_THRESHY
int "Y threshold"
default 12
---help---
New touch positions will only be reported when the X or Y data changes by these
thresholds. This trades reduced data rates for some loss in dragging accuracy. For
12-bit values the raw ranges are 0-4095. So for example, if your display is
320x240, then THRESHX=13 and THRESHY=17 would correspond to one pixel. Default: 12
endif # FT5X06_SINGLEPOINT
config FT5X06_NPOLLWAITERS config FT5X06_NPOLLWAITERS
int "Number FT5336/FT5x06 poll waiters" int "Number FT5336/FT5x06 poll waiters"
default 4 default 4

View File

@ -120,6 +120,12 @@ struct ft5x06_dev_s
* FT5x06 data */ * FT5x06 data */
volatile bool valid; /* True: New, valid touch data in volatile bool valid; /* True: New, valid touch data in
* touchbuf[] */ * touchbuf[] */
#ifdef CONFIG_FT5X06_SINGLEPOINT
uint8_t lastid; /* Last reported touch id */
uint8_t lastevent; /* Last reported event */
int16_t lastx; /* Last reported X position */
int16_t lasty; /* Last reported Y position */
#endif
sem_t devsem; /* Manages exclusive access to this sem_t devsem; /* Manages exclusive access to this
* structure */ * structure */
sem_t waitsem; /* Used to wait for the sem_t waitsem; /* Used to wait for the
@ -299,7 +305,12 @@ static void ft5x06_data_worker(FAR void *arg)
msg[0].buffer = &regaddr; /* Send one byte of data (no STOP) */ msg[0].buffer = &regaddr; /* Send one byte of data (no STOP) */
msg[0].length = 1; msg[0].length = 1;
/* Set up the data read operation */ /* Set up the data read operation.
*
* REVISIT: If CONFIG_FT5X06_SINGLEPOINT is selected, we we not just
* set the length for one sample? Or is there some reason why we have to
* read all of the points?
*/
msg[1].frequency = priv->frequency; /* I2C frequency */ msg[1].frequency = priv->frequency; /* I2C frequency */
msg[1].addr = config->address; /* 7-bit address */ msg[1].addr = config->address; /* 7-bit address */
@ -427,6 +438,113 @@ static int ft5x06_data_interrupt(int irq, FAR void *context, FAR void *arg)
* Name: ft5x06_sample * Name: ft5x06_sample
****************************************************************************/ ****************************************************************************/
#ifdef CONFIG_FT5X06_SINGLEPOINT
static ssize_t ft5x06_sample(FAR struct ft5x06_dev_s *priv, FAR char *buffer,
size_t len)
{
FAR struct ft5x06_touch_data_s *raw;
FAR struct ft5x06_touch_point_s *touch;
FAR struct touch_sample_s *sample;
FAR struct touch_point_s *point;
int16_t x;
int16_t y;
uint8_t event;
uint8_t id;
if (!priv->valid)
{
return 0; /* Nothing to read */
}
/* Raw data pointers (source) */
raw = (FAR struct ft5x06_touch_data_s *)priv->touchbuf;
if (raw->tdstatus != 1)
{
priv->valid = false;
return 0; /* No touches read. */
}
/* Get the reported X and Y positions */
touch = raw->touch;
#ifdef CONFIG_FT5X06_SWAPXY
y = TOUCH_POINT_GET_X(touch[0]);
x = TOUCH_POINT_GET_Y(touch[0]);
#else
x = TOUCH_POINT_GET_X(touch[0]);
y = TOUCH_POINT_GET_Y(touch[0]);
#endif
/* Get the touch point ID and event */
event = TOUCH_POINT_GET_EVENT(touch[0]);
id = TOUCH_POINT_GET_ID(touch[0]);
if (id == priv->lastid && event == priv->lastevent)
{
int16_t deltax;
int16_t deltay;
/* Same ID and event.. Compare the change in position from the last
* report.
*/
deltax = (x - priv->lastx);
if (deltax < 0)
{
deltax = -deltax;
}
if (deltax < CONFIG_FT5X06_THRESHX)
{
/* There as been no significant change in X, try Y */
deltay = (y - priv->lasty);
if (deltay < 0)
{
deltay = -deltay;
}
if (deltax < CONFIG_FT5X06_THRESHX)
{
/* Ignore... no significant change in Y either */
priv->valid = false;
return 0; /* No new touches read. */
}
}
}
priv->lastid = id;
priv->lastevent = event;
priv->lastx = x;
priv->lasty = y;
/* User data buffer points (sink) */
/* Return the number of touches read */
sample = (FAR struct touch_sample_s *)buffer;
sample->npoints = 1;
/* Decode and return the single touch point */
point = sample->point;
point[0].id = id;
point[0].flags = g_event_map[event];
point[0].x = x;
point[0].y = y;
point[0].h = 0;
point[0].w = 0;
point[0].pressure = 0;
priv->valid = false;
return SIZEOF_TOUCH_SAMPLE_S(1);
}
#else
static ssize_t ft5x06_sample(FAR struct ft5x06_dev_s *priv, FAR char *buffer, static ssize_t ft5x06_sample(FAR struct ft5x06_dev_s *priv, FAR char *buffer,
size_t len) size_t len)
{ {
@ -434,8 +552,8 @@ static ssize_t ft5x06_sample(FAR struct ft5x06_dev_s *priv, FAR char *buffer,
FAR struct ft5x06_touch_point_s *touch; FAR struct ft5x06_touch_point_s *touch;
FAR struct touch_sample_s *sample; FAR struct touch_sample_s *sample;
FAR struct touch_point_s *point; FAR struct touch_point_s *point;
unsigned int ntouches;
unsigned int maxtouches; unsigned int maxtouches;
unsigned int ntouches;
int i; int i;
maxtouches = (len - sizeof(int)) / sizeof(struct touch_point_s); maxtouches = (len - sizeof(int)) / sizeof(struct touch_point_s);
@ -454,6 +572,8 @@ static ssize_t ft5x06_sample(FAR struct ft5x06_dev_s *priv, FAR char *buffer,
/* Decode number of touches */ /* Decode number of touches */
ntouches = raw->tdstatus; ntouches = raw->tdstatus;
DEBUGASSERT(ntouches <= FT5x06_MAX_TOUCHES);
if (ntouches > maxtouches) if (ntouches > maxtouches)
{ {
ntouches = maxtouches; ntouches = maxtouches;
@ -465,8 +585,6 @@ static ssize_t ft5x06_sample(FAR struct ft5x06_dev_s *priv, FAR char *buffer,
return 0; /* No touches read. */ return 0; /* No touches read. */
} }
DEBUGASSERT(ntouches <= FT5x06_MAX_TOUCHES);
/* User data buffer points (sink) */ /* User data buffer points (sink) */
sample = (FAR struct touch_sample_s *)buffer; sample = (FAR struct touch_sample_s *)buffer;
@ -478,14 +596,19 @@ static ssize_t ft5x06_sample(FAR struct ft5x06_dev_s *priv, FAR char *buffer,
/* Decode and return the touch points */ /* Decode and return the touch points */
for (i = 0; i < raw->tdstatus; i++) for (i = 0; i < ntouches; i++)
{ {
int event = TOUCH_POINT_GET_EVENT(touch[i]); int event = TOUCH_POINT_GET_EVENT(touch[i]);
point[i].id = TOUCH_POINT_GET_ID(touch[i]); point[i].id = TOUCH_POINT_GET_ID(touch[i]);
point[i].flags = g_event_map[event]; point[i].flags = g_event_map[event];
#ifdef CONFIG_FT5X06_SWAPXY
point[i].y = TOUCH_POINT_GET_X(touch[i]);
point[i].x = TOUCH_POINT_GET_Y(touch[i]);
#else
point[i].x = TOUCH_POINT_GET_X(touch[i]); point[i].x = TOUCH_POINT_GET_X(touch[i]);
point[i].y = TOUCH_POINT_GET_Y(touch[i]); point[i].y = TOUCH_POINT_GET_Y(touch[i]);
#endif
point[i].h = 0; point[i].h = 0;
point[i].w = 0; point[i].w = 0;
point[i].pressure = 0; point[i].pressure = 0;
@ -494,6 +617,7 @@ static ssize_t ft5x06_sample(FAR struct ft5x06_dev_s *priv, FAR char *buffer,
priv->valid = false; priv->valid = false;
return SIZEOF_TOUCH_SAMPLE_S(ntouches); return SIZEOF_TOUCH_SAMPLE_S(ntouches);
} }
#endif /* CONFIG_FT5X06_SINGLEPOINT */
/**************************************************************************** /****************************************************************************
* Name: ft5x06_waitsample * Name: ft5x06_waitsample