PixArt / Mbed 2 deprecated PAT9125_OTS_L476RG

Dependencies:   mbed

pat9125_mbed/pat9125_mbed.cpp

Committer:
pixus_mbed
Date:
2017-10-03
Revision:
0:411244c71423
Child:
4:1cd61816c013
Child:
5:61318505e528

File content as of revision 0:411244c71423:


#include "pat9125_mbed.h"
#define delay(ms) wait_ms(ms)

//define OTS state - X
#define OTS_ROT_NO_CHANGE   0x00
#define OTS_ROT_UP          0x01
#define OTS_ROT_DOWN        0x02

//define downscale factor for rotation of shaft  
#define EXPECTED_COUNT_PER_ROUND    360
#define REAL_AVG_COUNT_PER_ROUND    446 //base on: sensor Reg0x0d=0x65, shaft diameter=2mm, sensor-to-shaft distance=2mm

//define OTS state - Y
#define OTS_BTN_NO_CHANGE   0x00
#define OTS_BTN_RELEASE     0x01
#define OTS_BTN_PRESS       0x02

#define LOW 0
#define HIGH 1
#define digitalRead(pin) *pin

static pat9125_mbed_state_s *gp_state ;

#define PIN_BTN_L       gp_state->pBTN_L
#define PIN_BTN_R       gp_state->pBTN_R
#define PIN_SEN_MOTION  gp_state->pINT

#define PIN_RLED        gp_state->pRLED
#define PIN_GLED        gp_state->pGLED
#define digitalWrite(pin,level) *pin =  level
#define LED_RED_ON      digitalWrite(PIN_RLED,LOW)
#define LED_RED_OFF     digitalWrite(PIN_RLED,HIGH)
#define LED_GREEN_ON    digitalWrite(PIN_GLED,LOW)
#define LED_GREEN_OFF   digitalWrite(PIN_GLED,HIGH)
#define attachInterrupt(pin,b,c)  //pin->enable_irq()
#define digitalPinToInterrupt(pin) pin
#define detachInterrupt(pin)  //pin->disable_irq()
#define LCM_DisplayString_Reset gp_state->pLCM->LCM_DisplayString_Reset
#define LCM_DisplayDecimal(a,b,c,d) gp_state->pLCM->LCM_DisplayDecimal(a,b,c,d)
#define LCM_DisplayString(a,b,c) gp_state->pLCM->LCM_DisplayString(a,b,c)

#define I2C_RESET gp_state->p_i2c = gp_state->p_i2c->reset(); //workaround for nRF51 mbed
        
//for OTS
signed int deltaX16;
signed int deltaY16;
unsigned char OTS_ROT_Status;
unsigned char OTS_BTN_Status;

signed long x_sum=0;
signed long ds_x_sum=0;
signed long pre_dsCountX=0;
unsigned int OTS_BTN_Press_Cnt=0;

volatile unsigned char MotionPinEventTriggered=0;

// Register write function
void OTS_Write_Reg(unsigned char address, unsigned char value) 
{
    int ret ;
    char data_write[2];
    
    data_write[0] = address;
    data_write[1] = value;
    ret = gp_state->p_i2c->write(gp_state->slave_id, data_write, 2, 0);
}

// Register Read function
unsigned char OTS_Read_Reg(unsigned char address)
{
    unsigned char rdata = 0;   
    gp_state->p_i2c->write(gp_state->slave_id, (char *)&address, 1, 0);
    gp_state->p_i2c->read(gp_state->slave_id, (char *)&rdata, 1, 0);

    return(rdata);  
}

// Register write & read back check function
void OTS_WriteRead_Reg(unsigned char address, unsigned char wdata) 
{
    unsigned char rdata;
    do
    {
      OTS_Write_Reg(address, wdata);    // Write data to specified address
      rdata = OTS_Read_Reg(address);    // Read back previous written data
    } while(rdata != wdata);            // Check if the data is correctly written
   
}

boolean OTS_Sensor_Init(void)
{
    unsigned char sensor_pid=0;
    boolean read_id_ok=false;
    
    // Read sensor_pid in address 0x00 to check if the serial link is valid, PID should be 0x31
    sensor_pid = OTS_Read_Reg(0x00);
    if(sensor_pid == 0x31)
    {   
        read_id_ok = true;

    //PAT9125 sensor recommended settings as below:     
        OTS_Write_Reg(0x7F, 0x00);  // switch to bank0, not allowed to perform OTS_WriteRead_Reg
        OTS_Write_Reg(0x06, 0x97); // Software Reset (i.e. set bit7 to 1), then it will reset to 0 automatically

        I2C_RESET;

        delay(1);    // delay 1ms
        OTS_Write_Reg(0x06, 0x17); // ensure the sensor has left the reset state.
    
        OTS_WriteRead_Reg(0x09, 0x5A);  // disable write protect
        OTS_WriteRead_Reg(0x0D, 0x65);  // set X-axis resolution (depends on application)
        OTS_WriteRead_Reg(0x0E, 0xFF);  // set Y-axis resolution (depends on application)
        OTS_WriteRead_Reg(0x19, 0x04);  // set 12-bit X/Y data format (depends on application)
        //OTS_WriteRead_Reg(0x4B, 0x04); // ONLY for VDD=VDDA=1.7~1.9V: for power saving    
        
        if(OTS_Read_Reg(0x5E) == 0x04)
        {
            OTS_WriteRead_Reg(0x5E, 0x08);
            if(OTS_Read_Reg(0x5D) == 0x10)
                OTS_WriteRead_Reg(0x5D, 0x19);
        }
    
        OTS_WriteRead_Reg(0x09, 0x00);  // enable write protect 
    }
    
    return read_id_ok;
} 

// Read motion
void OTS_Read_Motion(signed int *dx16, signed int *dy16) 
{
    int shift = (sizeof(signed int) << 3) - 12 ;
    signed int deltaX_l=0, deltaY_l=0, deltaXY_h=0; 
    signed int deltaX_h=0, deltaY_h=0;    
    char motion = OTS_Read_Reg(0x02) ;
    if(motion & 0x80)   //check motion bit in bit7
    {        
        deltaX_l = OTS_Read_Reg(0x03);
        deltaY_l = OTS_Read_Reg(0x04);                
        deltaXY_h = OTS_Read_Reg(0x12);                                     

        deltaX_h = (deltaXY_h<<4) & 0xF00;
        deltaX_h = (deltaX_h << shift) >> shift ;
        //if(deltaX_h & 0x800)    deltaX_h |= 0xfffff000; // 12-bit data convert to 16-bit 
        
        deltaY_h = (deltaXY_h<<8) & 0xF00;
        //if(deltaY_h & 0x800)    deltaY_h |= 0xfffff000; // 12-bit data convert to 16-bit
        deltaY_h = (deltaY_h << shift) >> shift ;
        
    }
    *dx16 = -(deltaX_h | deltaX_l);                 //inverse the data (depends on sensor's orientation and application)
    *dy16 = -(deltaY_h | deltaY_l);                 //inverse the data (depends on sensor's orientation and application) 
}

void OTS_Reset_Variables(void)
{
    //reset variables
    x_sum=0;
    ds_x_sum=0; 
    pre_dsCountX=0;
    
    OTS_BTN_Press_Cnt=0;
    LCM_DisplayString_Reset();
}

unsigned char Detect_Rotation(signed long dsCountX) 
{
    #define EVENT_NUM_PER_ROUND     360//10
    #define EVENT_COUNT_TH          (EXPECTED_COUNT_PER_ROUND / EVENT_NUM_PER_ROUND)    //360/10=36 //360/360=1

    signed long diff_count = 0;
    unsigned char OutRotState = OTS_ROT_NO_CHANGE;
    
    diff_count = dsCountX - pre_dsCountX;
    if( diff_count >= EVENT_COUNT_TH )
    {
        pre_dsCountX = dsCountX;
        OutRotState = OTS_ROT_UP;
    }
    else if( diff_count <= (-EVENT_COUNT_TH) )
    {
        pre_dsCountX = dsCountX;
        OutRotState = OTS_ROT_DOWN;
    }   
    
    return OutRotState;
}

signed long OTS_Resolution_Downscale(signed int delta_count) 
{       
    x_sum += delta_count;
    return (x_sum * EXPECTED_COUNT_PER_ROUND / REAL_AVG_COUNT_PER_ROUND);
}

unsigned char OTS_Detect_Rotation(signed int dx16, signed int dy16)
{   
    ds_x_sum = OTS_Resolution_Downscale(dx16);
    LCM_DisplayDecimal(1,12,ds_x_sum,4);//show downscale value
    
    return Detect_Rotation(ds_x_sum);
}

unsigned char OTS_Detect_Pressing(signed int dx16, signed int dy16)
{
    #define PRESS           1
    #define RELEASE         0
        
    #define DX_ROTATE_TH    2   
    #define DY_VALID_TH     1
    #define ACCY_PRESS_TH   5   
    #define DY_RELEASE_TH   (-2)        
    
    unsigned char OutBtnState = OTS_BTN_NO_CHANGE;
    static signed long AccY = 0;    
    static unsigned char State = RELEASE; //0:release, 1:press
    
    if((dx16 >= DX_ROTATE_TH)||(dx16 <= (-DX_ROTATE_TH)))
    {
        AccY = 0;   
    }
    else
    {                   
        if(State == PRESS) 
        {
            if(dy16 <= DY_RELEASE_TH)
            {       
                State = RELEASE;    
                OutBtnState = OTS_BTN_RELEASE;  
            }   
        }
        else 
        {
            if(dy16 < DY_VALID_TH)
            {
                AccY = 0;
            }
            else 
            {
                AccY += dy16;           
                if(AccY >= ACCY_PRESS_TH)
                {
                    AccY = 0;
                    State = PRESS;          
                    OutBtnState = OTS_BTN_PRESS;
                }               
            }
        }       
    }   
    
    return OutBtnState;
}

//-----------------------------------------------------------------------
void OTS_MotionPin_ISR(void) 
{
    detachInterrupt(digitalPinToInterrupt(PIN_SEN_MOTION));
    MotionPinEventTriggered=1;  
}

//-----------------------------------------------------------------------
void loop()
{
    
    if(digitalRead(PIN_BTN_L) == LOW)//or reset whenever idle_timer timeout
    {
        OTS_Reset_Variables();
    }
    
    if(MotionPinEventTriggered==1)      
    {
        MotionPinEventTriggered=0;//clear flag after read 'Motion Status and Data'
        OTS_Read_Motion(&deltaX16,&deltaY16);       
        
        if(deltaX16 || deltaY16)
        {
            OTS_ROT_Status = OTS_Detect_Rotation(deltaX16,deltaY16);
            OTS_BTN_Status = OTS_Detect_Pressing(deltaX16,deltaY16);
            
            if(OTS_ROT_Status == OTS_ROT_UP)        
            {
                LED_RED_ON; 
                LCM_DisplayString(1,8,"Up ");
            }
            else if(OTS_ROT_Status == OTS_ROT_DOWN)
            {
                LED_GREEN_ON;   
                LCM_DisplayString(1,8,"Dn ");
            }       
            
            if(OTS_BTN_Status == OTS_BTN_PRESS)
            {
                OTS_BTN_Press_Cnt++;
                if(OTS_BTN_Press_Cnt > 999) 
                {   
                    OTS_BTN_Press_Cnt=0;
                }
                LCM_DisplayString(2,8,"Pre");   
                LCM_DisplayDecimal(2,12,OTS_BTN_Press_Cnt,4);       
            }
            else if(OTS_BTN_Status == OTS_BTN_RELEASE)
            {
                LCM_DisplayString(2,8,"Rel");   
            }
        }
        
        //re-enable interrupt for MOTION pin
        attachInterrupt(digitalPinToInterrupt(PIN_SEN_MOTION), OTS_MotionPin_ISR, LOW);
        
    }

    if(digitalRead(PIN_SEN_MOTION) == HIGH) 
    {
        LED_GREEN_OFF;
        LED_RED_OFF;
    }   
      
}
pat9125_mbed::pat9125_mbed(pat9125_mbed_state_s *state)
{
    gp_state = state ;
    //gp_state->p_pc->printf("PAT9125 ADDR0 %x\n", OTS_Read_Reg(0));      
    gp_state->sen_status = OTS_Sensor_Init(); 
    gp_state->p_pc->printf("OTS_Sensor_Init\n"); 
    gp_state->pINT->fall(&OTS_MotionPin_ISR); //interrupt at low state
}

void pat9125_mbed::task()
{
   if(digitalRead(PIN_SEN_MOTION) == LOW)
   {
        //gp_state->p_pc->printf("Motion Low\n"); 
        MotionPinEventTriggered = 1 ;
    }
    loop();
}