ADNS2051 Optical Sensor library

Revision:
0:462017ee2a5b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ADNS2051.cpp	Wed May 23 06:56:50 2012 +0000
@@ -0,0 +1,328 @@
+/* mbed ADNS2051 Optical Sensor library.
+
+    Copyright (c) 2011 NXP 3787
+ 
+    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 "mbed.h"
+#include "ADNS2051.h"
+
+
+#define SCLK_HIGH    _sclk=1;
+#define SCLK_LOW    _sclk=0;
+//
+#define SOUT_HIGH    _sout=1;
+#define SOUT_LOW    _sout=0;
+//
+#define CLKSPEED_100KHZ      10
+#define CLKSPEED_200KHZ     5
+#define CLKSPEED_500KHZ     2
+#define CLKSPEED_1MHZ       1
+#define CLKSPEED            CLKSPEED_1MHZ
+
+// unsigned char pixmap[256];
+
+ADNS2051::ADNS2051(  PinName sout, PinName sclk) : _sout( sout), _sclk( sclk) {
+
+    _sout.output();
+
+}
+
+/*
+ Init the ADNS 2051 connection. 
+ @return
+    0 = OK
+    1 = BAD connection
+*/
+unsigned char ADNS2051::init( void)
+{
+    // sync the communication line to the ADNS chip
+    sync();
+    // check the connection
+    return ( chkconn());
+    
+    // for now I use the ADNS's default values.
+}
+
+/*
+ * Sync the communication to the ADNS.
+ * Start a sequence, and then wait the watchdog timer expire.
+ * After this sequence the sout and sclk are HIGH and ready to star a correct 
+ * write to or read from the ADNS chip.
+*/
+void ADNS2051::sync( void)
+{
+    // let the data pin as output!
+    _sout.output();
+    // 
+    SOUT_HIGH;
+    SCLK_HIGH;
+    wait_us(100);
+    SCLK_LOW;
+    wait_us(100);
+    SCLK_HIGH;
+    wait_us(100);
+    
+    /* the program wait until the ADNS's serial watchdog timer expire  */
+    wait_ms( 1200);        // Serial Port Transaction Timer [Tsptt] value: 1s (DS pag:10)
+}
+
+/* 
+ Verify the ADNS 2051 connection. 
+ return:
+    0 = OK
+    1 = BAD connection
+*/
+unsigned char ADNS2051::chkconn( void)
+{
+    if ( read( PRODUCTID_REG) == PRODUCTID_VAL)
+        return 0;
+    else
+        return 1;
+}
+
+/* */
+unsigned char ADNS2051::get_productID( void)
+{
+    return read( PRODUCTID_REG);
+}
+
+/* */
+unsigned char ADNS2051::get_revisionID( void)
+{
+    return read( REVISIONID_REG);
+}
+
+/** Change the default frame rate (1500 f/s) to 2300 f/s
+*/
+void ADNS2051::setframerate( void)
+{
+    // write to the lower reg first.
+    // the values are 2's compl hex for 2300 f/s (DS pag:38)
+    write( FRMPRDLW_REG, 0x6E);
+    write( FRMPRDUP_REG, 0xE1);
+}
+
+
+/** Return the SQUAL value.
+ *
+ *  SQUAL is a measure of the number of features visible by the sensor in the
+ *  current frame. The maximum value is 255. Since small changes in the current frame
+ *  can result in changes in SQUAL, variations in SQUAL when looking at a surface are
+ *  expected. SQUAL is nearly equal to zero, if there is no surface below the sensor.
+*/
+unsigned char ADNS2051::surfacequality( void)
+{
+    return read( SQUAL_REG);
+}
+
+/** Return the Average pixel value
+ * 
+ *  Average Pixel value in current frame. Minimum value = 0,
+ *  maximum = 63. The average pixel value can be adjusted every frame.
+*/
+unsigned char ADNS2051::averagepixel( void)
+{
+    return read( AVRPXL_REG);
+}
+
+/** Return the Maximum Pixel value
+ *
+ *  Maximum Pixel value in current frame. Minimum value = 0,
+ *  maximum value = 63. The maximum pixel value can be adjusted every frame.
+*/
+unsigned char ADNS2051::maxpixelval( void)
+{
+    return read( MAXPXL_REG);
+}
+
+
+/**
+ * read the motion register and update the deltaX and deltaY variable with the register value
+ * 
+ * @return :
+ *   value 0 => no motion, no led fault, no overflow
+ *   bit 0 == 1 => motion
+ *   bit 1 == 1 => led fault
+ *   bit 3 == 1 => overflow
+*/
+unsigned char ADNS2051::readmotion( void)
+{
+    unsigned char status;
+    unsigned char res=0;        // no motion, no LED fault...
+    
+    // Avago RECOMMENDS that registers 0x02, 0x03 and 0x04 be read sequentially
+    status = read( MOTION_REG);
+    deltaX = read( DELTAX_REG);
+    deltaY = read( DELTAY_REG);
+    
+    // 
+    if ( status & (1<<OVERFY_BIT) || status & (1<<OVERFX_BIT) ) {
+        res|=4;
+    }
+    //
+    if ( status & (1<<RESOLUTION_BIT) )
+        currentresolution=800;
+    else
+        currentresolution=400;
+    //
+    if ( status & (1<<MOTION_BIT) )
+        res|=1;
+    if ( status & (1<<LEDFAULT_BIT) )
+        res|=2;
+    
+    return( res);
+}
+
+/*
+ Start the dump of the pixel map. Store the value to the array pixmap
+*/
+void ADNS2051::pixeldump( unsigned char *buffer)
+{
+
+    unsigned char res;
+    unsigned char i;
+    
+    // set no sleep and start pixdump
+    write( CONFIGBIT_REG, 0x00 | (1<<SLEEP_BIT) | (1<<PIXDUMP_BIT));
+    
+    i=0;
+    while( 1) {
+        // read the pix address...
+        res=read( DTOUTUP_REG);
+        // read the pix value
+        res=read( DTOUTLW_REG);
+        // if the MSB is set: no valid data...
+        if ( res & (1<<PIXDATAVALID_BIT))
+            continue;
+        // store the pix value
+        buffer[i++]=res;
+        // check if the pixel counter overflow...
+        if ( i==0)
+            break;
+    }
+    
+    // reset PixDump bit.
+    write( CONFIGBIT_REG, 0x00);
+
+}
+
+
+/* 
+ * Read a register from the ADNS2051 sensor.
+ * Before to return wait 120us as required and set the IO pin as output.
+*/
+unsigned char ADNS2051::read(unsigned char address)
+{
+    unsigned char value;
+    int bit_pos;
+    
+    SCLK_HIGH;                 // Set the clock high. 
+    address &= 0x7F;         // A '0' as its MSB to indicate data direction as "READ".
+ 
+    /* Send the Address to the ADNS2051 */
+    for( bit_pos=7; bit_pos >=0; bit_pos--){
+        SCLK_LOW;                  // Set the clock LOW
+                                
+        // SDIO is changed on falling edges of SCLK
+        if(address & (1<<bit_pos)){
+            SOUT_HIGH;
+        }
+        else{
+            SOUT_LOW;
+        }
+        //
+        wait_us( CLKSPEED);
+        SCLK_HIGH;
+        wait_us( CLKSPEED);
+    }
+    /* 
+     SCLK will need to be delayed after the last address data bit to ensure that 
+     the ADNS-2051 has at least 100 µs to prepare the requested data (DS pag.19)
+    */
+    wait_us(120);
+    // Change the sout to input...
+    _sout.input();
+    _sout.mode( PullUp);
+    
+    /* Read the data byte from the ADNS2051 */
+    value=0;
+    for( bit_pos=7; bit_pos >= 0; bit_pos--){
+        SCLK_LOW;
+        wait_us( CLKSPEED);
+        SCLK_HIGH;            // data is ready on rising edge of clock signal.
+        wait_us( CLKSPEED);
+        /* read the input pin */
+        if ( _sout)
+            value |= (1<<bit_pos);
+
+    }
+    //
+    _sout.output();
+    // Timing between read and either write or subsequent read commands must be >120us
+    wait_us( 120);
+    
+    return value;
+}    
+
+void ADNS2051::write(unsigned char address, unsigned char value)
+{
+    int bit_pos;
+    
+    SCLK_HIGH;                 // Set the clock high. 
+    address |= 0x80;         // A '1' as its MSB to indicate data direction as "WRITE".
+
+    /* Send the Address to the ADNS2051 */
+    for( bit_pos=7; bit_pos >=0; bit_pos--){
+        SCLK_LOW;                  // Set the clock LOW
+                                
+        // SDIO is changed on falling edges of SCLK
+        if(address & (1<<bit_pos)){
+            SOUT_HIGH;
+        }
+        else{
+            SOUT_LOW;
+        }
+        //
+        wait_us( CLKSPEED);
+        SCLK_HIGH;
+        wait_us( CLKSPEED);
+    }
+
+    /* Send the value to the ADNS2051 */
+    for( bit_pos=7; bit_pos >=0; bit_pos--){
+        SCLK_LOW;                  // Set the clock LOW
+                                
+        // SDIO is changed on falling edges of SCLK
+        if(value & (1<<bit_pos)){
+            SOUT_HIGH;
+        }
+        else{
+            SOUT_LOW;
+        }
+        //
+        wait_us( CLKSPEED);
+        SCLK_HIGH;
+        wait_us( CLKSPEED);
+    }
+    // Timing between read and either write or subsequent read commands must be >120us
+    wait_us( 120);
+
+}