Initial Release of Library for PAT9125 OTS on L476RG Platform

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
pixus_mbed
Date:
Tue Oct 03 07:26:38 2017 +0000
Child:
1:73967d37f487
Commit message:
1st version : OTS, LCM and Serial output are work.

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
pat9125_mbed/pat9125_i2c.cpp Show annotated file Show diff for this revision Revisions of this file
pat9125_mbed/pat9125_i2c.h Show annotated file Show diff for this revision Revisions of this file
pat9125_mbed/pat9125_mbed.cpp Show annotated file Show diff for this revision Revisions of this file
pat9125_mbed/pat9125_mbed.h Show annotated file Show diff for this revision Revisions of this file
pixart_lcm/pixart_lcm.cpp Show annotated file Show diff for this revision Revisions of this file
pixart_lcm/pixart_lcm.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Oct 03 07:26:38 2017 +0000
@@ -0,0 +1,95 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mbed.h"
+#include "pixart_lcm.h"
+#include "pat9125_i2c.h"
+#include "pat9125_mbed.h"
+
+pat9125_mbed_state_s g_pat9125_mbed_state ;
+pat9125_mbed *gp_pat9125_mbed ;
+pixart_lcm *gp_pixart_lcm ;
+
+
+Serial  pc(USBTX, USBRX);
+//DigitalIn sdaDummy(I2C_SDA0, PullUp);
+//DigitalIn sclDummy(I2C_SCL0, PullUp);
+pat9125_i2c *gp_pat9125_i2c;//(I2C_SDA0, I2C_SCL0);
+SPI spi(SPI_PSELMOSI0, NC, SPI_PSELSCK0);
+
+DigitalOut PIN_LCM_CSB(SPI_PSELSS0);
+DigitalOut PIN_LCM_RSTB(p20);
+DigitalOut PIN_LCM_RS(p23);
+
+InterruptIn PIN_SEN_MOTION(p15);
+DigitalIn motionDummy(p15, PullUp);
+DigitalIn PIN_BTN_L(p1);
+DigitalIn PIN_BTN_R(p2);
+
+DigitalOut PIN_GLED(p14);
+DigitalOut PIN_RLED(p17);
+#define I2C_ADDRESS    0x73
+
+//-----------------------------------------------------------------------
+int main(void)
+{
+    char addr = 0;
+    char data ;
+    pc.set_flow_control(SerialBase::Disabled) ;
+    pc.baud(115200);
+    pc.printf("---------- Pixart PAT9125 Demo\n");  
+
+    // +++++++ LCM Initialization +++++++ //
+    // Chip must be deselected
+    PIN_LCM_CSB = 1 ;
+
+    // Setup the spi for 8 bit data, high steady state clock,
+    // second edge capture, with a 1MHz clock rate
+    spi.format(8,3);
+    spi.frequency(1000000);
+    gp_pixart_lcm = new pixart_lcm(&spi, &PIN_LCM_CSB, &PIN_LCM_RSTB, &PIN_LCM_RS) ;
+    // ------- LCM Initialization ------- //
+    
+    // +++++++ PAT9125 Initialization +++++++ //
+    gp_pat9125_i2c = new pat9125_i2c();
+    gp_pat9125_i2c->frequency(400000); 
+    g_pat9125_mbed_state.p_i2c = gp_pat9125_i2c;
+    g_pat9125_mbed_state.p_pc = &pc;
+    g_pat9125_mbed_state.pBTN_L = &PIN_BTN_L ;
+    g_pat9125_mbed_state.pBTN_R = &PIN_BTN_R ;
+    g_pat9125_mbed_state.pINT = &PIN_SEN_MOTION;
+    g_pat9125_mbed_state.pRLED = &PIN_RLED;
+    g_pat9125_mbed_state.pGLED = &PIN_GLED;
+    g_pat9125_mbed_state.pLCM = gp_pixart_lcm;    
+    g_pat9125_mbed_state.slave_id = (I2C_ADDRESS << 1);
+    g_pat9125_mbed_state.sen_status = 0;
+    
+    gp_pat9125_mbed = new pat9125_mbed(&g_pat9125_mbed_state) ;        
+    gp_pixart_lcm->LCM_DisplayString_Boot(g_pat9125_mbed_state.sen_status);
+    
+    if(g_pat9125_mbed_state.sen_status == true) 
+    {
+        pc.printf("Initial Sensor ... Done\n");
+    }
+    else    
+    {
+        pc.printf("Initial Sensor ... Fail\n");
+    }
+    while(true)
+    {
+      gp_pat9125_mbed->task();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Tue Oct 03 07:26:38 2017 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/675da3299148
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pat9125_mbed/pat9125_i2c.cpp	Tue Oct 03 07:26:38 2017 +0000
@@ -0,0 +1,20 @@
+#include "pat9125_i2c.h"
+
+static pat9125_i2c *_self ;
+static PinName _sda ;
+static PinName _scl ;
+
+
+pat9125_i2c::pat9125_i2c(PinName sda, PinName scl) : I2C(sda, scl) 
+{
+    _self = this ;
+    _sda = sda ,
+    _scl = scl ;
+}
+
+pat9125_i2c* pat9125_i2c::reset() 
+{
+   delete _self ;
+   _self = new pat9125_i2c(_sda, _scl);
+   return _self ;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pat9125_mbed/pat9125_i2c.h	Tue Oct 03 07:26:38 2017 +0000
@@ -0,0 +1,13 @@
+#ifndef PAT9125_I2C_H
+#define PAT9125_I2C_H
+#include "stdint.h"
+#include "mbed.h"
+
+class pat9125_i2c : public I2C
+{
+    public:           
+        pat9125_i2c(PinName sda = I2C_SDA0, PinName scl = I2C_SCL0);
+        static pat9125_i2c * reset() ;
+};
+
+#endif
\ No newline at end of file
--- /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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pat9125_mbed/pat9125_mbed.h	Tue Oct 03 07:26:38 2017 +0000
@@ -0,0 +1,30 @@
+#ifndef PAT9125_MBED_H
+#define PAT9125_MBED_H
+#include "stdint.h"
+#include "mbed.h"
+#include "pat9125_i2c.h"
+#include "pixart_lcm.h"
+
+typedef uint8_t boolean;
+typedef struct
+{
+    pat9125_i2c         *p_i2c;
+    Serial              *p_pc ;
+    DigitalIn           *pBTN_L ;
+    DigitalIn           *pBTN_R ;
+    InterruptIn         *pINT ;
+    DigitalOut          *pRLED ;
+    DigitalOut          *pGLED ;
+    pixart_lcm          *pLCM ;    
+    uint8_t             slave_id ;
+    boolean             sen_status ;
+} pat9125_mbed_state_s;
+
+class pat9125_mbed
+{
+    public:           
+        pat9125_mbed(pat9125_mbed_state_s *state) ;
+        void task() ;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pixart_lcm/pixart_lcm.cpp	Tue Oct 03 07:26:38 2017 +0000
@@ -0,0 +1,231 @@
+#include "pixart_lcm.h"
+
+
+
+typedef struct
+{
+    SPI                *pSPI ;
+    DigitalOut          *pCSB;
+    DigitalOut          *pRSTB;
+    DigitalOut          *pRS;
+} pixart_lcm_state_s;
+
+static pixart_lcm_state_s g_state ;
+
+
+#define LOW 0
+#define HIGH 1
+#define PIN_LCM_RS      g_state.pRS
+#define PIN_LCM_RSTB    g_state.pRSTB
+#define PIN_LCM_CSB     g_state.pCSB
+#define digitalWrite(pin,level) *pin =  level
+#define LCM_RS_LO       digitalWrite(PIN_LCM_RS,LOW)        
+#define LCM_RS_HI       digitalWrite(PIN_LCM_RS,HIGH)   
+#define LCM_RSTB_LO     digitalWrite(PIN_LCM_RSTB,LOW)
+#define LCM_RSTB_HI     digitalWrite(PIN_LCM_RSTB,HIGH)
+#define LCM_CSB_LO      digitalWrite(PIN_LCM_CSB,LOW)
+#define LCM_CSB_HI      digitalWrite(PIN_LCM_CSB,HIGH)
+
+#define I2C_ADDRESS    (0x73 << 1)
+#define delayMicroseconds(us) wait_us(us)
+#define delay(ms) wait_ms(ms)
+
+//-----------------------------------------------------------------------
+unsigned char hex2dec_nibble(unsigned char hex_nibble)
+{
+    unsigned char dec;
+
+    switch(hex_nibble)
+    {
+    case 0xA: dec=10;   break;
+    case 0xB: dec=11;   break;
+    case 0xC: dec=12;   break;
+    case 0xD: dec=13;   break;
+    case 0xE: dec=14;   break;
+    case 0xF: dec=15;   break;
+    default:    dec=hex_nibble; break;
+    }
+    
+    return (dec);
+}
+
+unsigned int hex2dec_word(unsigned int hex_word)
+{
+    unsigned char dec_nb[4];
+    unsigned char nibble3=(hex_word>>12)&0x000f;
+    unsigned char nibble2=(hex_word>>8)&0x000f;
+    unsigned char nibble1=(hex_word>>4)&0x000f;
+    unsigned char nibble0=hex_word&0x000f;
+
+    dec_nb[3]=hex2dec_nibble(nibble3);
+    dec_nb[2]=hex2dec_nibble(nibble2);
+    dec_nb[1]=hex2dec_nibble(nibble1);
+    dec_nb[0]=hex2dec_nibble(nibble0);
+    return ((dec_nb[3]<<12)+(dec_nb[2]<<8)+(dec_nb[1]<<4)+dec_nb[0]);
+}
+
+void LCM_WriteCom(unsigned char Command)
+{
+    LCM_CSB_LO;
+    LCM_RS_LO;
+    //SPI.transfer(Command);
+    g_state.pSPI->write(Command);
+    LCM_CSB_HI;
+
+    delayMicroseconds(30);
+}
+
+void LCM_WriteData(unsigned char Ascii)
+{
+    LCM_CSB_LO;
+    LCM_RS_HI;
+    //SPI.transfer(Ascii);
+    g_state.pSPI->write(Ascii);
+    LCM_CSB_HI;
+    
+    delayMicroseconds(30); 
+}
+
+void LCM_Init(void)
+{
+    LCM_RSTB_LO;
+    delay(3);
+    LCM_RSTB_HI;
+    delay(20);
+    LCM_WriteCom(0x30); //wake up
+    delay(3);
+    LCM_WriteCom(0x30); //wake up
+    LCM_WriteCom(0x30); //wake up   
+    LCM_WriteCom(0x39); //function set
+    LCM_WriteCom(0x14); //internal osc frequency
+    LCM_WriteCom(0x56); //Contrast set
+    LCM_WriteCom(0x6D); //follower control
+    LCM_WriteCom(0x75); //contrast//
+    LCM_WriteCom(0x0C); //display on
+    LCM_WriteCom(0x06); //entry mode
+    LCM_WriteCom(0x01); //clear
+    
+    delay(10);
+}
+
+void LCM_Clear(void)
+{
+    LCM_WriteCom(0x01);
+
+    delay(2);
+}
+
+void LCM_SetPosition(unsigned char line, unsigned char position)//line=1 or 2; position=1~16
+{
+    unsigned char address;
+    
+    address = ((line-1) * 0x40) + (position-1);
+    address = 0x80 + (address & 0x7F);
+    
+    LCM_WriteCom(address);
+}
+
+void LCM_DisplayString(unsigned char line, unsigned char position, const char *ptr)
+{
+    LCM_SetPosition(line,position);
+    
+    while (*ptr)  
+    {
+            LCM_WriteData(*ptr++);
+    }
+}
+
+void LCM_DisplayDecimal(unsigned char line, unsigned char position, unsigned int hex_word, unsigned char digits)
+{
+    unsigned char sign;//0:positive, 1:negative
+    unsigned int dec_num;
+    unsigned char digit[5];
+    signed char ii;
+    
+    if(hex_word & 0x8000)   
+        sign=1;
+    else    
+        sign=0;
+
+    if(sign==1) 
+        hex_word=~hex_word+1;
+
+    dec_num=hex2dec_word(hex_word);
+    digit[4]=dec_num/10000;
+    digit[3]=(dec_num%10000)/1000;
+    digit[2]=(dec_num%1000)/100;
+    digit[1]=(dec_num%100)/10;
+    digit[0]=dec_num%10;
+
+    LCM_SetPosition(line,position);
+
+    if(sign==1) 
+        LCM_WriteData('-');
+    else
+        LCM_WriteData('+');
+
+    for(ii=(digits-1);ii>=0;ii--)
+    {
+        LCM_WriteData(digit[ii] | 0x30);//decimal to ascii
+    }
+
+}
+
+void LCM_ClearLine(unsigned char line)//    line: 1 or 2
+{
+    LCM_DisplayString(line,1,"                ");
+}
+
+void LCM_DisplayString_Reset(void)
+{
+  LCM_DisplayString(1,1,"SHAFT"); LCM_DisplayString(1,8,"U/D");LCM_DisplayDecimal(1,12,0x000,4);
+  LCM_DisplayString(2,1,"SPRING");LCM_DisplayString(2,8,"P/R");LCM_DisplayDecimal(2,12,0x000,4);    
+}
+
+void LCM_DisplayString_Boot(boolean sen_status)
+{
+  LCM_DisplayString(1,1,"PixArt Shaft EVK");    
+  LCM_DisplayString(2,1,"PAT9125 FW V2.30");
+  delay(2000);
+  
+  LCM_ClearLine(1);
+  LCM_ClearLine(2);
+  
+  if(sen_status == true)
+  {
+    LCM_DisplayString_Reset();
+  }
+  else
+  {
+    LCM_DisplayString(2,1,"Read Sensor Fail");
+  }
+}
+
+//-----------------------------------------------------------------------
+
+pixart_lcm::pixart_lcm(SPI *pSPI, DigitalOut *pCSB, DigitalOut *pRSTB, DigitalOut *pRS)
+{
+    g_state.pSPI = pSPI;
+    g_state.pCSB = pCSB;
+    g_state.pRSTB = pRSTB;
+    g_state.pRS = pRS;
+    *g_state.pRS =  1;
+    LCM_Init();
+}
+
+void pixart_lcm::LCM_DisplayString(unsigned char line, unsigned char position, const char *ptr)
+{
+    ::LCM_DisplayString(line, position, ptr);
+}
+void pixart_lcm::LCM_DisplayDecimal(unsigned char line, unsigned char position, unsigned int hex_word, unsigned char digits)
+{
+    ::LCM_DisplayDecimal(line, position, hex_word, digits);
+}
+void pixart_lcm::LCM_DisplayString_Reset(void)
+{
+    ::LCM_DisplayString_Reset();
+}
+void pixart_lcm::LCM_DisplayString_Boot(boolean sen_status)
+{    
+    ::LCM_DisplayString_Boot(sen_status);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pixart_lcm/pixart_lcm.h	Tue Oct 03 07:26:38 2017 +0000
@@ -0,0 +1,20 @@
+#ifndef PIXART_LCM_H
+#define PIXART_LCM_H
+
+#include "stdint.h"
+#include "mbed.h"
+
+typedef uint8_t boolean ;
+
+class pixart_lcm
+{
+    public:           
+
+        pixart_lcm(SPI *pSPI, DigitalOut *pCSB, DigitalOut *pRSTB, DigitalOut *pRS) ;
+        void LCM_DisplayString(unsigned char line, unsigned char position, const char *ptr) ;
+        void LCM_DisplayDecimal(unsigned char line, unsigned char position, unsigned int hex_word, unsigned char digits) ;
+        void LCM_DisplayString_Reset(void);
+        void LCM_DisplayString_Boot(boolean sen_status);
+
+};
+#endif