ADNS2051 Optical Sensor library

Files at this revision

API Documentation at this revision

Comitter:
clemente
Date:
Wed May 23 06:56:50 2012 +0000
Commit message:

Changed in this revision

ADNS2051.cpp Show annotated file Show diff for this revision Revisions of this file
ADNS2051.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 462017ee2a5b ADNS2051.cpp
--- /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);
+
+}    
diff -r 000000000000 -r 462017ee2a5b ADNS2051.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ADNS2051.h	Wed May 23 06:56:50 2012 +0000
@@ -0,0 +1,230 @@
+/* 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.
+*/
+
+#ifndef __ADNS2051_H
+#define __ADNS2051_H
+
+#include "mbed.h"
+
+
+//
+#define PRODUCTID_REG    0x00    // Product ID = 2 (Fixed value)
+#define REVISIONID_REG    0x01    // Revision of IC [0xNN]
+#define MOTION_REG        0x02    // Register 0x02 allows the user to determine if motion has occurred since the last time it was read
+#define DELTAX_REG        0x03    // X movement is counts since last report. Absolute value is determined by resolution. Reading clears the register.
+#define DELTAY_REG        0x04    // Y movement is counts since last report. Absolute value is determined by resolution. Reading clears the register.
+#define SQUAL_REG        0x05    // Surface Quality. 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.
+#define AVRPXL_REG        0x06    // Average Pixel value in current frame. Minimum value = 0, maximum = 63. The average pixel value can be adjusted every frame.
+#define MAXPXL_REG        0x07    // Maximum Pixel value in current frame. Minimum value = 0, maximum value = 63. The maximum pixel value can be adjusted every frame.
+#define CONFIGBIT_REG    0x0A    // Configuration bits. Register 0x0a allows the user to change the configuration of the sensor.
+#define DTOUTLW_REG        0x0C    
+#define DTOUTUP_REG        0x0D    // Once the pixel dump command is given, the sensor
+                                // writes the address and the value for the first pixel into
+                                // the Data_Out_Upper and Data_Out_Lower registers.
+#define SHUTTERLW_REG    0x0E    
+#define SHUTTERUP_REG    0x0F    // Shutter register.
+#define FRMPRDLW_REG    0x10
+#define FRMPRDUP_REG    0x11    // The frame period counter counts up until it overflows. Units are clock cycles.
+
+// Motion register bits
+#define MOTION_BIT        0x07    // Motion since last report: 0=no motion, 1=motion occurred, data ready on deltaX and Y regs.
+#define LEDFAULT_BIT    0x05    // LED Fault detected: 0=no, 1=Fault detected
+#define OVERFY_BIT        0x04    // Motion overflow Y, dY buffer has overflowed since last report: 0=no, 1=overflow
+#define OVERFX_BIT        0x03    // Motion overflow X, dX buffer has overflowed since last report: 0=no, 1=overflow
+#define RESOLUTION_BIT    0x00    // Resolution in counts x inch: 0=400, 1=800
+
+// Confiuration register bits
+#define RESET_BIT        0x07
+#define LEDMODE_BIT        0x06
+#define RESOLMODE_BIT    0x04
+#define PIXDUMP_BIT        0x03
+#define SLEEP_BIT        0x00
+
+//
+#define PIXDATAVALID_BIT    0x07
+
+// Product ID value
+#define PRODUCTID_VAL    0x02    // The value in this register does not change, it can be used to verify that the
+                                // serial communications link is OK.
+
+/** ADNS2051 Optical Sensor
+* For this project I used an old Apple mouse. 
+* Obviously modified for this project has made it unusable as a mouse for the PC.
+*
+* From the datasheet:
+*   The ADNS-2051 is a low cost optical sensor used to
+*   implement a non-mechanical tracking engine for
+*   computer mice.
+*   It is based on optical navigation technology, which
+*   measures changes in position by optically acquiring
+*   sequential surface images (frames) and mathematically
+*   determining the direction and magnitude of
+*   movement.
+*   The sensor is housed in a 16-pin staggered dual inline
+*   package (DIP).
+*   
+*   Features
+*   . Precise optical navigation technology
+*   . No mechanical moving parts
+*   . Complete 2D motion sensor
+*   . Serial interface and/or quadrature interface
+*   . Smooth surface navigation
+*   . Programmable frame speed up to 2300 frames per sec (fps)
+*   . Accurate motion up to 14 ips
+*   . 800 cpi resolution
+*   . High reliability
+*   . High speed motion detector
+*   . No precision optical alignment
+*   . On chip LED drive with regulated current
+*   . Serial port registers
+*   – Programming
+*   – Data transfer
+*
+* Example code
+*
+* @code
+* #include "ADNS2051.h"
+*
+* // pin configuration: p19: sout, p20: sclk
+* ADNS2051 optical( p19, p20);
+*
+* // image buffer 
+* unsigned char tmpmap[256];
+*
+* int main( void)
+* {
+*   printf( "Images from optical mouse: Init");
+*   
+*   // wait until the ADNS chip become ready...
+*   while( optical.init() );
+*   
+*   optical.setframerate();
+*   
+*   printf("Images from optical mouse: PixelDump [Chip rev: 0x%X]", optical.get_revisionID());
+*   wait( 1.0);
+*   
+*   optical.pixeldump( &tmpmap[0]);
+*   // may be... do something with tmpmap...
+*   while(1);
+*   
+* }
+*/
+
+class ADNS2051 {
+
+public:
+    /** ADNS2051 pin assignement.
+     * 
+     * @param sout  This pin is used as data in and data out.
+     * @param sclk  This is the serial clock.
+     */
+    ADNS2051(  PinName sout, PinName sclk);
+    
+    /** Initialize the ADNS2051 chip.
+     *
+     * @param none
+     * @return 0 for OK, 1 for bad.
+     */
+    unsigned char init( void);
+    
+    /** Read the motion register and update the deltaX and deltaY variable with the register value.
+     *
+     * @param none
+     * @return a byte 0 = no motion, no led fault, no overflow
+     *                1 =  motion
+     *                2 =  led fault
+     *                4 =  overflow
+     */
+    unsigned char readmotion( void);
+    
+    /** Get revision ID
+     */
+    unsigned char get_revisionID( void);
+    
+    /** Get product ID
+     */
+    unsigned char get_productID( void);
+    
+    /**  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.
+     *
+     * @param the SQUAL value.
+     */
+    unsigned char surfacequality( void);
+    
+    /** Average Pixel value in current frame. Minimum value = 0,
+     *  maximum = 63. The average pixel value can be adjusted every frame.
+     *
+     * @param none
+     */
+    unsigned char averagepixel( void);
+    
+    /** Maximum Pixel value in current frame. Minimum value = 0,
+     *  maximum value = 63. The maximum pixel value can be adjusted every frame.
+     *
+     * @param none     
+     */
+    unsigned char maxpixelval( void);
+    
+    /** Change the default frame rate (1500 f/s) to 2300 f/s
+     *
+     * @param none     
+     */    
+    void setframerate( void);
+    
+    /** Verify the ADNS 2051 connection. 
+     *
+     * @param none
+     * @return 0 OK, 1 Bad connection
+     */
+    unsigned char chkconn( void);
+    
+    /** Start the dump of the pixel map. Store the value to the array pixmap
+     *
+     * @param buffer array of 256 chars
+     */
+    void pixeldump( unsigned char *buffer);
+    
+    /** this values are updates every readmotion call.
+     */
+    signed char deltaX, deltaY;
+    
+    /** This value is the current resolution in count per inch. Can be 400 or 800 cpi
+     */
+    unsigned int currentresolution;
+    
+private:
+    void sync( void);
+    unsigned char read(unsigned char address);
+    void write(unsigned char address, unsigned char value);
+    //
+    DigitalInOut _sout;
+    DigitalOut _sclk;
+    
+};
+
+#endif