Fix the newmouse STMPE811 driver.

Finalise the STM32F429i-Discovery board file for that touch controller
This commit is contained in:
inmarket 2014-11-07 12:05:23 +10:00
parent d0f8c12a2d
commit 2a1c7785cc
6 changed files with 198 additions and 92 deletions

View file

@ -19,18 +19,21 @@
// How much extra data to allocate at the end of the GMouse structure for the board's use // 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 #define GMOUSE_STMPE811_BOARD_DATA_SIZE 0
// Set this to TRUE if you want self-calibration. // Options - Leave these commented to make it user configurable in the gfxconf.h
// NOTE: This is not as accurate as real calibration. //#define GMOUSE_STMPE811_READ_PRESSURE FALSE
// It requires the orientation of the touch panel to match the display. //#define GMOUSE_STMPE811_SELF_CALIBRATE FALSE
// It requires the active area of the touch panel to exactly match the display size. //#define GMOUSE_STMPE811_TEST_MODE FALSE
#define GMOUSE_STMPE811_SELF_CALIBRATE FALSE
// If TRUE this board has the STMPE811 IRQ pin connected to a GPIO. // If TRUE this board has the STMPE811 IRQ pin connected to a GPIO.
#define GMOUSE_STMPE811_GPIO_IRQPIN TRUE // Note: Although this board has such a pin its reliability has not been tested on this board!!!!!
#define GMOUSE_STMPE811_GPIO_IRQPIN FALSE
// If TRUE this is a really slow CPU and we should always clear the FIFO between reads. // If TRUE this is a really slow CPU and we should always clear the FIFO between reads.
#define GMOUSE_STMPE811_SLOW_CPU FALSE #define GMOUSE_STMPE811_SLOW_CPU FALSE
// Slave address
#define STMPE811_ADDR (0x82 >> 1)
// Maximum timeout // Maximum timeout
#define STMPE811_TIMEOUT 0x3000 #define STMPE811_TIMEOUT 0x3000

View file

@ -19,18 +19,20 @@
// How much extra data to allocate at the end of the GMouse structure for the board's use // 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 #define GMOUSE_STMPE811_BOARD_DATA_SIZE 0
// Set this to TRUE if you want self-calibration. // Options - Leave these commented to make it user configurable in the gfxconf.h
// NOTE: This is not as accurate as real calibration. //#define GMOUSE_STMPE811_READ_PRESSURE FALSE
// It requires the orientation of the touch panel to match the display. //#define GMOUSE_STMPE811_SELF_CALIBRATE FALSE
// It requires the active area of the touch panel to exactly match the display size. //#define GMOUSE_STMPE811_TEST_MODE FALSE
#define GMOUSE_STMPE811_SELF_CALIBRATE FALSE
// If TRUE this board has the STMPE811 IRQ pin connected to a GPIO. // Set to FALSE because it does not work properly on this board even though the pin exists.
#define GMOUSE_STMPE811_GPIO_IRQPIN TRUE #define GMOUSE_STMPE811_GPIO_IRQPIN FALSE
// If TRUE this is a really slow CPU and we should always clear the FIFO between reads. // If TRUE this is a really slow CPU and we should always clear the FIFO between reads.
#define GMOUSE_STMPE811_SLOW_CPU FALSE #define GMOUSE_STMPE811_SLOW_CPU FALSE
// Slave address
#define STMPE811_ADDR 0x41
// Maximum timeout // Maximum timeout
#define STMPE811_TIMEOUT 0x3000 #define STMPE811_TIMEOUT 0x3000
@ -47,10 +49,12 @@ static bool_t init_board(GMouse* m, unsigned driverinstance) {
if (driverinstance) if (driverinstance)
return FALSE; return FALSE;
// Set pin modes
palSetPadMode(GPIOA, 15, PAL_MODE_INPUT | PAL_STM32_PUDR_FLOATING); /* TP IRQ */ palSetPadMode(GPIOA, 15, PAL_MODE_INPUT | PAL_STM32_PUDR_FLOATING); /* TP IRQ */
palSetPadMode(GPIOA, 8, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN); /* SCL */ palSetPadMode(GPIOA, 8, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN); /* SCL */
palSetPadMode(GPIOC, 9, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN); /* SDA */ palSetPadMode(GPIOC, 9, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN); /* SDA */
// Start the I2C
i2cStart(&I2CD3, &i2ccfg); i2cStart(&I2CD3, &i2ccfg);
return TRUE; return TRUE;

View file

@ -12,14 +12,51 @@
#define GMOUSE_DRIVER_VMT GMOUSEVMT_STMPE811 #define GMOUSE_DRIVER_VMT GMOUSEVMT_STMPE811
#include "src/ginput/driver_mouse.h" #include "src/ginput/driver_mouse.h"
#define GMOUSE_STMPE811_FLG_TOUCHED (GMOUSE_FLG_DRIVER_FIRST<<0)
// Hardware definitions // Hardware definitions
#include "drivers/ginput/touch/STMPE811/stmpe811.h" #include "drivers/ginput/touch/STMPE811/stmpe811.h"
// Get the hardware interface // Get the hardware interface
#include "gmouse_lld_STMPE811_board.h" #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) { static bool_t MouseInit(GMouse* m, unsigned driverinstance) {
if (!init_board(m, driverinstance)) if (!init_board(m, driverinstance))
return FALSE; 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 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 #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 #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 #endif
write_reg(m, STMPE811_REG_ADC_CTRL1, 0x48); // ADC conversion time = 80 clock ticks, 12-bit ADC, internal voltage refernce write_reg(m, STMPE811_REG_ADC_CTRL1, 0x48); // ADC conversion time = 80 clock ticks, 12-bit ADC, internal voltage refernce
gfxSleepMilliseconds(2); gfxSleepMilliseconds(2);
write_reg(m, STMPE811_REG_ADC_CTRL2, 0x01); // ADC speed 3.25MHz 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_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_TSC_CFG, 0xA3); // Averaging 4, touch detect delay 1ms, panel driver settling time 1ms
write_reg(m, STMPE811_REG_FIFO_TH, 0x40); // FIFO threshold = 64 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, 0x01); // FIFO reset enable
write_reg(m, STMPE811_REG_FIFO_STA, 0x00); // FIFO reset disable 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_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_I_DRIVE, 0x01); // max 50mA touchscreen line current
write_reg(m, STMPE811_REG_TSC_CTRL, 0x00); // X&Y&Z #if GMOUSE_STMPE811_READ_PRESSURE
write_reg(m, STMPE811_REG_TSC_CTRL, 0x01); // X&Y&Z, TSC enable write_reg(m, STMPE811_REG_TSC_CTRL, 0x30); // X&Y&Z, 16 reading window
write_reg(m, STMPE811_REG_INT_STA, 0xFF); // Clear all interrupts write_reg(m, STMPE811_REG_TSC_CTRL, 0x31); // X&Y&Z, 16 reading window, TSC enable
#if GMOUSE_STMPE811_GPIO_IRQPIN #else
if (read_byte(m, STMPE811_REG_TSC_CTRL) & 0x80) write_reg(m, STMPE811_REG_TSC_CTRL, 0x32); // X&Y, 16 reading window
m->flags |= GMOUSE_STMPE811_FLG_TOUCHED; write_reg(m, STMPE811_REG_TSC_CTRL, 0x33); // X&Y, 16 reading window, TSC enable
#endif #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); release_bus(m);
return TRUE; 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->buttons = 0;
pdr->z = 0;
aquire_bus(m); #if GMOUSE_STMPE811_TEST_MODE
aquire_bus(m);
#if GMOUSE_STMPE811_GPIO_IRQPIN // Set the buttons to match various touch signals
// Check if the touch controller IRQ pin has gone off if ((read_byte(m, STMPE811_REG_TSC_CTRL) & 0x80))
clearfifo = FALSE; pdr->buttons |= 0x02;
if(getpin_irq(m)) {
write_reg(m, STMPE811_REG_INT_STA, 0xFF); // clear all interrupts status = read_byte(m, STMPE811_REG_FIFO_STA);
if (read_byte(m, STMPE811_REG_TSC_CTRL) & 0x80) // set the new touched status if (!(status & 0x20))
m->flags |= GMOUSE_STMPE811_FLG_TOUCHED; pdr->buttons |= 0x04;
else
m->flags &= ~GMOUSE_STMPE811_FLG_TOUCHED; #if GMOUSE_STMPE811_GPIO_IRQPIN
clearfifo = TRUE; // only take the last FIFO reading if (getpin_irq(m))
pdr->buttons |= 0x08;
#endif
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;
} }
#else #else
// Poll to get the touched status // Is there a new sample or a touch transition
uint16_t last_touched; #if GMOUSE_STMPE811_GPIO_IRQPIN
if(!getpin_irq(m))
return FALSE;
#endif
// 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;
}
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 #endif
// If not touched don't do any more // Time to get some readings
if ((m->flags & GMOUSE_STMPE811_FLG_TOUCHED)) { 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
// Clear the fifo if it is too full #if !GMOUSE_STMPE811_SLOW_CPU
#if !GMOUSE_STMPE811_SLOW_CPU if (!(status & 0xC0)) {
if (!clearfifo && (read_byte(m, STMPE811_REG_FIFO_STA) & 0xD0)) // Is there more data to come
#endif if (!(read_byte(m, STMPE811_REG_FIFO_STA) & 0x20))
clearfifo = TRUE; _gmouseWakeup(m);
} else
#endif
do { // Clear the rest of the fifo
/* 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) */ write_reg(m, STMPE811_REG_FIFO_STA, 0x01); // FIFO reset enable
pdr->x = (coord_t)read_word(m, STMPE811_REG_TSC_DATA_X); write_reg(m, STMPE811_REG_FIFO_STA, 0x00); // FIFO reset disable
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 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));
#endif
/* Force another read if we have more results */
if (!clearfifo && !(read_byte(m, STMPE811_REG_FIFO_STA) & 0x20))
_gmouseWakeup(m);
} }
// All done
#if GMOUSE_STMPE811_GPIO_IRQPIN
write_reg(m, STMPE811_REG_INT_STA, 0xFF);
#endif
release_bus(m); 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] = {{ const GMouseVMT const GMOUSE_DRIVER_VMT[1] = {{
{ {
GDRIVER_TYPE_TOUCH, GDRIVER_TYPE_TOUCH,
#if GMOUSE_STMPE811_SELF_CALIBRATE #if GMOUSE_STMPE811_SELF_CALIBRATE
GMOUSE_VFLG_TOUCH | GMOUSE_VFLG_ONLY_DOWN | GMOUSE_VFLG_POORUPDOWN, GMOUSE_VFLG_TOUCH | GMOUSE_VFLG_ONLY_DOWN,
#else #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 #endif
sizeof(GMouse) + GMOUSE_STMPE811_BOARD_DATA_SIZE, sizeof(GMouse) + GMOUSE_STMPE811_BOARD_DATA_SIZE,
_gmouseInitDriver, _gmouseInitDriver,
_gmousePostInitDriver, _gmousePostInitDriver,
_gmouseDeInitDriver _gmouseDeInitDriver
}, },
255, // z_max 0, // z_max - 0 indicates full touch
0, // z_min 255, // z_min
200, // z_touchon 150, // z_touchon
20, // z_touchoff 255, // z_touchoff
{ // pen_jitter { // pen_jitter
GMOUSE_STMPE811_PEN_CALIBRATE_ERROR, // calibrate GMOUSE_STMPE811_PEN_CALIBRATE_ERROR, // calibrate
GMOUSE_STMPE811_PEN_CLICK_ERROR, // click GMOUSE_STMPE811_PEN_CLICK_ERROR, // click
GMOUSE_STMPE811_PEN_MOVE_ERROR // move GMOUSE_STMPE811_PEN_MOVE_ERROR // move
}, },
{ // finger_jitter { // finger_jitter

View file

@ -19,13 +19,15 @@
// How much extra data to allocate at the end of the GMouse structure for the board's use // 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 #define GMOUSE_STMPE811_BOARD_DATA_SIZE 0
// Set this to TRUE if you want self-calibration. // Options - Leave these commented to make it user configurable in the gfxconf.h
// NOTE: This is not as accurate as real calibration. //#define GMOUSE_STMPE811_READ_PRESSURE FALSE
// It requires the orientation of the touch panel to match the display. //#define GMOUSE_STMPE811_SELF_CALIBRATE FALSE
// It requires the active area of the touch panel to exactly match the display size. //#define GMOUSE_STMPE811_TEST_MODE FALSE
#define GMOUSE_STMPE811_SELF_CALIBRATE FALSE
// If TRUE this board has the STMPE811 IRQ pin connected to a GPIO. // 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 #define GMOUSE_STMPE811_GPIO_IRQPIN FALSE
// If TRUE this is a really slow CPU and we should always clear the FIFO between reads. // If TRUE this is a really slow CPU and we should always clear the FIFO between reads.

View file

@ -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.

View file

@ -8,9 +8,6 @@
#ifndef _STMPE811_H #ifndef _STMPE811_H
#define _STMPE811_H #define _STMPE811_H
// Slave address
#define STMPE811_ADDR (0x82 >> 1)
// Identification registers // Identification registers
#define STMPE811_REG_CHP_ID 0x00 // 16-bit #define STMPE811_REG_CHP_ID 0x00 // 16-bit
#define STMPE811_REG_ID_VER 0x02 #define STMPE811_REG_ID_VER 0x02