From a9beec902da2348e858dcd54550d99a40c1fbe87 Mon Sep 17 00:00:00 2001 From: Kumar Abhishek Date: Thu, 16 Aug 2012 15:14:16 +0530 Subject: [PATCH] XPT2046 LLD Major Update Added 7 point median filtering to reduce noise TOUCHPADDriver structure now encapsulates the IRQ pin, so removed the TP_CS_ and TP_IRQ_ macros Added generic tp_lld_read_value method to read any ADC channel from the XPT2046, this includes on-chip temperature sensor and VBAT input Improved SPI bus sharing, with the optional TOUCHPAD_SPI_PROLOGUE and TOUCHPAD_SPI_EPILOGUE macros --- drivers/touchpad/XPT2046/touchpad_lld.c | 155 +++++++++++++++++++----- include/touchpad_lld.h | 63 +++++++--- 2 files changed, 172 insertions(+), 46 deletions(-) diff --git a/drivers/touchpad/XPT2046/touchpad_lld.c b/drivers/touchpad/XPT2046/touchpad_lld.c index 24afcab4..16e4db79 100644 --- a/drivers/touchpad/XPT2046/touchpad_lld.c +++ b/drivers/touchpad/XPT2046/touchpad_lld.c @@ -36,9 +36,6 @@ /* Driver local definitions. */ /*===========================================================================*/ -#define TP_CS_HIGH palSetPad(TP_CS_PORT, TP_CS) -#define TP_CS_LOW palClearPad(TP_CS_PORT, TP_CS) - #ifdef UNUSED #elif defined(__GNUC__) # define UNUSED(x) UNUSED_ ## x __attribute__((unused)) @@ -52,13 +49,15 @@ /* Driver exported variables. */ /*===========================================================================*/ -#if !defined(__DOXYGEN__) - TOUCHPADDriver Touchpad; -#endif - /*===========================================================================*/ /* Driver local variables. */ /*===========================================================================*/ +#if !defined(__DOXYGEN__) + /* Local copy of the current touchpad driver */ + static const TOUCHPADDriver *tpDriver; + + static uint16_t sampleBuf[7]; +#endif /*===========================================================================*/ /* Driver local functions. */ @@ -79,30 +78,104 @@ * * @notapi */ -void tp_lld_init(TOUCHPADDriver *tp) { - spiStart(tp->spid, tp->spicfg); +void tp_lld_init(const TOUCHPADDriver *tp) { + tpDriver=tp; + + if (tpDriver->direct_init) + spiStart(tpDriver->spip, tpDriver->spicfg); +} + + +/** + * @brief Reads a conversion from the touchpad + * + * @param[in] cmd The command bits to send to the touchpad + * + * @return The read value 12-bit right-justified + * + * @note This function only reads data, it is assumed that the pins are + * configured properly and the bus has been acquired beforehand + * + * @notapi + */ +uint16_t tp_lld_read_value(uint8_t cmd) { + static uint8_t txbuf[3]={0}; + static uint8_t rxbuf[3]={0}; + uint16_t ret; + + txbuf[0]=cmd; + + spiExchange(tpDriver->spip, 3, txbuf, rxbuf); + + ret = (rxbuf[1] << 5) | (rxbuf[2] >> 3); + + return ret; +} + +/** + * @brief 7-point median filtering code for touchpad samples + * + * @note This is an internally used routine only. + * + * @notapi + */ +static void tp_lld_filter(void) { + uint16_t temp; + int i,j; + + for (i=0; i<4; i++) { + for (j=i; j<7; j++) { + if (sampleBuf[i] > sampleBuf[j]) { + /* Swap the values */ + temp=sampleBuf[i]; + sampleBuf[i]=sampleBuf[j]; + sampleBuf[j]=temp; + } + } + } + } /** * @brief Reads out the X direction. * + * @note The samples are median filtered for greater noise reduction + * * @notapi */ uint16_t tp_lld_read_x(void) { - uint8_t txbuf[1]; - uint8_t rxbuf[2]; - uint16_t x; + int i; - txbuf[0] = 0xd0; - TP_CS_LOW; - spiSend(&SPID1, 1, txbuf); - spiReceive(&SPID1, 2, rxbuf); - TP_CS_HIGH; +#if defined(SPI_USE_MUTUAL_EXCLUSION) + spiAcquireBus(tpDriver->spip); +#endif - x = rxbuf[0] << 4; - x |= rxbuf[1] >> 4; + TOUCHPAD_SPI_PROLOGUE(); + palClearPad(tpDriver->spicfg->ssport, tpDriver->spicfg->sspad); - return x; + /* Discard the first conversion - very noisy and keep the ADC on hereafter + * till we are done with the sampling. Note that PENIRQ is disabled. + */ + tp_lld_read_value(0xD1); + + for (i=0;i<7;i++) { + sampleBuf[i]=tp_lld_read_value(0xD1); + } + + /* Switch on PENIRQ once again - perform a dummy read */ + tp_lld_read_value(0xD0); + + palSetPad(tpDriver->spicfg->ssport, tpDriver->spicfg->sspad); + TOUCHPAD_SPI_EPILOGUE(); + +#if defined(SPI_USE_MUTUAL_EXCLUSION) + spiReleaseBus(tpDriver->spip); +#endif + + /* Find the median - use selection sort */ + tp_lld_filter(); + + return sampleBuf[3]; } /* @@ -111,20 +184,38 @@ uint16_t tp_lld_read_x(void) { * @notapi */ uint16_t tp_lld_read_y(void) { - uint8_t txbuf[1]; - uint8_t rxbuf[2]; - uint16_t y; + int i; - txbuf[0] = 0x90; - TP_CS_LOW; - spiSend(&SPID1, 1, txbuf); - spiReceive(&SPID1, 2, rxbuf); - TP_CS_HIGH; +#if defined(SPI_USE_MUTUAL_EXCLUSION) + spiAcquireBus(tpDriver->spip); +#endif - y = rxbuf[0] << 4; - y |= rxbuf[1] >> 4; + TOUCHPAD_SPI_PROLOGUE(); + palClearPad(tpDriver->spicfg->ssport, tpDriver->spicfg->sspad); - return y; + /* Discard the first conversion - very noisy and keep the ADC on hereafter + * till we are done with the sampling. Note that PENIRQ is disabled. + */ + tp_lld_read_value(0x91); + + for (i=0;i<7;i++) { + sampleBuf[i]=tp_lld_read_value(0x91); + } + + /* Switch on PENIRQ once again - perform a dummy read */ + tp_lld_read_value(0x90); + + palSetPad(tpDriver->spicfg->ssport, tpDriver->spicfg->sspad); + TOUCHPAD_SPI_EPILOGUE(); + +#ifdef SPI_USE_MUTUAL_EXCLUSION + spiReleaseBus(tpDriver->spip); +#endif + + /* Find the median - use selection sort */ + tp_lld_filter(); + + return sampleBuf[3]; } /* ---- Optional Routines ---- */ @@ -137,7 +228,7 @@ uint16_t tp_lld_read_y(void) { * @notapi */ uint8_t tp_lld_irq(void) { - return (!palReadPad(TP_IRQ_PORT, TP_IRQ)); + return (!palReadPad(tpDriver->tpIRQPort, tpDriver->tpIRQPin)); } #endif diff --git a/include/touchpad_lld.h b/include/touchpad_lld.h index 45a561d3..a3a7489c 100644 --- a/include/touchpad_lld.h +++ b/include/touchpad_lld.h @@ -49,41 +49,76 @@ #define TOUCHPAD_HAS_PRESSURE FALSE #endif +#ifndef TOUCHPAD_SPI_PROLOGUE + #define TOUCHPAD_SPI_PROLOGUE() +#endif + +#ifndef TOUCHPAD_SPI_EPILOGUE + #define TOUCHPAD_SPI_EPILOGUE() +#endif + /*===========================================================================*/ /* Driver types. */ /*===========================================================================*/ -typedef struct TOUCHPADDriver TOUCHPADDriver; +typedef struct _TOUCHPADDriver TOUCHPADDriver; /** * @brief Structure representing a Touchpad driver. */ -struct TOUCHPADDriver { - /* - * @brief Pointer to SPI driver. - */ - SPIDriver *spid; +struct _TOUCHPADDriver { + /* + * @brief Pointer to SPI driver. + * @note SPI driver must be enabled in mcuconf.h and halconf.h + */ + SPIDriver *spip; - /* - * @brief SPI configuration. - */ - SPIConfig *spicfg; + /* + * @brief Pointer to the SPI configuration structure. + * @note The lowest possible speed ~ 1-2MHz is to be used, otherwise + * will result in a lot of noise + */ + const SPIConfig *spicfg; + + /* + * @brief Touchscreen controller TPIRQ pin GPIO port + */ + ioportid_t tpIRQPort; + + /* + * @brief Touchscreen controller TPIRQ GPIO pin + * @note The interface is polled as of now, interrupt support is + * to be implemented in the future. + */ + ioportmask_t tpIRQPin; + + /* + * @brief Initialize the SPI with the configuration struct given or not + * If TRUE, spiStart is called by the init, otherwise not + * @note This is provided in such a case when SPI port is being shared + * across multiple peripherals, so not to disturb the SPI bus. + * You can use TOUCHPAD_SPI_PROLOGUE() and TOUCHPAD_SPI_EPILOGUE() + * macros to change the SPI configuration or speed before and + * after using the touchpad. An example case would be sharing the + * bus with a fast flash memory chip. + */ + bool_t direct_init; }; + /*===========================================================================*/ /* External declarations. */ /*===========================================================================*/ -#if !defined(__DOXYGEN__) - extern TOUCHPADDriver Touchpad; -#endif #ifdef __cplusplus extern "C" { #endif /* Core functions */ - void tp_lld_init(TOUCHPADDriver *tp); + void tp_lld_init(const TOUCHPADDriver *tp); + + uint16_t tp_lld_read_value(uint8_t cmd); uint16_t tp_lld_read_x(void); uint16_t tp_lld_read_y(void);