/* * AP_OpticalFlow_ADNS3080.cpp - ADNS3080 OpticalFlow Library for Ardupilot Mega * Code by Randy Mackay. DIYDrones.com * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * External ADNS3080 OpticalFlow is connected via Serial port 2 (in SPI mode) * TXD2 = MOSI = pin PH1 * RXD2 = MISO = pin PH0 * XCK2 = SCK = pin PH2 * Chip Select pin is PC4 (33) [PH6 (9)] * We are using the 16 clocks per conversion timming to increase efficiency (fast) * The sampling frequency is 400Hz (Timer2 overflow interrupt) * So if our loop is at 50Hz, our needed sampling freq should be 100Hz, so * we have an 4x oversampling and averaging. * * Methods: * Init() : Initialization of interrupts an Timers (Timer2 overflow interrupt) * Read() : Read latest values from OpticalFlow and store to x,y, surface_quality parameters * */ #include "AP_OpticalFlow_ADNS3080.h" #include "SPI.h" #if defined(ARDUINO) && ARDUINO >= 100 #include "Arduino.h" #else #include "WProgram.h" #endif #define AP_SPI_TIMEOUT 1000 // We use Serial Port 2 in SPI Mode #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) #define AP_SPI_DATAIN 15 // MISO #define AP_SPI_DATAOUT 14 // MOSI #define AP_SPI_CLOCK PJ2 // SCK #else // normal arduino SPI pins...these need to be checked # error Please check the Tools/Board menu to ensure you have selected Arduino Mega as your target. #endif // mask for saving bit order and data mode to avoid interference with other users of the bus #define UCSR3C_MASK 0x07 // SPI3 setting for UCSR3C #define SPI3_MODE_SPI 0xC0 // UMSEL31 = 1, UMSEL30 = 1 // settings for phase and polarity bits of UCSR3C #define SPI3_MODE_MASK 0x03 #define SPI3_MODE0 0x00 #define SPI3_MODE1 0x01 #define SPI3_MODE2 0x02 #define SPI3_MODE3 0x03 #define SPI3_MODE SPI3_MODE3 // settings for phase and polarity bits of UCSR3C #define SPI3_ORDER_MASK 0x04 #define SPI3_MSBFIRST 0x00 #define SPI3_LSBFIRST 0x04 #define SPI3_SPEED 0x04 // 2 megahertz? #define SPI3_DELAY 20 // delay in microseconds after sending data union NumericIntType { int intValue; unsigned int uintValue; byte byteValue[2]; }; // Constructors //////////////////////////////////////////////////////////////// AP_OpticalFlow_ADNS3080_APM2::AP_OpticalFlow_ADNS3080_APM2(int cs_pin, int reset_pin) : _cs_pin(cs_pin), _reset_pin(reset_pin) { num_pixels = ADNS3080_PIXELS_X; field_of_view = AP_OPTICALFLOW_ADNS3080_08_FOV; scaler = AP_OPTICALFLOW_ADNS3080_SCALER; } // SPI Methods // *** INTERNAL FUNCTIONS *** unsigned char AP_OpticalFlow_ADNS3080_APM2::SPI_transfer(uint8_t data) { /* Wait for empty transmit buffer */ while ( !( UCSR3A & (1< 0 ); } // set_led_always_on - set parameter to true if you want LED always on, otherwise false for only when required void AP_OpticalFlow_ADNS3080_APM2::set_led_always_on( bool alwaysOn ) { byte regVal = read_register(ADNS3080_CONFIGURATION_BITS); regVal = (regVal & 0xbf) | (alwaysOn << 6); delayMicroseconds(SPI3_DELAY); // small delay write_register(ADNS3080_CONFIGURATION_BITS, regVal); } // returns resolution (either 400 or 1600 counts per inch) int AP_OpticalFlow_ADNS3080_APM2::get_resolution() { if( (read_register(ADNS3080_CONFIGURATION_BITS) & 0x10) == 0 ) return 400; else return 1600; } // set parameter to 400 or 1600 counts per inch void AP_OpticalFlow_ADNS3080_APM2::set_resolution(int resolution) { byte regVal = read_register(ADNS3080_CONFIGURATION_BITS); if( resolution == ADNS3080_RESOLUTION_400 ) { regVal &= ~0x10; scaler = AP_OPTICALFLOW_ADNS3080_SCALER; }else if( resolution == ADNS3080_RESOLUTION_1600) { regVal |= 0x10; scaler = AP_OPTICALFLOW_ADNS3080_SCALER * 4; } delayMicroseconds(SPI3_DELAY); // small delay write_register(ADNS3080_CONFIGURATION_BITS, regVal); // this will affect conversion factors so update them update_conversion_factors(); } // get_frame_rate_auto - return whether frame rate is set to "auto" or manual bool AP_OpticalFlow_ADNS3080_APM2::get_frame_rate_auto() { byte regVal = read_register(ADNS3080_EXTENDED_CONFIG); if( (regVal & 0x01) != 0 ) { return false; }else{ return true; } } // set_frame_rate_auto - set frame rate to auto (true) or manual (false) void AP_OpticalFlow_ADNS3080_APM2::set_frame_rate_auto(bool auto_frame_rate) { byte regVal = read_register(ADNS3080_EXTENDED_CONFIG); delayMicroseconds(SPI3_DELAY); // small delay if( auto_frame_rate == true ) { // set specific frame period write_register(ADNS3080_FRAME_PERIOD_MAX_BOUND_LOWER,0xE0); delayMicroseconds(SPI3_DELAY); // small delay write_register(ADNS3080_FRAME_PERIOD_MAX_BOUND_UPPER,0x1A); delayMicroseconds(SPI3_DELAY); // small delay // decide what value to update in extended config regVal = (regVal & ~0x01); }else{ // decide what value to update in extended config regVal = (regVal & ~0x01) | 0x01; } write_register(ADNS3080_EXTENDED_CONFIG, regVal); } // get frame period unsigned int AP_OpticalFlow_ADNS3080_APM2::get_frame_period() { NumericIntType aNum; aNum.byteValue[1] = read_register(ADNS3080_FRAME_PERIOD_UPPER); delayMicroseconds(SPI3_DELAY); // small delay aNum.byteValue[0] = read_register(ADNS3080_FRAME_PERIOD_LOWER); return aNum.uintValue; } // set frame period void AP_OpticalFlow_ADNS3080_APM2::set_frame_period(unsigned int period) { NumericIntType aNum; aNum.uintValue = period; // set frame rate to manual set_frame_rate_auto(false); delayMicroseconds(SPI3_DELAY); // small delay // set specific frame period write_register(ADNS3080_FRAME_PERIOD_MAX_BOUND_LOWER,aNum.byteValue[0]); delayMicroseconds(SPI3_DELAY); // small delay write_register(ADNS3080_FRAME_PERIOD_MAX_BOUND_UPPER,aNum.byteValue[1]); } unsigned int AP_OpticalFlow_ADNS3080_APM2::get_frame_rate() { unsigned long clockSpeed = ADNS3080_CLOCK_SPEED; unsigned int rate = clockSpeed / get_frame_period(); return rate; } void AP_OpticalFlow_ADNS3080_APM2::set_frame_rate(unsigned int rate) { unsigned long clockSpeed = ADNS3080_CLOCK_SPEED; unsigned int period = (unsigned int)(clockSpeed / (unsigned long)rate); set_frame_period(period); } // get_shutter_speed_auto - returns true if shutter speed is adjusted automatically, false if manual bool AP_OpticalFlow_ADNS3080_APM2::get_shutter_speed_auto() { byte regVal = read_register(ADNS3080_EXTENDED_CONFIG); if( (regVal & 0x02) > 0 ) { return false; }else{ return true; } } // set_shutter_speed_auto - set shutter speed to auto (true), or manual (false) void AP_OpticalFlow_ADNS3080_APM2::set_shutter_speed_auto(bool auto_shutter_speed) { byte regVal = read_register(ADNS3080_EXTENDED_CONFIG); delayMicroseconds(SPI3_DELAY); // small delay if( auto_shutter_speed ) { // return shutter speed max to default write_register(ADNS3080_SHUTTER_MAX_BOUND_LOWER,0x8c); delayMicroseconds(SPI3_DELAY); // small delay write_register(ADNS3080_SHUTTER_MAX_BOUND_UPPER,0x20); delayMicroseconds(SPI3_DELAY); // small delay // determine value to put into extended config regVal &= ~0x02; }else{ // determine value to put into extended config regVal |= 0x02; } write_register(ADNS3080_EXTENDED_CONFIG, regVal); delayMicroseconds(SPI3_DELAY); // small delay } // get_shutter_speed_auto - returns true if shutter speed is adjusted automatically, false if manual unsigned int AP_OpticalFlow_ADNS3080_APM2::get_shutter_speed() { NumericIntType aNum; aNum.byteValue[1] = read_register(ADNS3080_SHUTTER_UPPER); delayMicroseconds(SPI3_DELAY); // small delay aNum.byteValue[0] = read_register(ADNS3080_SHUTTER_LOWER); return aNum.uintValue; } // set_shutter_speed_auto - set shutter speed to auto (true), or manual (false) void AP_OpticalFlow_ADNS3080_APM2::set_shutter_speed(unsigned int shutter_speed) { NumericIntType aNum; aNum.uintValue = shutter_speed; // set shutter speed to manual set_shutter_speed_auto(false); delayMicroseconds(SPI3_DELAY); // small delay // set specific shutter speed write_register(ADNS3080_SHUTTER_MAX_BOUND_LOWER,aNum.byteValue[0]); delayMicroseconds(SPI3_DELAY); // small delay write_register(ADNS3080_SHUTTER_MAX_BOUND_UPPER,aNum.byteValue[1]); delayMicroseconds(SPI3_DELAY); // small delay // larger delay delay(50); // need to update frame period to cause shutter value to take effect aNum.byteValue[1] = read_register(ADNS3080_FRAME_PERIOD_UPPER); delayMicroseconds(SPI3_DELAY); // small delay aNum.byteValue[0] = read_register(ADNS3080_FRAME_PERIOD_LOWER); delayMicroseconds(SPI3_DELAY); // small delay write_register(ADNS3080_FRAME_PERIOD_MAX_BOUND_LOWER,aNum.byteValue[0]); delayMicroseconds(SPI3_DELAY); // small delay write_register(ADNS3080_FRAME_PERIOD_MAX_BOUND_UPPER,aNum.byteValue[1]); delayMicroseconds(SPI3_DELAY); // small delay } // clear_motion - will cause the Delta_X, Delta_Y, and internal motion registers to be cleared void AP_OpticalFlow_ADNS3080_APM2::clear_motion() { write_register(ADNS3080_MOTION_CLEAR,0xFF); // writing anything to this register will clear the sensor's motion registers x = 0; y = 0; dx = 0; dy = 0; _motion = false; } // get_pixel_data - captures an image from the sensor and stores it to the pixe_data array void AP_OpticalFlow_ADNS3080_APM2::print_pixel_data(Stream *serPort) { int i,j; bool isFirstPixel = true; byte regValue; byte pixelValue; // write to frame capture register to force capture of frame write_register(ADNS3080_FRAME_CAPTURE,0x83); // wait 3 frame periods + 10 nanoseconds for frame to be captured delayMicroseconds(1510); // min frame speed is 2000 frames/second so 1 frame = 500 nano seconds. so 500 x 3 + 10 = 1510 // display the pixel data for( i=0; iprintln("failed to find first pixel"); } isFirstPixel = false; pixelValue = ( regValue << 2); serPort->print(pixelValue,DEC); if( j!= ADNS3080_PIXELS_X-1 ) serPort->print(","); delayMicroseconds(SPI3_DELAY); } serPort->println(); } // hardware reset to restore sensor to normal operation reset(); }