xypad theremin for LPC1768

Dependencies:   MODDMA mbed

touch.cpp

Committer:
exopiped
Date:
2016-03-14
Revision:
1:aa184d2eb2e3
Parent:
0:8ee38453bad9
Child:
2:c5eeaf1c8e69

File content as of revision 1:aa184d2eb2e3:

/*
 * touch.cpp -- touch screen monitor
 */
#include "mbed.h"
#include "debug.h"
#include "touch.h"

#define NIL (-1)
/* 
 * Connecting the touch screen 
 *    STMPE610 MODE pin is tied low for I2C interface
 *    STMPE610 A0 pin tied low for I2C address 0x41
 *                       (0x82 when shifted left 1)
 *    STMPE610 A0 pin tied high for I2C address 0x44
 *                        (0x88 when shifted left 1)
 *   
 *    I2C works on board pins 9 and 10. (SDA, SDL)
 *     ( STMPE610 pins SDAT and  SCLK )
 *   
 * Setting up the touch screen 
 *  
 * Disable Touch Screen and A/D clock -- SYS_CTRL2 
 *    Set TSC_OFF bit high, ADC_OFF bit high
 *  
 * ConfigureTouch Screen -- TSCFG register 
 *    Set up for 4 sample averaging
 *    Touch detect delay of 1 msec
 *    Settling time of 1 msec
 *  
 * Touchscreen Window -- WDW_TR_X, WDW_TR_Y, WDW_BL_X, WDW_BLY
 *     Set up for full screen ( default condition )
 *      
 */

typedef enum {TOUCH_NOTOUCH,TOUCH_DEBOUNCE,NOTOUCH_DEBOUNCE,TOUCH_PRESENT} TOUCH_STATE;


#define TSC_ADDR  0x82     // (i2c address for touchscreen)<<1

// CHIP_ID register
#define CHIP_ID       0x00  // 16 bit register

// ID_VER register
#define ID_VER        0x02  // 8 bit register

// SYS_CTRL1 Reset control register
#define SYS_CTRL1     0x03
#define SOFT_RESET 0x02

// SYS_CTRL2 clock control register
#define SYS_CTRL2     0x04
#define ADC_OFF    0x01
#define TSC_OFF    0x02
#define GPIO_OFF   0x04

// ADC_CTRL registers
#define ADC_CTRL1     0x20
#define ADC_CTRL2     0x21

// Interrupt control, enable and status registers
#define INT_CTRL      0x09
#define INT_EN        0x0A
#define INT_STA       0x0B

// TSC_CTRL touchscreen control register
#define TSC_CTRL             0x40
#define TSC_TOUCH_DET    0x80 // 1 when touch detected else 0 
#define TSC_TRACK_MASK   0x70 // 0 => no window tracking
#define TSC_OP_MOD_MASK  0x0E // 0 => XYZ acquisition
#define TSC_EN_MASK      0x01 // enable touchscreen

// TSC_CFG touchscreen config register
#define TSC_CFG       0x41
#define TSC_AVG4    0x80
#define TSC_DLY_1MS 0x20
#define TSC_STL_1MS 0x03

#define TSC_I_DRIVE   0x58
#define MAMP_50      0x01

// FIFO_TH touchscreen fifo threshold register
#define FIFO_TH       0x4A

// TSC_DATA_X X data register
#define TSC_DATA_X    0x4D

// TSC_DATA_Y  Y data register
#define TSC_DATA_Y    0x4F

// FIFO_STA  touchscreen fifo control-status register
#define FIFO_STA      0x4B
#define FIFO_OFLOW 0x80
#define FIFO_FULL  0x40
#define FIFO_EMPTY 0x20
#define FIFO_TRGD  0x10
#define FIFO_RESET 0x01

// TSC_DATA touchscreen data register
#define TSC_DATA      0xD7

// GPIO_AF -- GPIO Alternate FunctionRegister
#define GPIO_AF       0x17
DigitalOut led1(LED1);
DigitalOut led4(LED4);

i2c_t touch_ctrl;  // i2c interface struct for touch screen

static int touch_present(void);
static void touch_reset(void);
static void touch_compute_params(void);

static char tsc_reset[2]={SYS_CTRL1, SOFT_RESET};
static char clox_on[2]={SYS_CTRL2,0x00};
static char adc_ctrl1[2]={ADC_CTRL1,0x49};
static char adc_ctrl2[2]={ADC_CTRL2,0x01};
static char gpio_af[2]={GPIO_AF,0};
static char fifo_clear[2]={FIFO_STA,0x01};
static char fifo_operate[2]={FIFO_STA,0x00};
static char touch_int_en[2]={INT_EN,0x02};//enable FIFO_TH int
static char clr_intrupts[2]={INT_STA,0xFF};
static char ena_intrupt[2]={INT_CTRL,0x02};
static char tsc_cfg[2]={TSC_CFG,( TSC_AVG4 
                                  | TSC_DLY_1MS 
                                  | TSC_STL_1MS )};
static char tsc_enable[2]={TSC_CTRL,3};
static char tsc_ctrl=TSC_CTRL;
static char tsc_i_drive[2]={TSC_I_DRIVE,MAMP_50};
static char fifo_th[2]={FIFO_TH,1};
static char fifo_ctrl_sta=FIFO_STA;
static char tsc_data=TSC_DATA;

static int touch_audio_freq = 1000;
static int touch_audio_amplitude = 0;
static char touch_status=0; // result of reading TSC_CTR
static char fifo_status=0;  // result of reading FIFO_CTRL_STA

short touch_x,touch_y;
 
// used by state machine that debounces touch detection 
TOUCH_STATE touch_state=TOUCH_NOTOUCH;
#define GOOD_TOUCH_COUNT 4
#define NO_TOUCH_COUNT 4

bool touch_init(void)
{
    touch_reset();
    touch_state = TOUCH_NOTOUCH;
    return true;    
}
 
void touch_reset(void)
{
    char chipid[2];

    i2c_init(&touch_ctrl,p28,p27);
    i2c_frequency(&touch_ctrl,100000);
    wait_ms(1);

    // read chip id
    i2c_write(&touch_ctrl,TSC_ADDR,CHIP_ID,2,0);
    i2c_read(&touch_ctrl,TSC_ADDR,chipid,2,1);
    wait_ms(1);

    // reset touch screen chip
    i2c_write(&touch_ctrl,TSC_ADDR,tsc_reset,2,1);
    wait_ms(5);

    i2c_write(&touch_ctrl,TSC_ADDR,tsc_i_drive,2,1);
    wait_ms(1);

    // turn on ADC and TSC clocks
    i2c_write(&touch_ctrl,TSC_ADDR,clox_on,2,1);
    wait_ms(3);

    // enable touch interrupt
    i2c_write(&touch_ctrl,TSC_ADDR,touch_int_en,2,1);
    wait_ms(1);

    // 80 clock cycles for ADC conv, 12 bit ADC, internal ref
    i2c_write(&touch_ctrl,TSC_ADDR,adc_ctrl1,2,1);
    wait_ms(2);

    // ADC clock = 3.25 MHz
    i2c_write(&touch_ctrl,TSC_ADDR,adc_ctrl2,2,1);
    wait_ms(1);

    // 4 sample averaging and 1ms delays
    i2c_write(&touch_ctrl,TSC_ADDR,tsc_cfg,2,1); 
    wait_ms(1);

    // gpio alt function register to 0
    i2c_write(&touch_ctrl,TSC_ADDR,gpio_af,2,1);
    wait_ms(1);

    // FIFO threshold not zero
    i2c_write(&touch_ctrl,TSC_ADDR,fifo_th,2,1);
    wait_ms(1);

    // FIFO Reset
    i2c_write(&touch_ctrl,TSC_ADDR,fifo_clear,2,1);
    wait_ms(1);

    // FIFO out of reset
    i2c_write(&touch_ctrl,TSC_ADDR,fifo_operate,2,1);
    wait_ms(1);

    // enable touchscreen, no window tracking, x,y mode
    i2c_write(&touch_ctrl,TSC_ADDR,tsc_enable,2,1);
    wait_ms(1);

    i2c_write(&touch_ctrl,TSC_ADDR,clr_intrupts,2,1);
    wait_ms(1);

    i2c_write(&touch_ctrl,TSC_ADDR,ena_intrupt,2,1);
    wait_ms(1);
}

bool touch_debounce(void)
{
    static int debounce_count=0;
    int tret;

    tret=touch_present();
    switch (touch_state) {
    case TOUCH_NOTOUCH:
        if (tret>0) {
            debounce_count=0;
            touch_state = TOUCH_DEBOUNCE;
        }
        break;

    case TOUCH_DEBOUNCE:
        if (tret>0) {
            if (++debounce_count > GOOD_TOUCH_COUNT) {
                touch_state = TOUCH_PRESENT;
                led1=1;
            }
        } else if(tret == 0) {
            touch_state = TOUCH_NOTOUCH;
        }
        break;
        
    case NOTOUCH_DEBOUNCE:
        if(tret>0) {
            touch_state = TOUCH_PRESENT;
        } else if(tret== 0) {
            if(++debounce_count > NO_TOUCH_COUNT) {
                debounce_count=0;
                touch_state=TOUCH_NOTOUCH;
            }
        }
        break;

    case TOUCH_PRESENT:
        if (tret>0) {
            touch_compute_params();
        } else if(tret==0) {
            debounce_count=0;
            touch_state=NOTOUCH_DEBOUNCE;
        }
        break;

    }
    return ((touch_state==TOUCH_PRESENT) || (touch_state==NOTOUCH_DEBOUNCE));
}

int touch_frequency(void)
{
    return touch_audio_freq;
}

int touch_amplitude(void)
{
    return touch_audio_amplitude;
}
void touch_compute_params(void)
{
    if(0>touch_get_xy(&touch_x,&touch_y)) return;
    if((touch_y>0x3F) && (touch_y!=0xFFF)) {
        touch_audio_freq = (TOUCH_MIN_FREQUENCY 
        + (TOUCH_MAX_FREQUENCY - TOUCH_MIN_FREQUENCY)
        * touch_y)>>12;
    }
    if((touch_x > 0x3F) && (touch_x != 0xFFF)) {
        touch_audio_amplitude = (TOUCH_MAX_AMPLITUDE*touch_x)>>12;
    }
}
/*
 * return 1 if touch present, 0 if touch absent, and -1
 * if there was an i2c error
 */
int touch_present(void)
{
// <<<<<   i2c_init(&touch_ctrl,p28,p27); // sync i2c routines
// <<<<<    i2c_frequency(&touch_ctrl,100000); // 100kHz clock

    i2c_write(&touch_ctrl,TSC_ADDR,&tsc_ctrl,1,0);
    i2c_read(&touch_ctrl,TSC_ADDR,&touch_status,1,1);

    if ((touch_status & TSC_EN_MASK)==0) {  // i2c error
        led4=1;                             // disables screen
        touch_reset();                       // re-init fixes
        return -1;
    } else if ((touch_status & TSC_TOUCH_DET)>0) {
        return 1;
    }
    return 0; 
}

int touch_get_xy(short *x,short *y)
{
    unsigned char packed_xy[3];

    if(i2c_write(&touch_ctrl,TSC_ADDR,&fifo_ctrl_sta,1,0)<0)
        return NIL;
    if(i2c_read(&touch_ctrl,TSC_ADDR,&fifo_status,1,1)<0)
        return NIL;
    while ((fifo_status & FIFO_EMPTY)!=FIFO_EMPTY ) {
        if (i2c_write(&touch_ctrl,TSC_ADDR,&tsc_data,1,0) < 0)
            return NIL; 
        if(i2c_read(&touch_ctrl,TSC_ADDR,(char *)packed_xy,3,1)<0)
            return NIL;
        if(i2c_write(&touch_ctrl,TSC_ADDR,&fifo_ctrl_sta,1,0)<0)
            return NIL;
        if(i2c_read(&touch_ctrl,TSC_ADDR,&fifo_status,1,1)<0)
            return NIL;
    }
    if(i2c_write(&touch_ctrl,TSC_ADDR,clr_intrupts,2,1)<0)
        return NIL;
    *x = (short)(packed_xy[0]<<4) 
       | (short)((packed_xy[1] & 0xF0)>>4);
    *y = 0xFFF -((short)((packed_xy[1] & 0x0F)<<8) 
               | (short)(packed_xy[2]));
    // 0xFFF or 0x000 is some kind of glitch
    if (*x==0xFFF && *y==0xFFF) return NIL;
    if (*x==0 && *y==0) return NIL;
    debug_hexshort(*x);
    debug_putch(',');
    debug_hexshort(*y);
    debug_crlf();
    return 0; 
}