ADNS2051 Optical Sensor library

Committer:
clemente
Date:
Wed May 23 06:56:50 2012 +0000
Revision:
0:462017ee2a5b

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
clemente 0:462017ee2a5b 1 /* mbed ADNS2051 Optical Sensor library.
clemente 0:462017ee2a5b 2
clemente 0:462017ee2a5b 3 Copyright (c) 2011 NXP 3787
clemente 0:462017ee2a5b 4
clemente 0:462017ee2a5b 5 Permission is hereby granted, free of charge, to any person obtaining a copy
clemente 0:462017ee2a5b 6 of this software and associated documentation files (the "Software"), to deal
clemente 0:462017ee2a5b 7 in the Software without restriction, including without limitation the rights
clemente 0:462017ee2a5b 8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
clemente 0:462017ee2a5b 9 copies of the Software, and to permit persons to whom the Software is
clemente 0:462017ee2a5b 10 furnished to do so, subject to the following conditions:
clemente 0:462017ee2a5b 11
clemente 0:462017ee2a5b 12 The above copyright notice and this permission notice shall be included in
clemente 0:462017ee2a5b 13 all copies or substantial portions of the Software.
clemente 0:462017ee2a5b 14
clemente 0:462017ee2a5b 15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
clemente 0:462017ee2a5b 16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
clemente 0:462017ee2a5b 17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
clemente 0:462017ee2a5b 18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
clemente 0:462017ee2a5b 19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
clemente 0:462017ee2a5b 20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
clemente 0:462017ee2a5b 21 THE SOFTWARE.
clemente 0:462017ee2a5b 22 */
clemente 0:462017ee2a5b 23
clemente 0:462017ee2a5b 24 #include "mbed.h"
clemente 0:462017ee2a5b 25 #include "ADNS2051.h"
clemente 0:462017ee2a5b 26
clemente 0:462017ee2a5b 27
clemente 0:462017ee2a5b 28 #define SCLK_HIGH _sclk=1;
clemente 0:462017ee2a5b 29 #define SCLK_LOW _sclk=0;
clemente 0:462017ee2a5b 30 //
clemente 0:462017ee2a5b 31 #define SOUT_HIGH _sout=1;
clemente 0:462017ee2a5b 32 #define SOUT_LOW _sout=0;
clemente 0:462017ee2a5b 33 //
clemente 0:462017ee2a5b 34 #define CLKSPEED_100KHZ 10
clemente 0:462017ee2a5b 35 #define CLKSPEED_200KHZ 5
clemente 0:462017ee2a5b 36 #define CLKSPEED_500KHZ 2
clemente 0:462017ee2a5b 37 #define CLKSPEED_1MHZ 1
clemente 0:462017ee2a5b 38 #define CLKSPEED CLKSPEED_1MHZ
clemente 0:462017ee2a5b 39
clemente 0:462017ee2a5b 40 // unsigned char pixmap[256];
clemente 0:462017ee2a5b 41
clemente 0:462017ee2a5b 42 ADNS2051::ADNS2051( PinName sout, PinName sclk) : _sout( sout), _sclk( sclk) {
clemente 0:462017ee2a5b 43
clemente 0:462017ee2a5b 44 _sout.output();
clemente 0:462017ee2a5b 45
clemente 0:462017ee2a5b 46 }
clemente 0:462017ee2a5b 47
clemente 0:462017ee2a5b 48 /*
clemente 0:462017ee2a5b 49 Init the ADNS 2051 connection.
clemente 0:462017ee2a5b 50 @return
clemente 0:462017ee2a5b 51 0 = OK
clemente 0:462017ee2a5b 52 1 = BAD connection
clemente 0:462017ee2a5b 53 */
clemente 0:462017ee2a5b 54 unsigned char ADNS2051::init( void)
clemente 0:462017ee2a5b 55 {
clemente 0:462017ee2a5b 56 // sync the communication line to the ADNS chip
clemente 0:462017ee2a5b 57 sync();
clemente 0:462017ee2a5b 58 // check the connection
clemente 0:462017ee2a5b 59 return ( chkconn());
clemente 0:462017ee2a5b 60
clemente 0:462017ee2a5b 61 // for now I use the ADNS's default values.
clemente 0:462017ee2a5b 62 }
clemente 0:462017ee2a5b 63
clemente 0:462017ee2a5b 64 /*
clemente 0:462017ee2a5b 65 * Sync the communication to the ADNS.
clemente 0:462017ee2a5b 66 * Start a sequence, and then wait the watchdog timer expire.
clemente 0:462017ee2a5b 67 * After this sequence the sout and sclk are HIGH and ready to star a correct
clemente 0:462017ee2a5b 68 * write to or read from the ADNS chip.
clemente 0:462017ee2a5b 69 */
clemente 0:462017ee2a5b 70 void ADNS2051::sync( void)
clemente 0:462017ee2a5b 71 {
clemente 0:462017ee2a5b 72 // let the data pin as output!
clemente 0:462017ee2a5b 73 _sout.output();
clemente 0:462017ee2a5b 74 //
clemente 0:462017ee2a5b 75 SOUT_HIGH;
clemente 0:462017ee2a5b 76 SCLK_HIGH;
clemente 0:462017ee2a5b 77 wait_us(100);
clemente 0:462017ee2a5b 78 SCLK_LOW;
clemente 0:462017ee2a5b 79 wait_us(100);
clemente 0:462017ee2a5b 80 SCLK_HIGH;
clemente 0:462017ee2a5b 81 wait_us(100);
clemente 0:462017ee2a5b 82
clemente 0:462017ee2a5b 83 /* the program wait until the ADNS's serial watchdog timer expire */
clemente 0:462017ee2a5b 84 wait_ms( 1200); // Serial Port Transaction Timer [Tsptt] value: 1s (DS pag:10)
clemente 0:462017ee2a5b 85 }
clemente 0:462017ee2a5b 86
clemente 0:462017ee2a5b 87 /*
clemente 0:462017ee2a5b 88 Verify the ADNS 2051 connection.
clemente 0:462017ee2a5b 89 return:
clemente 0:462017ee2a5b 90 0 = OK
clemente 0:462017ee2a5b 91 1 = BAD connection
clemente 0:462017ee2a5b 92 */
clemente 0:462017ee2a5b 93 unsigned char ADNS2051::chkconn( void)
clemente 0:462017ee2a5b 94 {
clemente 0:462017ee2a5b 95 if ( read( PRODUCTID_REG) == PRODUCTID_VAL)
clemente 0:462017ee2a5b 96 return 0;
clemente 0:462017ee2a5b 97 else
clemente 0:462017ee2a5b 98 return 1;
clemente 0:462017ee2a5b 99 }
clemente 0:462017ee2a5b 100
clemente 0:462017ee2a5b 101 /* */
clemente 0:462017ee2a5b 102 unsigned char ADNS2051::get_productID( void)
clemente 0:462017ee2a5b 103 {
clemente 0:462017ee2a5b 104 return read( PRODUCTID_REG);
clemente 0:462017ee2a5b 105 }
clemente 0:462017ee2a5b 106
clemente 0:462017ee2a5b 107 /* */
clemente 0:462017ee2a5b 108 unsigned char ADNS2051::get_revisionID( void)
clemente 0:462017ee2a5b 109 {
clemente 0:462017ee2a5b 110 return read( REVISIONID_REG);
clemente 0:462017ee2a5b 111 }
clemente 0:462017ee2a5b 112
clemente 0:462017ee2a5b 113 /** Change the default frame rate (1500 f/s) to 2300 f/s
clemente 0:462017ee2a5b 114 */
clemente 0:462017ee2a5b 115 void ADNS2051::setframerate( void)
clemente 0:462017ee2a5b 116 {
clemente 0:462017ee2a5b 117 // write to the lower reg first.
clemente 0:462017ee2a5b 118 // the values are 2's compl hex for 2300 f/s (DS pag:38)
clemente 0:462017ee2a5b 119 write( FRMPRDLW_REG, 0x6E);
clemente 0:462017ee2a5b 120 write( FRMPRDUP_REG, 0xE1);
clemente 0:462017ee2a5b 121 }
clemente 0:462017ee2a5b 122
clemente 0:462017ee2a5b 123
clemente 0:462017ee2a5b 124 /** Return the SQUAL value.
clemente 0:462017ee2a5b 125 *
clemente 0:462017ee2a5b 126 * SQUAL is a measure of the number of features visible by the sensor in the
clemente 0:462017ee2a5b 127 * current frame. The maximum value is 255. Since small changes in the current frame
clemente 0:462017ee2a5b 128 * can result in changes in SQUAL, variations in SQUAL when looking at a surface are
clemente 0:462017ee2a5b 129 * expected. SQUAL is nearly equal to zero, if there is no surface below the sensor.
clemente 0:462017ee2a5b 130 */
clemente 0:462017ee2a5b 131 unsigned char ADNS2051::surfacequality( void)
clemente 0:462017ee2a5b 132 {
clemente 0:462017ee2a5b 133 return read( SQUAL_REG);
clemente 0:462017ee2a5b 134 }
clemente 0:462017ee2a5b 135
clemente 0:462017ee2a5b 136 /** Return the Average pixel value
clemente 0:462017ee2a5b 137 *
clemente 0:462017ee2a5b 138 * Average Pixel value in current frame. Minimum value = 0,
clemente 0:462017ee2a5b 139 * maximum = 63. The average pixel value can be adjusted every frame.
clemente 0:462017ee2a5b 140 */
clemente 0:462017ee2a5b 141 unsigned char ADNS2051::averagepixel( void)
clemente 0:462017ee2a5b 142 {
clemente 0:462017ee2a5b 143 return read( AVRPXL_REG);
clemente 0:462017ee2a5b 144 }
clemente 0:462017ee2a5b 145
clemente 0:462017ee2a5b 146 /** Return the Maximum Pixel value
clemente 0:462017ee2a5b 147 *
clemente 0:462017ee2a5b 148 * Maximum Pixel value in current frame. Minimum value = 0,
clemente 0:462017ee2a5b 149 * maximum value = 63. The maximum pixel value can be adjusted every frame.
clemente 0:462017ee2a5b 150 */
clemente 0:462017ee2a5b 151 unsigned char ADNS2051::maxpixelval( void)
clemente 0:462017ee2a5b 152 {
clemente 0:462017ee2a5b 153 return read( MAXPXL_REG);
clemente 0:462017ee2a5b 154 }
clemente 0:462017ee2a5b 155
clemente 0:462017ee2a5b 156
clemente 0:462017ee2a5b 157 /**
clemente 0:462017ee2a5b 158 * read the motion register and update the deltaX and deltaY variable with the register value
clemente 0:462017ee2a5b 159 *
clemente 0:462017ee2a5b 160 * @return :
clemente 0:462017ee2a5b 161 * value 0 => no motion, no led fault, no overflow
clemente 0:462017ee2a5b 162 * bit 0 == 1 => motion
clemente 0:462017ee2a5b 163 * bit 1 == 1 => led fault
clemente 0:462017ee2a5b 164 * bit 3 == 1 => overflow
clemente 0:462017ee2a5b 165 */
clemente 0:462017ee2a5b 166 unsigned char ADNS2051::readmotion( void)
clemente 0:462017ee2a5b 167 {
clemente 0:462017ee2a5b 168 unsigned char status;
clemente 0:462017ee2a5b 169 unsigned char res=0; // no motion, no LED fault...
clemente 0:462017ee2a5b 170
clemente 0:462017ee2a5b 171 // Avago RECOMMENDS that registers 0x02, 0x03 and 0x04 be read sequentially
clemente 0:462017ee2a5b 172 status = read( MOTION_REG);
clemente 0:462017ee2a5b 173 deltaX = read( DELTAX_REG);
clemente 0:462017ee2a5b 174 deltaY = read( DELTAY_REG);
clemente 0:462017ee2a5b 175
clemente 0:462017ee2a5b 176 //
clemente 0:462017ee2a5b 177 if ( status & (1<<OVERFY_BIT) || status & (1<<OVERFX_BIT) ) {
clemente 0:462017ee2a5b 178 res|=4;
clemente 0:462017ee2a5b 179 }
clemente 0:462017ee2a5b 180 //
clemente 0:462017ee2a5b 181 if ( status & (1<<RESOLUTION_BIT) )
clemente 0:462017ee2a5b 182 currentresolution=800;
clemente 0:462017ee2a5b 183 else
clemente 0:462017ee2a5b 184 currentresolution=400;
clemente 0:462017ee2a5b 185 //
clemente 0:462017ee2a5b 186 if ( status & (1<<MOTION_BIT) )
clemente 0:462017ee2a5b 187 res|=1;
clemente 0:462017ee2a5b 188 if ( status & (1<<LEDFAULT_BIT) )
clemente 0:462017ee2a5b 189 res|=2;
clemente 0:462017ee2a5b 190
clemente 0:462017ee2a5b 191 return( res);
clemente 0:462017ee2a5b 192 }
clemente 0:462017ee2a5b 193
clemente 0:462017ee2a5b 194 /*
clemente 0:462017ee2a5b 195 Start the dump of the pixel map. Store the value to the array pixmap
clemente 0:462017ee2a5b 196 */
clemente 0:462017ee2a5b 197 void ADNS2051::pixeldump( unsigned char *buffer)
clemente 0:462017ee2a5b 198 {
clemente 0:462017ee2a5b 199
clemente 0:462017ee2a5b 200 unsigned char res;
clemente 0:462017ee2a5b 201 unsigned char i;
clemente 0:462017ee2a5b 202
clemente 0:462017ee2a5b 203 // set no sleep and start pixdump
clemente 0:462017ee2a5b 204 write( CONFIGBIT_REG, 0x00 | (1<<SLEEP_BIT) | (1<<PIXDUMP_BIT));
clemente 0:462017ee2a5b 205
clemente 0:462017ee2a5b 206 i=0;
clemente 0:462017ee2a5b 207 while( 1) {
clemente 0:462017ee2a5b 208 // read the pix address...
clemente 0:462017ee2a5b 209 res=read( DTOUTUP_REG);
clemente 0:462017ee2a5b 210 // read the pix value
clemente 0:462017ee2a5b 211 res=read( DTOUTLW_REG);
clemente 0:462017ee2a5b 212 // if the MSB is set: no valid data...
clemente 0:462017ee2a5b 213 if ( res & (1<<PIXDATAVALID_BIT))
clemente 0:462017ee2a5b 214 continue;
clemente 0:462017ee2a5b 215 // store the pix value
clemente 0:462017ee2a5b 216 buffer[i++]=res;
clemente 0:462017ee2a5b 217 // check if the pixel counter overflow...
clemente 0:462017ee2a5b 218 if ( i==0)
clemente 0:462017ee2a5b 219 break;
clemente 0:462017ee2a5b 220 }
clemente 0:462017ee2a5b 221
clemente 0:462017ee2a5b 222 // reset PixDump bit.
clemente 0:462017ee2a5b 223 write( CONFIGBIT_REG, 0x00);
clemente 0:462017ee2a5b 224
clemente 0:462017ee2a5b 225 }
clemente 0:462017ee2a5b 226
clemente 0:462017ee2a5b 227
clemente 0:462017ee2a5b 228 /*
clemente 0:462017ee2a5b 229 * Read a register from the ADNS2051 sensor.
clemente 0:462017ee2a5b 230 * Before to return wait 120us as required and set the IO pin as output.
clemente 0:462017ee2a5b 231 */
clemente 0:462017ee2a5b 232 unsigned char ADNS2051::read(unsigned char address)
clemente 0:462017ee2a5b 233 {
clemente 0:462017ee2a5b 234 unsigned char value;
clemente 0:462017ee2a5b 235 int bit_pos;
clemente 0:462017ee2a5b 236
clemente 0:462017ee2a5b 237 SCLK_HIGH; // Set the clock high.
clemente 0:462017ee2a5b 238 address &= 0x7F; // A '0' as its MSB to indicate data direction as "READ".
clemente 0:462017ee2a5b 239
clemente 0:462017ee2a5b 240 /* Send the Address to the ADNS2051 */
clemente 0:462017ee2a5b 241 for( bit_pos=7; bit_pos >=0; bit_pos--){
clemente 0:462017ee2a5b 242 SCLK_LOW; // Set the clock LOW
clemente 0:462017ee2a5b 243
clemente 0:462017ee2a5b 244 // SDIO is changed on falling edges of SCLK
clemente 0:462017ee2a5b 245 if(address & (1<<bit_pos)){
clemente 0:462017ee2a5b 246 SOUT_HIGH;
clemente 0:462017ee2a5b 247 }
clemente 0:462017ee2a5b 248 else{
clemente 0:462017ee2a5b 249 SOUT_LOW;
clemente 0:462017ee2a5b 250 }
clemente 0:462017ee2a5b 251 //
clemente 0:462017ee2a5b 252 wait_us( CLKSPEED);
clemente 0:462017ee2a5b 253 SCLK_HIGH;
clemente 0:462017ee2a5b 254 wait_us( CLKSPEED);
clemente 0:462017ee2a5b 255 }
clemente 0:462017ee2a5b 256 /*
clemente 0:462017ee2a5b 257 SCLK will need to be delayed after the last address data bit to ensure that
clemente 0:462017ee2a5b 258 the ADNS-2051 has at least 100 µs to prepare the requested data (DS pag.19)
clemente 0:462017ee2a5b 259 */
clemente 0:462017ee2a5b 260 wait_us(120);
clemente 0:462017ee2a5b 261 // Change the sout to input...
clemente 0:462017ee2a5b 262 _sout.input();
clemente 0:462017ee2a5b 263 _sout.mode( PullUp);
clemente 0:462017ee2a5b 264
clemente 0:462017ee2a5b 265 /* Read the data byte from the ADNS2051 */
clemente 0:462017ee2a5b 266 value=0;
clemente 0:462017ee2a5b 267 for( bit_pos=7; bit_pos >= 0; bit_pos--){
clemente 0:462017ee2a5b 268 SCLK_LOW;
clemente 0:462017ee2a5b 269 wait_us( CLKSPEED);
clemente 0:462017ee2a5b 270 SCLK_HIGH; // data is ready on rising edge of clock signal.
clemente 0:462017ee2a5b 271 wait_us( CLKSPEED);
clemente 0:462017ee2a5b 272 /* read the input pin */
clemente 0:462017ee2a5b 273 if ( _sout)
clemente 0:462017ee2a5b 274 value |= (1<<bit_pos);
clemente 0:462017ee2a5b 275
clemente 0:462017ee2a5b 276 }
clemente 0:462017ee2a5b 277 //
clemente 0:462017ee2a5b 278 _sout.output();
clemente 0:462017ee2a5b 279 // Timing between read and either write or subsequent read commands must be >120us
clemente 0:462017ee2a5b 280 wait_us( 120);
clemente 0:462017ee2a5b 281
clemente 0:462017ee2a5b 282 return value;
clemente 0:462017ee2a5b 283 }
clemente 0:462017ee2a5b 284
clemente 0:462017ee2a5b 285 void ADNS2051::write(unsigned char address, unsigned char value)
clemente 0:462017ee2a5b 286 {
clemente 0:462017ee2a5b 287 int bit_pos;
clemente 0:462017ee2a5b 288
clemente 0:462017ee2a5b 289 SCLK_HIGH; // Set the clock high.
clemente 0:462017ee2a5b 290 address |= 0x80; // A '1' as its MSB to indicate data direction as "WRITE".
clemente 0:462017ee2a5b 291
clemente 0:462017ee2a5b 292 /* Send the Address to the ADNS2051 */
clemente 0:462017ee2a5b 293 for( bit_pos=7; bit_pos >=0; bit_pos--){
clemente 0:462017ee2a5b 294 SCLK_LOW; // Set the clock LOW
clemente 0:462017ee2a5b 295
clemente 0:462017ee2a5b 296 // SDIO is changed on falling edges of SCLK
clemente 0:462017ee2a5b 297 if(address & (1<<bit_pos)){
clemente 0:462017ee2a5b 298 SOUT_HIGH;
clemente 0:462017ee2a5b 299 }
clemente 0:462017ee2a5b 300 else{
clemente 0:462017ee2a5b 301 SOUT_LOW;
clemente 0:462017ee2a5b 302 }
clemente 0:462017ee2a5b 303 //
clemente 0:462017ee2a5b 304 wait_us( CLKSPEED);
clemente 0:462017ee2a5b 305 SCLK_HIGH;
clemente 0:462017ee2a5b 306 wait_us( CLKSPEED);
clemente 0:462017ee2a5b 307 }
clemente 0:462017ee2a5b 308
clemente 0:462017ee2a5b 309 /* Send the value to the ADNS2051 */
clemente 0:462017ee2a5b 310 for( bit_pos=7; bit_pos >=0; bit_pos--){
clemente 0:462017ee2a5b 311 SCLK_LOW; // Set the clock LOW
clemente 0:462017ee2a5b 312
clemente 0:462017ee2a5b 313 // SDIO is changed on falling edges of SCLK
clemente 0:462017ee2a5b 314 if(value & (1<<bit_pos)){
clemente 0:462017ee2a5b 315 SOUT_HIGH;
clemente 0:462017ee2a5b 316 }
clemente 0:462017ee2a5b 317 else{
clemente 0:462017ee2a5b 318 SOUT_LOW;
clemente 0:462017ee2a5b 319 }
clemente 0:462017ee2a5b 320 //
clemente 0:462017ee2a5b 321 wait_us( CLKSPEED);
clemente 0:462017ee2a5b 322 SCLK_HIGH;
clemente 0:462017ee2a5b 323 wait_us( CLKSPEED);
clemente 0:462017ee2a5b 324 }
clemente 0:462017ee2a5b 325 // Timing between read and either write or subsequent read commands must be >120us
clemente 0:462017ee2a5b 326 wait_us( 120);
clemente 0:462017ee2a5b 327
clemente 0:462017ee2a5b 328 }