aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ginput
diff options
context:
space:
mode:
authorinmarket <andrewh@inmarket.com.au>2014-11-07 12:05:23 +1000
committerinmarket <andrewh@inmarket.com.au>2014-11-07 12:05:23 +1000
commit2a1c7785ccd0cb0b4675c06c2c48e270e7d926e4 (patch)
treedb076068f876343bcc409fb7df26ec526bb3e88f /drivers/ginput
parentd0f8c12a2d79d6328269a7931fdf673bd23f4dc7 (diff)
downloaduGFX-2a1c7785ccd0cb0b4675c06c2c48e270e7d926e4.tar.gz
uGFX-2a1c7785ccd0cb0b4675c06c2c48e270e7d926e4.tar.bz2
uGFX-2a1c7785ccd0cb0b4675c06c2c48e270e7d926e4.zip
Fix the newmouse STMPE811 driver.
Finalise the STM32F429i-Discovery board file for that touch controller
Diffstat (limited to 'drivers/ginput')
-rw-r--r--drivers/ginput/touch/STMPE811/gmouse_lld_STMPE811.c231
-rw-r--r--drivers/ginput/touch/STMPE811/gmouse_lld_STMPE811_board_template.h12
-rw-r--r--drivers/ginput/touch/STMPE811/readme.txt11
-rw-r--r--drivers/ginput/touch/STMPE811/stmpe811.h3
4 files changed, 178 insertions, 79 deletions
diff --git a/drivers/ginput/touch/STMPE811/gmouse_lld_STMPE811.c b/drivers/ginput/touch/STMPE811/gmouse_lld_STMPE811.c
index 71c3c5d7..27bc280e 100644
--- a/drivers/ginput/touch/STMPE811/gmouse_lld_STMPE811.c
+++ b/drivers/ginput/touch/STMPE811/gmouse_lld_STMPE811.c
@@ -12,14 +12,51 @@
#define GMOUSE_DRIVER_VMT GMOUSEVMT_STMPE811
#include "src/ginput/driver_mouse.h"
-#define GMOUSE_STMPE811_FLG_TOUCHED (GMOUSE_FLG_DRIVER_FIRST<<0)
-
// Hardware definitions
#include "drivers/ginput/touch/STMPE811/stmpe811.h"
// Get the hardware interface
#include "gmouse_lld_STMPE811_board.h"
+// Extra settings for the users gfxconf.h file. See readme.txt
+#ifndef GMOUSE_STMPE811_SELF_CALIBRATE
+ #define GMOUSE_STMPE811_SELF_CALIBRATE FALSE
+#endif
+#ifndef GMOUSE_STMPE811_READ_PRESSURE
+ #define GMOUSE_STMPE811_READ_PRESSURE FALSE
+#endif
+#ifndef GMOUSE_STMPE811_TEST_MODE
+ #define GMOUSE_STMPE811_TEST_MODE FALSE
+#endif
+
+/**
+ * Notes:
+ *
+ * This chip has some problems which required careful coding to overcome.
+ *
+ * The interrupt pin seems to be unreliable, at least on some boards, so we at most
+ * use the pin for filtering results to reduce cpu load.
+ * The symptoms are that readings will just stop due to the irq not being asserted
+ * even though there are items in the fifo. Another interrupt source such as a
+ * touch transition will restart the irq.
+ *
+ * There is no fifo entry created when a touch up event occurs. We must therefore
+ * generate a pseudo result on touch up. Fortunately the touch detection appears
+ * reliable and so we turn off the driver GMOUSE_VFLG_POORUPDOWN setting. In practice
+ * if touch is up we always return a pseudo event as this saves having to remember the
+ * previous touch state.
+ *
+ * Z readings range from around 90 (fully touched) to around 150 (on the verge of non-touched).
+ * Note the above is on the STM32F429i-Discovery board. Other boards may be different.
+ * To be conservative we use 255 as touch off, anything else is a touch on.
+ *
+ * GMOUSE_STMPE811_TEST_MODE is designed to be used with the "touch_raw_readings" tool which shows
+ * a steady stream of raw readings.
+ *
+ * Settings that may need tweaking on other hardware:
+ * The settling times. We have set these conservatively at 1ms.
+ * The reading window. We set this to 16 just to reduce noise. High-res panels may need a lower value.
+ */
static bool_t MouseInit(GMouse* m, unsigned driverinstance) {
if (!init_board(m, driverinstance))
return FALSE;
@@ -32,120 +69,172 @@ static bool_t MouseInit(GMouse* m, unsigned driverinstance) {
write_reg(m, STMPE811_REG_SYS_CTRL2, 0x0C); // Temperature sensor clock off, GPIO clock off, touch clock on, ADC clock on
#if GMOUSE_STMPE811_GPIO_IRQPIN
- write_reg(m, STMPE811_REG_INT_EN, 0x01); // Interrupt on INT pin when touch is detected
+ write_reg(m, STMPE811_REG_INT_EN, 0x03); // Interrupt on INT pin when there is a sample or a touch transition.
#else
- write_reg(m, STMPE811_REG_INT_EN, 0x00); // Don't Interrupt on INT pin when touch is detected
+ write_reg(m, STMPE811_REG_INT_EN, 0x00); // Don't Interrupt on INT pin
#endif
write_reg(m, STMPE811_REG_ADC_CTRL1, 0x48); // ADC conversion time = 80 clock ticks, 12-bit ADC, internal voltage refernce
gfxSleepMilliseconds(2);
-
write_reg(m, STMPE811_REG_ADC_CTRL2, 0x01); // ADC speed 3.25MHz
write_reg(m, STMPE811_REG_GPIO_AF, 0x00); // GPIO alternate function - OFF
- write_reg(m, STMPE811_REG_TSC_CFG, 0x9A); // Averaging 4, touch detect delay 500 us, panel driver settling time 500 us
- write_reg(m, STMPE811_REG_FIFO_TH, 0x40); // FIFO threshold = 64
+ write_reg(m, STMPE811_REG_TSC_CFG, 0xA3); // Averaging 4, touch detect delay 1ms, panel driver settling time 1ms
+ write_reg(m, STMPE811_REG_FIFO_TH, 0x01); // FIFO threshold = 1
write_reg(m, STMPE811_REG_FIFO_STA, 0x01); // FIFO reset enable
write_reg(m, STMPE811_REG_FIFO_STA, 0x00); // FIFO reset disable
write_reg(m, STMPE811_REG_TSC_FRACT_XYZ, 0x07); // Z axis data format
- write_reg(m, STMPE811_REG_TSC_I_DRIVE, 0x01); // 50mA touchscreen line current
- write_reg(m, STMPE811_REG_TSC_CTRL, 0x00); // X&Y&Z
- write_reg(m, STMPE811_REG_TSC_CTRL, 0x01); // X&Y&Z, TSC enable
- write_reg(m, STMPE811_REG_INT_STA, 0xFF); // Clear all interrupts
- #if GMOUSE_STMPE811_GPIO_IRQPIN
- if (read_byte(m, STMPE811_REG_TSC_CTRL) & 0x80)
- m->flags |= GMOUSE_STMPE811_FLG_TOUCHED;
+ write_reg(m, STMPE811_REG_TSC_I_DRIVE, 0x01); // max 50mA touchscreen line current
+ #if GMOUSE_STMPE811_READ_PRESSURE
+ write_reg(m, STMPE811_REG_TSC_CTRL, 0x30); // X&Y&Z, 16 reading window
+ write_reg(m, STMPE811_REG_TSC_CTRL, 0x31); // X&Y&Z, 16 reading window, TSC enable
+ #else
+ write_reg(m, STMPE811_REG_TSC_CTRL, 0x32); // X&Y, 16 reading window
+ write_reg(m, STMPE811_REG_TSC_CTRL, 0x33); // X&Y, 16 reading window, TSC enable
#endif
- write_reg(m, STMPE811_REG_INT_CTRL, 0x01); // Level interrupt, enable interrupts
+ write_reg(m, STMPE811_REG_INT_STA, 0xFF); // Clear all interrupts
+ write_reg(m, STMPE811_REG_INT_CTRL, 0x01); // Level interrupt, enable interrupts
release_bus(m);
return TRUE;
}
-static void read_xyz(GMouse* m, GMouseReading* pdr)
+static bool_t read_xyz(GMouse* m, GMouseReading* pdr)
{
- bool_t clearfifo; // Do we need to clear the FIFO
+ #if GMOUSE_STMPE811_TEST_MODE
+ static GMouseReading n;
+ #endif
+ uint8_t status;
- // Assume not touched.
+ // Button information will be regenerated
pdr->buttons = 0;
- pdr->z = 0;
-
- aquire_bus(m);
- #if GMOUSE_STMPE811_GPIO_IRQPIN
- // Check if the touch controller IRQ pin has gone off
- clearfifo = FALSE;
- if(getpin_irq(m)) {
- write_reg(m, STMPE811_REG_INT_STA, 0xFF); // clear all interrupts
- if (read_byte(m, STMPE811_REG_TSC_CTRL) & 0x80) // set the new touched status
- m->flags |= GMOUSE_STMPE811_FLG_TOUCHED;
- else
- m->flags &= ~GMOUSE_STMPE811_FLG_TOUCHED;
- clearfifo = TRUE; // only take the last FIFO reading
- }
+ #if GMOUSE_STMPE811_TEST_MODE
+ aquire_bus(m);
- #else
- // Poll to get the touched status
- uint16_t last_touched;
-
- last_touched = m->flags;
- if (read_byte(m, STMPE811_REG_TSC_CTRL) & 0x80) // set the new touched status
- m->flags |= GMOUSE_STMPE811_FLG_TOUCHED;
- else
- m->flags &= ~GMOUSE_STMPE811_FLG_TOUCHED;
- clearfifo = ((m->flags ^ last_touched) & GMOUSE_STMPE811_FLG_TOUCHED) ? TRUE : FALSE;
- #endif
+ // Set the buttons to match various touch signals
+ if ((read_byte(m, STMPE811_REG_TSC_CTRL) & 0x80))
+ pdr->buttons |= 0x02;
- // If not touched don't do any more
- if ((m->flags & GMOUSE_STMPE811_FLG_TOUCHED)) {
+ status = read_byte(m, STMPE811_REG_FIFO_STA);
+ if (!(status & 0x20))
+ pdr->buttons |= 0x04;
- // Clear the fifo if it is too full
- #if !GMOUSE_STMPE811_SLOW_CPU
- if (!clearfifo && (read_byte(m, STMPE811_REG_FIFO_STA) & 0xD0))
+ #if GMOUSE_STMPE811_GPIO_IRQPIN
+ if (getpin_irq(m))
+ pdr->buttons |= 0x08;
#endif
- clearfifo = TRUE;
- do {
- /* Get the X, Y, Z values */
- /* This could be done in a single 4 byte read to STMPE811_REG_TSC_DATA_XYZ (incr or non-incr) */
- pdr->x = (coord_t)read_word(m, STMPE811_REG_TSC_DATA_X);
- pdr->y = (coord_t)read_word(m, STMPE811_REG_TSC_DATA_Y);
- pdr->z = (coord_t)read_byte(m, STMPE811_REG_TSC_DATA_Z);
- } while(clearfifo && !(read_byte(m, STMPE811_REG_FIFO_STA) & 0x20));
+ if ((status & 0x20)) {
+ // Nothing in the fifo - just return the last position and pressure
+ pdr->x = n.x;
+ pdr->y = n.y;
+ pdr->z = n.z;
+ #if GMOUSE_STMPE811_GPIO_IRQPIN
+ write_reg(m, STMPE811_REG_INT_STA, 0xFF);
+ #endif
+ release_bus(m);
+ return TRUE;
+ }
- #if GMOUSE_STMPE811_SELF_CALIBRATE
- // Rescale X,Y,Z - If we are using self-calibration
- pdr->x = gdispGGetWidth(m->display) - pdr->x / (4096/gdispGGetWidth(m->display));
- pdr->y = pdr->y / (4096/gdispGGetHeight(m->display));
+ #else
+ // Is there a new sample or a touch transition
+ #if GMOUSE_STMPE811_GPIO_IRQPIN
+ if(!getpin_irq(m))
+ return FALSE;
#endif
- /* Force another read if we have more results */
- if (!clearfifo && !(read_byte(m, STMPE811_REG_FIFO_STA) & 0x20))
- _gmouseWakeup(m);
+ // Is there something in the fifo
+ status = read_byte(m, STMPE811_REG_FIFO_STA);
+ if ((status & 0x20)) {
+
+ // Nothing in the fifo.
+
+ // If not touched return the pseudo result
+ if (!(read_byte(m, STMPE811_REG_TSC_CTRL) & 0x80)) {
+
+ pdr->z = gmvmt(m)->z_min;
+ #if GMOUSE_STMPE811_GPIO_IRQPIN
+ write_reg(m, STMPE811_REG_INT_STA, 0xFF);
+ #endif
+ release_bus(m);
+ return TRUE;
+ }
+
+ // No new result
+ #if GMOUSE_STMPE811_GPIO_IRQPIN
+ write_reg(m, STMPE811_REG_INT_STA, 0xFF);
+ #endif
+ release_bus(m);
+ return FALSE;
+ }
+
+ #endif
+
+ // Time to get some readings
+ pdr->x = (coord_t)read_word(m, STMPE811_REG_TSC_DATA_X);
+ pdr->y = (coord_t)read_word(m, STMPE811_REG_TSC_DATA_Y);
+ #if GMOUSE_STMPE811_READ_PRESSURE
+ pdr->z = (coord_t)read_byte(m, STMPE811_REG_TSC_DATA_Z);
+ #else
+ pdr->z = gmvmt(m)->z_max;
+ #endif
+
+ #if !GMOUSE_STMPE811_SLOW_CPU
+ if (!(status & 0xC0)) {
+ // Is there more data to come
+ if (!(read_byte(m, STMPE811_REG_FIFO_STA) & 0x20))
+ _gmouseWakeup(m);
+ } else
+ #endif
+
+ // Clear the rest of the fifo
+ {
+ write_reg(m, STMPE811_REG_FIFO_STA, 0x01); // FIFO reset enable
+ write_reg(m, STMPE811_REG_FIFO_STA, 0x00); // FIFO reset disable
}
+ // All done
+ #if GMOUSE_STMPE811_GPIO_IRQPIN
+ write_reg(m, STMPE811_REG_INT_STA, 0xFF);
+ #endif
release_bus(m);
+
+ #if GMOUSE_STMPE811_TEST_MODE
+ // Save the result for later
+ n.x = pdr->x;
+ n.y = pdr->y;
+ n.z = pdr->z;
+ #endif
+
+ // Rescale X,Y if we are using self-calibration
+ #if GMOUSE_STMPE811_SELF_CALIBRATE
+ pdr->x = gdispGGetWidth(m->display) - pdr->x / (4096/gdispGGetWidth(m->display));
+ pdr->y = pdr->y / (4096/gdispGGetHeight(m->display));
+ #endif
+
+ return TRUE;
}
const GMouseVMT const GMOUSE_DRIVER_VMT[1] = {{
{
GDRIVER_TYPE_TOUCH,
#if GMOUSE_STMPE811_SELF_CALIBRATE
- GMOUSE_VFLG_TOUCH | GMOUSE_VFLG_ONLY_DOWN | GMOUSE_VFLG_POORUPDOWN,
+ GMOUSE_VFLG_TOUCH | GMOUSE_VFLG_ONLY_DOWN,
#else
- GMOUSE_VFLG_TOUCH | GMOUSE_VFLG_ONLY_DOWN | GMOUSE_VFLG_POORUPDOWN | GMOUSE_VFLG_CALIBRATE | GMOUSE_VFLG_CAL_TEST,
+ GMOUSE_VFLG_TOUCH | GMOUSE_VFLG_ONLY_DOWN | GMOUSE_VFLG_CALIBRATE | GMOUSE_VFLG_CAL_TEST,
#endif
sizeof(GMouse) + GMOUSE_STMPE811_BOARD_DATA_SIZE,
_gmouseInitDriver,
_gmousePostInitDriver,
_gmouseDeInitDriver
},
- 255, // z_max
- 0, // z_min
- 200, // z_touchon
- 20, // z_touchoff
+ 0, // z_max - 0 indicates full touch
+ 255, // z_min
+ 150, // z_touchon
+ 255, // z_touchoff
{ // pen_jitter
- GMOUSE_STMPE811_PEN_CALIBRATE_ERROR, // calibrate
- GMOUSE_STMPE811_PEN_CLICK_ERROR, // click
+ GMOUSE_STMPE811_PEN_CALIBRATE_ERROR, // calibrate
+ GMOUSE_STMPE811_PEN_CLICK_ERROR, // click
GMOUSE_STMPE811_PEN_MOVE_ERROR // move
},
{ // finger_jitter
diff --git a/drivers/ginput/touch/STMPE811/gmouse_lld_STMPE811_board_template.h b/drivers/ginput/touch/STMPE811/gmouse_lld_STMPE811_board_template.h
index 437abc09..4520cf67 100644
--- a/drivers/ginput/touch/STMPE811/gmouse_lld_STMPE811_board_template.h
+++ b/drivers/ginput/touch/STMPE811/gmouse_lld_STMPE811_board_template.h
@@ -19,13 +19,15 @@
// How much extra data to allocate at the end of the GMouse structure for the board's use
#define GMOUSE_STMPE811_BOARD_DATA_SIZE 0
-// Set this to TRUE if you want self-calibration.
-// NOTE: This is not as accurate as real calibration.
-// It requires the orientation of the touch panel to match the display.
-// It requires the active area of the touch panel to exactly match the display size.
-#define GMOUSE_STMPE811_SELF_CALIBRATE FALSE
+// Options - Leave these commented to make it user configurable in the gfxconf.h
+//#define GMOUSE_STMPE811_READ_PRESSURE FALSE
+//#define GMOUSE_STMPE811_SELF_CALIBRATE FALSE
+//#define GMOUSE_STMPE811_TEST_MODE FALSE
// If TRUE this board has the STMPE811 IRQ pin connected to a GPIO.
+// Note: For tested hardware this is unreliable and should be set to FALSE until tested.
+// Symptoms are that mouse readings just appear to stop for a bit. Lifting the touch
+// and re-applying the touch cause readings to start again.
#define GMOUSE_STMPE811_GPIO_IRQPIN FALSE
// If TRUE this is a really slow CPU and we should always clear the FIFO between reads.
diff --git a/drivers/ginput/touch/STMPE811/readme.txt b/drivers/ginput/touch/STMPE811/readme.txt
new file mode 100644
index 00000000..60d7f603
--- /dev/null
+++ b/drivers/ginput/touch/STMPE811/readme.txt
@@ -0,0 +1,11 @@
+This driver has a number of optional settings which can be specified in gfxconf.h:
+
+#define GMOUSE_STMPE811_READ_PRESSURE TRUE
+ Returns pressure values when the touch is down. On tested boards this ranges from 90 to 150. 255 is touch off.
+
+#define GMOUSE_STMPE811_SELF_CALIBRATE TRUE
+ Scale the touch readings to avoid calibration. This is not as accurate as real calibration.
+
+#define GMOUSE_STMPE811_TEST_MODE TRUE
+ Return raw readings for diagnostic use with the "touch_raw_readings" tool.
+
diff --git a/drivers/ginput/touch/STMPE811/stmpe811.h b/drivers/ginput/touch/STMPE811/stmpe811.h
index f0d2df42..df85889f 100644
--- a/drivers/ginput/touch/STMPE811/stmpe811.h
+++ b/drivers/ginput/touch/STMPE811/stmpe811.h
@@ -8,9 +8,6 @@
#ifndef _STMPE811_H
#define _STMPE811_H
-// Slave address
-#define STMPE811_ADDR (0x82 >> 1)
-
// Identification registers
#define STMPE811_REG_CHP_ID 0x00 // 16-bit
#define STMPE811_REG_ID_VER 0x02