touch screen handler for the microchip AR1020

ar1020.cpp

Committer:
hlipka
Date:
2011-02-22
Revision:
1:264ad2a00fd9
Parent:
0:cf4dd04052e3
Child:
2:1a436d154c84

File content as of revision 1:264ad2a00fd9:

/*
* mbed AR1020 library
* Copyright (c) 2010 Hendrik Lipka
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include "ar1020.h"
#include "wait_api.h"

AR1020::AR1020(SPI *spi, PinName enable, PinName sqi, PinName power, bool swapX, bool swapY, bool swapXY)
{
    _spi=spi;
    _enable=new DigitalOut(enable);
    _enable->write(1);
    _irq=new InterruptIn(sqi);
    _x=-1;
    _y=-1;
    _pen=0;
    _oldPen=false;
    _led=new DigitalOut(LED1);
    _power=new DigitalOut(power);
    _power->write(0);
}

AR1020::AR1020(PinName mosi, PinName miso, PinName clk, PinName enable, PinName sqi, PinName power, bool swapX, bool swapY, bool swapXY)
{
    _mosi=new DigitalOut(mosi);
    _miso=new DigitalIn(miso);
    _clk=new DigitalOut(clk);
    _clk->write(0);

    _enable=new DigitalOut(enable);
    _enable->write(1);
    _irq=new InterruptIn(sqi);
    _sqi=new DigitalIn(sqi);
    _x=-1;
    _y=-1;
    _pen=0;
    _oldPen=false;
    _led=new DigitalOut(LED1);
    _power=new DigitalOut(power);
    _power->write(0);
}

AR1020::~AR1020()
{
    delete _enable;
    delete _irq;
}

void AR1020::init()
{
    _power->write(1);
    wait_ms(100);
    int r=cmd(0x13,NULL,0);    
    printf("disable touch=%i\n",r);

    int regStart=cmd(0x22,NULL,0);
    printf("reg offset=%i\n",regStart);

    if (regStart<0)
        return;

    char cid2[4]={0x00,0x0d+regStart,0x01,0x01};
    r=cmd(0x21,cid2,4);
    printf("set mode=1 => %i\n",r);


    r=cmd(0x12,NULL,0);    
    printf("enable touch=%i\n",r);
    _irq->rise(this, &AR1020::read);
}

int AR1020::x()
{
    return _x;
}

int AR1020::y()
{
    return _y;
}

int AR1020::pen()
{
    return _pen;
}


void AR1020::read()
{
    _led->write(1);
    _enable->write(0);
    wait_us(60);
    
    int pen=readByte();
    wait_us(60);
    
    int xlo=readByte();
    wait_us(60);
    
    int xhi=readByte();
    wait_us(60);
    
    int ylo=readByte();
    wait_us(60);
    
    int yhi=readByte();
    _enable->write(1);

//        printf("0x%x|0x%x|0x%x|0x%x|0x%x\n", pen,xlo,xhi,ylo,yhi);
    if (0x4d==pen || 0==pen || 255==pen)
    {
        // ignore invalid stuff, do nothing...
    }
    else if (0x81!=pen&0x81) // pen set?
    {
        _pen=0;
        int x=xlo+(xhi<<7);
        int y=ylo+(yhi<<7);
        if (0!=x&&0!=y)
        {
            _x=x;
            _y=y;
        }
    }
    else
    {
        _pen=1;
        int x=xlo+(xhi<<7);
        int y=ylo+(yhi<<7);
        if (0!=x&&0!=y)
        {
            _x=x;
            _y=y;
        }
    }
    _event.x=_x;
    _event.y=_y;
    _event.pen=_pen;
    if (_pen==1 && _oldPen==false)
    { // pen down
        _callbackPD.call((uint32_t)&_event);
    }
    else if (_pen==1 && _oldPen==true)
    { // pen moved
        _callbackPM.call((uint32_t)&_event);
    }
    else if (_pen==0 && _oldPen==true)
    { // pen up
        _callbackPU.call((uint32_t)&_event);
    }
    else
    {
        // happens on the first touch (the first report is send with pen=0).
    }
    _oldPen=(_pen==1);
    _led->write(0);
}

int AR1020::cmd(char cmd,char* data, int len)
{
    _enable->write(1);
    wait_us(1000);
    _enable->write(0);
    
    wait_us(10);
    
    writeByte(0x55);
    wait_us(100);
    
    writeByte(len+1);
    wait_us(100);
    
    writeByte(cmd);
    wait_us(100);
    
    for (int i=0;i<len;i++)
    {
        writeByte(data[i]);
        wait_us(100);
    }
    Timer t;
    t.start();
    while (true)
    {
      wait_us(100);
      if (1==_sqi->read())
        break;
      if (t.read_ms()>1)
        break;
    }
    char rhead=readByte();
    wait_us(100);
    if (rhead!=0x55)
    {
        _enable->write(1);
        printf("rh=0x%x\n",rhead);
        return -1000;
    }
    char rlen=readByte();
    wait_us(100);
    if (rlen==2)
    {
        char r=readByte();
        wait_us(100);
        char rc=readByte();
        wait_us(100);
        _enable->write(1);
        if (rc!=cmd)
            return -2000;
        return -r;
    }
    else if (rlen==3)
    {
        char r=readByte();
        wait_us(100);
        char rc=readByte();
        wait_us(100);
        if (rc!=cmd)
        {
            _enable->write(1);
            return -3000;
        }
        char rd=readByte();
        wait_us(100);
        _enable->write(1);
        if (r==0)
            return rd;
        return -r;
    }
    else
    {
        _enable->write(1);
        return -4000;
    }
}
void AR1020::calibrate()
{
    _irq->rise(NULL);

    DigitalOut led1(LED1);
    DigitalOut led2(LED2);
    DigitalOut led3(LED3);
    DigitalOut led4(LED4);
    led1=0;led2=0;led3=1;led4=1;
    
    int r=cmd(0x13,NULL,0);    
    printf("disable touch=%i\n",r);
    wait_ms(100);
    if (r<0)
        return;
    led4=0;
    
    int regStart=cmd(0x22,NULL,0);
    printf("reg offset=%i\n",regStart);

    char cid[3]={0x00,0x0d+regStart,0x01};
    int mode=cmd(0x20,cid,3);
    printf("mode=%i\n",mode);

    if (regStart<0)
        return;
    printf("start calibrate\n");
    led3=0;    
    char cid2[4]={0x00,0x0e+regStart,0x01,0x19};
    r=cmd(0x21,cid2,4);
    printf("set inset=%i\n",r);
    if (r<0)
        return;

    _enable->write(1);
    _enable->write(0);
    wait_us(10);
    writeByte(0x55);
    wait_us(100);
    writeByte(0x02);
    wait_us(100);
    writeByte(0x14);
    wait_us(100);
    writeByte(0x04);
    
    wait_ms(10);

    int resp=readCalibResponse();
    printf("status=%i\n",resp);
    printf("start OK, press upper left");
    led1=1;
    resp=readCalibResponse();
    printf("status=%i\n",resp);
    printf("press upper right");
    led2=1;
    resp=readCalibResponse();
    printf("status=%i\n",resp);
    printf("press lower right");
    led3=1;
    resp=readCalibResponse();
    printf("status=%i\n",resp);
    printf("press lower left");
    led4=1;
    resp=readCalibResponse();
    printf("status=%i\n",resp);
    
     _enable->write(1);
   
    r=cmd(0x12,NULL,0);    
    printf("enable touch=%i\n",r);
   
    _irq->rise(this, &AR1020::read);
    
}

int AR1020::readCalibResponse()
{
    while (true)
    {
        int r=readByte();
        if (r!=0x55)
        {
            printf("1=0x%x\n",r);
            wait_ms(100);
            continue;
        }

        r=readByte();
        wait_us(100);
        if (r!=0x02)
        {
            printf("2=0x%x\n",r);
            continue;
        }
            
        r=readByte();
        wait_us(100);
        if (r!=0x00)
        {
            printf("3=0x%x\n",r);
            continue;
        }
        int rc=readByte();
        wait_us(100);
        if (rc!=0x14)
        {
            printf("4=0x%x\n",r);
            continue;
        }
        
        return r;
    }
}

int AR1020::readByte()
{
    _clk->write(0);
    wait_us(10);
    int r=0;
    for (int i=0;i<8;i++)
    {
        r=r<<1;
        _clk->write(1);
        wait_us(10);
        _clk->write(0);
        wait_us(10);
        int bit=_miso->read();
        r+=bit;
    }
//    printf("<-%i\n",r);
    return r;
}

void AR1020::writeByte(char byte)
{
    _clk->write(0);
    wait_us(10);
//    printf("->0x%x\n",byte);
    for (int i=0;i<8;i++)
    {
        int bit=byte>127;
//        printf("%i",bit);
        _clk->write(1);
        wait_us(10);
        _mosi->write(bit);
        wait_us(10);
        _clk->write(0);
        wait_us(10);
        byte=(char)(byte<<1);

    }
//    printf("\n");
}