Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed
Diff: pat9125_mbed/pat9125_mbed.cpp
- Revision:
- 0:411244c71423
- Child:
- 4:1cd61816c013
- Child:
- 5:61318505e528
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pat9125_mbed/pat9125_mbed.cpp Tue Oct 03 07:26:38 2017 +0000 @@ -0,0 +1,336 @@ + +#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(); +} \ No newline at end of file